e2e: fix subtests and block parallel unsafe tests

The big mechanical change here is to NOT store `t` as a field on
the `CLI` object (which has been renamed as well to fix the odd
capitalization). The way the tests are structured meant that the
"subtests" were using the _parent_ `*testing.T` instance, which
causes various oddities including confusing messages on failure
about a child test causing a panic in the parent.

Additionally, a few tests have been blocked from running in
parallel because they are sharing `compose.yaml` fixtures and
can fail as a result (e.g. due to a port conflict on the host).
I'll fix these in follow-up PRs but want to focus on correctness
for the tests before optimizing them.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
This commit is contained in:
Milas Bowman 2022-06-15 15:55:58 -04:00
parent 005fc25823
commit d9065050fd
22 changed files with 395 additions and 358 deletions

View File

@ -33,10 +33,10 @@ import (
) )
func TestComposeCancel(t *testing.T) { func TestComposeCancel(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("metrics on cancel Compose build", func(t *testing.T) { t.Run("metrics on cancel Compose build", func(t *testing.T) {
c.RunDockerComposeCmd("ls") c.RunDockerComposeCmd(t, "ls")
buildProjectPath := "fixtures/build-infinite/compose.yaml" buildProjectPath := "fixtures/build-infinite/compose.yaml"
// require a separate groupID from the process running tests, in order to simulate ctrl+C from a terminal. // require a separate groupID from the process running tests, in order to simulate ctrl+C from a terminal.
@ -44,19 +44,22 @@ func TestComposeCancel(t *testing.T) {
cmd, stdout, stderr, err := StartWithNewGroupID(c.NewDockerCmd("compose", "-f", buildProjectPath, "build", "--progress", "plain")) cmd, stdout, stderr, err := StartWithNewGroupID(c.NewDockerCmd("compose", "-f", buildProjectPath, "build", "--progress", "plain"))
assert.NilError(t, err) assert.NilError(t, err)
c.WaitForCondition(func() (bool, string) { c.WaitForCondition(t, func() (bool, string) {
out := stdout.String() out := stdout.String()
errors := stderr.String() errors := stderr.String()
return strings.Contains(out, "RUN sleep infinity"), fmt.Sprintf("'RUN sleep infinity' not found in : \n%s\nStderr: \n%s\n", out, errors) return strings.Contains(out,
"RUN sleep infinity"), fmt.Sprintf("'RUN sleep infinity' not found in : \n%s\nStderr: \n%s\n", out,
errors)
}, 30*time.Second, 1*time.Second) }, 30*time.Second, 1*time.Second)
err = syscall.Kill(-cmd.Process.Pid, syscall.SIGINT) // simulate Ctrl-C : send signal to processGroup, children will have same groupId by default err = syscall.Kill(-cmd.Process.Pid, syscall.SIGINT) // simulate Ctrl-C : send signal to processGroup, children will have same groupId by default
assert.NilError(t, err) assert.NilError(t, err)
c.WaitForCondition(func() (bool, string) { c.WaitForCondition(t, func() (bool, string) {
out := stdout.String() out := stdout.String()
errors := stderr.String() errors := stderr.String()
return strings.Contains(out, "CANCELED"), fmt.Sprintf("'CANCELED' not found in : \n%s\nStderr: \n%s\n", out, errors) return strings.Contains(out, "CANCELED"), fmt.Sprintf("'CANCELED' not found in : \n%s\nStderr: \n%s\n", out,
errors)
}, 10*time.Second, 1*time.Second) }, 10*time.Second, 1*time.Second)
}) })
} }

View File

@ -23,28 +23,28 @@ import (
) )
func TestCascadeStop(t *testing.T) { func TestCascadeStop(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-cascade-stop" const projectName = "e2e-cascade-stop"
t.Run("abort-on-container-exit", func(t *testing.T) { t.Run("abort-on-container-exit", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--abort-on-container-exit") res := c.RunDockerOrExitError(t, "compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--abort-on-container-exit")
res.Assert(t, icmd.Expected{ExitCode: 1, Out: `should_fail-1 exited with code 1`}) res.Assert(t, icmd.Expected{ExitCode: 1, Out: `should_fail-1 exited with code 1`})
res.Assert(t, icmd.Expected{ExitCode: 1, Out: `Aborting on container exit...`}) res.Assert(t, icmd.Expected{ExitCode: 1, Out: `Aborting on container exit...`})
}) })
t.Run("exit-code-from", func(t *testing.T) { t.Run("exit-code-from", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=sleep") res := c.RunDockerOrExitError(t, "compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=sleep")
res.Assert(t, icmd.Expected{ExitCode: 137, Out: `should_fail-1 exited with code 1`}) res.Assert(t, icmd.Expected{ExitCode: 137, Out: `should_fail-1 exited with code 1`})
res.Assert(t, icmd.Expected{ExitCode: 137, Out: `Aborting on container exit...`}) res.Assert(t, icmd.Expected{ExitCode: 137, Out: `Aborting on container exit...`})
}) })
t.Run("exit-code-from unknown", func(t *testing.T) { t.Run("exit-code-from unknown", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=unknown") res := c.RunDockerOrExitError(t, "compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=unknown")
res.Assert(t, icmd.Expected{ExitCode: 1, Err: `no such service: unknown`}) res.Assert(t, icmd.Expected{ExitCode: 1, Err: `no such service: unknown`})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }

View File

@ -28,55 +28,55 @@ import (
) )
func TestLocalComposeBuild(t *testing.T) { func TestLocalComposeBuild(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("build named and unnamed images", func(t *testing.T) { t.Run("build named and unnamed images", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "build-test_nginx") c.RunDockerOrExitError(t, "rmi", "build-test_nginx")
c.RunDockerOrExitError("rmi", "custom-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx")
res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "build") res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "build")
res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
c.RunDockerCmd("image", "inspect", "build-test_nginx") c.RunDockerCmd(t, "image", "inspect", "build-test_nginx")
c.RunDockerCmd("image", "inspect", "custom-nginx") c.RunDockerCmd(t, "image", "inspect", "custom-nginx")
}) })
t.Run("build with build-arg", func(t *testing.T) { t.Run("build with build-arg", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "build-test_nginx") c.RunDockerOrExitError(t, "rmi", "build-test_nginx")
c.RunDockerOrExitError("rmi", "custom-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx")
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO=BAR") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO=BAR")
res := c.RunDockerCmd("image", "inspect", "build-test_nginx") res := c.RunDockerCmd(t, "image", "inspect", "build-test_nginx")
res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`})
}) })
t.Run("build with build-arg set by env", func(t *testing.T) { t.Run("build with build-arg set by env", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "build-test_nginx") c.RunDockerOrExitError(t, "rmi", "build-test_nginx")
c.RunDockerOrExitError("rmi", "custom-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx")
icmd.RunCmd(c.NewDockerCmd("compose", "--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO"), icmd.RunCmd(c.NewDockerCmd("compose", "--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO"),
func(cmd *icmd.Cmd) { func(cmd *icmd.Cmd) {
cmd.Env = append(cmd.Env, "FOO=BAR") cmd.Env = append(cmd.Env, "FOO=BAR")
}) })
res := c.RunDockerCmd("image", "inspect", "build-test_nginx") res := c.RunDockerCmd(t, "image", "inspect", "build-test_nginx")
res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`})
}) })
t.Run("build with multiple build-args ", func(t *testing.T) { t.Run("build with multiple build-args ", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "-f", "multi-args_multiargs") c.RunDockerOrExitError(t, "rmi", "-f", "multi-args_multiargs")
cmd := c.NewDockerCmd("compose", "--project-directory", "fixtures/build-test/multi-args", "build") cmd := c.NewDockerCmd("compose", "--project-directory", "fixtures/build-test/multi-args", "build")
icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { icmd.RunCmd(cmd, func(cmd *icmd.Cmd) {
cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=0") cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=0")
}) })
res := c.RunDockerCmd("image", "inspect", "multi-args_multiargs") res := c.RunDockerCmd(t, "image", "inspect", "multi-args_multiargs")
res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`}) res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`})
}) })
@ -86,7 +86,7 @@ func TestLocalComposeBuild(t *testing.T) {
os.Unsetenv("SSH_AUTH_SOCK") //nolint:errcheck os.Unsetenv("SSH_AUTH_SOCK") //nolint:errcheck
defer os.Setenv("SSH_AUTH_SOCK", defaultSSHAUTHSOCK) //nolint:errcheck defer os.Setenv("SSH_AUTH_SOCK", defaultSSHAUTHSOCK) //nolint:errcheck
res := c.RunDockerComposeCmdNoCheck("--project-directory", "fixtures/build-test", "build", "--ssh", "") res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "")
res.Assert(t, icmd.Expected{ res.Assert(t, icmd.Expected{
ExitCode: 1, ExitCode: 1,
Err: "invalid empty ssh agent socket: make sure SSH_AUTH_SOCK is set", Err: "invalid empty ssh agent socket: make sure SSH_AUTH_SOCK is set",
@ -95,24 +95,24 @@ func TestLocalComposeBuild(t *testing.T) {
}) })
t.Run("build succeed with ssh from Compose file", func(t *testing.T) { t.Run("build succeed with ssh from Compose file", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh") c.RunDockerOrExitError(t, "rmi", "build-test-ssh")
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/ssh", "build") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/ssh", "build")
c.RunDockerCmd("image", "inspect", "build-test-ssh") c.RunDockerCmd(t, "image", "inspect", "build-test-ssh")
}) })
t.Run("build succeed with ssh from CLI", func(t *testing.T) { t.Run("build succeed with ssh from CLI", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh") c.RunDockerOrExitError(t, "rmi", "build-test-ssh")
c.RunDockerComposeCmd("-f", "fixtures/build-test/ssh/compose-without-ssh.yaml", "--project-directory", c.RunDockerComposeCmd(t, "-f", "fixtures/build-test/ssh/compose-without-ssh.yaml", "--project-directory",
"fixtures/build-test/ssh", "build", "--no-cache", "--ssh", "fake-ssh=./fixtures/build-test/ssh/fake_rsa") "fixtures/build-test/ssh", "build", "--no-cache", "--ssh", "fake-ssh=./fixtures/build-test/ssh/fake_rsa")
c.RunDockerCmd("image", "inspect", "build-test-ssh") c.RunDockerCmd(t, "image", "inspect", "build-test-ssh")
}) })
t.Run("build failed with wrong ssh key id from CLI", func(t *testing.T) { t.Run("build failed with wrong ssh key id from CLI", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh") c.RunDockerOrExitError(t, "rmi", "build-test-ssh")
res := c.RunDockerComposeCmdNoCheck("-f", "fixtures/build-test/ssh/compose-without-ssh.yaml", res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/build-test/ssh/compose-without-ssh.yaml",
"--project-directory", "fixtures/build-test/ssh", "build", "--no-cache", "--ssh", "--project-directory", "fixtures/build-test/ssh", "build", "--no-cache", "--ssh",
"wrong-ssh=./fixtures/build-test/ssh/fake_rsa") "wrong-ssh=./fixtures/build-test/ssh/fake_rsa")
res.Assert(t, icmd.Expected{ res.Assert(t, icmd.Expected{
@ -122,22 +122,22 @@ func TestLocalComposeBuild(t *testing.T) {
}) })
t.Run("build succeed as part of up with ssh from Compose file", func(t *testing.T) { t.Run("build succeed as part of up with ssh from Compose file", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test-ssh") c.RunDockerOrExitError(t, "rmi", "build-test-ssh")
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/ssh", "up", "-d", "--build") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/ssh", "up", "-d", "--build")
t.Cleanup(func() { t.Cleanup(func() {
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/ssh", "down") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/ssh", "down")
}) })
c.RunDockerCmd("image", "inspect", "build-test-ssh") c.RunDockerCmd(t, "image", "inspect", "build-test-ssh")
}) })
t.Run("build as part of up", func(t *testing.T) { t.Run("build as part of up", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "build-test_nginx") c.RunDockerOrExitError(t, "rmi", "build-test_nginx")
c.RunDockerOrExitError("rmi", "custom-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx")
res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "up", "-d") res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d")
t.Cleanup(func() { t.Cleanup(func() {
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "down") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down")
}) })
res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
@ -146,53 +146,53 @@ func TestLocalComposeBuild(t *testing.T) {
output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second) output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second)
assert.Assert(t, strings.Contains(output, "Hello from Nginx container")) assert.Assert(t, strings.Contains(output, "Hello from Nginx container"))
c.RunDockerCmd("image", "inspect", "build-test_nginx") c.RunDockerCmd(t, "image", "inspect", "build-test_nginx")
c.RunDockerCmd("image", "inspect", "custom-nginx") c.RunDockerCmd(t, "image", "inspect", "custom-nginx")
}) })
t.Run("no rebuild when up again", func(t *testing.T) { t.Run("no rebuild when up again", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "up", "-d") res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d")
assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout()) assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout())
}) })
t.Run("rebuild when up --build", func(t *testing.T) { t.Run("rebuild when up --build", func(t *testing.T) {
res := c.RunDockerComposeCmd("--workdir", "fixtures/build-test", "up", "-d", "--build") res := c.RunDockerComposeCmd(t, "--workdir", "fixtures/build-test", "up", "-d", "--build")
res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"})
}) })
t.Run("cleanup build project", func(t *testing.T) { t.Run("cleanup build project", func(t *testing.T) {
c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "down") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down")
c.RunDockerCmd("rmi", "build-test_nginx") c.RunDockerCmd(t, "rmi", "build-test_nginx")
c.RunDockerCmd("rmi", "custom-nginx") c.RunDockerCmd(t, "rmi", "custom-nginx")
}) })
} }
func TestBuildSecrets(t *testing.T) { func TestBuildSecrets(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("build with secrets", func(t *testing.T) { t.Run("build with secrets", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "build-test-secret") c.RunDockerOrExitError(t, "rmi", "build-test-secret")
res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test/secrets", "build") res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/secrets", "build")
res.Assert(t, icmd.Success) res.Assert(t, icmd.Success)
}) })
} }
func TestBuildTags(t *testing.T) { func TestBuildTags(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("build with tags", func(t *testing.T) { t.Run("build with tags", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "build-test-tags") c.RunDockerOrExitError(t, "rmi", "build-test-tags")
c.RunDockerComposeCmd("--project-directory", "./fixtures/build-test/tags", "build", "--no-cache") c.RunDockerComposeCmd(t, "--project-directory", "./fixtures/build-test/tags", "build", "--no-cache")
res := c.RunDockerCmd("image", "inspect", "build-test-tags") res := c.RunDockerCmd(t, "image", "inspect", "build-test-tags")
expectedOutput := `"RepoTags": [ expectedOutput := `"RepoTags": [
"docker/build-test-tags:1.0.0", "docker/build-test-tags:1.0.0",
"build-test-tags:latest", "build-test-tags:latest",

View File

@ -23,12 +23,12 @@ import (
) )
func TestDown(t *testing.T) { func TestDown(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-down" const projectName = "e2e-down"
t.Run("no resource to remove", func(t *testing.T) { t.Run("no resource to remove", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "--project-name", projectName, "down") res := c.RunDockerOrExitError(t, "compose", "--project-name", projectName, "down")
res.Assert(t, icmd.Expected{ExitCode: 0, Err: `No resource found to remove for project "e2e-down"`}) res.Assert(t, icmd.Expected{ExitCode: 0, Err: `No resource found to remove for project "e2e-down"`})
}) })
} }

View File

@ -26,13 +26,13 @@ import (
) )
func TestEnvPriority(t *testing.T) { func TestEnvPriority(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
projectDir := "./fixtures/environment/env-priority" projectDir := "./fixtures/environment/env-priority"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "env-compose-priority") c.RunDockerOrExitError(t, "rmi", "env-compose-priority")
c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose-with-env.yaml", c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml",
"--project-directory", projectDir, "up", "-d", "--build") "--project-directory", projectDir, "up", "-d", "--build")
}) })
@ -46,7 +46,7 @@ func TestEnvPriority(t *testing.T) {
os.Setenv("WHEREAMI", "shell") //nolint:errcheck os.Setenv("WHEREAMI", "shell") //nolint:errcheck
defer os.Unsetenv("WHEREAMI") //nolint:errcheck defer os.Unsetenv("WHEREAMI") //nolint:errcheck
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose-with-env.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml",
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override",
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority") "run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
@ -63,7 +63,7 @@ func TestEnvPriority(t *testing.T) {
os.Setenv("WHEREAMI", "shell") //nolint:errcheck os.Setenv("WHEREAMI", "shell") //nolint:errcheck
defer os.Unsetenv("WHEREAMI") //nolint:errcheck defer os.Unsetenv("WHEREAMI") //nolint:errcheck
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml",
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override",
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority") "run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell") assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell")
@ -76,9 +76,9 @@ func TestEnvPriority(t *testing.T) {
// 4. Dockerfile // 4. Dockerfile
// 5. Variable is not defined // 5. Variable is not defined
t.Run("shell priority from run command", func(t *testing.T) { t.Run("shell priority from run command", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory",
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e",
"run", "--rm", "-e", "WHEREAMI=shell-run", "env-compose-priority") "WHEREAMI=shell-run", "env-compose-priority")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell-run") assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell-run")
}) })
@ -89,9 +89,9 @@ func TestEnvPriority(t *testing.T) {
// 4. Dockerfile // 4. Dockerfile
// 5. Variable is not defined // 5. Variable is not defined
t.Run("override env file", func(t *testing.T) { t.Run("override env file", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory",
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e",
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority") "WHEREAMI", "env-compose-priority")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "override") assert.Equal(t, strings.TrimSpace(res.Stdout()), "override")
}) })
@ -102,8 +102,8 @@ func TestEnvPriority(t *testing.T) {
// 4. Dockerfile // 4. Dockerfile
// 5. Variable is not defined // 5. Variable is not defined
t.Run("env file", func(t *testing.T) { t.Run("env file", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory",
"--project-directory", projectDir, "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") projectDir, "run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "Env File") assert.Equal(t, strings.TrimSpace(res.Stdout()), "Env File")
}) })
@ -114,19 +114,19 @@ func TestEnvPriority(t *testing.T) {
// 4. Dockerfile <-- Result expected // 4. Dockerfile <-- Result expected
// 5. Variable is not defined // 5. Variable is not defined
t.Run("use Dockerfile", func(t *testing.T) { t.Run("use Dockerfile", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-priority/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory",
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.empty", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.empty", "run", "--rm", "-e", "WHEREAMI",
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority") "env-compose-priority")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "Dockerfile") assert.Equal(t, strings.TrimSpace(res.Stdout()), "Dockerfile")
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
c.RunDockerComposeCmd("--project-directory", projectDir, "down") c.RunDockerComposeCmd(t, "--project-directory", projectDir, "down")
}) })
} }
func TestEnvInterpolation(t *testing.T) { func TestEnvInterpolation(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
projectDir := "./fixtures/environment/env-interpolation" projectDir := "./fixtures/environment/env-interpolation"
@ -139,7 +139,7 @@ func TestEnvInterpolation(t *testing.T) {
t.Run("shell priority from run command", func(t *testing.T) { t.Run("shell priority from run command", func(t *testing.T) {
os.Setenv("WHEREAMI", "shell") //nolint:errcheck os.Setenv("WHEREAMI", "shell") //nolint:errcheck
defer os.Unsetenv("WHEREAMI") //nolint:errcheck defer os.Unsetenv("WHEREAMI") //nolint:errcheck
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-interpolation/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml",
"--project-directory", projectDir, "config") "--project-directory", projectDir, "config")
res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`}) res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`})
@ -147,23 +147,22 @@ func TestEnvInterpolation(t *testing.T) {
} }
func TestCommentsInEnvFile(t *testing.T) { func TestCommentsInEnvFile(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
projectDir := "./fixtures/environment/env-file-comments" projectDir := "./fixtures/environment/env-file-comments"
t.Run("comments in env files", func(t *testing.T) { t.Run("comments in env files", func(t *testing.T) {
c.RunDockerOrExitError("rmi", "env-file-comments") c.RunDockerOrExitError(t, "rmi", "env-file-comments")
c.RunDockerComposeCmd("-f", "./fixtures/environment/env-file-comments/compose.yaml", c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml", "--project-directory",
"--project-directory", projectDir, "up", "-d", "--build") projectDir, "up", "-d", "--build")
res := c.RunDockerComposeCmd("-f", "./fixtures/environment/env-file-comments/compose.yaml", res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml",
"--project-directory", projectDir, "run", "--rm", "--project-directory", projectDir, "run", "--rm", "-e", "COMMENT", "-e", "NO_COMMENT", "env-file-comments")
"-e", "COMMENT", "-e", "NO_COMMENT", "env-file-comments")
res.Assert(t, icmd.Expected{Out: `COMMENT=1234`}) res.Assert(t, icmd.Expected{Out: `COMMENT=1234`})
res.Assert(t, icmd.Expected{Out: `NO_COMMENT=1234#5`}) res.Assert(t, icmd.Expected{Out: `NO_COMMENT=1234#5`})
c.RunDockerComposeCmd("--project-directory", projectDir, "down", "--rmi", "all") c.RunDockerComposeCmd(t, "--project-directory", projectDir, "down", "--rmi", "all")
}) })
} }

