Skip to content

Commit f8b01bf

Browse files
milantracygvisor-bot
authored andcommitted
Add tests for running docker compose in gVisor sandbox.
PiperOrigin-RevId: 795255502
1 parent 305c56d commit f8b01bf

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

test/image/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ go_test(
2828
"//pkg/test/dockerutil",
2929
"//pkg/test/testutil",
3030
"@com_github_docker_docker//api/types/mount:go_default_library",
31+
"@in_gopkg_yaml_v3//:go_default_library",
3132
],
3233
)
3334

test/image/image_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"time"
3535

3636
"github.com/docker/docker/api/types/mount"
37+
yaml "gopkg.in/yaml.v3"
3738
"gvisor.dev/gvisor/pkg/test/dockerutil"
3839
"gvisor.dev/gvisor/pkg/test/testutil"
3940
)
@@ -411,6 +412,23 @@ type dockerCommandOptions struct {
411412
privileged bool
412413
}
413414

415+
type dockerComposeConfig struct {
416+
Name string `yaml:"name,omitempty"`
417+
Services map[string]dockerService `yaml:"services,omitempty"`
418+
}
419+
420+
type dockerService struct {
421+
Image string `yaml:"image,omitempty"`
422+
Build dockerBuild `yaml:"build,omitempty"`
423+
Privileged bool `yaml:"privileged,omitempty"`
424+
NetworkdMode string `yaml:"network_mode,omitempty"`
425+
}
426+
427+
type dockerBuild struct {
428+
Context string `yaml:"context,omitempty"`
429+
Network string `yaml:"network,omitempty"`
430+
}
431+
414432
func testDockerMatrix(ctx context.Context, t *testing.T, d *dockerutil.Container) {
415433
definitions := []struct {
416434
name string
@@ -421,6 +439,8 @@ func testDockerMatrix(ctx context.Context, t *testing.T, d *dockerutil.Container
421439
{"docker_run", testDockerRun, true, true},
422440
{"docker_build", testDockerBuild, true, false},
423441
{"docker_exec", testDockerExec, false, true},
442+
{"docker_compose_run", testDockerComposeRun, true, true},
443+
{"docker_compose_build", testDockerComposeBuild, true, false},
424444
}
425445
for _, def := range definitions {
426446
hostNetworkOpts := []bool{false}
@@ -653,6 +673,101 @@ func testDockerExec(ctx context.Context, t *testing.T, d *dockerutil.Container,
653673
}
654674
}
655675

676+
func testDockerComposeBuild(ctx context.Context, t *testing.T, d *dockerutil.Container, opts dockerCommandOptions) {
677+
dockerComposeFileName := strings.ToLower(strings.ReplaceAll(testutil.RandomID("docker-compose-build"), "/", "-"))
678+
// Letters in image name must be lowercase.
679+
imageName := strings.ToLower(strings.ReplaceAll(testutil.RandomID("testdockercomposebuild"), "/", "-"))
680+
network := ""
681+
if opts.hostNetwork {
682+
network = "host"
683+
}
684+
config := dockerComposeConfig{
685+
Name: "image_test",
686+
Services: map[string]dockerService{
687+
imageName: dockerService{
688+
Image: imageName,
689+
Build: dockerBuild{
690+
Context: ".",
691+
Network: network,
692+
},
693+
},
694+
},
695+
}
696+
buildConfig, err := yaml.Marshal(config)
697+
if err != nil {
698+
log.Fatalf("error marshaling to docker-compose.yml: %v", err)
699+
}
700+
dockerfileContent := fmt.Sprintf("\"FROM %s\nRUN apk add curl\"", testAlpineImage)
701+
cmd := []string{"echo", dockerfileContent, ">", "Dockerfile"}
702+
_, err = d.ExecProcess(ctx, dockerutil.ExecOpts{},
703+
"/bin/sh", "-c", strings.Join(cmd, " "))
704+
if err != nil {
705+
t.Fatalf("failed to write Dockerfile: %v", err)
706+
}
707+
cmd = []string{"echo", fmt.Sprintf("\"%s\"", string(buildConfig)), ">", dockerComposeFileName}
708+
// Write a config file for docker compose.
709+
_, err = d.ExecProcess(ctx, dockerutil.ExecOpts{},
710+
"/bin/sh", "-c", strings.Join(cmd, " "))
711+
if err != nil {
712+
t.Fatalf("failed to write docker-compose.yml: %v", err)
713+
}
714+
_, err = d.ExecProcess(ctx, dockerutil.ExecOpts{}, "/bin/sh", "-c", fmt.Sprintf("docker compose -f %s build", dockerComposeFileName))
715+
if err != nil {
716+
t.Fatalf("docker compose build failed: %v", err)
717+
}
718+
defer removeDockerImage(ctx, imageName, d)
719+
d.WaitForOutput(ctx, fmt.Sprintf("%s Built", imageName), defaultWait)
720+
if err := checkDockerImage(ctx, imageName, d); err != nil {
721+
t.Fatalf("failed to find docker image: %v", err)
722+
}
723+
}
724+
725+
func testDockerComposeRun(ctx context.Context, t *testing.T, d *dockerutil.Container, opts dockerCommandOptions) {
726+
dockerComposeAppName := strings.ToLower(strings.ReplaceAll(testutil.RandomID("docker-compose-run-test-app"), "/", "-"))
727+
dockerComposeFileName := strings.ToLower(strings.ReplaceAll(testutil.RandomID("docker-compose-run"), "/", "-"))
728+
networkMode := ""
729+
// TODO(b/436936268): test bridge network driver in docker compose run.
730+
// The option now has no impact since the test command doesn't attempt to connect to internet.
731+
if opts.hostNetwork {
732+
networkMode = "host"
733+
}
734+
config := dockerComposeConfig{
735+
Name: "image_test",
736+
Services: map[string]dockerService{
737+
dockerComposeAppName: dockerService{
738+
Image: testAlpineImage,
739+
Privileged: opts.privileged,
740+
NetworkdMode: networkMode,
741+
},
742+
},
743+
}
744+
dockerComposeContent, err := yaml.Marshal(config)
745+
if err != nil {
746+
log.Fatalf("error marshaling to docker-compose.yml: %v", err)
747+
}
748+
cmd := []string{"echo", fmt.Sprintf("\"%s\"", string(dockerComposeContent)), ">", dockerComposeFileName}
749+
_, err = d.ExecProcess(
750+
ctx,
751+
dockerutil.ExecOpts{},
752+
"/bin/sh", "-c", strings.Join(cmd, " "))
753+
if err != nil {
754+
t.Fatalf("failed to write %s: %v", dockerComposeFileName, err)
755+
}
756+
execProc, err := d.ExecProcess(ctx, dockerutil.ExecOpts{},
757+
[]string{"docker", "compose", "-f", dockerComposeFileName, "run", "--rm", dockerComposeAppName, "sh", "-c", "echo hello gVisor"}...)
758+
if err != nil {
759+
t.Fatalf("docker compose run failed: %v", err)
760+
}
761+
output, err := execProc.Logs()
762+
if err != nil {
763+
t.Fatalf("docker logs failed: %v", err)
764+
}
765+
expectedOutput := "hello gVisor"
766+
if !strings.Contains(output, expectedOutput) {
767+
t.Fatalf("docker didn't get output expected: %q, got: %q", expectedOutput, output)
768+
}
769+
}
770+
656771
func TestMain(m *testing.M) {
657772
dockerutil.EnsureSupportedDockerVersion()
658773
flag.Parse()

0 commit comments

Comments
 (0)