Skip to content

Commit 1e58d4f

Browse files
committed
feat(tests): enhance sideContainers to support multi-containers tests
1 parent 3c2a37f commit 1e58d4f

11 files changed

Lines changed: 1396 additions & 1184 deletions

File tree

tests/e2e/common.go

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,26 @@ type containerVolume struct {
5252
Dest string
5353
}
5454

55+
type sideContainerNetMode string
56+
57+
const (
58+
// sideContainerNetModeNetwork joins the same named/user-defined
59+
// network as the primary container (docker/nerdctl --network <name>).
60+
sideContainerNetModeNetwork sideContainerNetMode = "network"
61+
// sideContainerNetModeShared joins the primary container's network
62+
// namespace directly, similar to containers sharing a namespace
63+
// inside a Kubernetes pod (docker/nerdctl --network container:<id>).
64+
sideContainerNetModeShared sideContainerNetMode = "shared"
65+
)
66+
67+
type sideContainer struct {
68+
Name string
69+
Image string
70+
Cli string
71+
Volumes []containerVolume
72+
NetMode sideContainerNetMode
73+
}
74+
5575
type containerTestArgs struct {
5676
Name string
5777
Image string
@@ -63,8 +83,9 @@ type containerTestArgs struct {
6383
Memory string
6484
Cli string
6585
Volumes []containerVolume
86+
Network string
6687
StaticNet bool
67-
SideContainers []string
88+
SideContainers []sideContainer
6889
Skippable bool
6990
TestFunc testMethod
7091
ExpectOut string
@@ -90,6 +111,9 @@ func commonNewContainerCmd(a containerTestArgs) string {
90111
if a.Memory != "" {
91112
cmdBase += fmt.Sprintf("-m %s ", a.Memory)
92113
}
114+
if a.Network != "" {
115+
cmdBase += fmt.Sprintf("--network %s ", a.Network)
116+
}
93117
if a.UID != 0 && a.GID != 0 {
94118
cmdBase += fmt.Sprintf("-u %d:%d ", a.UID, a.GID)
95119
}
@@ -136,6 +160,72 @@ func commonCmdExecStderr(command string) (string, string, error) {
136160
return output, errorOut, err
137161
}
138162

163+
func commonSideContainerCmd(sc sideContainer, netArg string) string {
164+
cmdBase := ""
165+
if netArg != "" {
166+
cmdBase += fmt.Sprintf("--network %s ", netArg)
167+
}
168+
for _, vol := range sc.Volumes {
169+
cmdBase += fmt.Sprintf("--mount type=bind,src=%s,dst=%s ", vol.Source, vol.Dest)
170+
}
171+
cmdBase += "--name "
172+
cmdBase += sc.Name + " "
173+
cmdBase += sc.Image + " "
174+
cmdBase += sc.Cli
175+
return cmdBase
176+
}
177+
178+
func commonRunSideContainer(tool string, sc sideContainer, netArg string) (output string, err error) {
179+
cmdBase := tool + " run -d "
180+
cmdBase += commonSideContainerCmd(sc, netArg)
181+
return commonCmdExec(cmdBase)
182+
}
183+
184+
// commonStartSideContainers starts every side container defined and
185+
// joining each one of them int the primary container's network per its NetMode,
186+
// and returns their container IDs for later cleanup.
187+
func commonStartSideContainers(tool string, a containerTestArgs, primaryID string) ([]string, error) {
188+
var ids []string
189+
for _, sc := range a.SideContainers {
190+
var netArg string
191+
switch sc.NetMode {
192+
case sideContainerNetModeNetwork:
193+
// a.Network may be "": docker/nerdctl both attach a
194+
// container to the default "bridge" network when
195+
// --network is omitted.
196+
netArg = a.Network
197+
case sideContainerNetModeShared:
198+
netArg = "container:" + primaryID
199+
default:
200+
return ids, fmt.Errorf("side container %s has unknown network mode %q", sc.Name, sc.NetMode)
201+
}
202+
cID, err := commonRunSideContainer(tool, sc, netArg)
203+
if err != nil {
204+
return ids, fmt.Errorf("failed to start side container %s: %s -- %v", sc.Name, cID, err)
205+
}
206+
ids = append(ids, cID)
207+
}
208+
return ids, nil
209+
}
210+
211+
func commonStopSideContainers(tool string, ids []string) error {
212+
for _, cID := range ids {
213+
if _, err := commonStopContainer(tool, cID); err != nil {
214+
return fmt.Errorf("failed to stop side container %s: %v", cID, err)
215+
}
216+
}
217+
return nil
218+
}
219+
220+
func commonRmSideContainers(tool string, ids []string) error {
221+
for _, cID := range ids {
222+
if _, err := commonRmContainer(tool, cID); err != nil {
223+
return fmt.Errorf("failed to remove side container %s: %v", cID, err)
224+
}
225+
}
226+
return nil
227+
}
228+
139229
func commonPull(tool string, image string) error {
140230
pullCmd := tool + " image pull " + image
141231

tests/e2e/crictl.go

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ const podConfigFilename = "pod.json"
3030
const cntrConfigFilename = "container.json"
3131

3232
type crictlInfo struct {
33-
testArgs containerTestArgs
34-
podID string
35-
containerID string
33+
testArgs containerTestArgs
34+
podID string
35+
containerID string
36+
sideContainerIDs []string
3637
}
3738

3839
func newCrictlTool(args containerTestArgs) *crictlInfo {
@@ -133,6 +134,39 @@ func crictlNewContainerConfig(path string, a containerTestArgs) (string, error)
133134
return absContConf, nil
134135
}
135136

137+
// crictlNewSideContainerConfig writes a container config for a side container,
138+
// named after it so multiple side containers don't collide on disk.
139+
func crictlNewSideContainerConfig(path string, sc sideContainer) (string, error) {
140+
var mounts []*criruntimeapi.Mount
141+
for _, vol := range sc.Volumes {
142+
mounts = append(mounts, &criruntimeapi.Mount{
143+
ContainerPath: vol.Dest,
144+
HostPath: vol.Source,
145+
Readonly: false,
146+
})
147+
}
148+
containerConfig := criruntimeapi.ContainerConfig{
149+
Metadata: &criruntimeapi.ContainerMetadata{
150+
Name: sc.Name,
151+
},
152+
Image: &criruntimeapi.ImageSpec{
153+
Image: sc.Image,
154+
},
155+
Command: strings.Fields(sc.Cli),
156+
Mounts: mounts,
157+
}
158+
cc, err := json.MarshalIndent(&containerConfig, "", " ")
159+
if err != nil {
160+
return "", fmt.Errorf("Failed to marshal side container config: %v", err)
161+
}
162+
absConf := filepath.Join(path, sc.Name+".json")
163+
err = writeToFile(absConf, string(cc))
164+
if err != nil {
165+
return "", fmt.Errorf("Failed to write side container config: %v", err)
166+
}
167+
return absConf, nil
168+
}
169+
136170
func (i *crictlInfo) Name() string {
137171
return crictlName
138172
}
@@ -201,14 +235,56 @@ func (i *crictlInfo) createContainer() (string, error) {
201235
return commonCmdExec(cmdBase)
202236
}
203237

238+
// startSideContainers starts every side container declared on the test
239+
// case as an extra container in the SAME pod as the primary container.
240+
func (i *crictlInfo) startSideContainers() error {
241+
if len(i.testArgs.SideContainers) == 0 {
242+
return nil
243+
}
244+
245+
cwd, err := os.Getwd()
246+
if err != nil {
247+
return fmt.Errorf("Failed to get CWD to write side container configs: %v", err)
248+
}
249+
absPodConf := filepath.Join(cwd, podConfigFilename)
250+
251+
for _, sc := range i.testArgs.SideContainers {
252+
if sc.NetMode != sideContainerNetModeShared {
253+
return fmt.Errorf("crictl does not support side container network mode %q: crictl has no named/user-defined network, only pod-shared networking (sideContainerNetModeShared)", sc.NetMode)
254+
}
255+
256+
absSideConf, err := crictlNewSideContainerConfig(cwd, sc)
257+
if err != nil {
258+
return err
259+
}
260+
261+
cmdBase := crictlName + " create " + i.podID + " " + absSideConf + " " + absPodConf
262+
cID, err := commonCmdExec(cmdBase)
263+
if err != nil {
264+
return fmt.Errorf("failed to create side container %s: %s -- %v", sc.Name, cID, err)
265+
}
266+
if output, err := commonCmdExec(crictlName + " start " + cID); err != nil {
267+
return fmt.Errorf("failed to start side container %s: %s -- %v", sc.Name, output, err)
268+
}
269+
i.sideContainerIDs = append(i.sideContainerIDs, cID)
270+
}
271+
return nil
272+
}
273+
204274
func (i *crictlInfo) startContainer(bool) (string, error) {
275+
if err := i.startSideContainers(); err != nil {
276+
return "", err
277+
}
205278
cmdBase := crictlName
206279
cmdBase += " start "
207280
cmdBase += i.containerID
208281
return commonCmdExec(cmdBase)
209282
}
210283

211284
func (i *crictlInfo) runContainer(bool) (string, error) {
285+
if err := i.startSideContainers(); err != nil {
286+
return "", err
287+
}
212288
cwd, err := os.Getwd()
213289
if err != nil {
214290
return "", fmt.Errorf("Failed to get CWD to write Container/Pod config: %v", err)
@@ -234,6 +310,10 @@ func (i *crictlInfo) runContainer(bool) (string, error) {
234310
}
235311

236312
func (i *crictlInfo) stopContainer() error {
313+
if err := commonStopSideContainers(crictlName, i.sideContainerIDs); err != nil {
314+
return err
315+
}
316+
237317
output, err := commonStopContainer(crictlName, i.containerID)
238318
err = checkExpectedOut(i.containerID, output, err)
239319
if err != nil {
@@ -257,6 +337,10 @@ func (i *crictlInfo) stopPod() error {
257337
}
258338

259339
func (i *crictlInfo) rmContainer() error {
340+
if err := commonRmSideContainers(crictlName, i.sideContainerIDs); err != nil {
341+
return err
342+
}
343+
260344
output, err := commonRmContainer(crictlName, i.containerID)
261345
err = checkExpectedOut(i.containerID, output, err)
262346
if err != nil {
@@ -272,6 +356,13 @@ func (i *crictlInfo) rmContainer() error {
272356
if err != nil {
273357
return fmt.Errorf("Could not remove container config file: %v", err)
274358
}
359+
360+
for _, sc := range i.testArgs.SideContainers {
361+
absSideConf := filepath.Join(cwd, sc.Name+".json")
362+
if err := os.Remove(absSideConf); err != nil {
363+
return fmt.Errorf("Could not remove side container %s config file: %v", sc.Name, err)
364+
}
365+
}
275366
return nil
276367
}
277368

tests/e2e/crictl_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ var _ = Describe("Crictl", Ordered, ContinueOnFailure, func() {
6666
}
6767
})
6868

69+
if len(tc.SideContainers) > 0 {
70+
runDetachedSideContainerTest(tool, tc)
71+
return
72+
}
6973
runDetachedTest(tool, tc)
7074
},
7175
toTableEntries(crictlTestCases()),

tests/e2e/ctr.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,28 @@ func (i *ctrInfo) startPod() (string, error) {
103103
return "", errToolDoesNotSupport
104104
}
105105

106+
func (i *ctrInfo) startSideContainers() error {
107+
if len(i.testArgs.SideContainers) == 0 {
108+
return nil
109+
}
110+
// Not supported by ctr
111+
return errToolDoesNotSupport
112+
}
113+
106114
func (i *ctrInfo) startContainer(detach bool) (string, error) {
115+
if err := i.startSideContainers(); err != nil {
116+
return "", err
117+
}
107118
if detach {
108119
i.detached = true
109120
}
110121
return commonStart(ctrName+" t", i.containerID, detach)
111122
}
112123

113124
func (i *ctrInfo) runContainer(detach bool) (string, error) {
125+
if err := i.startSideContainers(); err != nil {
126+
return "", err
127+
}
114128
cmdBase := ctrName
115129
cmdBase += " run "
116130
if detach {

tests/e2e/docker.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import (
2121
const dockerName = "docker"
2222

2323
type dockerInfo struct {
24-
testArgs containerTestArgs
25-
containerID string
24+
testArgs containerTestArgs
25+
containerID string
26+
sideContainerIDs []string
2627
}
2728

2829
func newDockerTool(args containerTestArgs) *dockerInfo {
@@ -73,14 +74,30 @@ func (i *dockerInfo) startPod() (string, error) {
7374
}
7475

7576
func (i *dockerInfo) startContainer(detach bool) (string, error) {
76-
return commonStart(dockerName, i.containerID, detach)
77+
output, err := commonStart(dockerName, i.containerID, detach)
78+
if err != nil {
79+
return output, err
80+
}
81+
if err := i.startSideContainers(); err != nil {
82+
return output, err
83+
}
84+
return output, nil
85+
}
86+
87+
func (i *dockerInfo) startSideContainers() error {
88+
ids, err := commonStartSideContainers(dockerName, i.testArgs, i.containerID)
89+
i.sideContainerIDs = ids
90+
return err
7791
}
7892

7993
func (i *dockerInfo) runContainer(detach bool) (string, error) {
8094
return commonRun(dockerName, i.testArgs, detach)
8195
}
8296

8397
func (i *dockerInfo) stopContainer() error {
98+
if err := commonStopSideContainers(dockerName, i.sideContainerIDs); err != nil {
99+
return err
100+
}
84101
output, err := commonStopContainer(dockerName, i.containerID)
85102
err = checkExpectedOut(i.containerID, output, err)
86103
if err != nil {
@@ -95,6 +112,9 @@ func (i *dockerInfo) stopPod() error {
95112
}
96113

97114
func (i *dockerInfo) rmContainer() error {
115+
if err := commonRmSideContainers(dockerName, i.sideContainerIDs); err != nil {
116+
return err
117+
}
98118
output, err := commonRmContainer(dockerName, i.containerID)
99119
err = checkExpectedOut(i.containerID, output, err)
100120
if err != nil {

tests/e2e/docker_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ var _ = Describe("Docker", Ordered, ContinueOnFailure, func() {
4747
func(tc containerTestArgs) {
4848
skipMissingVolumes(tc)
4949
tool = newDockerTool(tc)
50+
if len(tc.SideContainers) > 0 {
51+
runDetachedSideContainerTest(tool, tc)
52+
return
53+
}
5054
runDetachedTest(tool, tc)
5155
},
5256
toTableEntries(dockerTestCases()),

0 commit comments

Comments
 (0)