From 0b1c86726eb27b904afedc08525d4e8d4fb777ce Mon Sep 17 00:00:00 2001 From: Laura Brehm Date: Tue, 17 Jan 2023 15:48:58 +0100 Subject: [PATCH] Add tests for filtering containers not created by Compose Signed-off-by: Laura Brehm --- e2e/cucumber-features/ps.feature | 27 ++++++++++++++++++ e2e/cucumber-features/up.feature | 4 ++- e2e/cucumber_test.go | 48 ++++++++++++++++++++++++++++---- pkg/compose/convergence_test.go | 2 ++ pkg/compose/kill_test.go | 5 ++-- pkg/compose/logs_test.go | 4 +-- pkg/compose/ps_test.go | 2 +- 7 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 e2e/cucumber-features/ps.feature diff --git a/e2e/cucumber-features/ps.feature b/e2e/cucumber-features/ps.feature new file mode 100644 index 000000000..e4e256f9d --- /dev/null +++ b/e2e/cucumber-features/ps.feature @@ -0,0 +1,27 @@ +Feature: PS + +Background: + Given a compose file + """ + services: + build: + image: test:latest + build: + context: ./ + pull: + image: alpine + command: top + """ + And a dockerfile + """ + FROM golang:1.19-alpine + """ + +Scenario: external container from compose image exists + When I run "compose build" + Then the exit code is 0 + And I run "docker run --name external-test test:latest ls" + Then the exit code is 0 + And I run "compose ps -a" + Then the output does not contain "external-test" + diff --git a/e2e/cucumber-features/up.feature b/e2e/cucumber-features/up.feature index 10fc77ffd..ccd33d3cd 100644 --- a/e2e/cucumber-features/up.feature +++ b/e2e/cucumber-features/up.feature @@ -11,5 +11,7 @@ Background: Scenario: --pull always When I run "compose up --pull=always -d" - Then the output contains "simple Pulled" + And the output contains "simple Pulled" + Then I run "compose up --pull=always -d" + And the output contains "simple Pulled" diff --git a/e2e/cucumber_test.go b/e2e/cucumber_test.go index f9c44e7bd..d9d2128a7 100644 --- a/e2e/cucumber_test.go +++ b/e2e/cucumber_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "os" + "path/filepath" "regexp" "strings" "testing" @@ -78,9 +79,12 @@ func setup(s *godog.ScenarioContext) { }) s.Step(`^a compose file$`, th.setComposeFile) + s.Step(`^a dockerfile$`, th.setDockerfile) s.Step(`^I run "compose (.*)"$`, th.runComposeCommand) + s.Step(`^I run "docker (.*)"$`, th.runDockerCommand) s.Step(`service "(.*)" is "(.*)"$`, th.serviceIsStatus) - s.Step(`output contains "(.*)"$`, th.outputContains) + s.Step(`output contains "(.*)"$`, th.outputContains(true)) + s.Step(`output does not contain "(.*)"$`, th.outputContains(false)) s.Step(`exit code is (\d+)$`, th.exitCodeIs) } @@ -88,6 +92,7 @@ type testHelper struct { T *testing.T ProjectName string ComposeFile string + TestDir string CommandOutput string CommandExitCode int CLI *e2e.CLI @@ -104,16 +109,21 @@ func (th *testHelper) serviceIsStatus(service, status string) error { return nil } -func (th *testHelper) outputContains(substring string) error { - if !strings.Contains(th.CommandOutput, substring) { - return fmt.Errorf("Missing output substring: %s\noutput: %s", substring, th.CommandOutput) +func (th *testHelper) outputContains(expected bool) func(string) error { + return func(substring string) error { + contains := strings.Contains(th.CommandOutput, substring) + if contains && !expected { + return fmt.Errorf("Unexpected substring in output: %s\noutput: %s", substring, th.CommandOutput) + } else if !contains && expected { + return fmt.Errorf("Missing substring in output: %s\noutput: %s", substring, th.CommandOutput) + } + return nil } - return nil } func (th *testHelper) exitCodeIs(exitCode int) error { if exitCode != th.CommandExitCode { - return fmt.Errorf("Wrong exit code: %d expected: %d", th.CommandExitCode, exitCode) + return fmt.Errorf("Wrong exit code: %d expected: %d || command output: %s", th.CommandExitCode, exitCode, th.CommandOutput) } return nil } @@ -127,6 +137,21 @@ func (th *testHelper) runComposeCommand(command string) error { cmd := th.CLI.NewDockerComposeCmd(th.T, commandArgs...) cmd.Stdin = strings.NewReader(th.ComposeFile) + cmd.Dir = th.TestDir + res := icmd.RunCmd(cmd) + th.CommandOutput = res.Combined() + th.CommandExitCode = res.ExitCode + return nil +} + +func (th *testHelper) runDockerCommand(command string) error { + commandArgs, err := shellwords.Parse(command) + if err != nil { + return err + } + + cmd := th.CLI.NewDockerCmd(th.T, commandArgs...) + cmd.Dir = th.TestDir res := icmd.RunCmd(cmd) th.CommandOutput = res.Combined() th.CommandExitCode = res.ExitCode @@ -137,3 +162,14 @@ func (th *testHelper) setComposeFile(composeString string) error { th.ComposeFile = composeString return nil } + +func (th *testHelper) setDockerfile(dockerfileString string) error { + tempDir := th.T.TempDir() + th.TestDir = tempDir + + err := os.WriteFile(filepath.Join(tempDir, "Dockerfile"), []byte(dockerfileString), 0o644) + if err != nil { + return err + } + return nil +} diff --git a/pkg/compose/convergence_test.go b/pkg/compose/convergence_test.go index 3fc8092f1..1cf8f8b8b 100644 --- a/pkg/compose/convergence_test.go +++ b/pkg/compose/convergence_test.go @@ -68,6 +68,7 @@ func TestServiceLinks(t *testing.T) { projectFilter(testProject), serviceFilter("db"), oneOffFilter(false), + hasConfigHashLabel(), ), All: true, } @@ -193,6 +194,7 @@ func TestServiceLinks(t *testing.T) { projectFilter(testProject), serviceFilter("web"), oneOffFilter(false), + hasConfigHashLabel(), ), All: true, } diff --git a/pkg/compose/kill_test.go b/pkg/compose/kill_test.go index a9f623eea..f17845f73 100644 --- a/pkg/compose/kill_test.go +++ b/pkg/compose/kill_test.go @@ -50,7 +50,7 @@ func TestKillAll(t *testing.T) { ctx := context.Background() api.EXPECT().ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs(projectFilter(name)), + Filters: filters.NewArgs(projectFilter(name), hasConfigHashLabel()), }).Return( []moby.Container{testContainer("service1", "123", false), testContainer("service1", "456", false), testContainer("service2", "789", false)}, nil) api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))). @@ -81,7 +81,7 @@ func TestKillSignal(t *testing.T) { name := strings.ToLower(testProject) listOptions := moby.ContainerListOptions{ - Filters: filters.NewArgs(projectFilter(name), serviceFilter(serviceName)), + Filters: filters.NewArgs(projectFilter(name), serviceFilter(serviceName), hasConfigHashLabel()), } ctx := context.Background() @@ -133,6 +133,7 @@ func anyCancellableContext() gomock.Matcher { func projectFilterListOpt(withOneOff bool) moby.ContainerListOptions { filter := filters.NewArgs( projectFilter(strings.ToLower(testProject)), + hasConfigHashLabel(), ) if !withOneOff { filter.Add("label", fmt.Sprintf("%s=False", compose.OneoffLabel)) diff --git a/pkg/compose/logs_test.go b/pkg/compose/logs_test.go index b81f976c7..de80a9875 100644 --- a/pkg/compose/logs_test.go +++ b/pkg/compose/logs_test.go @@ -52,7 +52,7 @@ func TestComposeService_Logs_Demux(t *testing.T) { ctx := context.Background() api.EXPECT().ContainerList(ctx, moby.ContainerListOptions{ All: true, - Filters: filters.NewArgs(oneOffFilter(false), projectFilter(name)), + Filters: filters.NewArgs(oneOffFilter(false), projectFilter(name), hasConfigHashLabel()), }).Return( []moby.Container{ testContainer("service", "c", false), @@ -125,7 +125,7 @@ func TestComposeService_Logs_ServiceFiltering(t *testing.T) { ctx := context.Background() api.EXPECT().ContainerList(ctx, moby.ContainerListOptions{ All: true, - Filters: filters.NewArgs(oneOffFilter(false), projectFilter(name)), + Filters: filters.NewArgs(oneOffFilter(false), projectFilter(name), hasConfigHashLabel()), }).Return( []moby.Container{ testContainer("serviceA", "c1", false), diff --git a/pkg/compose/ps_test.go b/pkg/compose/ps_test.go index 7e079202b..c5e7fdb97 100644 --- a/pkg/compose/ps_test.go +++ b/pkg/compose/ps_test.go @@ -42,7 +42,7 @@ func TestPs(t *testing.T) { cli.EXPECT().Client().Return(api).AnyTimes() ctx := context.Background() - args := filters.NewArgs(projectFilter(strings.ToLower(testProject))) + args := filters.NewArgs(projectFilter(strings.ToLower(testProject)), hasConfigHashLabel()) args.Add("label", "com.docker.compose.oneoff=False") listOpts := moby.ContainerListOptions{Filters: args, All: false} c1, inspect1 := containerDetails("service1", "123", "running", "healthy", 0)