View File

@ -25,19 +25,20 @@ import (
) )
func TestLocalComposeExec(t *testing.T) { func TestLocalComposeExec(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "compose-e2e-exec" const projectName = "compose-e2e-exec"
c.RunDockerComposeCmd("--project-directory", "fixtures/simple-composefile", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/simple-composefile", "--project-name", projectName, "up",
"-d")
t.Run("exec true", func(t *testing.T) { t.Run("exec true", func(t *testing.T) {
res := c.RunDockerOrExitError("exec", "compose-e2e-exec-simple-1", "/bin/true") res := c.RunDockerOrExitError(t, "exec", "compose-e2e-exec-simple-1", "/bin/true")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
}) })
t.Run("exec false", func(t *testing.T) { t.Run("exec false", func(t *testing.T) {
res := c.RunDockerOrExitError("exec", "compose-e2e-exec-simple-1", "/bin/false") res := c.RunDockerOrExitError(t, "exec", "compose-e2e-exec-simple-1", "/bin/false")
res.Assert(t, icmd.Expected{ExitCode: 1}) res.Assert(t, icmd.Expected{ExitCode: 1})
}) })
@ -50,7 +51,7 @@ func TestLocalComposeExec(t *testing.T) {
}) })
t.Run("exec without env set", func(t *testing.T) { t.Run("exec without env set", func(t *testing.T) {
res := c.RunDockerOrExitError("exec", "-e", "FOO", "compose-e2e-exec-simple-1", "/usr/bin/env") res := c.RunDockerOrExitError(t, "exec", "-e", "FOO", "compose-e2e-exec-simple-1", "/usr/bin/env")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
assert.Check(t, !strings.Contains(res.Stdout(), "FOO=")) assert.Check(t, !strings.Contains(res.Stdout(), "FOO="))
}) })

View File

