From 3878b011a731b9e0292c64cd7b14f438d9993ac6 Mon Sep 17 00:00:00 2001 From: apostasie Date: Fri, 18 Apr 2025 11:31:22 -0700 Subject: [PATCH 1/2] Allow multiple needles in Contains and DoesNotContain Signed-off-by: apostasie --- mod/tigron/expect/comparators.go | 14 ++++++++++++-- mod/tigron/expect/comparators_test.go | 3 +++ mod/tigron/expect/doc.md | 4 ++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/mod/tigron/expect/comparators.go b/mod/tigron/expect/comparators.go index 7bf87803f41..84f5fe13bd2 100644 --- a/mod/tigron/expect/comparators.go +++ b/mod/tigron/expect/comparators.go @@ -41,18 +41,28 @@ func All(comparators ...test.Comparator) test.Comparator { // Contains can be used as a parameter for expected.Output and ensures a comparison string is found contained in the // output. -func Contains(compare string) test.Comparator { +func Contains(compare string, more ...string) test.Comparator { return func(stdout, _ string, t *testing.T) { t.Helper() + assertive.Contains(assertive.WithFailLater(t), stdout, compare, "Inspecting output (contains)") + + for _, m := range more { + assertive.Contains(assertive.WithFailLater(t), stdout, m, "Inspecting output (contains)") + } } } // DoesNotContain is to be used for expected.Output to ensure a comparison string is NOT found in the output. -func DoesNotContain(compare string) test.Comparator { +func DoesNotContain(compare string, more ...string) test.Comparator { return func(stdout, _ string, t *testing.T) { t.Helper() + assertive.DoesNotContain(assertive.WithFailLater(t), stdout, compare, "Inspecting output (does not contain)") + + for _, m := range more { + assertive.DoesNotContain(assertive.WithFailLater(t), stdout, m, "Inspecting output (does not contain)") + } } } diff --git a/mod/tigron/expect/comparators_test.go b/mod/tigron/expect/comparators_test.go index f216d3ecb51..d0d76c3b701 100644 --- a/mod/tigron/expect/comparators_test.go +++ b/mod/tigron/expect/comparators_test.go @@ -30,6 +30,7 @@ import ( ) func TestExpect(t *testing.T) { + // TODO: write more tests once we can mock t in Comparator signature t.Parallel() expect.Contains("b")("a b c", "contains works", t) @@ -39,7 +40,9 @@ func TestExpect(t *testing.T) { expect.All( expect.Contains("b"), + expect.Contains("b", "c"), expect.DoesNotContain("d"), + expect.DoesNotContain("d", "e"), expect.Equals("a b c"), expect.Match(regexp.MustCompile("[a-z ]+")), )("a b c", "all", t) diff --git a/mod/tigron/expect/doc.md b/mod/tigron/expect/doc.md index 7b2e9828df6..566f92d8c55 100644 --- a/mod/tigron/expect/doc.md +++ b/mod/tigron/expect/doc.md @@ -53,8 +53,8 @@ The last parameter of `test.Expects` accepts a `test.Comparator`, which allows t output on `stdout`. The following ready-made `test.Comparator` generators are provided: -- `expect.Contains(string)`: verifies that stdout contains the string parameter -- `expect.DoesNotContain(string)`: negation of above +- `expect.Contains(string, ...string)`: verifies that stdout does contain the provided parameters +- `expect.DoesNotContain(string, ...string)`: verifies that stdout does not contain any of the passed parameters - `expect.Equals(string)`: strict equality - `expect.Match(*regexp.Regexp)`: regexp matching - `expect.All(comparators ...Comparator)`: allows to bundle together a bunch of other comparators From 4e961136d5b3158dea3ae972003e45644a8a72f5 Mon Sep 17 00:00:00 2001 From: apostasie Date: Fri, 18 Apr 2025 11:31:49 -0700 Subject: [PATCH 2/2] Streamline tests to leverage Contain/DoesNotContain multi parameters Signed-off-by: apostasie --- cmd/nerdctl/completion/completion_test.go | 15 ++------ .../compose/compose_build_linux_test.go | 5 +-- cmd/nerdctl/compose/compose_config_test.go | 33 ++++++++--------- .../compose/compose_exec_linux_test.go | 17 ++++----- cmd/nerdctl/container/container_diff_test.go | 15 ++++---- cmd/nerdctl/container/container_logs_test.go | 12 +++---- cmd/nerdctl/container/container_run_test.go | 36 ++++++++++--------- cmd/nerdctl/image/image_list_test.go | 15 ++++---- cmd/nerdctl/image/image_remove_test.go | 7 ++-- cmd/nerdctl/volume/volume_inspect_test.go | 3 +- cmd/nerdctl/volume/volume_prune_linux_test.go | 14 ++++---- 11 files changed, 78 insertions(+), 94 deletions(-) diff --git a/cmd/nerdctl/completion/completion_test.go b/cmd/nerdctl/completion/completion_test.go index bde281ab497..89266ceda4a 100644 --- a/cmd/nerdctl/completion/completion_test.go +++ b/cmd/nerdctl/completion/completion_test.go @@ -91,10 +91,7 @@ func TestCompletion(t *testing.T) { Command: test.Command("__complete", "run", "--net", ""), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: expect.All( - expect.Contains("host\n"), - expect.Contains(data.Labels().Get("identifier")+"\n"), - ), + Output: expect.Contains("host\n", data.Labels().Get("identifier")+"\n"), } }, }, @@ -103,10 +100,7 @@ func TestCompletion(t *testing.T) { Command: test.Command("__complete", "run", "-it", "--net", ""), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: expect.All( - expect.Contains("host\n"), - expect.Contains(data.Labels().Get("identifier")+"\n"), - ), + Output: expect.Contains("host\n", data.Labels().Get("identifier")+"\n"), } }, }, @@ -115,10 +109,7 @@ func TestCompletion(t *testing.T) { Command: test.Command("__complete", "run", "-it", "--rm", "--net", ""), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: expect.All( - expect.Contains("host\n"), - expect.Contains(data.Labels().Get("identifier")+"\n"), - ), + Output: expect.Contains("host\n", data.Labels().Get("identifier")+"\n"), } }, }, diff --git a/cmd/nerdctl/compose/compose_build_linux_test.go b/cmd/nerdctl/compose/compose_build_linux_test.go index 6ea0663240a..2c967a331e2 100644 --- a/cmd/nerdctl/compose/compose_build_linux_test.go +++ b/cmd/nerdctl/compose/compose_build_linux_test.go @@ -95,10 +95,7 @@ services: Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: expect.All( - expect.Contains(data.Labels().Get("imageSvc0")), - expect.Contains(data.Labels().Get("imageSvc1")), - ), + Output: expect.Contains(data.Labels().Get("imageSvc0"), data.Labels().Get("imageSvc1")), } }, }, diff --git a/cmd/nerdctl/compose/compose_config_test.go b/cmd/nerdctl/compose/compose_config_test.go index 5df0c9eeebb..e9f16c6a92d 100644 --- a/cmd/nerdctl/compose/compose_config_test.go +++ b/cmd/nerdctl/compose/compose_config_test.go @@ -162,12 +162,11 @@ services: "config", ) }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( - expect.Contains("alpine:3.13"), - expect.Contains("alpine:3.14"), - expect.Contains("hello1"), - expect.Contains("hello2"), - )), + Expected: test.Expects( + expect.ExitCodeSuccess, + nil, + expect.Contains("alpine:3.13", "alpine:3.14", "hello1", "hello2"), + ), }, { Description: "project dir", @@ -230,12 +229,11 @@ services: cmd.Setenv("COMPOSE_PATH_SEPARATOR", ",") return cmd }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( - expect.Contains("alpine:3.13"), - expect.Contains("alpine:3.14"), - expect.Contains("hello1"), - expect.Contains("hello2"), - )), + Expected: test.Expects( + expect.ExitCodeSuccess, + nil, + expect.Contains("alpine:3.13", "alpine:3.14", "hello1", "hello2"), + ), }, { Description: "env with project dir", @@ -249,12 +247,11 @@ services: cmd.Setenv("COMPOSE_PATH_SEPARATOR", ",") return cmd }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( - expect.Contains("alpine:3.13"), - expect.Contains("alpine:3.14"), - expect.Contains("hello1"), - expect.Contains("hello2"), - )), + Expected: test.Expects( + expect.ExitCodeSuccess, + nil, + expect.Contains("alpine:3.13", "alpine:3.14", "hello1", "hello2"), + ), }, } diff --git a/cmd/nerdctl/compose/compose_exec_linux_test.go b/cmd/nerdctl/compose/compose_exec_linux_test.go index be437cb94d0..0f86c447de4 100644 --- a/cmd/nerdctl/compose/compose_exec_linux_test.go +++ b/cmd/nerdctl/compose/compose_exec_linux_test.go @@ -128,15 +128,16 @@ services: "env") }, Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( - expect.Contains("\nFOO=foo1,foo2\n"), - expect.Contains("\nBAR=bar1 bar2\n"), - expect.Contains("\nBAZ=\n"), + expect.Contains( + "\nFOO=foo1,foo2\n", + "\nBAR=bar1 bar2\n", + "\nBAZ=\n", + "\nQUUX=quux2\n", + "\nCORGE=corge-value-in-host\n", + "\nGRAULT=grault_key=grault_value\n", + "\nGARPLY=\n", + "\nWALDO=\n"), expect.DoesNotContain("QUX"), - expect.Contains("\nQUUX=quux2\n"), - expect.Contains("\nCORGE=corge-value-in-host\n"), - expect.Contains("\nGRAULT=grault_key=grault_value\n"), - expect.Contains("\nGARPLY=\n"), - expect.Contains("\nWALDO=\n"), )), }, } diff --git a/cmd/nerdctl/container/container_diff_test.go b/cmd/nerdctl/container/container_diff_test.go index 07e0cb4fd45..dc09244a3a0 100644 --- a/cmd/nerdctl/container/container_diff_test.go +++ b/cmd/nerdctl/container/container_diff_test.go @@ -51,12 +51,15 @@ func TestDiff(t *testing.T) { return helpers.Command("diff", data.Identifier()) } - testCase.Expected = test.Expects(0, nil, expect.All( - expect.Contains("A /a"), - expect.Contains("C /bin"), - expect.Contains("A /bin/b"), - expect.Contains("D /bin/base64"), - )) + testCase.Expected = test.Expects( + 0, + nil, + expect.Contains( + "A /a", + "C /bin", + "A /bin/b", + "D /bin/base64"), + ) testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_logs_test.go b/cmd/nerdctl/container/container_logs_test.go index 05b6ea67190..76fe2f96fd6 100644 --- a/cmd/nerdctl/container/container_logs_test.go +++ b/cmd/nerdctl/container/container_logs_test.go @@ -247,8 +247,7 @@ func TestLogsWithForegroundContainers(t *testing.T) { return helpers.Command("logs", data.Identifier()) }, Expected: test.Expects(0, nil, expect.All( - expect.Contains("foo"), - expect.Contains("bar"), + expect.Contains("foo", "bar"), expect.DoesNotContain("baz"), )), }, @@ -264,8 +263,7 @@ func TestLogsWithForegroundContainers(t *testing.T) { return helpers.Command("logs", data.Identifier()) }, Expected: test.Expects(0, nil, expect.All( - expect.Contains("foo"), - expect.Contains("bar"), + expect.Contains("foo", "bar"), expect.DoesNotContain("baz"), )), }, @@ -283,8 +281,7 @@ func TestLogsWithForegroundContainers(t *testing.T) { return helpers.Command("logs", data.Identifier()) }, Expected: test.Expects(0, nil, expect.All( - expect.Contains("foo"), - expect.Contains("bar"), + expect.Contains("foo", "bar"), expect.DoesNotContain("baz"), )), }, @@ -302,8 +299,7 @@ func TestLogsWithForegroundContainers(t *testing.T) { return helpers.Command("logs", data.Identifier()) }, Expected: test.Expects(0, nil, expect.All( - expect.Contains("foo"), - expect.Contains("bar"), + expect.Contains("foo", "bar"), expect.DoesNotContain("baz"), )), }, diff --git a/cmd/nerdctl/container/container_run_test.go b/cmd/nerdctl/container/container_run_test.go index eb0d22c9674..82b7cbd7f53 100644 --- a/cmd/nerdctl/container/container_run_test.go +++ b/cmd/nerdctl/container/container_run_test.go @@ -87,8 +87,7 @@ CMD ["echo", "bar"] }, Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( expect.Contains("blah"), - expect.DoesNotContain("foo"), - expect.DoesNotContain("bar"), + expect.DoesNotContain("foo", "bar"), )), }, { @@ -98,8 +97,7 @@ CMD ["echo", "bar"] }, Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( expect.Contains("blah"), - expect.DoesNotContain("foo"), - expect.DoesNotContain("bar"), + expect.DoesNotContain("foo", "bar"), )), }, }, @@ -207,11 +205,11 @@ func TestRunEnvFile(t *testing.T) { testutil.CommonImage, "env") } - testCase.Expected = test.Expects(expect.ExitCodeSuccess, nil, expect.All( - expect.Contains("TESTKEY1=TESTVAL1"), - expect.Contains("TESTKEY2=TESTVAL2"), - expect.Contains("HOST_ENV=ENV-IN-HOST"), - )) + testCase.Expected = test.Expects( + expect.ExitCodeSuccess, + nil, + expect.Contains("TESTKEY1=TESTVAL1", "TESTKEY2=TESTVAL2", "HOST_ENV=ENV-IN-HOST"), + ) testCase.Run(t) } @@ -240,20 +238,24 @@ func TestRunEnv(t *testing.T) { } validate := []test.Comparator{ - expect.Contains("\nFOO=foo1,foo2\n"), - expect.Contains("\nBAR=bar1 bar2\n"), + expect.Contains( + "\nFOO=foo1,foo2\n", + "\nBAR=bar1 bar2\n", + "\nQUUX=quux2\n", + "\nCORGE=corge-value-in-host\n", + "\nGRAULT=grault_key=grault_value\n", + ), expect.DoesNotContain("QUX"), - expect.Contains("\nQUUX=quux2\n"), - expect.Contains("\nCORGE=corge-value-in-host\n"), - expect.Contains("\nGRAULT=grault_key=grault_value\n"), } if runtime.GOOS != "windows" { validate = append( validate, - expect.Contains("\nBAZ=\n"), - expect.Contains("\nGARPLY=\n"), - expect.Contains("\nWALDO=\n"), + expect.Contains( + "\nBAZ=\n", + "\nGARPLY=\n", + "\nWALDO=\n", + ), ) } diff --git a/cmd/nerdctl/image/image_list_test.go b/cmd/nerdctl/image/image_list_test.go index a1db81ee440..6eba01c84c5 100644 --- a/cmd/nerdctl/image/image_list_test.go +++ b/cmd/nerdctl/image/image_list_test.go @@ -223,10 +223,11 @@ RUN echo "actually creating a layer so that docker sets the createdAt time" { Description: "reference=tagged*:*fragment*", Command: test.Command("images", "--filter", "reference=tagged*:*fragment*"), - Expected: test.Expects(0, nil, expect.All( - expect.Contains("one-"), - expect.Contains("two-"), - )), + Expected: test.Expects( + 0, + nil, + expect.Contains("one-", "two-"), + ), }, { Description: "before=ID:latest", @@ -259,9 +260,9 @@ RUN echo "actually creating a layer so that docker sets the createdAt time" Command: test.Command("images", "--filter", fmt.Sprintf("since=%s", testutil.CommonImage), testutil.CommonImage), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: expect.All( - expect.DoesNotContain(data.Labels().Get("builtImageID")), - expect.DoesNotContain(testutil.ImageRepo(testutil.CommonImage)), + Output: expect.DoesNotContain( + data.Labels().Get("builtImageID"), + testutil.ImageRepo(testutil.CommonImage), ), } }, diff --git a/cmd/nerdctl/image/image_remove_test.go b/cmd/nerdctl/image/image_remove_test.go index db5fa47f722..11f2f050636 100644 --- a/cmd/nerdctl/image/image_remove_test.go +++ b/cmd/nerdctl/image/image_remove_test.go @@ -186,11 +186,8 @@ func TestRemove(t *testing.T) { return &test.Expected{ Output: func(stdout string, info string, t *testing.T) { helpers.Command("images").Run(&test.Expected{ - Output: expect.All( - expect.DoesNotContain(repoName), - // a created container with removed image doesn't impact other `rmi` command - expect.DoesNotContain(nginxRepoName), - ), + // a created container with removed image doesn't impact other `rmi` command + Output: expect.DoesNotContain(repoName, nginxRepoName), }) }, } diff --git a/cmd/nerdctl/volume/volume_inspect_test.go b/cmd/nerdctl/volume/volume_inspect_test.go index af2e7938884..b42b3d41558 100644 --- a/cmd/nerdctl/volume/volume_inspect_test.go +++ b/cmd/nerdctl/volume/volume_inspect_test.go @@ -152,8 +152,7 @@ func TestVolumeInspect(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ Output: expect.All( - expect.Contains(data.Labels().Get("vol1")), - expect.Contains(data.Labels().Get("vol2")), + expect.Contains(data.Labels().Get("vol1"), data.Labels().Get("vol2")), expect.JSON([]native.Volume{}, func(dc []native.Volume, info string, t tig.T) { assert.Assert(t, len(dc) == 2, fmt.Sprintf("two results, not %d", len(dc))) assert.Assert(t, dc[0].Name == data.Labels().Get("vol1"), fmt.Sprintf("expected name to be %q (was %q)", data.Labels().Get("vol1"), dc[0].Name)) diff --git a/cmd/nerdctl/volume/volume_prune_linux_test.go b/cmd/nerdctl/volume/volume_prune_linux_test.go index 16f69bca559..6565f578733 100644 --- a/cmd/nerdctl/volume/volume_prune_linux_test.go +++ b/cmd/nerdctl/volume/volume_prune_linux_test.go @@ -69,10 +69,12 @@ func TestVolumePrune(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ Output: expect.All( - expect.DoesNotContain(data.Labels().Get("anonIDBusy")), expect.Contains(data.Labels().Get("anonIDDangling")), - expect.DoesNotContain(data.Labels().Get("namedBusy")), - expect.DoesNotContain(data.Labels().Get("namedDangling")), + expect.DoesNotContain( + data.Labels().Get("anonIDBusy"), + data.Labels().Get("namedBusy"), + data.Labels().Get("namedDangling"), + ), func(stdout string, info string, t *testing.T) { helpers.Ensure("volume", "inspect", data.Labels().Get("anonIDBusy")) helpers.Fail("volume", "inspect", data.Labels().Get("anonIDDangling")) @@ -92,10 +94,8 @@ func TestVolumePrune(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ Output: expect.All( - expect.DoesNotContain(data.Labels().Get("anonIDBusy")), - expect.Contains(data.Labels().Get("anonIDDangling")), - expect.DoesNotContain(data.Labels().Get("namedBusy")), - expect.Contains(data.Labels().Get("namedDangling")), + expect.DoesNotContain(data.Labels().Get("anonIDBusy"), data.Labels().Get("namedBusy")), + expect.Contains(data.Labels().Get("anonIDDangling"), data.Labels().Get("namedDangling")), func(stdout string, info string, t *testing.T) { helpers.Ensure("volume", "inspect", data.Labels().Get("anonIDBusy")) helpers.Fail("volume", "inspect", data.Labels().Get("anonIDDangling"))