From e09ad2a7189132e94f53e48316619bbead4b09c7 Mon Sep 17 00:00:00 2001 From: apostasie Date: Sun, 22 Sep 2024 11:07:02 -0700 Subject: [PATCH] Migrate system tests to new tooling Signed-off-by: apostasie --- .../system/system_events_linux_test.go | 128 +++++++--------- cmd/nerdctl/system/system_info_test.go | 69 +++++---- cmd/nerdctl/system/system_prune_linux_test.go | 144 +++++++++--------- 3 files changed, 174 insertions(+), 167 deletions(-) diff --git a/cmd/nerdctl/system/system_events_linux_test.go b/cmd/nerdctl/system/system_events_linux_test.go index 5838e710866..c12d0161576 100644 --- a/cmd/nerdctl/system/system_events_linux_test.go +++ b/cmd/nerdctl/system/system_events_linux_test.go @@ -17,96 +17,84 @@ package system import ( - "fmt" - "strings" "testing" "time" - "gotest.tools/v3/assert" - "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) -func testEventFilter(t *testing.T, args ...string) string { - t.Parallel() - base := testutil.NewBase(t) - testContainerName := testutil.Identifier(t) - defer base.Cmd("rm", "-f", testContainerName).Run() - - fullArgs := []string{"events", "--filter"} - fullArgs = append(fullArgs, args...) - fullArgs = append(fullArgs, - "--format", - "json", - ) - - eventsCmd := base.Cmd(fullArgs...).Start() - base.Cmd("run", "--rm", testutil.CommonImage).Start() - time.Sleep(3 * time.Second) - return eventsCmd.Stdout() +func testEventFilterExecutor(data test.Data, helpers test.Helpers) test.Command { + cmd := helpers.Command("events", "--filter", data.Get("filter"), "--format", "json") + cmd.Background(1 * time.Second) + helpers.Ensure("run", "--rm", testutil.CommonImage) + return cmd } func TestEventFilters(t *testing.T) { + nerdtest.Setup() - type testCase struct { - name string - args []string - nerdctlOut string - dockerOut string - dockerSkip bool - } - testCases := []testCase{ + testGroup := &test.Group{ { - name: "CapitializedFilter", - args: []string{"event=START"}, - nerdctlOut: "\"Status\":\"start\"", - dockerOut: "\"status\":\"start\"", - dockerSkip: true, + Description: "CapitalizedFilter", + Require: test.Not(nerdtest.Docker), + Command: testEventFilterExecutor, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Get("output")), + } + }, + Data: test.WithData("filter", "event=START"). + Set("output", "\"Status\":\"start\""), }, { - name: "StartEventFilter", - args: []string{"event=start"}, - nerdctlOut: "\"Status\":\"start\"", - dockerOut: "\"status\":\"start\"", - dockerSkip: false, + Description: "StartEventFilter", + Command: testEventFilterExecutor, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Get("output")), + } + }, + Data: test.WithData("filter", "event=start"). + Set("output", "tatus\":\"start\""), }, { - name: "UnsupportedEventFilter", - args: []string{"event=unknown"}, - nerdctlOut: "\"Status\":\"unknown\"", - dockerSkip: true, + Description: "UnsupportedEventFilter", + Require: test.Not(nerdtest.Docker), + Command: testEventFilterExecutor, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Get("output")), + } + }, + Data: test.WithData("filter", "event=unknown"). + Set("output", "\"Status\":\"unknown\""), }, { - name: "StatusFilter", - args: []string{"status=start"}, - nerdctlOut: "\"Status\":\"start\"", - dockerOut: "\"status\":\"start\"", - dockerSkip: false, + Description: "StatusFilter", + Command: testEventFilterExecutor, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Get("output")), + } + }, + Data: test.WithData("filter", "status=start"). + Set("output", "tatus\":\"start\""), }, { - name: "UnsupportedStatusFilter", - args: []string{"status=unknown"}, - nerdctlOut: "\"Status\":\"unknown\"", - dockerSkip: true, + Description: "UnsupportedStatusFilter", + Require: test.Not(nerdtest.Docker), + Command: testEventFilterExecutor, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Get("output")), + } + }, + Data: test.WithData("filter", "status=unknown"). + Set("output", "\"Status\":\"unknown\""), }, } - for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - actualOut := testEventFilter(t, tc.args...) - errorMsg := fmt.Sprintf("%s failed;\nActual Filter Result: '%s'", tc.name, actualOut) - - isDocker := testutil.GetTarget() == testutil.Docker - if isDocker && tc.dockerSkip { - t.Skip("test is incompatible with Docker") - } - - if isDocker { - assert.Equal(t, true, strings.Contains(actualOut, tc.dockerOut), errorMsg) - } else { - assert.Equal(t, true, strings.Contains(actualOut, tc.nerdctlOut), errorMsg) - } - }) - } + testGroup.Run(t) } diff --git a/cmd/nerdctl/system/system_info_test.go b/cmd/nerdctl/system/system_info_test.go index 3a10033930d..3c8f5c252da 100644 --- a/cmd/nerdctl/system/system_info_test.go +++ b/cmd/nerdctl/system/system_info_test.go @@ -21,41 +21,56 @@ import ( "fmt" "testing" + "gotest.tools/v3/assert" + "github.com/containerd/nerdctl/v2/pkg/infoutil" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" - "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) -func testInfoJSON(stdout string) error { - var info dockercompat.Info - if err := json.Unmarshal([]byte(stdout), &info); err != nil { - return err - } +func testInfoComparator(stdout string, info string, t *testing.T) { + var dinf dockercompat.Info + err := json.Unmarshal([]byte(stdout), &dinf) + assert.NilError(t, err, "failed to unmarshal stdout"+info) unameM := infoutil.UnameM() - if info.Architecture != unameM { - return fmt.Errorf("expected info.Architecture to be %q, got %q", unameM, info.Architecture) - } - return nil + assert.Assert(t, dinf.Architecture == unameM, fmt.Sprintf("expected info.Architecture to be %q, got %q", unameM, dinf.Architecture)+info) } func TestInfo(t *testing.T) { - base := testutil.NewBase(t) - base.Cmd("info", "--format", "{{json .}}").AssertOutWithFunc(testInfoJSON) -} + nerdtest.Setup() -func TestInfoConvenienceForm(t *testing.T) { - testutil.DockerIncompatible(t) // until https://github.com/docker/cli/pull/3355 gets merged - base := testutil.NewBase(t) - base.Cmd("info", "--format", "json").AssertOutWithFunc(testInfoJSON) -} - -func TestInfoWithNamespace(t *testing.T) { - testutil.DockerIncompatible(t) - base := testutil.NewBase(t) - base.Args = nil // unset "--namespace=nerdctl-test" - - base.Cmd("info").AssertOutContains("Namespace: default") + testGroup := &test.Group{ + { + Description: "info", + Command: test.RunCommand("info", "--format", "{{json .}}"), + Expected: test.Expects(0, nil, testInfoComparator), + }, + { + Description: "info convenience form", + Command: test.RunCommand("info", "--format", "json"), + Expected: test.Expects(0, nil, testInfoComparator), + }, + { + Description: "info with namespace", + Require: test.Not(nerdtest.Docker), + Command: func(data test.Data, helpers test.Helpers) test.Command { + return helpers.Command().Clear().WithBinary("nerdctl").WithArgs("info") + }, + Expected: test.Expects(0, nil, test.Contains("Namespace: default")), + }, + { + Description: "info with namespace env var", + Env: map[string]string{ + "CONTAINERD_NAMESPACE": "test", + }, + Require: test.Not(nerdtest.Docker), + Command: func(data test.Data, helpers test.Helpers) test.Command { + return helpers.Command().Clear().WithBinary("nerdctl").WithArgs("info") + }, + Expected: test.Expects(0, nil, test.Contains("Namespace: test")), + }, + } - base.Env = append(base.Env, "CONTAINERD_NAMESPACE=test") - base.Cmd("info").AssertOutContains("Namespace: test") + testGroup.Run(t) } diff --git a/cmd/nerdctl/system/system_prune_linux_test.go b/cmd/nerdctl/system/system_prune_linux_test.go index d792282398f..40d08f1beea 100644 --- a/cmd/nerdctl/system/system_prune_linux_test.go +++ b/cmd/nerdctl/system/system_prune_linux_test.go @@ -17,86 +17,90 @@ package system import ( - "bytes" "fmt" - "io" - "os" - "os/exec" "strings" "testing" - "github.com/containerd/log" + "gotest.tools/v3/assert" "github.com/containerd/nerdctl/v2/pkg/buildkitutil" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestSystemPrune(t *testing.T) { - testutil.RequiresBuild(t) - // FIXME: using a dedicated namespace does not work with rootful (because of buildkit running) - // t.Parallel() - // namespaceID := testutil.Identifier(t) - // base := testutil.NewBaseWithNamespace(t, namespaceID) - base := testutil.NewBase(t) - base.Cmd("container", "prune", "-f").AssertOK() - base.Cmd("network", "prune", "-f").AssertOK() - base.Cmd("volume", "prune", "-f").AssertOK() - base.Cmd("image", "prune", "-f", "--all").AssertOK() - - nID := testutil.Identifier(t) - base.Cmd("network", "create", nID).AssertOK() - defer base.Cmd("network", "rm", nID).Run() - - vID := testutil.Identifier(t) - base.Cmd("volume", "create", vID).AssertOK() - defer base.Cmd("volume", "rm", vID).Run() - - vID2 := base.Cmd("volume", "create").Out() - defer base.Cmd("volume", "rm", vID2).Run() - - tID := testutil.Identifier(t) - base.Cmd("run", "-v", fmt.Sprintf("%s:/volume", vID), "--net", nID, - "--name", tID, testutil.CommonImage).AssertOK() - defer base.Cmd("rm", "-f", tID).Run() - - base.Cmd("ps", "-a").AssertOutContains(tID) - base.Cmd("images").AssertOutContains(testutil.ImageRepo(testutil.CommonImage)) - - base.Cmd("system", "prune", "-f", "--volumes", "--all").AssertOK() - base.Cmd("volume", "ls").AssertOutContains(vID) // docker system prune --all --volume does not prune named volume - base.Cmd("volume", "ls").AssertOutNotContains(vID2) // docker system prune --all --volume prune anonymous volume - base.Cmd("ps", "-a").AssertOutNotContains(tID) - base.Cmd("network", "ls").AssertOutNotContains(nID) - base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.CommonImage)) - - if testutil.GetTarget() != testutil.Nerdctl { - t.Skip("test skipped for buildkitd is not available with docker-compatible tests") + nerdtest.Setup() + + testGroup := &test.Group{ + { + Description: "volume prune all success", + // Private because of prune evidently + Require: nerdtest.Private, + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("network", "create", data.Identifier()) + helpers.Ensure("volume", "create", data.Identifier()) + anonIdentifier := helpers.Capture("volume", "create") + helpers.Ensure("run", "-v", fmt.Sprintf("%s:/volume", data.Identifier()), + "--net", data.Identifier(), "--name", data.Identifier(), testutil.CommonImage) + + data.Set("anonIdentifier", anonIdentifier) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("network", "rm", data.Identifier()) + helpers.Anyhow("volume", "rm", data.Identifier()) + helpers.Anyhow("volume", "rm", data.Get("anonIdentifier")) + helpers.Anyhow("rm", "-f", data.Identifier()) + }, + Command: test.RunCommand("system", "prune", "-f", "--volumes", "--all"), + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + ExitCode: 0, + Output: func(stdout string, info string, t *testing.T) { + volumes := helpers.Capture("volume", "ls") + networks := helpers.Capture("network", "ls") + images := helpers.Capture("images") + containers := helpers.Capture("ps", "-a") + assert.Assert(t, strings.Contains(volumes, data.Identifier()), volumes) + assert.Assert(t, !strings.Contains(volumes, data.Get("anonIdentifier")), volumes) + assert.Assert(t, !strings.Contains(containers, data.Identifier()), containers) + assert.Assert(t, !strings.Contains(networks, data.Identifier()), networks) + assert.Assert(t, !strings.Contains(images, testutil.CommonImage), images) + }, + } + }, + }, + { + Description: "buildkit", + // FIXME: using a dedicated namespace does not work with rootful (because of buildkitd) + NoParallel: true, + // buildkitd is not available with docker + Require: test.Require(nerdtest.Build, test.Not(nerdtest.Docker)), + // FIXME: this test will happily say "green" even if the command actually fails to do its duty + // if there is nothing in the build cache. + // Ensure with setup here that we DO build something first + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("system", "prune", "-f", "--volumes", "--all") + }, + Command: func(data test.Data, helpers test.Helpers) test.Command { + buildctlBinary, err := buildkitutil.BuildctlBinary() + if err != nil { + t.Fatal(err) + } + + host, err := buildkitutil.GetBuildkitHost(testutil.Namespace) + if err != nil { + t.Fatal(err) + } + + buildctlArgs := buildkitutil.BuildctlBaseArgs(host) + buildctlArgs = append(buildctlArgs, "du") + + return helpers.CustomCommand(buildctlBinary, buildctlArgs...) + }, + Expected: test.Expects(0, nil, test.Contains("Total:\t\t0B")), + }, } - buildctlBinary, err := buildkitutil.BuildctlBinary() - if err != nil { - t.Fatal(err) - } - host, err := buildkitutil.GetBuildkitHost(testutil.Namespace) - if err != nil { - t.Fatal(err) - } - - buildctlArgs := buildkitutil.BuildctlBaseArgs(host) - buildctlArgs = append(buildctlArgs, "du") - log.L.Debugf("running %s %v", buildctlBinary, buildctlArgs) - buildctlCmd := exec.Command(buildctlBinary, buildctlArgs...) - buildctlCmd.Env = os.Environ() - stdout := bytes.NewBuffer(nil) - buildctlCmd.Stdout = stdout - if err := buildctlCmd.Run(); err != nil { - t.Fatal(err) - } - readAll, err := io.ReadAll(stdout) - if err != nil { - t.Fatal(err) - } - if !strings.Contains(string(readAll), "Total:\t\t0B") { - t.Errorf("buildkit cache is not pruned: %s", string(readAll)) - } + testGroup.Run(t) }