@ -26,21 +26,22 @@ import (
) )
func TestLocalComposeRun(t *testing.T) { func TestLocalComposeRun(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("compose run", func(t *testing.T) { t.Run("compose run", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "back") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back")
lines := Lines(res.Stdout()) lines := Lines(res.Stdout())
assert.Equal(t, lines[len(lines)-1], "Hello there!!", res.Stdout()) assert.Equal(t, lines[len(lines)-1], "Hello there!!", res.Stdout())
assert.Assert(t, !strings.Contains(res.Combined(), "orphan")) assert.Assert(t, !strings.Contains(res.Combined(), "orphan"))
res = c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello one more time") res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo",
"Hello one more time")
lines = Lines(res.Stdout()) lines = Lines(res.Stdout())
assert.Equal(t, lines[len(lines)-1], "Hello one more time", res.Stdout()) assert.Equal(t, lines[len(lines)-1], "Hello one more time", res.Stdout())
assert.Assert(t, !strings.Contains(res.Combined(), "orphan")) assert.Assert(t, !strings.Contains(res.Combined(), "orphan"))
}) })
t.Run("check run container exited", func(t *testing.T) { t.Run("check run container exited", func(t *testing.T) {
res := c.RunDockerCmd("ps", "--all") res := c.RunDockerCmd(t, "ps", "--all")
lines := Lines(res.Stdout()) lines := Lines(res.Stdout())
var runContainerID string var runContainerID string
var truncatedSlug string var truncatedSlug string
@ -59,7 +60,7 @@ func TestLocalComposeRun(t *testing.T) {
} }
} }
assert.Assert(t, runContainerID != "") assert.Assert(t, runContainerID != "")
res = c.RunDockerCmd("inspect", runContainerID) res = c.RunDockerCmd(t, "inspect", runContainerID)
res.Assert(t, icmd.Expected{Out: ` "Status": "exited"`}) res.Assert(t, icmd.Expected{Out: ` "Status": "exited"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "run-test"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "run-test"`})
@ -68,40 +69,43 @@ func TestLocalComposeRun(t *testing.T) {
}) })
t.Run("compose run --rm", func(t *testing.T) { t.Run("compose run --rm", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "--rm", "back", "echo", "Hello again") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--rm", "back", "echo",
"Hello again")
lines := Lines(res.Stdout()) lines := Lines(res.Stdout())
assert.Equal(t, lines[len(lines)-1], "Hello again", res.Stdout()) assert.Equal(t, lines[len(lines)-1], "Hello again", res.Stdout())
res = c.RunDockerCmd("ps", "--all") res = c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout()) assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout())
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "down") c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "down")
res := c.RunDockerCmd("ps", "--all") res := c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout()) assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout())
}) })
t.Run("compose run --volumes", func(t *testing.T) { t.Run("compose run --volumes", func(t *testing.T) {
wd, err := os.Getwd() wd, err := os.Getwd()
assert.NilError(t, err) assert.NilError(t, err)
res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "--volumes", wd+":/foo", "back", "/bin/sh", "-c", "ls /foo") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--volumes", wd+":/foo",
"back", "/bin/sh", "-c", "ls /foo")
res.Assert(t, icmd.Expected{Out: "compose_run_test.go"}) res.Assert(t, icmd.Expected{Out: "compose_run_test.go"})
res = c.RunDockerCmd("ps", "--all") res = c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout()) assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout())
}) })
t.Run("compose run --publish", func(t *testing.T) { t.Run("compose run --publish", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "--publish", "8081:80", "-d", "back", "/bin/sh", "-c", "sleep 1") c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--publish", "8081:80", "-d", "back",
res := c.RunDockerCmd("ps") "/bin/sh", "-c", "sleep 1")
res := c.RunDockerCmd(t, "ps")
assert.Assert(t, strings.Contains(res.Stdout(), "8081->80/tcp"), res.Stdout()) assert.Assert(t, strings.Contains(res.Stdout(), "8081->80/tcp"), res.Stdout())
}) })
t.Run("compose run orphan", func(t *testing.T) { t.Run("compose run orphan", func(t *testing.T) {
// Use different compose files to get an orphan container // Use different compose files to get an orphan container
c.RunDockerComposeCmd("-f", "./fixtures/run-test/orphan.yaml", "run", "simple") c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/orphan.yaml", "run", "simple")
res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello")
assert.Assert(t, strings.Contains(res.Combined(), "orphan")) assert.Assert(t, strings.Contains(res.Combined(), "orphan"))
cmd := c.NewDockerCmd("compose", "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello") cmd := c.NewDockerCmd("compose", "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello")
@ -112,21 +116,21 @@ func TestLocalComposeRun(t *testing.T) {
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "down") c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "down")
c.RunDockerComposeCmd("-f", "./fixtures/run-test/orphan.yaml", "down") c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/orphan.yaml", "down")
res := c.RunDockerCmd("ps", "--all") res := c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout()) assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout())
}) })
t.Run("run starts only container and dependencies", func(t *testing.T) { t.Run("run starts only container and dependencies", func(t *testing.T) {
// ensure that even if another service is up run does not start it: https://github.com/docker/compose/issues/9459 // ensure that even if another service is up run does not start it: https://github.com/docker/compose/issues/9459
res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/deps.yaml", "up", "service_b") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/deps.yaml", "up", "service_b")
res.Assert(t, icmd.Success) res.Assert(t, icmd.Success)
res = c.RunDockerComposeCmd("-f", "./fixtures/run-test/deps.yaml", "run", "service_a") res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/deps.yaml", "run", "service_a")
assert.Assert(t, strings.Contains(res.Combined(), "shared_dep"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "shared_dep"), res.Combined())
assert.Assert(t, !strings.Contains(res.Combined(), "service_b"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "service_b"), res.Combined())
c.RunDockerComposeCmd("-f", "./fixtures/run-test/deps.yaml", "down", "--remove-orphans") c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/deps.yaml", "down", "--remove-orphans")
}) })
} }

View File

