diff --git a/local/compose.go b/local/compose.go index 9818cb97d..4651492f6 100644 --- a/local/compose.go +++ b/local/compose.go @@ -143,6 +143,25 @@ func (s *composeService) Down(ctx context.Context, projectName string) error { return nil }) } + err = eg.Wait() + if err != nil { + return err + } + networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{ + Filters: filters.NewArgs( + projectFilter(projectName), + ), + }) + if err != nil { + return err + } + for _, network := range networks { + networkID := network.ID + networkName := network.Name + eg.Go(func() error { + return s.ensureNetworkDown(ctx, networkID, networkName) + }) + } return eg.Wait() } @@ -593,6 +612,32 @@ func (s *composeService) ensureNetwork(ctx context.Context, n types.NetworkConfi return nil } +func (s *composeService) ensureNetworkDown(ctx context.Context, networkID string, networkName string) error { + w := progress.ContextWriter(ctx) + w.Event(progress.Event{ + ID: fmt.Sprintf("Network %q", networkName), + Status: progress.Working, + StatusText: "Delete", + }) + + if err := s.apiClient.NetworkRemove(ctx, networkID); err != nil { + msg := fmt.Sprintf("failed to create network %s", networkID) + w.Event(progress.Event{ + ID: fmt.Sprintf("Network %q", networkName), + Status: progress.Error, + StatusText: "Error: " + msg, + }) + return errors.Wrapf(err, msg) + } + + w.Event(progress.Event{ + ID: fmt.Sprintf("Network %q", networkName), + Status: progress.Done, + StatusText: "Deleted", + }) + return nil +} + func (s *composeService) ensureVolume(ctx context.Context, volume types.VolumeConfig) error { // TODO could identify volume by label vs name _, err := s.apiClient.VolumeInspect(ctx, volume.Name) diff --git a/local/e2e/compose_test.go b/local/e2e/compose_test.go index 8aa477a73..5507c29fa 100644 --- a/local/e2e/compose_test.go +++ b/local/e2e/compose_test.go @@ -35,12 +35,11 @@ func TestLocalBackendComposeUp(t *testing.T) { const projectName = "compose-e2e-demo" + networkList := c.RunDockerCmd("--context", "default", "network", "ls") + t.Run("up", func(t *testing.T) { c.RunDockerCmd("compose", "up", "-f", "../../tests/composefiles/demo_multi_port.yaml", "--project-name", projectName) }) - t.Cleanup(func() { - _ = c.RunDockerCmd("compose", "down", "--project-name", projectName) - }) t.Run("check running project", func(t *testing.T) { res := c.RunDockerCmd("compose", "ps", "-p", projectName) @@ -49,6 +48,9 @@ func TestLocalBackendComposeUp(t *testing.T) { endpoint := "http://localhost:80" output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second) assert.Assert(t, strings.Contains(output, `"word":`)) + + res = c.RunDockerCmd("--context", "default", "network", "ls") + assert.Equal(t, len(Lines(res.Stdout())), len(Lines(networkList.Stdout()))+1) }) t.Run("check compose labels", func(t *testing.T) { @@ -67,4 +69,13 @@ func TestLocalBackendComposeUp(t *testing.T) { res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": `}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version": `}) }) + + t.Run("down", func(t *testing.T) { + _ = c.RunDockerCmd("compose", "down", "--project-name", projectName) + }) + + t.Run("check compose labels", func(t *testing.T) { + networksAfterDown := c.RunDockerCmd("--context", "default", "network", "ls") + assert.Equal(t, networkList.Stdout(), networksAfterDown.Stdout()) + }) } diff --git a/tests/aci-e2e/e2e-aci_test.go b/tests/aci-e2e/e2e-aci_test.go index 8c860a552..ccc950ee1 100644 --- a/tests/aci-e2e/e2e-aci_test.go +++ b/tests/aci-e2e/e2e-aci_test.go @@ -206,7 +206,7 @@ func TestRunVolume(t *testing.T) { t.Cleanup(func() { c.RunDockerCmd("volume", "rm", volumeID) res := c.RunDockerCmd("volume", "ls") - lines := lines(res.Stdout()) + lines := Lines(res.Stdout()) assert.Equal(t, len(lines), 1) }) @@ -217,13 +217,13 @@ func TestRunVolume(t *testing.T) { t.Run("list volumes", func(t *testing.T) { res := c.RunDockerCmd("volume", "ls", "--quiet") - l := lines(res.Stdout()) + l := Lines(res.Stdout()) assert.Equal(t, len(l), 2) assert.Equal(t, l[0], volumeID) assert.Equal(t, l[1], volumeID2) res = c.RunDockerCmd("volume", "ls") - l = lines(res.Stdout()) + l = Lines(res.Stdout()) assert.Equal(t, len(l), 3) firstAccount := l[1] fields := strings.Fields(firstAccount) @@ -251,7 +251,7 @@ func TestRunVolume(t *testing.T) { t.Run("delete only fileshare", func(t *testing.T) { c.RunDockerCmd("volume", "rm", volumeID2) res := c.RunDockerCmd("volume", "ls") - lines := lines(res.Stdout()) + lines := Lines(res.Stdout()) assert.Equal(t, len(lines), 2) assert.Assert(t, !strings.Contains(res.Stdout(), fileshareName2), "second fileshare still visible after rm") }) @@ -288,7 +288,7 @@ func TestRunVolume(t *testing.T) { t.Run("ps", func(t *testing.T) { res := c.RunDockerCmd("ps") - out := lines(res.Stdout()) + out := Lines(res.Stdout()) l := out[len(out)-1] assert.Assert(t, strings.Contains(l, container), "Looking for %q in line: %s", container, l) assert.Assert(t, strings.Contains(l, "nginx")) @@ -379,10 +379,6 @@ func TestRunVolume(t *testing.T) { }) } -func lines(output string) []string { - return strings.Split(strings.TrimSpace(output), "\n") -} - func TestContainerRunAttached(t *testing.T) { c := NewParallelE2eCLI(t, binDir) _, groupID, location := setupTestResourceGroup(t, c) @@ -472,11 +468,11 @@ func TestContainerRunAttached(t *testing.T) { t.Run("ps stopped container with --all", func(t *testing.T) { res := c.RunDockerCmd("ps", container) - out := lines(res.Stdout()) + out := Lines(res.Stdout()) assert.Assert(t, is.Len(out, 1)) res = c.RunDockerCmd("ps", "--all", container) - out = lines(res.Stdout()) + out = Lines(res.Stdout()) assert.Assert(t, is.Len(out, 2)) }) @@ -497,14 +493,14 @@ func TestContainerRunAttached(t *testing.T) { res := c.RunDockerCmd("prune") assert.Equal(t, "Deleted resources:\nTotal CPUs reclaimed: 0.00, total memory reclaimed: 0.00 GB\n", res.Stdout()) res = c.RunDockerCmd("ps") - l := lines(res.Stdout()) + l := Lines(res.Stdout()) assert.Equal(t, 2, len(l)) res = c.RunDockerCmd("prune", "--force") assert.Equal(t, "Deleted resources:\n"+container+"\nTotal CPUs reclaimed: 0.10, total memory reclaimed: 0.10 GB\n", res.Stdout()) res = c.RunDockerCmd("ps", "--all") - l = lines(res.Stdout()) + l = Lines(res.Stdout()) assert.Equal(t, 1, len(l)) }) } @@ -539,7 +535,7 @@ func TestUpSecretsResources(t *testing.T) { t.Run("compose up", func(t *testing.T) { c.RunDockerCmd("compose", "up", "-f", composefilePath, "--project-name", composeProjectName) res := c.RunDockerCmd("ps") - out := lines(res.Stdout()) + out := Lines(res.Stdout()) // Check 2 containers running assert.Assert(t, is.Len(out, 3)) }) @@ -547,7 +543,7 @@ func TestUpSecretsResources(t *testing.T) { t.Cleanup(func() { c.RunDockerCmd("compose", "down", "--project-name", composeProjectName) res := c.RunDockerCmd("ps") - out := lines(res.Stdout()) + out := Lines(res.Stdout()) assert.Equal(t, len(out), 1) }) @@ -689,7 +685,7 @@ func TestUpUpdate(t *testing.T) { t.Run("check deployed compose app", func(t *testing.T) { res := c.RunDockerCmd("ps") - out := lines(res.Stdout()) + out := Lines(res.Stdout()) // Check three containers are running assert.Assert(t, is.Len(out, 4)) webRunning := false @@ -729,11 +725,11 @@ func TestUpUpdate(t *testing.T) { t.Run("compose ps", func(t *testing.T) { res := c.RunDockerCmd("compose", "ps", "--project-name", composeProjectName, "--quiet") - l := lines(res.Stdout()) + l := Lines(res.Stdout()) assert.Assert(t, is.Len(l, 3)) res = c.RunDockerCmd("compose", "ps", "--project-name", composeProjectName) - l = lines(res.Stdout()) + l = Lines(res.Stdout()) assert.Assert(t, is.Len(l, 4)) var wordsDisplayed, webDisplayed, dbDisplayed bool for _, line := range l { @@ -757,10 +753,10 @@ func TestUpUpdate(t *testing.T) { t.Run("compose ls", func(t *testing.T) { res := c.RunDockerCmd("compose", "ls", "--quiet") - l := lines(res.Stdout()) + l := Lines(res.Stdout()) assert.Assert(t, is.Len(l, 1)) res = c.RunDockerCmd("compose", "ls") - l = lines(res.Stdout()) + l = Lines(res.Stdout()) assert.Equal(t, 2, len(l)) fields := strings.Fields(l[1]) @@ -777,7 +773,7 @@ func TestUpUpdate(t *testing.T) { t.Run("update", func(t *testing.T) { c.RunDockerCmd("compose", "up", "-f", multiPortComposefile, "--project-name", composeProjectName) res := c.RunDockerCmd("ps") - out := lines(res.Stdout()) + out := Lines(res.Stdout()) // Check three containers are running assert.Assert(t, is.Len(out, 4)) @@ -812,7 +808,7 @@ func TestUpUpdate(t *testing.T) { t.Run("down", func(t *testing.T) { c.RunDockerCmd("compose", "down", "--project-name", composeProjectName) res := c.RunDockerCmd("ps") - out := lines(res.Stdout()) + out := Lines(res.Stdout()) assert.Equal(t, len(out), 1) }) } @@ -835,7 +831,7 @@ func TestRunEnvVars(t *testing.T) { cmd.Env = append(cmd.Env, "MYSQL_USER=user1") res := icmd.RunCmd(cmd) res.Assert(t, icmd.Success) - out := lines(res.Stdout()) + out := Lines(res.Stdout()) container := strings.TrimSpace(out[len(out)-1]) res = c.RunDockerCmd("inspect", container) @@ -882,7 +878,7 @@ func setupTestResourceGroup(t *testing.T, c *E2eCLI) (string, string, string) { createAciContextAndUseIt(t, c, sID, rg, location) // Check nothing is running res := c.RunDockerCmd("ps") - assert.Assert(t, is.Len(lines(res.Stdout()), 1)) + assert.Assert(t, is.Len(Lines(res.Stdout()), 1)) return sID, rg, location } @@ -945,7 +941,7 @@ func uploadFile(t *testing.T, cred azfile.SharedKeyCredential, baseURL, fileName } func getContainerName(stdout string) string { - out := lines(stdout) + out := Lines(stdout) return strings.TrimSpace(out[len(out)-1]) } diff --git a/tests/framework/e2e.go b/tests/framework/e2e.go index edf450c0c..5844806f9 100644 --- a/tests/framework/e2e.go +++ b/tests/framework/e2e.go @@ -192,6 +192,11 @@ func GoldenFile(name string) string { return name + ".golden" } +//Lines split output into lines +func Lines(output string) []string { + return strings.Split(strings.TrimSpace(output), "\n") +} + // 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, // returning the response body as a string (empty if we could not reach it)