diff --git a/pkg/e2e/build_test.go b/pkg/e2e/build_test.go index 3097a261d5..01e84f6a05 100644 --- a/pkg/e2e/build_test.go +++ b/pkg/e2e/build_test.go @@ -410,6 +410,25 @@ func TestBuildPlatformsStandardErrors(t *testing.T) { }) t.Run("builder does not support multi-arch", func(t *testing.T) { + // Docker Desktop with containerd image store uses the docker driver + // but supports multi-platform builds, so this error won't occur. + inspect := c.RunDockerCmd(t, "buildx", "inspect", "--bootstrap") + output := inspect.Stdout() + isDockerDriver := false + platforms := "" + for _, line := range strings.Split(output, "\n") { + trimmed := strings.TrimSpace(line) + if strings.HasPrefix(trimmed, "Driver:") { + isDockerDriver = strings.TrimSpace(strings.TrimPrefix(trimmed, "Driver:")) == "docker" + } + if strings.HasPrefix(trimmed, "Platforms:") { + platforms = trimmed + } + } + if isDockerDriver && strings.Contains(platforms, "linux/amd64") && strings.Contains(platforms, "linux/arm64") { + t.Skip("docker driver supports multi-platform (containerd image store enabled)") + } + res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test/platforms", "build") res.Assert(t, icmd.Expected{ ExitCode: 1, diff --git a/pkg/e2e/compose_run_build_once_test.go b/pkg/e2e/compose_run_build_once_test.go index 24fead8c04..c1d9f24177 100644 --- a/pkg/e2e/compose_run_build_once_test.go +++ b/pkg/e2e/compose_run_build_once_test.go @@ -36,8 +36,11 @@ func TestRunBuildOnce(t *testing.T) { t.Run("dependency with pull_policy build is built only once", func(t *testing.T) { projectName := randomProjectName("build-once") - _ = c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once.yaml", "down", "--rmi", "local", "--remove-orphans", "-v") - res := c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once.yaml", "--verbose", "run", "--build", "--rm", "curl") + composeFile := "./fixtures/run-test/build-once.yaml" + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "-p", projectName, "-f", composeFile, "down", "--rmi", "local", "--remove-orphans", "-v") + }) + res := c.RunDockerComposeCmd(t, "-p", projectName, "-f", composeFile, "--verbose", "run", "--build", "--rm", "curl") output := res.Stdout() @@ -45,14 +48,15 @@ func TestRunBuildOnce(t *testing.T) { assert.Equal(t, nginxBuilds, 1, "nginx should build once, built %d times\nOutput:\n%s", nginxBuilds, output) assert.Assert(t, strings.Contains(res.Stdout(), "curl service")) - - c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once.yaml", "down", "--remove-orphans") }) t.Run("nested dependencies build only once each", func(t *testing.T) { projectName := randomProjectName("build-nested") - _ = c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once-nested.yaml", "down", "--rmi", "local", "--remove-orphans", "-v") - res := c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once-nested.yaml", "--verbose", "run", "--build", "--rm", "app") + composeFile := "./fixtures/run-test/build-once-nested.yaml" + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "-p", projectName, "-f", composeFile, "down", "--rmi", "local", "--remove-orphans", "-v") + }) + res := c.RunDockerComposeCmd(t, "-p", projectName, "-f", composeFile, "--verbose", "run", "--build", "--rm", "app") output := res.Stdout() @@ -64,14 +68,15 @@ func TestRunBuildOnce(t *testing.T) { assert.Equal(t, apiBuilds, 1, "api should build once, built %d times\nOutput:\n%s", apiBuilds, output) assert.Equal(t, appBuilds, 1, "app should build once, built %d times\nOutput:\n%s", appBuilds, output) assert.Assert(t, strings.Contains(output, "App running")) - - c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once-nested.yaml", "down", "--rmi", "local", "--remove-orphans", "-v") }) t.Run("service with no dependencies builds once", func(t *testing.T) { projectName := randomProjectName("build-simple") - _ = c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once-no-deps.yaml", "down", "--rmi", "local", "--remove-orphans") - res := c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once-no-deps.yaml", "run", "--build", "--rm", "simple") + composeFile := "./fixtures/run-test/build-once-no-deps.yaml" + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "-p", projectName, "-f", composeFile, "down", "--rmi", "local", "--remove-orphans", "-v") + }) + res := c.RunDockerComposeCmd(t, "-p", projectName, "-f", composeFile, "run", "--build", "--rm", "simple") output := res.Stdout() @@ -79,8 +84,6 @@ func TestRunBuildOnce(t *testing.T) { assert.Equal(t, simpleBuilds, 1, "simple should build once, built %d times\nOutput:\n%s", simpleBuilds, output) assert.Assert(t, strings.Contains(res.Stdout(), "Simple service")) - - c.RunDockerComposeCmd(t, "-p", projectName, "-f", "./fixtures/run-test/build-once-no-deps.yaml", "down", "--remove-orphans") }) } diff --git a/pkg/e2e/compose_run_test.go b/pkg/e2e/compose_run_test.go index 44c797cb14..9c44009895 100644 --- a/pkg/e2e/compose_run_test.go +++ b/pkg/e2e/compose_run_test.go @@ -20,9 +20,11 @@ import ( "os" "strings" "testing" + "time" "gotest.tools/v3/assert" "gotest.tools/v3/icmd" + "gotest.tools/v3/poll" ) func TestLocalComposeRun(t *testing.T) { @@ -207,8 +209,14 @@ func TestLocalComposeRun(t *testing.T) { res = c.RunDockerCmd(t, "stop", containerID) res.Assert(t, icmd.Success) - res = c.RunDockerCmd(t, "ps", "--all", "--filter", "name=run-test-nginx", "--format", "'{{.Names}}'") - assert.Assert(t, !strings.Contains(res.Stdout(), "run-test-nginx"), res.Stdout()) + // --rm auto-removal is async, wait for the container to be removed + poll.WaitOn(t, func(l poll.LogT) poll.Result { + res = c.RunDockerCmd(t, "ps", "--all", "--filter", "name=run-test-nginx", "--format", "'{{.Names}}'") + if strings.Contains(res.Stdout(), "run-test-nginx") { + return poll.Continue("container still present: %s", res.Stdout()) + } + return poll.Success() + }, poll.WithTimeout(10*time.Second), poll.WithDelay(500*time.Millisecond)) }) t.Run("compose run --env", func(t *testing.T) { diff --git a/pkg/e2e/compose_test.go b/pkg/e2e/compose_test.go index 5d7c78c229..41e2a89d7a 100644 --- a/pkg/e2e/compose_test.go +++ b/pkg/e2e/compose_test.go @@ -140,16 +140,13 @@ func TestDownComposefileInParentFolder(t *testing.T) { } func TestAttachRestart(t *testing.T) { - t.Skip("Skipping test until we can fix it") - - if _, ok := os.LookupEnv("CI"); ok { - t.Skip("Skipping test on CI... flaky") - } c := NewParallelCLI(t) cmd := c.NewDockerComposeCmd(t, "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up") res := icmd.StartCmd(cmd) - defer c.RunDockerComposeCmd(t, "-p", "attach-restart", "down") + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "-p", "attach-restart", "down") + }) c.WaitForCondition(t, func() (bool, string) { debug := res.Combined() diff --git a/pkg/e2e/env_file_test.go b/pkg/e2e/env_file_test.go index d9ea1d4c2b..f41723b88b 100644 --- a/pkg/e2e/env_file_test.go +++ b/pkg/e2e/env_file_test.go @@ -46,8 +46,9 @@ func TestUnusedMissingEnvFile(t *testing.T) { func TestRunEnvFile(t *testing.T) { c := NewParallelCLI(t) - defer c.cleanupWithDown(t, "run_dotenv") + const projectName = "run-dotenv" + defer c.cleanupWithDown(t, projectName) - res := c.RunDockerComposeCmd(t, "--project-directory", "./fixtures/env_file", "run", "serviceC", "env") + res := c.RunDockerComposeCmd(t, "-p", projectName, "--project-directory", "./fixtures/env_file", "run", "--rm", "serviceC", "env") res.Assert(t, icmd.Expected{Out: "FOO=BAR"}) } diff --git a/pkg/e2e/model_test.go b/pkg/e2e/model_test.go index f30d7c5bb0..3545bf4a5d 100644 --- a/pkg/e2e/model_test.go +++ b/pkg/e2e/model_test.go @@ -21,9 +21,11 @@ import ( ) func TestComposeModel(t *testing.T) { - t.Skip("waiting for docker-model release") + if _, err := findPluginExecutable(DockerModelExecutableName); err != nil { + t.Skip("docker-model plugin not available") + } c := NewParallelCLI(t) defer c.cleanupWithDown(t, "model-test") - c.RunDockerComposeCmd(t, "-f", "./fixtures/model/compose.yaml", "run", "test", "sh", "-c", "curl ${FOO_URL}") + c.RunDockerComposeCmd(t, "-p", "model-test", "-f", "./fixtures/model/compose.yaml", "run", "--rm", "test", "sh", "-c", "curl ${FOO_URL}") } diff --git a/pkg/e2e/networks_test.go b/pkg/e2e/networks_test.go index d4fbc36599..88cbf27c04 100644 --- a/pkg/e2e/networks_test.go +++ b/pkg/e2e/networks_test.go @@ -147,7 +147,6 @@ func TestNetworkModes(t *testing.T) { } func TestNetworkConfigChanged(t *testing.T) { - t.Skip("unstable") // fixture is shared with TestNetworks and is not safe to run concurrently c := NewCLI(t) const projectName = "network_config_change" diff --git a/pkg/e2e/pause_test.go b/pkg/e2e/pause_test.go index 005407b556..8b94e4653b 100644 --- a/pkg/e2e/pause_test.go +++ b/pkg/e2e/pause_test.go @@ -22,7 +22,6 @@ import ( "fmt" "net" "net/http" - "os" "testing" "time" @@ -31,9 +30,6 @@ import ( ) func TestPause(t *testing.T) { - if _, ok := os.LookupEnv("CI"); ok { - t.Skip("Skipping test on CI... flaky") - } cli := NewParallelCLI(t, WithEnv( "COMPOSE_PROJECT_NAME=e2e-pause", "COMPOSE_FILE=./fixtures/pause/compose.yaml")) diff --git a/pkg/e2e/ps_test.go b/pkg/e2e/ps_test.go index 34eb380fbc..26e799d679 100644 --- a/pkg/e2e/ps_test.go +++ b/pkg/e2e/ps_test.go @@ -32,6 +32,9 @@ func TestPs(t *testing.T) { c := NewParallelCLI(t) const projectName = "e2e-ps" + // ensure clean state from any previous failed run + c.RunDockerComposeCmdNoCheck(t, "--project-name", projectName, "down", "--remove-orphans") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "up", "-d") assert.NilError(t, res.Error) t.Cleanup(func() { diff --git a/pkg/e2e/publish_test.go b/pkg/e2e/publish_test.go index 1dd83d031e..7c8455822f 100644 --- a/pkg/e2e/publish_test.go +++ b/pkg/e2e/publish_test.go @@ -18,11 +18,14 @@ package e2e import ( "fmt" + "net/http" "strings" "testing" + "time" "gotest.tools/v3/assert" "gotest.tools/v3/icmd" + "gotest.tools/v3/poll" ) func TestPublishChecks(t *testing.T) { @@ -136,6 +139,20 @@ func TestPublish(t *testing.T) { c.RunDockerCmd(t, "rm", "--force", registryName) }) + // Wait for registry to be ready + registryURL := "http://" + registry + "/v2/" + poll.WaitOn(t, func(l poll.LogT) poll.Result { + resp, err := http.Get(registryURL) //nolint:gosec,noctx + if err != nil { + return poll.Continue("registry not ready: %v", err) + } + _ = resp.Body.Close() + if resp.StatusCode < 500 { + return poll.Success() + } + return poll.Continue("registry not ready, status %d", resp.StatusCode) + }, poll.WithTimeout(10*time.Second), poll.WithDelay(100*time.Millisecond)) + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/publish/oci/compose.yaml", "-f", "./fixtures/publish/oci/compose-override.yaml", "-p", projectName, "publish", "--with-env", "--yes", "--insecure-registry", registry+"/test:test") res.Assert(t, icmd.Expected{ExitCode: 0}) diff --git a/pkg/e2e/watch_test.go b/pkg/e2e/watch_test.go index 5fd59a9fd8..1716be05d0 100644 --- a/pkg/e2e/watch_test.go +++ b/pkg/e2e/watch_test.go @@ -335,7 +335,7 @@ func TestWatchMultiServices(t *testing.T) { testFile := filepath.Join(tmpdir, "test") assert.NilError(t, os.WriteFile(testFile, []byte("test"), 0o600)) - cmd := c.NewDockerComposeCmd(t, "-p", projectName, "-f", composeFilePath, "up", "--watch") + cmd := c.NewDockerComposeCmd(t, "-p", projectName, "-f", composeFilePath, "up", "--build", "--watch") buffer := bytes.NewBuffer(nil) cmd.Stdout = buffer watch := icmd.StartCmd(cmd) @@ -345,7 +345,7 @@ func TestWatchMultiServices(t *testing.T) { return poll.Success() } return poll.Continue("%v", watch.Stdout()) - }) + }, poll.WithTimeout(90*time.Second)) waitRebuild := func(service string, expected string) { poll.WaitOn(t, func(l poll.LogT) poll.Result { @@ -354,7 +354,7 @@ func TestWatchMultiServices(t *testing.T) { return poll.Success() } return poll.Continue("%v", cat.Combined()) - }) + }, poll.WithTimeout(90*time.Second)) } waitRebuild("a", "test") waitRebuild("b", "test") diff --git a/pkg/utils/safebuffer.go b/pkg/utils/safebuffer.go index 8623f8ca99..dd0f976fe8 100644 --- a/pkg/utils/safebuffer.go +++ b/pkg/utils/safebuffer.go @@ -79,7 +79,9 @@ func (b *SafeBuffer) RequireEventuallyContains(t testing.TB, v string) { } return poll.Success() }, - poll.WithTimeout(2*time.Second), + // 10s: container startup on Docker Desktop (macOS) with VM overhead + // can take 3-8s vs <1s on native Linux CI + poll.WithTimeout(10*time.Second), poll.WithDelay(20*time.Millisecond), ) }