@ -31,31 +31,30 @@ import (
"gotest.tools/v3/icmd" "gotest.tools/v3/icmd"
) )
var binDir string
func TestLocalComposeUp(t *testing.T) { func TestLocalComposeUp(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) // this test shares a fixture with TestCompatibility and can't run at the same time
c := NewCLI(t)
const projectName = "compose-e2e-demo" const projectName = "compose-e2e-demo"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/sentences/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "--project-name", projectName, "up", "-d")
}) })
t.Run("check accessing running app", func(t *testing.T) { t.Run("check accessing running app", func(t *testing.T) {
res := c.RunDockerComposeCmd("-p", projectName, "ps") res := c.RunDockerComposeCmd(t, "-p", projectName, "ps")
res.Assert(t, icmd.Expected{Out: `web`}) res.Assert(t, icmd.Expected{Out: `web`})
endpoint := "http://localhost:90" endpoint := "http://localhost:90"
output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second) output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second)
assert.Assert(t, strings.Contains(output, `"word":`)) assert.Assert(t, strings.Contains(output, `"word":`))
res = c.RunDockerCmd("network", "ls") res = c.RunDockerCmd(t, "network", "ls")
res.Assert(t, icmd.Expected{Out: projectName + "_default"}) res.Assert(t, icmd.Expected{Out: projectName + "_default"})
}) })
t.Run("top", func(t *testing.T) { t.Run("top", func(t *testing.T) {
res := c.RunDockerComposeCmd("-p", projectName, "top") res := c.RunDockerComposeCmd(t, "-p", projectName, "top")
output := res.Stdout() output := res.Stdout()
head := []string{"UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"} head := []string{"UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"}
for _, h := range head { for _, h := range head {
@ -66,7 +65,7 @@ func TestLocalComposeUp(t *testing.T) {
}) })
t.Run("check compose labels", func(t *testing.T) { t.Run("check compose labels", func(t *testing.T) {
res := c.RunDockerCmd("inspect", projectName+"-web-1") res := c.RunDockerCmd(t, "inspect", projectName+"-web-1")
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "compose-e2e-demo"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "compose-e2e-demo"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.oneoff": "False",`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.oneoff": "False",`})
@ -76,55 +75,55 @@ func TestLocalComposeUp(t *testing.T) {
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.service": "web"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.service": "web"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version":`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version":`})
res = c.RunDockerCmd("network", "inspect", projectName+"_default") res = c.RunDockerCmd(t, "network", "inspect", projectName+"_default")
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.network": "default"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.network": "default"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": `}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": `})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version": `}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version": `})
}) })
t.Run("check user labels", func(t *testing.T) { t.Run("check user labels", func(t *testing.T) {
res := c.RunDockerCmd("inspect", projectName+"-web-1") res := c.RunDockerCmd(t, "inspect", projectName+"-web-1")
res.Assert(t, icmd.Expected{Out: `"my-label": "test"`}) res.Assert(t, icmd.Expected{Out: `"my-label": "test"`})
}) })
t.Run("check healthcheck output", func(t *testing.T) { t.Run("check healthcheck output", func(t *testing.T) {
c.WaitForCmdResult(c.NewDockerCmd("compose", "-p", projectName, "ps", "--format", "json"), c.WaitForCmdResult(t, c.NewDockerCmd("compose", "-p", projectName, "ps", "--format", "json"),
StdoutContains(`"Name":"compose-e2e-demo-web-1","Command":"/dispatcher","Project":"compose-e2e-demo","Service":"web","State":"running","Health":"healthy"`), StdoutContains(`"Name":"compose-e2e-demo-web-1","Command":"/dispatcher","Project":"compose-e2e-demo","Service":"web","State":"running","Health":"healthy"`),
5*time.Second, 1*time.Second) 5*time.Second, 1*time.Second)
res := c.RunDockerComposeCmd("-p", projectName, "ps") res := c.RunDockerComposeCmd(t, "-p", projectName, "ps")
res.Assert(t, icmd.Expected{Out: `NAME COMMAND SERVICE STATUS PORTS`}) res.Assert(t, icmd.Expected{Out: `NAME COMMAND SERVICE STATUS PORTS`})
res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 "/dispatcher" web running (healthy) 0.0.0.0:90->80/tcp`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 "/dispatcher" web running (healthy) 0.0.0.0:90->80/tcp`})
res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-db-1 "docker-entrypoint.s…" db running 5432/tcp`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-db-1 "docker-entrypoint.s…" db running 5432/tcp`})
}) })
t.Run("images", func(t *testing.T) { t.Run("images", func(t *testing.T) {
res := c.RunDockerComposeCmd("-p", projectName, "images") res := c.RunDockerComposeCmd(t, "-p", projectName, "images")
res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-db-1 gtardif/sentences-db latest`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-db-1 gtardif/sentences-db latest`})
res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 gtardif/sentences-web latest`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 gtardif/sentences-web latest`})
res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-words-1 gtardif/sentences-api latest`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-words-1 gtardif/sentences-api latest`})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
t.Run("check containers after down", func(t *testing.T) { t.Run("check containers after down", func(t *testing.T) {
res := c.RunDockerCmd("ps", "--all") res := c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined())
}) })
t.Run("check networks after down", func(t *testing.T) { t.Run("check networks after down", func(t *testing.T) {
res := c.RunDockerCmd("network", "ls") res := c.RunDockerCmd(t, "network", "ls")
assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined())
}) })
} }
func TestComposePull(t *testing.T) { func TestComposePull(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
res := c.RunDockerOrExitError("compose", "--project-directory", "fixtures/simple-composefile", "pull") res := c.RunDockerOrExitError(t, "compose", "--project-directory", "fixtures/simple-composefile", "pull")
output := res.Combined() output := res.Combined()
assert.Assert(t, strings.Contains(output, "simple Pulled")) assert.Assert(t, strings.Contains(output, "simple Pulled"))
@ -132,102 +131,108 @@ func TestComposePull(t *testing.T) {
} }
func TestDownComposefileInParentFolder(t *testing.T) { func TestDownComposefileInParentFolder(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
tmpFolder, err := ioutil.TempDir("fixtures/simple-composefile", "test-tmp") tmpFolder, err := ioutil.TempDir("fixtures/simple-composefile", "test-tmp")
assert.NilError(t, err) assert.NilError(t, err)
defer os.Remove(tmpFolder) // nolint: errcheck defer os.Remove(tmpFolder) // nolint: errcheck
projectName := filepath.Base(tmpFolder) projectName := filepath.Base(tmpFolder)
res := c.RunDockerComposeCmd("--project-directory", tmpFolder, "up", "-d") res := c.RunDockerComposeCmd(t, "--project-directory", tmpFolder, "up", "-d")
res.Assert(t, icmd.Expected{Err: "Started", ExitCode: 0}) res.Assert(t, icmd.Expected{Err: "Started", ExitCode: 0})
res = c.RunDockerComposeCmd("-p", projectName, "down") res = c.RunDockerComposeCmd(t, "-p", projectName, "down")
res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0}) res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0})
} }
func TestAttachRestart(t *testing.T) { func TestAttachRestart(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
cmd := c.NewDockerCmd("compose", "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up") cmd := c.NewDockerCmd("compose", "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up")
res := icmd.StartCmd(cmd) res := icmd.StartCmd(cmd)
defer c.RunDockerOrExitError("compose", "-p", "attach-restart", "down") defer c.RunDockerOrExitError(t, "compose", "-p", "attach-restart", "down")
c.WaitForCondition(func() (bool, string) { c.WaitForCondition(t, func() (bool, string) {
debug := res.Combined() debug := res.Combined()
return strings.Count(res.Stdout(), "failing-1 exited with code 1") == 3, fmt.Sprintf("'failing-1 exited with code 1' not found 3 times in : \n%s\n", debug) return strings.Count(res.Stdout(),
"failing-1 exited with code 1") == 3, fmt.Sprintf("'failing-1 exited with code 1' not found 3 times in : \n%s\n",
debug)
}, 2*time.Minute, 2*time.Second) }, 2*time.Minute, 2*time.Second)
assert.Equal(t, strings.Count(res.Stdout(), "failing-1 | world"), 3, res.Combined()) assert.Equal(t, strings.Count(res.Stdout(), "failing-1 | world"), 3, res.Combined())
} }
func TestInitContainer(t *testing.T) { func TestInitContainer(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
res := c.RunDockerOrExitError("compose", "--ansi=never", "--project-directory", "./fixtures/init-container", "up") res := c.RunDockerOrExitError(t, "compose", "--ansi=never", "--project-directory", "./fixtures/init-container", "up")
defer c.RunDockerOrExitError("compose", "-p", "init-container", "down") defer c.RunDockerOrExitError(t, "compose", "-p", "init-container", "down")
testify.Regexp(t, "foo-1 | hello(?m:.*)bar-1 | world", res.Stdout()) testify.Regexp(t, "foo-1 | hello(?m:.*)bar-1 | world", res.Stdout())
} }
func TestRm(t *testing.T) { func TestRm(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "compose-e2e-rm" const projectName = "compose-e2e-rm"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "up", "-d")
}) })
t.Run("rm -sf", func(t *testing.T) { t.Run("rm -sf", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm", "-sf", "simple") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm",
"-sf", "simple")
res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0}) res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0})
}) })
t.Run("check containers after rm -sf", func(t *testing.T) { t.Run("check containers after rm -sf", func(t *testing.T) {
res := c.RunDockerCmd("ps", "--all") res := c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, !strings.Contains(res.Combined(), projectName+"_simple"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), projectName+"_simple"), res.Combined())
}) })
t.Run("rm -sf <none>", func(t *testing.T) { t.Run("rm -sf <none>", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm", "-sf", "simple") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm",
"-sf", "simple")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
c.RunDockerComposeCmd("-p", projectName, "down") c.RunDockerComposeCmd(t, "-p", projectName, "down")
}) })
} }
func TestCompatibility(t *testing.T) { func TestCompatibility(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) // this test shares a fixture with TestLocalComposeUp and can't run at the same time
c := NewCLI(t)
const projectName = "compose-e2e-compatibility" const projectName = "compose-e2e-compatibility"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("--compatibility", "-f", "./fixtures/sentences/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "--compatibility", "-f", "./fixtures/sentences/compose.yaml", "--project-name",
projectName, "up", "-d")
}) })
t.Run("check container names", func(t *testing.T) { t.Run("check container names", func(t *testing.T) {
res := c.RunDockerCmd("ps", "--format", "{{.Names}}") res := c.RunDockerCmd(t, "ps", "--format", "{{.Names}}")
res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_web_1"}) res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_web_1"})
res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_words_1"}) res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_words_1"})
res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_db_1"}) res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_db_1"})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
c.RunDockerComposeCmd("-p", projectName, "down") c.RunDockerComposeCmd(t, "-p", projectName, "down")
}) })
} }
func TestConvert(t *testing.T) { func TestConvert(t *testing.T) {
const projectName = "compose-e2e-convert" const projectName = "compose-e2e-convert"
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
wd, err := os.Getwd() wd, err := os.Getwd()
assert.NilError(t, err) assert.NilError(t, err)
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/simple-build-test/compose.yaml", "-p", projectName, "convert") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-build-test/compose.yaml", "-p", projectName, "convert")
res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`services: res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`services:
nginx: nginx:
build: build:

View File

@ -26,12 +26,12 @@ import (
) )
func TestCopy(t *testing.T) { func TestCopy(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "copy_e2e" const projectName = "copy_e2e"
t.Cleanup(func() { t.Cleanup(func() {
c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "down") c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "down")
os.Remove("./fixtures/cp-test/from-default.txt") //nolint:errcheck os.Remove("./fixtures/cp-test/from-default.txt") //nolint:errcheck
os.Remove("./fixtures/cp-test/from-indexed.txt") //nolint:errcheck os.Remove("./fixtures/cp-test/from-indexed.txt") //nolint:errcheck
@ -39,41 +39,45 @@ func TestCopy(t *testing.T) {
}) })
t.Run("start service", func(t *testing.T) { t.Run("start service", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "up", "--scale", "nginx=5", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "up",
"--scale", "nginx=5", "-d")
}) })
t.Run("make sure service is running", func(t *testing.T) { t.Run("make sure service is running", func(t *testing.T) {
res := c.RunDockerComposeCmd("-p", projectName, "ps") res := c.RunDockerComposeCmd(t, "-p", projectName, "ps")
res.Assert(t, icmd.Expected{Out: `nginx running`}) res.Assert(t, icmd.Expected{Out: `nginx running`})
}) })
t.Run("copy to container copies the file to the all containers by default", func(t *testing.T) { t.Run("copy to container copies the file to the all containers by default", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/default.txt") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp",
"./fixtures/cp-test/cp-me.txt", "nginx:/tmp/default.txt")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
output := c.RunDockerCmd("exec", projectName+"-nginx-1", "cat", "/tmp/default.txt").Stdout() output := c.RunDockerCmd(t, "exec", projectName+"-nginx-1", "cat", "/tmp/default.txt").Stdout()
assert.Assert(t, strings.Contains(output, `hello world`), output) assert.Assert(t, strings.Contains(output, `hello world`), output)
output = c.RunDockerCmd("exec", projectName+"-nginx-2", "cat", "/tmp/default.txt").Stdout() output = c.RunDockerCmd(t, "exec", projectName+"-nginx-2", "cat", "/tmp/default.txt").Stdout()
assert.Assert(t, strings.Contains(output, `hello world`), output) assert.Assert(t, strings.Contains(output, `hello world`), output)
output = c.RunDockerCmd("exec", projectName+"-nginx-3", "cat", "/tmp/default.txt").Stdout() output = c.RunDockerCmd(t, "exec", projectName+"-nginx-3", "cat", "/tmp/default.txt").Stdout()
assert.Assert(t, strings.Contains(output, `hello world`), output) assert.Assert(t, strings.Contains(output, `hello world`), output)
}) })
t.Run("copy to container with a given index copies the file to the given container", func(t *testing.T) { t.Run("copy to container with a given index copies the file to the given container", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/indexed.txt") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3",
"./fixtures/cp-test/cp-me.txt", "nginx:/tmp/indexed.txt")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
output := c.RunDockerCmd("exec", projectName+"-nginx-3", "cat", "/tmp/indexed.txt").Stdout() output := c.RunDockerCmd(t, "exec", projectName+"-nginx-3", "cat", "/tmp/indexed.txt").Stdout()
assert.Assert(t, strings.Contains(output, `hello world`), output) assert.Assert(t, strings.Contains(output, `hello world`), output)
res = c.RunDockerOrExitError("exec", projectName+"-nginx-2", "cat", "/tmp/indexed.txt") res = c.RunDockerOrExitError(t, "exec", projectName+"-nginx-2", "cat", "/tmp/indexed.txt")
res.Assert(t, icmd.Expected{ExitCode: 1}) res.Assert(t, icmd.Expected{ExitCode: 1})
}) })
t.Run("copy from a container copies the file to the host from the first container by default", func(t *testing.T) { t.Run("copy from a container copies the file to the host from the first container by default", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "nginx:/tmp/default.txt", "./fixtures/cp-test/from-default.txt") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp",
"nginx:/tmp/default.txt", "./fixtures/cp-test/from-default.txt")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
data, err := os.ReadFile("./fixtures/cp-test/from-default.txt") data, err := os.ReadFile("./fixtures/cp-test/from-default.txt")
@ -82,7 +86,8 @@ func TestCopy(t *testing.T) {
}) })
t.Run("copy from a container with a given index copies the file to host", func(t *testing.T) { t.Run("copy from a container with a given index copies the file to host", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3", "nginx:/tmp/indexed.txt", "./fixtures/cp-test/from-indexed.txt") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3",
"nginx:/tmp/indexed.txt", "./fixtures/cp-test/from-indexed.txt")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
data, err := os.ReadFile("./fixtures/cp-test/from-indexed.txt") data, err := os.ReadFile("./fixtures/cp-test/from-indexed.txt")
@ -91,13 +96,15 @@ func TestCopy(t *testing.T) {
}) })
t.Run("copy to and from a container also work with folder", func(t *testing.T) { t.Run("copy to and from a container also work with folder", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "./fixtures/cp-test/cp-folder", "nginx:/tmp") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp",
"./fixtures/cp-test/cp-folder", "nginx:/tmp")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
output := c.RunDockerCmd("exec", projectName+"-nginx-1", "cat", "/tmp/cp-folder/cp-me.txt").Stdout() output := c.RunDockerCmd(t, "exec", projectName+"-nginx-1", "cat", "/tmp/cp-folder/cp-me.txt").Stdout()
assert.Assert(t, strings.Contains(output, `hello world from folder`), output) assert.Assert(t, strings.Contains(output, `hello world from folder`), output)
res = c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "nginx:/tmp/cp-folder", "./fixtures/cp-test/cp-folder2") res = c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp",
"nginx:/tmp/cp-folder", "./fixtures/cp-test/cp-folder2")
res.Assert(t, icmd.Expected{ExitCode: 0}) res.Assert(t, icmd.Expected{ExitCode: 0})
data, err := os.ReadFile("./fixtures/cp-test/cp-folder2/cp-me.txt") data, err := os.ReadFile("./fixtures/cp-test/cp-folder2/cp-me.txt")

View File

