Skip to content

Commit 4902e9c

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

File tree

3 files changed

+129
-6
lines changed

3 files changed

+129
-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: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"time"
9+
10+
"github.com/mndrix/tap-go"
11+
rspecs "github.com/opencontainers/runtime-spec/specs-go"
12+
"github.com/opencontainers/runtime-tools/specerror"
13+
"github.com/opencontainers/runtime-tools/validation/util"
14+
uuid "github.com/satori/go.uuid"
15+
)
16+
17+
func main() {
18+
t := tap.New()
19+
t.Header(0)
20+
21+
bundleDir, err := util.PrepareBundle()
22+
if err != nil {
23+
util.Fatal(err)
24+
}
25+
defer os.RemoveAll(bundleDir)
26+
27+
containerID := uuid.NewV4().String()
28+
29+
r, err := util.NewRuntime(util.RuntimeCommand, bundleDir)
30+
if err != nil {
31+
util.Fatal(err)
32+
}
33+
g := util.GetDefaultGenerator()
34+
g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")})
35+
r.SetConfig(g)
36+
output := filepath.Join(bundleDir, g.Spec().Root.Path, "output")
37+
38+
// start without id
39+
err = r.Start()
40+
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)
41+
42+
// set id for the remaining tests
43+
r.SetID(containerID)
44+
45+
// start a not `created` container - case one: non-exist container
46+
err = r.Start()
47+
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)
48+
49+
err = r.Create()
50+
if err != nil {
51+
util.Fatal(err)
52+
}
53+
// start a `created` container
54+
err = r.Start()
55+
if err != nil {
56+
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)
57+
} else {
58+
err := util.WaitingForStatus(r, util.LifecycleStatusStopped, time.Second*10, time.Second*1)
59+
if err != nil {
60+
util.Fatal(err)
61+
}
62+
outputData, outputErr := ioutil.ReadFile(output)
63+
// check the output
64+
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)
65+
}
66+
67+
// start a not `created` container - case two: exist and `stopped`
68+
err = r.Start()
69+
// must generate an error
70+
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)
71+
72+
err = util.WaitingForStatus(r, util.LifecycleStatusStopped, time.Second*10, time.Second*1)
73+
if err != nil {
74+
util.Fatal(err)
75+
}
76+
77+
outputData, outputErr := ioutil.ReadFile(output)
78+
// must have no effect, it will not be something like 'process called\nprocess called\n'
79+
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)
80+
81+
err = r.Delete()
82+
if err != nil {
83+
util.Fatal(err)
84+
}
85+
86+
g.Spec().Process = nil
87+
r.SetConfig(g)
88+
err = r.Create()
89+
if err != nil {
90+
util.Fatal(err)
91+
}
92+
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+
103+
t.AutoPlan()
104+
}

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)