Skip to content

Commit 3ba4371

Browse files
committed
implement start operation tests
Signed-off-by: Liang Chenye <liangchenye@huawei.com>
1 parent 64e1103 commit 3ba4371

File tree

3 files changed

+141
-6
lines changed

3 files changed

+141
-6
lines changed

specerror/runtime.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ const (
6868
PropApplyFailNotCreate
6969
// StartWithoutIDGenError represents "`start` operation MUST generate an error if it is not provided the container ID."
7070
StartWithoutIDGenError
71-
// StartNonCreateHaveNoEffect represents "Attempting to `start` a container that is not `created` MUST have no effect on the container."
72-
StartNonCreateHaveNoEffect
73-
// StartNonCreateGenError represents "Attempting to `start` a container that is not `created` MUST generate an error."
74-
StartNonCreateGenError
71+
// StartNotCreatedHaveNoEffect represents "Attempting to `start` a container that is not `created` MUST have no effect on the container."
72+
StartNotCreatedHaveNoEffect
73+
// StartNotCreatedGenError represents "Attempting to `start` a container that is not `created` MUST generate an error."
74+
StartNotCreatedGenError
7575
// StartProcImplement represents "`start` operation MUST run the user-specified program as specified by `process`."
7676
StartProcImplement
7777
// StartWithProcUnsetGenError represents "`start` operation MUST generate an error if `process` was not set."
@@ -163,8 +163,8 @@ func init() {
163163
register(PropApplyFailGenError, rfc2119.Must, createRef)
164164
register(PropApplyFailNotCreate, rfc2119.Must, createRef)
165165
register(StartWithoutIDGenError, rfc2119.Must, startRef)
166-
register(StartNonCreateHaveNoEffect, rfc2119.Must, startRef)
167-
register(StartNonCreateGenError, rfc2119.Must, startRef)
166+
register(StartNotCreatedHaveNoEffect, rfc2119.Must, startRef)
167+
register(StartNotCreatedGenError, rfc2119.Must, startRef)
168168
register(StartProcImplement, rfc2119.Must, startRef)
169169
register(StartWithProcUnsetGenError, rfc2119.Must, startRef)
170170
register(KillWithoutIDGenError, rfc2119.Must, killRef)

validation/start.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
"time"
10+
11+
"github.com/mndrix/tap-go"
12+
rspecs "github.com/opencontainers/runtime-spec/specs-go"
13+
"github.com/opencontainers/runtime-tools/specerror"
14+
"github.com/opencontainers/runtime-tools/validation/util"
15+
uuid "github.com/satori/go.uuid"
16+
)
17+
18+
func main() {
19+
t := tap.New()
20+
t.Header(0)
21+
22+
bundleDir, err := util.PrepareBundle()
23+
if err != nil {
24+
util.Fatal(err)
25+
}
26+
defer os.RemoveAll(bundleDir)
27+
28+
containerID := uuid.NewV4().String()
29+
30+
r, err := util.NewRuntime(util.RuntimeCommand, bundleDir)
31+
if err != nil {
32+
util.Fatal(err)
33+
}
34+
g := util.GetDefaultGenerator()
35+
g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")})
36+
r.SetConfig(g)
37+
output := filepath.Join(bundleDir, g.Spec().Root.Path, "output")
38+
39+
// start without id
40+
err = r.Start()
41+
util.SpecErrorOK(t, err != nil, specerror.NewError(specerror.StartWithoutIDGenError, fmt.Errorf("start` operation MUST generate an error if it is not provided the container ID"), rspecs.Version), err)
42+
43+
// set id for the remaining tests
44+
r.SetID(containerID)
45+
46+
// start a not `created` container - case one: non-exist container
47+
err = r.Start()
48+
util.SpecErrorOK(t, err != nil, specerror.NewError(specerror.StartNotCreatedGenError, fmt.Errorf("attempting to `start` a container that is not `created` MUST generate an error"), rspecs.Version), err)
49+
50+
err = r.Create()
51+
if err != nil {
52+
util.Fatal(err)
53+
}
54+
// start a `created` container
55+
err = r.Start()
56+
if err != nil {
57+
util.SpecErrorOK(t, false, specerror.NewError(specerror.StartProcImplement, fmt.Errorf("`start` operation MUST run the user-specified program as specified by `process`"), rspecs.Version), err)
58+
} else {
59+
err := util.WaitingForStatus(r, util.LifecycleStatusStopped, time.Second*10, time.Second*1)
60+
if err != nil {
61+
util.Fatal(err)
62+
}
63+
outputData, outputErr := ioutil.ReadFile(output)
64+
// check the output
65+
util.SpecErrorOK(t, outputErr == nil && string(outputData) == "process called\n", specerror.NewError(specerror.StartProcImplement, fmt.Errorf("`start` operation MUST run the user-specified program as specified by `process`"), rspecs.Version), outputErr)
66+
}
67+
68+
// start a not `created` container - case two: exist and `stopped`
69+
err = r.Start()
70+
// must generate an error
71+
util.SpecErrorOK(t, err != nil, specerror.NewError(specerror.StartNotCreatedGenError, fmt.Errorf("attempting to `start` a container that is not `created` MUST generate an error"), rspecs.Version), err)
72+
73+
err = util.WaitingForStatus(r, util.LifecycleStatusStopped, time.Second*10, time.Second*1)
74+
if err != nil {
75+
util.Fatal(err)
76+
}
77+
78+
outputData, outputErr := ioutil.ReadFile(output)
79+
// must have no effect, it will not be something like 'process called\nprocess called\n'
80+
util.SpecErrorOK(t, outputErr == nil && string(outputData) == "process called\n", specerror.NewError(specerror.StartNotCreatedHaveNoEffect, fmt.Errorf("attempting to `start` a container that is not `created` MUST have no effect on the container"), rspecs.Version), outputErr)
81+
82+
err = r.Delete()
83+
if err != nil {
84+
util.Fatal(err)
85+
}
86+
87+
g.Spec().Process = nil
88+
r.SetConfig(g)
89+
err = r.Create()
90+
// 'create' could fail according to the spec when the process is nil
91+
// only do the test when a container is created
92+
if err == nil {
93+
err = r.Start()
94+
util.SpecErrorOK(t, err == nil, specerror.NewError(specerror.StartWithProcUnsetGenError, fmt.Errorf("`start` operation MUST generate an error if `process` was not set"), rspecs.Version), err)
95+
err = util.WaitingForStatus(r, util.LifecycleStatusStopped, time.Second*10, time.Second*1)
96+
if err == nil {
97+
err = r.Delete()
98+
}
99+
if err != nil {
100+
util.Fatal(err)
101+
}
102+
} else {
103+
diagnostic := map[string]string{
104+
"error": err.Error(),
105+
}
106+
if e, ok := err.(*exec.ExitError); ok {
107+
if len(e.Stderr) > 0 {
108+
diagnostic["stderr"] = string(e.Stderr)
109+
}
110+
}
111+
t.Skip(1, "`start` operation MUST generate an error if `process` was not set")
112+
t.YAML(diagnostic)
113+
}
114+
115+
t.AutoPlan()
116+
}

validation/util/test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/mrunalp/fileutils"
1515
rspec "github.com/opencontainers/runtime-spec/specs-go"
1616
"github.com/opencontainers/runtime-tools/generate"
17+
"github.com/opencontainers/runtime-tools/specerror"
1718
"github.com/satori/go.uuid"
1819
)
1920

@@ -102,6 +103,24 @@ func Skip(message string, diagnostic interface{}) {
102103
}
103104
}
104105

106+
// SpecErrorOK generates TAP output indicating whether a spec code test passed or failed.
107+
func SpecErrorOK(t *tap.T, expected bool, specErr error, detailedErr error) {
108+
t.Ok(expected, specErr.(*specerror.Error).Err.Err.Error())
109+
diagnostic := map[string]string{
110+
"reference": specErr.(*specerror.Error).Err.Reference,
111+
}
112+
113+
if detailedErr != nil {
114+
diagnostic["error"] = detailedErr.Error()
115+
if e, ok := detailedErr.(*exec.ExitError); ok {
116+
if len(e.Stderr) > 0 {
117+
diagnostic["stderr"] = string(e.Stderr)
118+
}
119+
}
120+
}
121+
t.YAML(diagnostic)
122+
}
123+
105124
// PrepareBundle creates a test bundle in a temporary directory.
106125
func PrepareBundle() (string, error) {
107126
bundleDir, err := ioutil.TempDir("", "ocitest")

0 commit comments

Comments
 (0)