@ -38,7 +38,7 @@ func TestComposeRunDdev(t *testing.T) {
} }
_ = os.Setenv("DDEV_DEBUG", "true") _ = os.Setenv("DDEV_DEBUG", "true")
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
dir, err := os.MkdirTemp("", t.Name()+"-") dir, err := os.MkdirTemp("", t.Name()+"-")
assert.NilError(t, err) assert.NilError(t, err)
@ -48,8 +48,8 @@ func TestComposeRunDdev(t *testing.T) {
siteName := filepath.Base(dir) siteName := filepath.Base(dir)
t.Cleanup(func() { t.Cleanup(func() {
_ = c.RunCmdInDir(dir, "./ddev", "delete", "-Oy") _ = c.RunCmdInDir(t, dir, "./ddev", "delete", "-Oy")
_ = c.RunCmdInDir(dir, "./ddev", "poweroff") _ = c.RunCmdInDir(t, dir, "./ddev", "poweroff")
_ = os.RemoveAll(dir) _ = os.RemoveAll(dir)
}) })
@ -59,28 +59,28 @@ func TestComposeRunDdev(t *testing.T) {
} }
compressedFilename := fmt.Sprintf("ddev_%s-%s.%s.tar.gz", osName, runtime.GOARCH, ddevVersion) compressedFilename := fmt.Sprintf("ddev_%s-%s.%s.tar.gz", osName, runtime.GOARCH, ddevVersion)
c.RunCmdInDir(dir, "curl", "-LO", c.RunCmdInDir(t, dir, "curl", "-LO",
fmt.Sprintf("https://github.com/drud/ddev/releases/download/%s/%s", fmt.Sprintf("https://github.com/drud/ddev/releases/download/%s/%s",
ddevVersion, ddevVersion,
compressedFilename)) compressedFilename))
c.RunCmdInDir(dir, "tar", "-xzf", compressedFilename) c.RunCmdInDir(t, dir, "tar", "-xzf", compressedFilename)
// Create a simple index.php we can test against. // Create a simple index.php we can test against.
c.RunCmdInDir(dir, "sh", "-c", "echo '<?php\nprint \"ddev is working\";' >index.php") c.RunCmdInDir(t, dir, "sh", "-c", "echo '<?php\nprint \"ddev is working\";' >index.php")
c.RunCmdInDir(dir, "./ddev", "config", "--auto") c.RunCmdInDir(t, dir, "./ddev", "config", "--auto")
c.RunCmdInDir(dir, "./ddev", "config", "global", "--use-docker-compose-from-path") c.RunCmdInDir(t, dir, "./ddev", "config", "global", "--use-docker-compose-from-path")
vRes := c.RunCmdInDir(dir, "./ddev", "version") vRes := c.RunCmdInDir(t, dir, "./ddev", "version")
out := vRes.Stdout() out := vRes.Stdout()
fmt.Printf("ddev version: %s\n", out) fmt.Printf("ddev version: %s\n", out)
c.RunCmdInDir(dir, "./ddev", "poweroff") c.RunCmdInDir(t, dir, "./ddev", "poweroff")
c.RunCmdInDir(dir, "./ddev", "start", "-y") c.RunCmdInDir(t, dir, "./ddev", "start", "-y")
curlRes := c.RunCmdInDir(dir, "curl", "-sSL", fmt.Sprintf("http://%s.ddev.site", siteName)) curlRes := c.RunCmdInDir(t, dir, "curl", "-sSL", fmt.Sprintf("http://%s.ddev.site", siteName))
out = curlRes.Stdout() out = curlRes.Stdout()
fmt.Println(out) fmt.Println(out)
assert.Assert(c.test, strings.Contains(out, "ddev is working"), "Could not start project") assert.Assert(t, strings.Contains(out, "ddev is working"), "Could not start project")
} }

View File

@ -29,12 +29,13 @@ import (
"testing" "testing"
"time" "time"
"github.com/docker/compose/v2/cmd/compose"
"github.com/pkg/errors" "github.com/pkg/errors"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/icmd" "gotest.tools/v3/icmd"
"gotest.tools/v3/poll" "gotest.tools/v3/poll"
"github.com/docker/compose/v2/cmd/compose"
) )
var ( var (
@ -56,21 +57,19 @@ func init() {
} }
} }
// E2eCLI is used to wrap the CLI for end to end testing // CLI is used to wrap the CLI for end to end testing
// nolint stutter type CLI struct {
type E2eCLI struct {
BinDir string
ConfigDir string ConfigDir string
test *testing.T
} }
// NewParallelE2eCLI returns a configured TestE2eCLI with t.Parallel() set // NewParallelCLI returns a configured CLI with t.Parallel() set
func NewParallelE2eCLI(t *testing.T, binDir string) *E2eCLI { func NewParallelCLI(t *testing.T) *CLI {
t.Parallel() t.Parallel()
return newE2eCLI(t, binDir) return NewCLI(t)
} }
func newE2eCLI(t *testing.T, binDir string) *E2eCLI { // NewCLI returns a CLI to use for E2E tests
func NewCLI(t testing.TB) *CLI {
d, err := ioutil.TempDir("", "") d, err := ioutil.TempDir("", "")
assert.Check(t, is.Nil(err)) assert.Check(t, is.Nil(err))
@ -103,7 +102,7 @@ func newE2eCLI(t *testing.T, binDir string) *E2eCLI {
} }
} }
return &E2eCLI{binDir, d, t} return &CLI{ConfigDir: d}
} }
func dirContents(dir string) []string { func dirContents(dir string) []string {
@ -156,7 +155,7 @@ func CopyFile(sourceFile string, destinationFile string) error {
} }
// NewCmd creates a cmd object configured with the test environment set // NewCmd creates a cmd object configured with the test environment set
func (c *E2eCLI) NewCmd(command string, args ...string) icmd.Cmd { func (c *CLI) NewCmd(command string, args ...string) icmd.Cmd {
env := append(os.Environ(), env := append(os.Environ(),
"DOCKER_CONFIG="+c.ConfigDir, "DOCKER_CONFIG="+c.ConfigDir,
"KUBECONFIG=invalid", "KUBECONFIG=invalid",
@ -168,7 +167,7 @@ func (c *E2eCLI) NewCmd(command string, args ...string) icmd.Cmd {
} }
// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars // NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
func (c *E2eCLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd { func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
env := append(os.Environ(), env := append(os.Environ(),
append(envvars, append(envvars,
"DOCKER_CONFIG="+c.ConfigDir, "DOCKER_CONFIG="+c.ConfigDir,
@ -181,63 +180,63 @@ func (c *E2eCLI) NewCmdWithEnv(envvars []string, command string, args ...string)
} }
// MetricsSocket get the path where test metrics will be sent // MetricsSocket get the path where test metrics will be sent
func (c *E2eCLI) MetricsSocket() string { func (c *CLI) MetricsSocket() string {
return filepath.Join(c.ConfigDir, "./docker-cli.sock") return filepath.Join(c.ConfigDir, "./docker-cli.sock")
} }
// NewDockerCmd creates a docker cmd without running it // NewDockerCmd creates a docker cmd without running it
func (c *E2eCLI) NewDockerCmd(args ...string) icmd.Cmd { func (c *CLI) NewDockerCmd(args ...string) icmd.Cmd {
return c.NewCmd(DockerExecutableName, args...) return c.NewCmd(DockerExecutableName, args...)
} }
// RunDockerOrExitError runs a docker command and returns a result // RunDockerOrExitError runs a docker command and returns a result
func (c *E2eCLI) RunDockerOrExitError(args ...string) *icmd.Result { func (c *CLI) RunDockerOrExitError(t testing.TB, args ...string) *icmd.Result {
fmt.Printf("\t[%s] docker %s\n", c.test.Name(), strings.Join(args, " ")) fmt.Printf("\t[%s] docker %s\n", t.Name(), strings.Join(args, " "))
return icmd.RunCmd(c.NewDockerCmd(args...)) return icmd.RunCmd(c.NewDockerCmd(args...))
} }
// RunCmd runs a command, expects no error and returns a result // RunCmd runs a command, expects no error and returns a result
func (c *E2eCLI) RunCmd(args ...string) *icmd.Result { func (c *CLI) RunCmd(t testing.TB, args ...string) *icmd.Result {
fmt.Printf("\t[%s] %s\n", c.test.Name(), strings.Join(args, " ")) fmt.Printf("\t[%s] %s\n", t.Name(), strings.Join(args, " "))
assert.Assert(c.test, len(args) >= 1, "require at least one command in parameters") assert.Assert(t, len(args) >= 1, "require at least one command in parameters")
res := icmd.RunCmd(c.NewCmd(args[0], args[1:]...)) res := icmd.RunCmd(c.NewCmd(args[0], args[1:]...))
res.Assert(c.test, icmd.Success) res.Assert(t, icmd.Success)
return res return res
} }
// RunCmdInDir runs a command in a given dir, expects no error and returns a result // RunCmdInDir runs a command in a given dir, expects no error and returns a result
func (c *E2eCLI) RunCmdInDir(dir string, args ...string) *icmd.Result { func (c *CLI) RunCmdInDir(t testing.TB, dir string, args ...string) *icmd.Result {
fmt.Printf("\t[%s] %s\n", c.test.Name(), strings.Join(args, " ")) fmt.Printf("\t[%s] %s\n", t.Name(), strings.Join(args, " "))
assert.Assert(c.test, len(args) >= 1, "require at least one command in parameters") assert.Assert(t, len(args) >= 1, "require at least one command in parameters")
cmd := c.NewCmd(args[0], args[1:]...) cmd := c.NewCmd(args[0], args[1:]...)
cmd.Dir = dir cmd.Dir = dir
res := icmd.RunCmd(cmd) res := icmd.RunCmd(cmd)
res.Assert(c.test, icmd.Success) res.Assert(t, icmd.Success)
return res return res
} }
// RunDockerCmd runs a docker command, expects no error and returns a result // RunDockerCmd runs a docker command, expects no error and returns a result
func (c *E2eCLI) RunDockerCmd(args ...string) *icmd.Result { func (c *CLI) RunDockerCmd(t testing.TB, args ...string) *icmd.Result {
if len(args) > 0 && args[0] == compose.PluginName { if len(args) > 0 && args[0] == compose.PluginName {
c.test.Fatal("This test called 'RunDockerCmd' for 'compose'. Please prefer 'RunDockerComposeCmd' to be able to test as a plugin and standalone") t.Fatal("This test called 'RunDockerCmd' for 'compose'. Please prefer 'RunDockerComposeCmd' to be able to test as a plugin and standalone")
} }
res := c.RunDockerOrExitError(args...) res := c.RunDockerOrExitError(t, args...)
res.Assert(c.test, icmd.Success) res.Assert(t, icmd.Success)
return res return res
} }
// RunDockerComposeCmd runs a docker compose command, expects no error and returns a result // RunDockerComposeCmd runs a docker compose command, expects no error and returns a result
func (c *E2eCLI) RunDockerComposeCmd(args ...string) *icmd.Result { func (c *CLI) RunDockerComposeCmd(t testing.TB, args ...string) *icmd.Result {
res := c.RunDockerComposeCmdNoCheck(args...) res := c.RunDockerComposeCmdNoCheck(t, args...)
res.Assert(c.test, icmd.Success) res.Assert(t, icmd.Success)
return res return res
} }
// RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result // RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result
func (c *E2eCLI) RunDockerComposeCmdNoCheck(args ...string) *icmd.Result { func (c *CLI) RunDockerComposeCmdNoCheck(t testing.TB, args ...string) *icmd.Result {
if composeStandaloneMode { if composeStandaloneMode {
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"})
assert.NilError(c.test, err) assert.NilError(t, err)
return icmd.RunCmd(c.NewCmd(composeBinary, args...)) return icmd.RunCmd(c.NewCmd(composeBinary, args...))
} }
args = append([]string{"compose"}, args...) args = append([]string{"compose"}, args...)
@ -252,22 +251,22 @@ func StdoutContains(expected string) func(*icmd.Result) bool {
} }
// WaitForCmdResult try to execute a cmd until resulting output matches given predicate // WaitForCmdResult try to execute a cmd until resulting output matches given predicate
func (c *E2eCLI) WaitForCmdResult(command icmd.Cmd, predicate func(*icmd.Result) bool, timeout time.Duration, delay time.Duration) { func (c *CLI) WaitForCmdResult(t testing.TB, command icmd.Cmd, predicate func(*icmd.Result) bool, timeout time.Duration, delay time.Duration) {
assert.Assert(c.test, timeout.Nanoseconds() > delay.Nanoseconds(), "timeout must be greater than delay") assert.Assert(t, timeout.Nanoseconds() > delay.Nanoseconds(), "timeout must be greater than delay")
var res *icmd.Result var res *icmd.Result
checkStopped := func(logt poll.LogT) poll.Result { checkStopped := func(logt poll.LogT) poll.Result {
fmt.Printf("\t[%s] %s\n", c.test.Name(), strings.Join(command.Command, " ")) fmt.Printf("\t[%s] %s\n", t.Name(), strings.Join(command.Command, " "))
res = icmd.RunCmd(command) res = icmd.RunCmd(command)
if !predicate(res) { if !predicate(res) {
return poll.Continue("Cmd output did not match requirement: %q", res.Combined()) return poll.Continue("Cmd output did not match requirement: %q", res.Combined())
} }
return poll.Success() return poll.Success()
} }
poll.WaitOn(c.test, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout)) poll.WaitOn(t, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout))
} }
// WaitForCondition wait for predicate to execute to true // WaitForCondition wait for predicate to execute to true
func (c *E2eCLI) WaitForCondition(predicate func() (bool, string), timeout time.Duration, delay time.Duration) { func (c *CLI) WaitForCondition(t testing.TB, predicate func() (bool, string), timeout time.Duration, delay time.Duration) {
checkStopped := func(logt poll.LogT) poll.Result { checkStopped := func(logt poll.LogT) poll.Result {
pass, description := predicate() pass, description := predicate()
if !pass { if !pass {
@ -275,7 +274,7 @@ func (c *E2eCLI) WaitForCondition(predicate func() (bool, string), timeout time.
} }
return poll.Success() return poll.Success()
} }
poll.WaitOn(c.test, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout)) poll.WaitOn(t, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout))
} }
// Lines split output into lines // Lines split output into lines
@ -286,7 +285,7 @@ func Lines(output string) []string {
// HTTPGetWithRetry performs an HTTP GET on an `endpoint`, using retryDelay also as a request timeout. // HTTPGetWithRetry performs an HTTP GET on an `endpoint`, using retryDelay also as a request timeout.
// In the case of an error or the response status is not the expeted one, it retries the same request, // In the case of an error or the response status is not the expeted one, it retries the same request,
// returning the response body as a string (empty if we could not reach it) // returning the response body as a string (empty if we could not reach it)
func HTTPGetWithRetry(t *testing.T, endpoint string, expectedStatus int, retryDelay time.Duration, timeout time.Duration) string { func HTTPGetWithRetry(t testing.TB, endpoint string, expectedStatus int, retryDelay time.Duration, timeout time.Duration) string {
var ( var (
r *http.Response r *http.Response
err error err error

View File

@ -25,39 +25,40 @@ import (
) )
func TestIPC(t *testing.T) { func TestIPC(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "ipc_e2e" const projectName = "ipc_e2e"
var cid string var cid string
t.Run("create ipc mode container", func(t *testing.T) { t.Run("create ipc mode container", func(t *testing.T) {
res := c.RunDockerCmd("run", "-d", "--rm", "--ipc=shareable", "--name", "ipc_mode_container", "alpine", "top") res := c.RunDockerCmd(t, "run", "-d", "--rm", "--ipc=shareable", "--name", "ipc_mode_container", "alpine",
"top")
cid = strings.Trim(res.Stdout(), "\n") cid = strings.Trim(res.Stdout(), "\n")
}) })
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/ipc-test/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/ipc-test/compose.yaml", "--project-name", projectName, "up", "-d")
}) })
t.Run("check running project", func(t *testing.T) { t.Run("check running project", func(t *testing.T) {
res := c.RunDockerComposeCmd("-p", projectName, "ps") res := c.RunDockerComposeCmd(t, "-p", projectName, "ps")
res.Assert(t, icmd.Expected{Out: `shareable`}) res.Assert(t, icmd.Expected{Out: `shareable`})
}) })
t.Run("check ipcmode in container inspect", func(t *testing.T) { t.Run("check ipcmode in container inspect", func(t *testing.T) {
res := c.RunDockerCmd("inspect", projectName+"-shareable-1") res := c.RunDockerCmd(t, "inspect", projectName+"-shareable-1")
res.Assert(t, icmd.Expected{Out: `"IpcMode": "shareable",`}) res.Assert(t, icmd.Expected{Out: `"IpcMode": "shareable",`})
res = c.RunDockerCmd("inspect", projectName+"-service-1") res = c.RunDockerCmd(t, "inspect", projectName+"-service-1")
res.Assert(t, icmd.Expected{Out: `"IpcMode": "container:`}) res.Assert(t, icmd.Expected{Out: `"IpcMode": "container:`})
res = c.RunDockerCmd("inspect", projectName+"-container-1") res = c.RunDockerCmd(t, "inspect", projectName+"-container-1")
res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`"IpcMode": "container:%s",`, cid)}) res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`"IpcMode": "container:%s",`, cid)})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
t.Run("remove ipc mode container", func(t *testing.T) { t.Run("remove ipc mode container", func(t *testing.T) {
_ = c.RunDockerCmd("rm", "-f", "ipc_mode_container") _ = c.RunDockerCmd(t, "rm", "-f", "ipc_mode_container")
}) })
} }

View File

@ -26,33 +26,33 @@ import (
) )
func TestLocalComposeLogs(t *testing.T) { func TestLocalComposeLogs(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "compose-e2e-logs" const projectName = "compose-e2e-logs"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/logs-test/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/logs-test/compose.yaml", "--project-name", projectName, "up", "-d")
}) })
t.Run("logs", func(t *testing.T) { t.Run("logs", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-name", projectName, "logs") res := c.RunDockerComposeCmd(t, "--project-name", projectName, "logs")
res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`}) res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`})
res.Assert(t, icmd.Expected{Out: `hello`}) res.Assert(t, icmd.Expected{Out: `hello`})
}) })
t.Run("logs ping", func(t *testing.T) { t.Run("logs ping", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-name", projectName, "logs", "ping") res := c.RunDockerComposeCmd(t, "--project-name", projectName, "logs", "ping")
res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`}) res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`})
assert.Assert(t, !strings.Contains(res.Stdout(), "hello")) assert.Assert(t, !strings.Contains(res.Stdout(), "hello"))
}) })
t.Run("logs hello", func(t *testing.T) { t.Run("logs hello", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-name", projectName, "logs", "hello", "ping") res := c.RunDockerComposeCmd(t, "--project-name", projectName, "logs", "hello", "ping")
res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`}) res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`})
res.Assert(t, icmd.Expected{Out: `hello`}) res.Assert(t, icmd.Expected{Out: `hello`})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }

View File

@ -24,32 +24,32 @@ import (
) )
func TestComposeMetrics(t *testing.T) { func TestComposeMetrics(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("catch specific failure metrics", func(t *testing.T) { t.Run("catch specific failure metrics", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "-f", "fixtures/does-not-exist/compose.yaml", "build") res := c.RunDockerOrExitError(t, "compose", "-f", "fixtures/does-not-exist/compose.yaml", "build")
expectedErr := "fixtures/does-not-exist/compose.yaml: no such file or directory" expectedErr := "fixtures/does-not-exist/compose.yaml: no such file or directory"
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
expectedErr = "does-not-exist\\compose.yaml: The system cannot find the path specified" expectedErr = "does-not-exist\\compose.yaml: The system cannot find the path specified"
} }
res.Assert(t, icmd.Expected{ExitCode: 14, Err: expectedErr}) res.Assert(t, icmd.Expected{ExitCode: 14, Err: expectedErr})
res = c.RunDockerOrExitError("compose", "-f", "fixtures/wrong-composefile/compose.yaml", "up", "-d") res = c.RunDockerOrExitError(t, "compose", "-f", "fixtures/wrong-composefile/compose.yaml", "up", "-d")
res.Assert(t, icmd.Expected{ExitCode: 15, Err: "services.simple Additional property wrongField is not allowed"}) res.Assert(t, icmd.Expected{ExitCode: 15, Err: "services.simple Additional property wrongField is not allowed"})
res = c.RunDockerOrExitError("compose", "up") res = c.RunDockerOrExitError(t, "compose", "up")
res.Assert(t, icmd.Expected{ExitCode: 14, Err: "no configuration file provided: not found"}) res.Assert(t, icmd.Expected{ExitCode: 14, Err: "no configuration file provided: not found"})
res = c.RunDockerOrExitError("compose", "up", "-f", "fixtures/wrong-composefile/compose.yaml") res = c.RunDockerOrExitError(t, "compose", "up", "-f", "fixtures/wrong-composefile/compose.yaml")
res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown shorthand flag: 'f' in -f"}) res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown shorthand flag: 'f' in -f"})
res = c.RunDockerOrExitError("compose", "up", "--file", "fixtures/wrong-composefile/compose.yaml") res = c.RunDockerOrExitError(t, "compose", "up", "--file", "fixtures/wrong-composefile/compose.yaml")
res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown flag: --file"}) res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown flag: --file"})
res = c.RunDockerOrExitError("compose", "donw", "--file", "fixtures/wrong-composefile/compose.yaml") res = c.RunDockerOrExitError(t, "compose", "donw", "--file", "fixtures/wrong-composefile/compose.yaml")
res.Assert(t, icmd.Expected{ExitCode: 16, Err: `unknown docker command: "compose donw"`}) res.Assert(t, icmd.Expected{ExitCode: 16, Err: `unknown docker command: "compose donw"`})
res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/build-error.yml", "build") res = c.RunDockerOrExitError(t, "compose", "--file", "fixtures/wrong-composefile/build-error.yml", "build")
res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`}) res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`})
res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/build-error.yml", "up") res = c.RunDockerOrExitError(t, "compose", "--file", "fixtures/wrong-composefile/build-error.yml", "up")
res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`}) res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`})
res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/unknown-image.yml", "pull") res = c.RunDockerOrExitError(t, "compose", "--file", "fixtures/wrong-composefile/unknown-image.yml", "pull")
res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`}) res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`})
res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/unknown-image.yml", "up") res = c.RunDockerOrExitError(t, "compose", "--file", "fixtures/wrong-composefile/unknown-image.yml", "up")
res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`}) res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`})
}) })
} }

View File

@ -27,126 +27,135 @@ import (
) )
func TestNetworks(t *testing.T) { func TestNetworks(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) // fixture is shared with TestNetworkModes and is not safe to run concurrently
c := NewCLI(t)
const projectName = "network_e2e" const projectName = "network_e2e"
t.Run("ensure we do not reuse previous networks", func(t *testing.T) { t.Run("ensure we do not reuse previous networks", func(t *testing.T) {
c.RunDockerOrExitError("network", "rm", projectName+"_dbnet") c.RunDockerOrExitError(t, "network", "rm", projectName+"_dbnet")
c.RunDockerOrExitError("network", "rm", "microservices") c.RunDockerOrExitError(t, "network", "rm", "microservices")
}) })
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "up",
"-d")
}) })
t.Run("check running project", func(t *testing.T) { t.Run("check running project", func(t *testing.T) {
res := c.RunDockerComposeCmd("-p", projectName, "ps") res := c.RunDockerComposeCmd(t, "-p", projectName, "ps")
res.Assert(t, icmd.Expected{Out: `web`}) res.Assert(t, icmd.Expected{Out: `web`})
endpoint := "http://localhost:80" endpoint := "http://localhost:80"
output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second) output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second)
assert.Assert(t, strings.Contains(output, `"word":`)) assert.Assert(t, strings.Contains(output, `"word":`))
res = c.RunDockerCmd("network", "ls") res = c.RunDockerCmd(t, "network", "ls")
res.Assert(t, icmd.Expected{Out: projectName + "_dbnet"}) res.Assert(t, icmd.Expected{Out: projectName + "_dbnet"})
res.Assert(t, icmd.Expected{Out: "microservices"}) res.Assert(t, icmd.Expected{Out: "microservices"})
}) })
t.Run("port", func(t *testing.T) { t.Run("port", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-name", projectName, "port", "words", "8080") res := c.RunDockerComposeCmd(t, "--project-name", projectName, "port", "words", "8080")
res.Assert(t, icmd.Expected{Out: `0.0.0.0:8080`}) res.Assert(t, icmd.Expected{Out: `0.0.0.0:8080`})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
t.Run("check networks after down", func(t *testing.T) { t.Run("check networks after down", func(t *testing.T) {
res := c.RunDockerCmd("network", "ls") res := c.RunDockerCmd(t, "network", "ls")
assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined())
assert.Assert(t, !strings.Contains(res.Combined(), "microservices"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "microservices"), res.Combined())
}) })
} }
func TestNetworkAliasses(t *testing.T) { func TestNetworkAliases(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "network_alias_e2e" const projectName = "network_alias_e2e"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "up",
"-d")
}) })
t.Run("curl alias", func(t *testing.T) { t.Run("curl alias", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "exec", "-T", "container1", "curl", "http://alias-of-container2/") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName,
"exec", "-T", "container1", "curl", "http://alias-of-container2/")
assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout()) assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout())
}) })
t.Run("curl links", func(t *testing.T) { t.Run("curl links", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "exec", "-T", "container1", "curl", "http://container/") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName,
"exec", "-T", "container1", "curl", "http://container/")
assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout()) assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout())
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }
func TestNetworkLinks(t *testing.T) { func TestNetworkLinks(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "network_link_e2e" const projectName = "network_link_e2e"
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/network-links/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/network-links/compose.yaml", "--project-name", projectName, "up",
"-d")
}) })
t.Run("curl links in default bridge network", func(t *testing.T) { t.Run("curl links in default bridge network", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/network-links/compose.yaml", "--project-name", projectName, "exec", "-T", "container2", "curl", "http://container1/") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-links/compose.yaml", "--project-name", projectName,
"exec", "-T", "container2", "curl", "http://container1/")
assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout()) assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout())
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }
func TestIPAMConfig(t *testing.T) { func TestIPAMConfig(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "ipam_e2e" const projectName = "ipam_e2e"
t.Run("ensure we do not reuse previous networks", func(t *testing.T) { t.Run("ensure we do not reuse previous networks", func(t *testing.T) {
c.RunDockerOrExitError("network", "rm", projectName+"_default") c.RunDockerOrExitError(t, "network", "rm", projectName+"_default")
}) })
t.Run("up", func(t *testing.T) { t.Run("up", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/ipam/compose.yaml", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "-f", "./fixtures/ipam/compose.yaml", "--project-name", projectName, "up", "-d")
}) })
t.Run("ensure service get fixed IP assigned", func(t *testing.T) { t.Run("ensure service get fixed IP assigned", func(t *testing.T) {
res := c.RunDockerCmd("inspect", projectName+"-foo-1", "-f", "{{ .NetworkSettings.Networks."+projectName+"_default.IPAddress }}") res := c.RunDockerCmd(t, "inspect", projectName+"-foo-1", "-f",
"{{ .NetworkSettings.Networks."+projectName+"_default.IPAddress }}")
res.Assert(t, icmd.Expected{Out: "10.1.0.100"}) res.Assert(t, icmd.Expected{Out: "10.1.0.100"})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }
func TestNetworkModes(t *testing.T) { func TestNetworkModes(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) // fixture is shared with TestNetworks and is not safe to run concurrently
c := NewCLI(t)
const projectName = "network_mode_service_run" const projectName = "network_mode_service_run"
t.Run("run with service mode dependency", func(t *testing.T) { t.Run("run with service mode dependency", func(t *testing.T) {
res := c.RunDockerOrExitError("compose", "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "run", "-T", "mydb", "echo", "success") res := c.RunDockerOrExitError(t, "compose", "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "run", "-T", "mydb", "echo", "success")
res.Assert(t, icmd.Expected{Out: "success"}) res.Assert(t, icmd.Expected{Out: "success"})
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }

View File

@ -27,20 +27,20 @@ import (
) )
func TestPs(t *testing.T) { func TestPs(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-ps" const projectName = "e2e-ps"
res := c.RunDockerComposeCmd("-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "up", "-d") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "up", "-d")
if assert.NoError(t, res.Error) { if assert.NoError(t, res.Error) {
t.Cleanup(func() { t.Cleanup(func() {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }
assert.Contains(t, res.Combined(), "Container e2e-ps-busybox-1 Started", res.Combined()) assert.Contains(t, res.Combined(), "Container e2e-ps-busybox-1 Started", res.Combined())
t.Run("pretty", func(t *testing.T) { t.Run("pretty", func(t *testing.T) {
res = c.RunDockerComposeCmd("-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps") res = c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps")
lines := strings.Split(res.Combined(), "\n") lines := strings.Split(res.Combined(), "\n")
assert.Equal(t, 4, len(lines)) assert.Equal(t, 4, len(lines))
count := 0 count := 0
@ -58,7 +58,8 @@ func TestPs(t *testing.T) {
}) })
t.Run("json", func(t *testing.T) { t.Run("json", func(t *testing.T) {
res = c.RunDockerComposeCmd("-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps", "--format", "json") res = c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps",
"--format", "json")
var output []api.ContainerSummary var output []api.ContainerSummary
err := json.Unmarshal([]byte(res.Combined()), &output) err := json.Unmarshal([]byte(res.Combined()), &output)
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -27,7 +27,7 @@ import (
) )
func TestRestart(t *testing.T) { func TestRestart(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-restart" const projectName = "e2e-restart"
getServiceRegx := func(service string, status string) string { getServiceRegx := func(service string, status string) string {
@ -38,27 +38,26 @@ func TestRestart(t *testing.T) {
t.Run("Up a project", func(t *testing.T) { t.Run("Up a project", func(t *testing.T) {
// This is just to ensure the containers do NOT exist // This is just to ensure the containers do NOT exist
c.RunDockerOrExitError("compose", "--project-name", projectName, "down") c.RunDockerOrExitError(t, "compose", "--project-name", projectName, "down")
res := c.RunDockerOrExitError("compose", "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "up", "-d") res := c.RunDockerOrExitError(t, "compose", "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "up", "-d")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-restart-restart-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-restart-restart-1 Started"), res.Combined())
c.WaitForCmdResult(c.NewDockerCmd("compose", "--project-name", projectName, "ps", "-a", "--format", "json"), c.WaitForCmdResult(t, c.NewDockerCmd("compose", "--project-name", projectName, "ps", "-a", "--format", "json"),
StdoutContains(`"State":"exited"`), StdoutContains(`"State":"exited"`), 10*time.Second, 1*time.Second)
10*time.Second, 1*time.Second)
res = c.RunDockerOrExitError("compose", "--project-name", projectName, "ps", "-a") res = c.RunDockerOrExitError(t, "compose", "--project-name", projectName, "ps", "-a")
testify.Regexp(t, getServiceRegx("restart", "exited"), res.Stdout()) testify.Regexp(t, getServiceRegx("restart", "exited"), res.Stdout())
_ = c.RunDockerOrExitError("compose", "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "restart") _ = c.RunDockerOrExitError(t, "compose", "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "restart")
// Give the same time but it must NOT exit // Give the same time but it must NOT exit
time.Sleep(time.Second) time.Sleep(time.Second)
res = c.RunDockerOrExitError("compose", "--project-name", projectName, "ps") res = c.RunDockerOrExitError(t, "compose", "--project-name", projectName, "ps")
testify.Regexp(t, getServiceRegx("restart", "running"), res.Stdout()) testify.Regexp(t, getServiceRegx("restart", "running"), res.Stdout())
// Clean up // Clean up
c.RunDockerOrExitError("compose", "--project-name", projectName, "down") c.RunDockerOrExitError(t, "compose", "--project-name", projectName, "down")
}) })
} }

View File

@ -30,39 +30,44 @@ import (
) )
func TestDisplayScanMessageAfterBuild(t *testing.T) { func TestDisplayScanMessageAfterBuild(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
// assert docker scan plugin is available // assert docker scan plugin is available
c.RunDockerOrExitError("scan", "--help") c.RunDockerOrExitError(t, "scan", "--help")
t.Run("display on compose build", func(t *testing.T) { t.Run("display on compose build", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-compose-build", "build") res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p",
defer c.RunDockerOrExitError("rmi", "-f", "scan-msg-test-compose-build_nginx") "scan-msg-test-compose-build", "build")
defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-compose-build_nginx")
res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg}) res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg})
}) })
t.Run("do not display on compose build with quiet flag", func(t *testing.T) { t.Run("do not display on compose build with quiet flag", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-quiet", "build", "--quiet") res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-quiet",
"build", "--quiet")
assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined())
res = c.RunDockerCmd("rmi", "-f", "scan-msg-test-quiet_nginx") res = c.RunDockerCmd(t, "rmi", "-f", "scan-msg-test-quiet_nginx")
assert.Assert(t, !strings.Contains(res.Combined(), "No such image")) assert.Assert(t, !strings.Contains(res.Combined(), "No such image"))
res = c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-q", "build", "-q") res = c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-q",
defer c.RunDockerOrExitError("rmi", "-f", "scan-msg-test-q_nginx") "build", "-q")
defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-q_nginx")
assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined())
}) })
_ = c.RunDockerOrExitError("rmi", "scan-msg-test_nginx") _ = c.RunDockerOrExitError(t, "rmi", "scan-msg-test_nginx")
t.Run("display on compose up if image is built", func(t *testing.T) { t.Run("display on compose up if image is built", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", "-d") res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up",
defer c.RunDockerOrExitError("compose", "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down") "-d")
defer c.RunDockerOrExitError(t, "compose", "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down")
res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg}) res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg})
}) })
t.Run("do not display on compose up if no image built", func(t *testing.T) { // re-run the same Compose aproject t.Run("do not display on compose up if no image built", func(t *testing.T) { // re-run the same Compose aproject
res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", "-d") res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up",
defer c.RunDockerOrExitError("compose", "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down", "--rmi", "all") "-d")
defer c.RunDockerOrExitError(t, "compose", "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down", "--rmi", "all")
assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined())
}) })
@ -72,7 +77,7 @@ func TestDisplayScanMessageAfterBuild(t *testing.T) {
err := ioutil.WriteFile(scanConfigFile, []byte(`{"optin":true}`), 0644) err := ioutil.WriteFile(scanConfigFile, []byte(`{"optin":true}`), 0644)
assert.NilError(t, err) assert.NilError(t, err)
res := c.RunDockerCmd("build", "-t", "test-image-scan-msg", "fixtures/simple-build-test/nginx-build") res := c.RunDockerCmd(t, "build", "-t", "test-image-scan-msg", "fixtures/simple-build-test/nginx-build")
assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined())
}) })
} }

View File

@ -23,7 +23,7 @@ import (
) )
func TestSecretFromEnv(t *testing.T) { func TestSecretFromEnv(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
t.Run("compose run", func(t *testing.T) { t.Run("compose run", func(t *testing.T) {
res := icmd.RunCmd(c.NewDockerCmd("compose", "-f", "./fixtures/env-secret/compose.yaml", "run", "foo"), res := icmd.RunCmd(c.NewDockerCmd("compose", "-f", "./fixtures/env-secret/compose.yaml", "run", "foo"),

View File

@ -23,11 +23,11 @@ import (
) )
func TestStartFail(t *testing.T) { func TestStartFail(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-start-fail" const projectName = "e2e-start-fail"
res := c.RunDockerOrExitError("compose", "-f", "fixtures/start-fail/compose.yaml", "--project-name", projectName, "up", "-d") res := c.RunDockerOrExitError(t, "compose", "-f", "fixtures/start-fail/compose.yaml", "--project-name", projectName, "up", "-d")
res.Assert(t, icmd.Expected{ExitCode: 1, Err: `container for service "fail" is unhealthy`}) res.Assert(t, icmd.Expected{ExitCode: 1, Err: `container for service "fail" is unhealthy`})
c.RunDockerComposeCmd("--project-name", projectName, "down") c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
} }

View File

@ -26,7 +26,7 @@ import (
) )
func TestStartStop(t *testing.T) { func TestStartStop(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-start-stop-no-dependencies" const projectName = "e2e-start-stop-no-dependencies"
getProjectRegx := func(status string) string { getProjectRegx := func(status string) string {
@ -42,103 +42,106 @@ func TestStartStop(t *testing.T) {
} }
t.Run("Up a project", func(t *testing.T) { t.Run("Up a project", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "up", "-d") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "up",
"-d")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-no-dependencies-simple-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-no-dependencies-simple-1 Started"), res.Combined())
res = c.RunDockerComposeCmd("ls", "--all") res = c.RunDockerComposeCmd(t, "ls", "--all")
testify.Regexp(t, getProjectRegx("running"), res.Stdout()) testify.Regexp(t, getProjectRegx("running"), res.Stdout())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps") res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps")
testify.Regexp(t, getServiceRegx("simple", "running"), res.Stdout()) testify.Regexp(t, getServiceRegx("simple", "running"), res.Stdout())
testify.Regexp(t, getServiceRegx("another", "running"), res.Stdout()) testify.Regexp(t, getServiceRegx("another", "running"), res.Stdout())
}) })
t.Run("stop project", func(t *testing.T) { t.Run("stop project", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "stop") c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "stop")
res := c.RunDockerComposeCmd("ls") res := c.RunDockerComposeCmd(t, "ls")
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies"), res.Combined())
res = c.RunDockerComposeCmd("ls", "--all") res = c.RunDockerComposeCmd(t, "ls", "--all")
testify.Regexp(t, getProjectRegx("exited"), res.Stdout()) testify.Regexp(t, getProjectRegx("exited"), res.Stdout())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps") res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps")
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies-words-1"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies-words-1"), res.Combined())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps", "--all") res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--all")
testify.Regexp(t, getServiceRegx("simple", "exited"), res.Stdout()) testify.Regexp(t, getServiceRegx("simple", "exited"), res.Stdout())
testify.Regexp(t, getServiceRegx("another", "exited"), res.Stdout()) testify.Regexp(t, getServiceRegx("another", "exited"), res.Stdout())
}) })
t.Run("start project", func(t *testing.T) { t.Run("start project", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "start") c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "start")
res := c.RunDockerComposeCmd("ls") res := c.RunDockerComposeCmd(t, "ls")
testify.Regexp(t, getProjectRegx("running"), res.Stdout()) testify.Regexp(t, getProjectRegx("running"), res.Stdout())
}) })
t.Run("pause project", func(t *testing.T) { t.Run("pause project", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "pause") c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "pause")
res := c.RunDockerComposeCmd("ls", "--all") res := c.RunDockerComposeCmd(t, "ls", "--all")
testify.Regexp(t, getProjectRegx("paused"), res.Stdout()) testify.Regexp(t, getProjectRegx("paused"), res.Stdout())
}) })
t.Run("unpause project", func(t *testing.T) { t.Run("unpause project", func(t *testing.T) {
c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "unpause") c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "unpause")
res := c.RunDockerComposeCmd("ls") res := c.RunDockerComposeCmd(t, "ls")
testify.Regexp(t, getProjectRegx("running"), res.Stdout()) testify.Regexp(t, getProjectRegx("running"), res.Stdout())
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }
func TestStartStopWithDependencies(t *testing.T) { func TestStartStopWithDependencies(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "e2e-start-stop-with-dependencies" const projectName = "e2e-start-stop-with-dependencies"
defer c.RunDockerComposeCmd("--project-name", projectName, "rm", "-fsv") defer c.RunDockerComposeCmd(t, "--project-name", projectName, "rm", "-fsv")
t.Run("Up", func(t *testing.T) { t.Run("Up", func(t *testing.T) {
res := c.RunDockerComposeCmd("-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName, "up", "-d") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName,
"up", "-d")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined())
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined())
}) })
t.Run("stop foo", func(t *testing.T) { t.Run("stop foo", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-name", projectName, "stop", "foo") res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop", "foo")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Stopped"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Stopped"), res.Combined())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps", "--status", "running") res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--status", "running")
assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined())
assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined())
}) })
t.Run("start foo", func(t *testing.T) { t.Run("start foo", func(t *testing.T) {
res := c.RunDockerComposeCmd("--project-name", projectName, "stop") res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Stopped"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Stopped"), res.Combined())
res = c.RunDockerComposeCmd("--project-name", projectName, "start", "foo") res = c.RunDockerComposeCmd(t, "--project-name", projectName, "start", "foo")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined())
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined())
res = c.RunDockerComposeCmd("--project-name", projectName, "ps", "--status", "running") res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--status", "running")
assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined())
assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined())
}) })
t.Run("Up no-deps links", func(t *testing.T) { t.Run("Up no-deps links", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
res := c.RunDockerComposeCmd("-f", "./fixtures/links/compose.yaml", "--project-name", projectName, "up", "--no-deps", "-d", "foo") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/links/compose.yaml", "--project-name", projectName, "up",
"--no-deps", "-d", "foo")
assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined()) assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined())
assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined())
}) })
t.Run("down", func(t *testing.T) { t.Run("down", func(t *testing.T) {
_ = c.RunDockerComposeCmd("--project-name", projectName, "down") _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}) })
} }

View File

@ -29,16 +29,17 @@ import (
) )
func TestLocalComposeVolume(t *testing.T) { func TestLocalComposeVolume(t *testing.T) {
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "compose-e2e-volume" const projectName = "compose-e2e-volume"
t.Run("up with build and no image name, volume", func(t *testing.T) { t.Run("up with build and no image name, volume", func(t *testing.T) {
// ensure local test run does not reuse previously build image // ensure local test run does not reuse previously build image
c.RunDockerOrExitError("rmi", "compose-e2e-volume_nginx") c.RunDockerOrExitError(t, "rmi", "compose-e2e-volume_nginx")
c.RunDockerOrExitError("volume", "rm", projectName+"_staticVol") c.RunDockerOrExitError(t, "volume", "rm", projectName+"_staticVol")
c.RunDockerOrExitError("volume", "rm", "myvolume") c.RunDockerOrExitError(t, "volume", "rm", "myvolume")
c.RunDockerComposeCmd("--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "-d") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up",
"-d")
}) })
t.Run("access bind mount data", func(t *testing.T) { t.Run("access bind mount data", func(t *testing.T) {
@ -47,7 +48,7 @@ func TestLocalComposeVolume(t *testing.T) {
}) })
t.Run("check container volume specs", func(t *testing.T) { t.Run("check container volume specs", func(t *testing.T) {
res := c.RunDockerCmd("inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}") res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}")
output := res.Stdout() output := res.Stdout()
// nolint // nolint
assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output) assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output)
@ -55,17 +56,17 @@ func TestLocalComposeVolume(t *testing.T) {
}) })
t.Run("check config content", func(t *testing.T) { t.Run("check config content", func(t *testing.T) {
output := c.RunDockerCmd("exec", "compose-e2e-volume-nginx2-1", "cat", "/myconfig").Stdout() output := c.RunDockerCmd(t, "exec", "compose-e2e-volume-nginx2-1", "cat", "/myconfig").Stdout()
assert.Assert(t, strings.Contains(output, `Hello from Nginx container`), output) assert.Assert(t, strings.Contains(output, `Hello from Nginx container`), output)
}) })
t.Run("check secrets content", func(t *testing.T) { t.Run("check secrets content", func(t *testing.T) {
output := c.RunDockerCmd("exec", "compose-e2e-volume-nginx2-1", "cat", "/run/secrets/mysecret").Stdout() output := c.RunDockerCmd(t, "exec", "compose-e2e-volume-nginx2-1", "cat", "/run/secrets/mysecret").Stdout()
assert.Assert(t, strings.Contains(output, `Hello from Nginx container`), output) assert.Assert(t, strings.Contains(output, `Hello from Nginx container`), output)
}) })
t.Run("check container bind-mounts specs", func(t *testing.T) { t.Run("check container bind-mounts specs", func(t *testing.T) {
res := c.RunDockerCmd("inspect", "compose-e2e-volume-nginx-1", "--format", "{{ json .Mounts }}") res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx-1", "--format", "{{ json .Mounts }}")
output := res.Stdout() output := res.Stdout()
// nolint // nolint
assert.Assert(t, strings.Contains(output, `"Type":"bind"`)) assert.Assert(t, strings.Contains(output, `"Type":"bind"`))
@ -73,20 +74,20 @@ func TestLocalComposeVolume(t *testing.T) {
}) })
t.Run("should inherit anonymous volumes", func(t *testing.T) { t.Run("should inherit anonymous volumes", func(t *testing.T) {
c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test") c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test")
c.RunDockerOrExitError("compose", "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "-d") c.RunDockerOrExitError(t, "compose", "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "-d")
c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test") c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test")
}) })
t.Run("should renew anonymous volumes", func(t *testing.T) { t.Run("should renew anonymous volumes", func(t *testing.T) {
c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test") c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test")
c.RunDockerOrExitError("compose", "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "--renew-anon-volumes", "-d") c.RunDockerOrExitError(t, "compose", "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "--renew-anon-volumes", "-d")
c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test") c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test")
}) })
t.Run("cleanup volume project", func(t *testing.T) { t.Run("cleanup volume project", func(t *testing.T) {
c.RunDockerComposeCmd("--project-name", projectName, "down", "--volumes") c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--volumes")
ls := c.RunDockerCmd("volume", "ls").Stdout() ls := c.RunDockerCmd(t, "volume", "ls").Stdout()
assert.Assert(t, !strings.Contains(ls, projectName+"_staticVol")) assert.Assert(t, !strings.Contains(ls, projectName+"_staticVol"))
assert.Assert(t, !strings.Contains(ls, "myvolume")) assert.Assert(t, !strings.Contains(ls, "myvolume"))
}) })
@ -96,7 +97,7 @@ func TestProjectVolumeBind(t *testing.T) {
if composeStandaloneMode { if composeStandaloneMode {
t.Skip() t.Skip()
} }
c := NewParallelE2eCLI(t, binDir) c := NewParallelCLI(t)
const projectName = "compose-e2e-project-volume-bind" const projectName = "compose-e2e-project-volume-bind"
t.Run("up on project volume with bind specification", func(t *testing.T) { t.Run("up on project volume with bind specification", func(t *testing.T) {
@ -104,17 +105,17 @@ func TestProjectVolumeBind(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
defer os.RemoveAll(tmpDir) // nolint defer os.RemoveAll(tmpDir) // nolint
c.RunDockerComposeCmd("--project-name", projectName, "down") c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
c.RunDockerOrExitError("volume", "rm", "-f", projectName+"_project_data").Assert(t, icmd.Success) c.RunDockerOrExitError(t, "volume", "rm", "-f", projectName+"_project_data").Assert(t, icmd.Success)
cmd := c.NewCmdWithEnv([]string{"TEST_DIR=" + tmpDir}, cmd := c.NewCmdWithEnv([]string{"TEST_DIR=" + tmpDir},
"docker", "compose", "--project-directory", "fixtures/project-volume-bind-test", "--project-name", projectName, "up", "-d") "docker", "compose", "--project-directory", "fixtures/project-volume-bind-test", "--project-name", projectName, "up", "-d")
icmd.RunCmd(cmd).Assert(t, icmd.Success) icmd.RunCmd(cmd).Assert(t, icmd.Success)
defer c.RunDockerComposeCmd("--project-name", projectName, "down") defer c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
c.RunCmd("sh", "-c", "echo SUCCESS > "+filepath.Join(tmpDir, "resultfile")).Assert(t, icmd.Success) c.RunCmd(t, "sh", "-c", "echo SUCCESS > "+filepath.Join(tmpDir, "resultfile")).Assert(t, icmd.Success)
ret := c.RunDockerOrExitError("exec", "frontend", "bash", "-c", "cat /data/resultfile").Assert(t, icmd.Success) ret := c.RunDockerOrExitError(t, "exec", "frontend", "bash", "-c", "cat /data/resultfile").Assert(t, icmd.Success)
assert.Assert(t, strings.Contains(ret.Stdout(), "SUCCESS")) assert.Assert(t, strings.Contains(ret.Stdout(), "SUCCESS"))
}) })
} }