From 161dc0412a803992e03a63d6f426bd83b556cd8f Mon Sep 17 00:00:00 2001 From: apostasie Date: Fri, 11 Oct 2024 14:35:05 -0700 Subject: [PATCH] Migrate container tests Signed-off-by: apostasie --- .../container/container_attach_linux_test.go | 158 +++--- .../container/container_commit_test.go | 80 ++- .../container/container_cp_linux_test.go | 505 +++++++++++------- .../container/container_create_linux_test.go | 6 +- .../container_create_windows_test.go | 95 +++- cmd/nerdctl/container/container_diff_test.go | 4 +- cmd/nerdctl/container/container_logs_test.go | 2 + .../container/container_prune_linux_test.go | 46 +- .../container/container_remove_test.go | 29 +- .../container/container_run_linux_test.go | 135 +++-- .../container_run_verify_linux_test.go | 78 +-- .../container/container_start_linux_test.go | 71 +-- .../container/container_stats_linux_test.go | 66 ++- .../container/container_top_unix_test.go | 21 +- .../container/container_top_windows_test.go | 42 +- cmd/nerdctl/container/container_wait_test.go | 35 +- cmd/nerdctl/image/image_convert_linux_test.go | 12 +- cmd/nerdctl/image/image_list_test.go | 6 +- cmd/nerdctl/image/image_load_test.go | 2 +- cmd/nerdctl/image/image_prune_test.go | 8 +- cmd/nerdctl/image/image_pull_linux_test.go | 4 +- cmd/nerdctl/image/image_push_linux_test.go | 16 +- cmd/nerdctl/ipfs/ipfs_compose_linux_test.go | 11 +- cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go | 4 +- cmd/nerdctl/ipfs/ipfs_registry_linux_test.go | 8 +- cmd/nerdctl/ipfs/ipfs_simple_linux_test.go | 20 +- cmd/nerdctl/login/login_linux_test.go | 9 +- pkg/testutil/test/helpers.go | 2 +- 28 files changed, 907 insertions(+), 568 deletions(-) diff --git a/cmd/nerdctl/container/container_attach_linux_test.go b/cmd/nerdctl/container/container_attach_linux_test.go index 71a74eae59e..69c8cf3c6f6 100644 --- a/cmd/nerdctl/container/container_attach_linux_test.go +++ b/cmd/nerdctl/container/container_attach_linux_test.go @@ -24,81 +24,99 @@ import ( "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" ) -// skipAttachForDocker should be called by attach-related tests that assert 'read detach keys' in stdout. -func skipAttachForDocker(t *testing.T) { - t.Helper() - if testutil.GetTarget() == testutil.Docker { - t.Skip("When detaching from a container, for a session started with 'docker attach'" + - ", it prints 'read escape sequence', but for one started with 'docker (run|start)', it prints nothing." + - " However, the flag is called '--detach-keys' in all cases" + - ", so nerdctl prints 'read detach keys' for all cases" + - ", and that's why this test is skipped for Docker.") - } -} - -// prepareContainerToAttach spins up a container (entrypoint = shell) with `-it` and detaches from it -// so that it can be re-attached to later. -func prepareContainerToAttach(base *testutil.Base, containerName string) { - opts := []func(*testutil.Cmd){ - testutil.WithStdin(testutil.NewDelayOnceReader(bytes.NewReader( +func TestAttachDetachKeys(t *testing.T) { + testCase := nerdtest.Setup() + + setup := func(data test.Data, helpers test.Helpers) { + // unbuffer(1) emulates tty, which is required by `nerdctl run -t`. + // unbuffer(1) can be installed with `apt-get install expect`. + // + // "-p" is needed because we need unbuffer to read from stdin, and from [1]: + // "Normally, unbuffer does not read from stdin. This simplifies use of unbuffer in some situations. + // To use unbuffer in a pipeline, use the -p flag." + // + // [1] https://linux.die.net/man/1/unbuffer + + si := testutil.NewDelayOnceReader(bytes.NewReader( []byte{16, 17}, // ctrl+p,ctrl+q, see https://www.physics.udel.edu/~watson/scen103/ascii.html - ))), + )) + + cmd := helpers. + Command("run", "-it", "--name", data.Identifier(), testutil.CommonImage) + cmd.WithWrapper("unbuffer", "-p") + cmd.WithStdin(si) + cmd.Run(&test.Expected{ + Output: test.All( + // NOTE: + // When detaching from a container, for a session started with 'docker attach', + // it prints 'read escape sequence', but for one started with 'docker (run|start)', it prints nothing. + // However, the flag is called '--detach-keys' in all cases, and nerdctl does print read detach keys + // in all cases. + // Disabling the contains test here allow both cli to run the test. + // test.Contains("read detach keys"), + func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.Running, true, info) + }), + }) } - // unbuffer(1) emulates tty, which is required by `nerdctl run -t`. - // unbuffer(1) can be installed with `apt-get install expect`. - // - // "-p" is needed because we need unbuffer to read from stdin, and from [1]: - // "Normally, unbuffer does not read from stdin. This simplifies use of unbuffer in some situations. - // To use unbuffer in a pipeline, use the -p flag." - // - // [1] https://linux.die.net/man/1/unbuffer - base.CmdWithHelper([]string{"unbuffer", "-p"}, "run", "-it", "--name", containerName, testutil.CommonImage). - CmdOption(opts...).AssertOutContains("read detach keys") - container := base.InspectContainer(containerName) - assert.Equal(base.T, container.State.Running, true) -} - -func TestAttach(t *testing.T) { - t.Parallel() - - skipAttachForDocker(t) - - base := testutil.NewBase(t) - containerName := testutil.Identifier(t) - defer base.Cmd("container", "rm", "-f", containerName).AssertOK() - prepareContainerToAttach(base, containerName) - - opts := []func(*testutil.Cmd){ - testutil.WithStdin(testutil.NewDelayOnceReader(strings.NewReader("expr 1 + 1\nexit\n"))), + testCase.SubTests = []*test.Case{ + { + Description: "TestAttachDefaultKeys", + Require: test.Binary("unbuffer"), + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("container", "rm", "-f", data.Identifier()) + }, + Setup: setup, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + si := testutil.NewDelayOnceReader(strings.NewReader("expr 1 + 1\nexit\n")) + // `unbuffer -p` returns 0 even if the underlying nerdctl process returns a non-zero exit code, + // so the exit code cannot be easily tested here. + cmd := helpers.Command("attach", data.Identifier()) + cmd.WithStdin(si) + cmd.WithWrapper("unbuffer", "-p") + + return cmd + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.Running, false, info) + }, + } + }, + }, + { + Description: "TestAttachCustomKeys", + Require: test.Binary("unbuffer"), + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("container", "rm", "-f", data.Identifier()) + }, + Setup: setup, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + si := testutil.NewDelayOnceReader(bytes.NewReader([]byte{1, 2})) + cmd := helpers. + Command("attach", "--detach-keys=ctrl-a,ctrl-b", data.Identifier()) + cmd.WithStdin(si) + cmd.WithWrapper("unbuffer", "-p") + return cmd + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.Running, true, info) + }, + } + }, + }, } - // `unbuffer -p` returns 0 even if the underlying nerdctl process returns a non-zero exit code, - // so the exit code cannot be easily tested here. - base.CmdWithHelper([]string{"unbuffer", "-p"}, "attach", containerName).CmdOption(opts...).AssertOutContains("2") - container := base.InspectContainer(containerName) - assert.Equal(base.T, container.State.Running, false) -} - -func TestAttachDetachKeys(t *testing.T) { - t.Parallel() - skipAttachForDocker(t) - - base := testutil.NewBase(t) - containerName := testutil.Identifier(t) - - defer base.Cmd("container", "rm", "-f", containerName).AssertOK() - prepareContainerToAttach(base, containerName) - - opts := []func(*testutil.Cmd){ - testutil.WithStdin(testutil.NewDelayOnceReader(bytes.NewReader( - []byte{1, 2}, // https://www.physics.udel.edu/~watson/scen103/ascii.html - ))), - } - base.CmdWithHelper([]string{"unbuffer", "-p"}, "attach", "--detach-keys=ctrl-a,ctrl-b", containerName). - CmdOption(opts...).AssertOutContains("read detach keys") - container := base.InspectContainer(containerName) - assert.Equal(base.T, container.State.Running, true) + testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_commit_test.go b/cmd/nerdctl/container/container_commit_test.go index f9f553d9ca1..fc8688c3075 100644 --- a/cmd/nerdctl/container/container_commit_test.go +++ b/cmd/nerdctl/container/container_commit_test.go @@ -17,39 +17,63 @@ package container import ( - "fmt" "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestCommit(t *testing.T) { - t.Parallel() - base := testutil.NewBase(t) - switch base.Info().CgroupDriver { - case "none", "": - t.Skip("requires cgroup (for pausing)") - } - testContainer := testutil.Identifier(t) - testImage := testutil.Identifier(t) + "-img" - defer base.Cmd("rm", "-f", testContainer).Run() - defer base.Cmd("rmi", testImage).Run() - - for _, pause := range []string{ - "true", - "false", - } { - base.Cmd("run", "-d", "--name", testContainer, testutil.CommonImage, "sleep", "infinity").AssertOK() - base.EnsureContainerStarted(testContainer) - base.Cmd("exec", testContainer, "sh", "-euxc", `echo hello-test-commit > /foo`).AssertOK() - base.Cmd( - "commit", - "-c", `CMD ["/foo"]`, - "-c", `ENTRYPOINT ["cat"]`, - fmt.Sprintf("--pause=%s", pause), - testContainer, testImage).AssertOK() - base.Cmd("run", "--rm", testImage).AssertOutExactly("hello-test-commit\n") - base.Cmd("rm", "-f", testContainer).Run() - base.Cmd("rmi", testImage).Run() + testCase := nerdtest.Setup() + + testCase.SubTests = []*test.Case{ + { + Description: "with pause", + Require: nerdtest.CGroup, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) + }, + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier(), testutil.CommonImage, "sleep", "infinity") + nerdtest.EnsureContainerStarted(helpers, data.Identifier()) + helpers.Ensure("exec", data.Identifier(), "sh", "-euxc", `echo hello-test-commit > /foo`) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + helpers.Ensure( + "commit", + "-c", `CMD ["/foo"]`, + "-c", `ENTRYPOINT ["cat"]`, + "--pause=true", + data.Identifier(), data.Identifier()) + return helpers.Command("run", "--rm", data.Identifier()) + }, + Expected: test.Expects(0, nil, test.Equals("hello-test-commit\n")), + }, + { + Description: "no pause", + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) + }, + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier(), testutil.CommonImage, "sleep", "infinity") + nerdtest.EnsureContainerStarted(helpers, data.Identifier()) + helpers.Ensure("exec", data.Identifier(), "sh", "-euxc", `echo hello-test-commit > /foo`) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + helpers.Ensure( + "commit", + "-c", `CMD ["/foo"]`, + "-c", `ENTRYPOINT ["cat"]`, + "--pause=false", + data.Identifier(), data.Identifier()) + return helpers.Command("run", "--rm", data.Identifier()) + }, + Expected: test.Expects(0, nil, test.Equals("hello-test-commit\n")), + }, } + + testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_cp_linux_test.go b/cmd/nerdctl/container/container_cp_linux_test.go index a94f46561b2..a308163c0f1 100644 --- a/cmd/nerdctl/container/container_cp_linux_test.go +++ b/cmd/nerdctl/container/container_cp_linux_test.go @@ -20,6 +20,7 @@ import ( "fmt" "os" "path/filepath" + "strconv" "strings" "syscall" "testing" @@ -28,221 +29,325 @@ import ( "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestCopyToContainer(t *testing.T) { - t.Parallel() - base := testutil.NewBase(t) - testContainer := testutil.Identifier(t) - testStoppedContainer := "stopped-container-" + testutil.Identifier(t) + testCase := nerdtest.Setup() - base.Cmd("run", "-d", "--name", testContainer, testutil.CommonImage, "sleep", "1h").AssertOK() - defer base.Cmd("rm", "-f", testContainer).Run() + testCase.Require = nerdtest.RootFul - base.Cmd("run", "-d", "--name", testStoppedContainer, testutil.CommonImage, "sleep", "1h").AssertOK() - defer base.Cmd("rm", "-f", testStoppedContainer).Run() - // Stop container immediately after starting for testing copying into stopped container - base.Cmd("stop", testStoppedContainer).AssertOK() - srcUID := os.Geteuid() - srcDir := t.TempDir() - srcFile := filepath.Join(srcDir, "test-file") - srcFileContent := []byte("test-file-content") - err := os.WriteFile(srcFile, srcFileContent, 0o644) - assert.NilError(t, err) - - assertCat := func(catPath string, testContainer string, stopped bool) { - if stopped { - base.Cmd("start", testContainer).AssertOK() - defer base.Cmd("stop", testContainer).AssertOK() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + srcFileContent := "test-file-content" + srcFile := filepath.Join(data.TempDir(), "test-file") + err := os.WriteFile(srcFile, []byte(srcFileContent), 0o644) + assert.NilError(t, err) + + data.Set("srcFile", srcFile) + data.Set("srcUID", strconv.Itoa(os.Geteuid())) + data.Set("srcFileContent", srcFileContent) + } + + genSub := func(description string, customSetup func(data test.Data, helpers test.Helpers), stopped bool, success bool) *test.Case { + tc := &test.Case{ + Description: description, + Setup: func(data test.Data, helpers test.Helpers) { + if customSetup != nil { + customSetup(data, helpers) + } else { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + } + if stopped { + helpers.Ensure("stop", data.Identifier("container")) + } + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("container")) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("cp", data.Get("srcPath"), data.Identifier("container")+":"+data.Get("destPath")) + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + exitCode := 0 + if !success { + exitCode = 1 + } + return &test.Expected{ + ExitCode: exitCode, + Output: func(stdout string, info string, t *testing.T) { + if !success { + return + } + + if stopped { + helpers.Ensure("start", data.Identifier("container")) + } + + so := helpers.Capture("exec", data.Identifier("container"), "sh", "-c", "--", fmt.Sprintf("cat %q; stat -c %%u %q", data.Get("catPath"), data.Get("catPath"))) + assert.Equal(t, so, fmt.Sprintf("%s%s\n", data.Get("srcFileContent"), data.Get("srcUID")), info) + }, + } + }, } - t.Logf("catPath=%q", catPath) - base.Cmd("exec", testContainer, "cat", catPath).AssertOutExactly(string(srcFileContent)) - base.Cmd("exec", testContainer, "stat", "-c", "%u", catPath).AssertOutExactly(fmt.Sprintf("%d\n", srcUID)) + return tc } // For the test matrix, see https://docs.docker.com/engine/reference/commandline/cp/ - t.Run("SRC_PATH specifies a file", func(t *testing.T) { - srcPath := srcFile - t.Run("DEST_PATH does not exist", func(t *testing.T) { - destPath := "/dest-no-exist-no-slash" - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertOK() - catPath := destPath - assertCat(catPath, testContainer, false) - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertOK() - assertCat(catPath, testStoppedContainer, true) - }) - t.Run("DEST_PATH does not exist and ends with /", func(t *testing.T) { - destPath := "/dest-no-exist-with-slash/" - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertFail() - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertFail() - }) - t.Run("DEST_PATH exists and is a file", func(t *testing.T) { - destPath := "/dest-file-exists" - base.Cmd("exec", testContainer, "touch", destPath).AssertOK() - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertOK() - catPath := destPath - assertCat(catPath, testContainer, false) - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertOK() - assertCat(catPath, testStoppedContainer, true) - }) - t.Run("DEST_PATH exists and is a directory", func(t *testing.T) { - destPath := "/dest-dir-exists" - base.Cmd("exec", testContainer, "mkdir", "-p", destPath).AssertOK() - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertOK() - catPath := filepath.Join(destPath, filepath.Base(srcFile)) - assertCat(catPath, testContainer, false) - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("start", testStoppedContainer).AssertOK() - base.Cmd("exec", testStoppedContainer, "mkdir", "-p", destPath).AssertOK() - base.Cmd("stop", testStoppedContainer).AssertOK() - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertOK() - assertCat(catPath, testStoppedContainer, true) - }) - t.Run("DEST_PATH is in a volume", func(t *testing.T) { - // Create a volume - vol := "somevol" - base.Cmd("volume", "create", vol).AssertOK() - defer base.Cmd("volume", "rm", vol).Run() - con := fmt.Sprintf("%s-with-volume", testContainer) - mountDir := "/some_dir" - base.Cmd("run", "-d", "--name", con, "-v", fmt.Sprintf("%s:%s", vol, mountDir), testutil.CommonImage, "sleep", "1h").AssertOK() - defer base.Cmd("rm", "-f", con).Run() - catPath := filepath.Join(mountDir, filepath.Base(srcFile)) - // Running container test - base.Cmd("cp", srcPath, con+":"+mountDir).AssertOK() - assertCat(catPath, con, false) + testCase.SubTests = []*test.Case{ + { + Description: "SRC_PATH specifies a file", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("srcPath", data.Get("srcFile")) + }, + SubTests: []*test.Case{ + { + Description: "DEST_PATH does not exist", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-no-exist-no-slash") + data.Set("catPath", "/dest-no-exist-no-slash") + }, + SubTests: []*test.Case{ + genSub("running", nil, false, true), + genSub("stopped", nil, true, true), + }, + }, + { + Description: "DEST_PATH does not exist and ends with /", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-no-exist-with-slash/") + data.Set("catPath", "/dest-no-exist-with-slash/") + }, + SubTests: []*test.Case{ + genSub("running", nil, false, false), + genSub("stopped", nil, true, false), + }, + }, + { + Description: "DEST_PATH exist and is a file", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-file-exists") + data.Set("catPath", "/dest-file-exists") + }, + SubTests: []*test.Case{ + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "touch", data.Get("destPath")) + }, false, true), + genSub("stopped", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "touch", data.Get("destPath")) + }, true, true), + }, + }, + { + Description: "DEST_PATH exist and is a directory", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-dir-exists") + data.Set("catPath", filepath.Join("/dest-dir-exists", filepath.Base(data.Get("srcPath")))) + }, + SubTests: []*test.Case{ + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "mkdir", "-p", data.Get("destPath")) + }, false, true), + genSub("stopped", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "mkdir", "-p", data.Get("destPath")) + }, true, true), + }, + }, + { + Description: "DEST_PATH is the root of a volume", + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("volume", "create", data.Identifier("volume")) + data.Set("destPath", "/in-a-volume") + data.Set("catPath", filepath.Join("/in-a-volume", filepath.Base(data.Get("srcPath")))) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("volume", "rm", data.Identifier("volume")) + }, + SubTests: []*test.Case{ + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), "-v", fmt.Sprintf("%s:%s", data.Identifier("volume"), data.Get("destPath")), testutil.CommonImage, "sleep", "inf") + }, false, true), + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), "-v", fmt.Sprintf("%s:%s", data.Identifier("volume"), data.Get("destPath")), testutil.CommonImage, "sleep", "inf") + }, true, true), + }, + }, + { + Description: "DEST_PATH is the root of a read-only volume", + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("volume", "create", data.Identifier("volume")) + data.Set("destPath", "/in-a-volume") + data.Set("catPath", filepath.Join("/in-a-volume", filepath.Base(data.Get("srcPath")))) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("volume", "rm", data.Identifier("volume")) + }, + SubTests: []*test.Case{ + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), "-v", fmt.Sprintf("%s:%s:ro", data.Identifier("volume"), data.Get("destPath")), testutil.CommonImage, "sleep", "inf") + }, false, false), + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), "-v", fmt.Sprintf("%s:%s:ro", data.Identifier("volume"), data.Get("destPath")), testutil.CommonImage, "sleep", "inf") + }, true, false), + }, + }, + { + Description: "DEST_PATH is the root of /tmp (read-only)", + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("volume", "create", data.Identifier("volume")) + data.Set("destPath", "/tmp") + data.Set("catPath", filepath.Join("/tmp", filepath.Base(data.Get("srcPath")))) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("volume", "rm", data.Identifier("volume")) + }, + SubTests: []*test.Case{ + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), "-v", fmt.Sprintf("%s:%s:ro", data.Identifier("volume"), data.Get("destPath")), testutil.CommonImage, "sleep", "inf") + }, false, false), + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), "-v", fmt.Sprintf("%s:%s:ro", data.Identifier("volume"), data.Get("destPath")), testutil.CommonImage, "sleep", "inf") + }, true, false), + }, + }, + }, + }, + { + Description: "SRC_PATH specifies a directory", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("srcPath", filepath.Dir(data.Get("srcFile"))) + }, + SubTests: []*test.Case{ + { + Description: "DEST_PATH does not exist", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-no-exist-no-slash") + data.Set("catPath", filepath.Join("/dest-no-exist-no-slash", filepath.Base(data.Get("srcFile")))) + }, + SubTests: []*test.Case{ + genSub("running", nil, false, true), + genSub("stopped", nil, true, true), + }, + }, + { + Description: "DEST_PATH exist and is a file", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-file-exists") + }, + SubTests: []*test.Case{ + genSub("running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "touch", data.Get("destPath")) + }, false, false), + genSub("stopped", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "touch", data.Get("destPath")) + }, true, false), + }, + }, + { + Description: "DEST_PATH exist and is a directory", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", "/dest-dir-exists") + data.Set("catPath", filepath.Join("/dest-dir-exists", filepath.Base(data.Get("srcPath")))) + }, + SubTests: []*test.Case{ + genSub("SRC_PATH does not end with `/.` running", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "mkdir", "-p", data.Get("destPath")) + }, false, true), + genSub("SRC_PATH does not end with `/.` stopped", func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "mkdir", "-p", data.Get("destPath")) + }, true, true), + genSub("SRC_PATH ends with `/.` running", func(data test.Data, helpers test.Helpers) { + data.Set("srcPath", data.Get("srcPath")+"/.") + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "mkdir", "-p", data.Get("destPath")) + }, false, true), + genSub("SRC_PATH ends with `/.` stopped", func(data test.Data, helpers test.Helpers) { + data.Set("srcPath", data.Get("srcPath")+"/.") + helpers.Ensure("run", "-d", "--name", data.Identifier("container"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("exec", data.Identifier("container"), "mkdir", "-p", data.Get("destPath")) + }, true, true), + }, + }, + }, + }, + } - // Skip for rootless - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - // Stopped container test - // Delete previously copied file - base.Cmd("exec", con, "rm", catPath).AssertOK() - base.Cmd("stop", con).AssertOK() - base.Cmd("cp", srcPath, con+":"+mountDir).AssertOK() - assertCat(catPath, con, true) - }) - t.Run("Destination path is a read-only", func(t *testing.T) { - vol := "somevol" - base.Cmd("volume", "create", vol).AssertOK() - defer base.Cmd("volume", "rm", vol).Run() - con := fmt.Sprintf("%s-with-read-only-volume", testContainer) - mountDir := "/some_dir" - // Create container with read-only volume mounted - base.Cmd("run", "-d", "--name", con, "-v", fmt.Sprintf("%s:%s:ro", vol, mountDir), testutil.CommonImage, "sleep", "1h").AssertOK() - defer base.Cmd("rm", "-f", con).Run() - base.Cmd("cp", srcPath, con+":"+mountDir).AssertFail() + testCase.Run(t) +} - // Skip for rootless - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } +func TestCopyFromContainer(t *testing.T) { + testCase := nerdtest.Setup() - // Stopped container test - // Delete previously copied file - base.Cmd("stop", con).AssertOK() - base.Cmd("cp", srcPath, con+":"+mountDir).AssertFail() - }) - t.Run("Destination path is a read-only and default tmpfs mount point", func(t *testing.T) { - vol := "somevol" - base.Cmd("volume", "create", vol).AssertOK() - defer base.Cmd("volume", "rm", vol).Run() - con := fmt.Sprintf("%s-with-read-only-volume", testContainer) + testCase.Require = nerdtest.RootFul - // /tmp is from rootfs of alpine - mountDir := "/tmp" - // Create container with read-only mounted volume mounted at /tmp - base.Cmd("run", "-d", "--name", con, "-v", fmt.Sprintf("%s:%s:ro", vol, mountDir), testutil.CommonImage, "sleep", "1h").AssertOK() - defer base.Cmd("rm", "-f", con).Run() - base.Cmd("cp", srcPath, con+":"+mountDir).AssertFail() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + srcFileContent := "test-file-content" + srcFile := filepath.Join("/test-dir", "test-file") + err := os.WriteFile(srcFile, []byte(srcFileContent), 0o644) + assert.NilError(t, err) - // Skip for rootless - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } + data.Set("srcFile", srcFile) + data.Set("srcUID", "42") + data.Set("eUID", strconv.Itoa(os.Geteuid())) + data.Set("srcFileContent", srcFileContent) - // Stopped container test - // Delete previously copied file - base.Cmd("stop", con).AssertOK() - base.Cmd("cp", srcPath, con+":"+mountDir).AssertFail() - }) - }) - t.Run("SRC_PATH specifies a directory", func(t *testing.T) { - srcPath := srcDir - t.Run("DEST_PATH does not exist", func(t *testing.T) { - destPath := "/dest2-no-exist" - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertOK() - catPath := filepath.Join(destPath, filepath.Base(srcFile)) - assertCat(catPath, testContainer, false) - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertOK() - assertCat(catPath, testStoppedContainer, true) - }) - t.Run("DEST_PATH exists and is a file", func(t *testing.T) { - destPath := "/dest2-file-exists" - base.Cmd("exec", testContainer, "touch", destPath).AssertOK() - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertFail() - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("start", testStoppedContainer).AssertOK() - base.Cmd("exec", testStoppedContainer, "touch", destPath).AssertOK() - base.Cmd("stop", testStoppedContainer).AssertOK() - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertFail() - }) - t.Run("DEST_PATH exists and is a directory", func(t *testing.T) { - t.Run("SRC_PATH does not end with `/.`", func(t *testing.T) { - destPath := "/dest2-dir-exists" - base.Cmd("exec", testContainer, "mkdir", "-p", destPath).AssertOK() - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertOK() - catPath := filepath.Join(destPath, strings.TrimPrefix(srcFile, filepath.Dir(srcDir)+"/")) - assertCat(catPath, testContainer, false) - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("start", testStoppedContainer).AssertOK() - base.Cmd("exec", testStoppedContainer, "mkdir", "-p", destPath).AssertOK() - base.Cmd("stop", testStoppedContainer).AssertOK() - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertOK() - assertCat(catPath, testStoppedContainer, true) - }) - t.Run("SRC_PATH does end with `/.`", func(t *testing.T) { - srcPath += "/." - destPath := "/dest2-dir2-exists" - base.Cmd("exec", testContainer, "mkdir", "-p", destPath).AssertOK() - base.Cmd("cp", srcPath, testContainer+":"+destPath).AssertOK() - catPath := filepath.Join(destPath, filepath.Base(srcFile)) - t.Logf("catPath=%q", catPath) - assertCat(catPath, testContainer, false) - if rootlessutil.IsRootless() { - t.Skip("Test skipped in rootless mode for testStoppedContainer") - } - base.Cmd("start", testStoppedContainer).AssertOK() - base.Cmd("exec", testStoppedContainer, "mkdir", "-p", destPath).AssertOK() - base.Cmd("stop", testStoppedContainer).AssertOK() - base.Cmd("cp", srcPath, testStoppedContainer+":"+destPath).AssertOK() - assertCat(catPath, testStoppedContainer, true) - }) - }) - }) -} + helpers.Ensure("run", "-d", "--name", data.Identifier("running"), testutil.CommonImage, "sleep", "inf") + helpers.Ensure("run", "-d", "--name", data.Identifier("stopped"), testutil.CommonImage, "sleep", "inf") + + mkSrcScript := fmt.Sprintf("mkdir -p %q && echo -n %q >%q && chown %d %q", "/test-dir", srcFileContent, srcFile, data.Get("srcUID"), srcFile) + helpers.Ensure("exec", data.Identifier("running"), "sh", "-euc", mkSrcScript) + helpers.Ensure("exec", data.Identifier("stopped"), "sh", "-euc", mkSrcScript) + helpers.Ensure("stop", data.Identifier("stopped")) + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("running")) + helpers.Anyhow("rm", "-f", data.Identifier("stopped")) + } + + testCase.SubTests = []*test.Case{ + { + Description: "SRC_PATH specifies a file", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("srcPath", data.Get("srcFile")) + }, + SubTests: []*test.Case{ + { + Description: "DEST_PATH does not exist", + Setup: func(data test.Data, helpers test.Helpers) { + data.Set("destPath", filepath.Join(data.TempDir(), "dest-no-exist-no-slash")) + data.Set("catPath", filepath.Join(data.TempDir(), "dest-no-exist-no-slash")) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("cp", testContainer+":"+data.Get("srcPath"), data.Get("destPath")) + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + got, err := os.ReadFile(data.Get("catPath")) + assert.NilError(helpers.T(), err) + assert.Equal(helpers.T(), data.Get("srcFileContent"), got) + st, err := os.Stat(data.Get("catPath")) + assert.NilError(helpers.T(), err) + stSys := st.Sys().(*syscall.Stat_t) + // stSys.Uid matches euid, not srcUID + e, _ := strconv.Atoi(data.Get("eUID")) + assert.Equal(helpers.T(), uint32(e), stSys.Uid) + return &test.Expected{} + }, + }, + }, + }, + } + + testCase.Run(t) -func TestCopyFromContainer(t *testing.T) { - t.Parallel() base := testutil.NewBase(t) testContainer := testutil.Identifier(t) testStoppedContainer := "stopped-container-" + testutil.Identifier(t) @@ -256,7 +361,7 @@ func TestCopyFromContainer(t *testing.T) { srcUID := 42 srcDir := "/test-dir" srcFile := filepath.Join(srcDir, "test-file") - srcFileContent := []byte("test-file-content") + srcFileContent := []byte("test-file-content")data mkSrcScript := fmt.Sprintf("mkdir -p %q && echo -n %q >%q && chown %d %q", srcDir, srcFileContent, srcFile, srcUID, srcFile) base.Cmd("exec", testContainer, "sh", "-euc", mkSrcScript).AssertOK() base.Cmd("exec", testStoppedContainer, "sh", "-euc", mkSrcScript).AssertOK() diff --git a/cmd/nerdctl/container/container_create_linux_test.go b/cmd/nerdctl/container/container_create_linux_test.go index e0823ec3af0..de2a447c96c 100644 --- a/cmd/nerdctl/container/container_create_linux_test.go +++ b/cmd/nerdctl/container/container_create_linux_test.go @@ -218,8 +218,7 @@ func TestIssue2993(t *testing.T) { h := getAddrHash(defaults.DefaultAddress) dataStore := filepath.Join(dataRoot, h) - // FIXME: update with next tooling iteration to retrieve from the command - namespace := "nerdctl-test" + namespace := string(helpers.Read(nerdtest.Namespace)) containersPath := filepath.Join(dataStore, "containers", namespace) containersDirs, err := os.ReadDir(containersPath) @@ -266,8 +265,7 @@ func TestIssue2993(t *testing.T) { h := getAddrHash(defaults.DefaultAddress) dataStore := filepath.Join(dataRoot, h) - // FIXME: update with next tooling iteration to retrieve from the command - namespace := "nerdctl-test" + namespace := string(helpers.Read(nerdtest.Namespace)) containersPath := filepath.Join(dataStore, "containers", namespace) containersDirs, err := os.ReadDir(containersPath) diff --git a/cmd/nerdctl/container/container_create_windows_test.go b/cmd/nerdctl/container/container_create_windows_test.go index d80f5bb6d1d..cee87e0e28b 100644 --- a/cmd/nerdctl/container/container_create_windows_test.go +++ b/cmd/nerdctl/container/container_create_windows_test.go @@ -21,35 +21,86 @@ import ( "time" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestCreateProcessContainer(t *testing.T) { - base := testutil.NewBase(t) - tID := testutil.Identifier(t) - - base.Cmd("create", "--name", tID, testutil.CommonImage, "echo", "foo").AssertOK() - defer base.Cmd("rm", "-f", tID).Run() - base.Cmd("ps", "-a").AssertOutContains("Created") - base.Cmd("start", tID).AssertOK() - base.Cmd("logs", tID).AssertOutContains("foo") + testCase := nerdtest.Setup() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("create", "--name", data.Identifier("container"), testutil.CommonImage, "echo", "foo") + data.Set("cID", data.Identifier("container")) + } + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("container")) + } + + testCase.SubTests = []*test.Case{ + { + Description: "ps -a", + NoParallel: true, + Command: test.Command("ps", "-a"), + // FIXME: this might get a false positive if other tests have created a container + Expected: test.Expects(0, nil, test.Contains("Created")), + }, + { + Description: "start", + NoParallel: true, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("start", data.Get("cID")) + }, + Expected: test.Expects(0, nil, nil), + }, + { + Description: "logs", + NoParallel: true, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("logs", data.Get("cID")) + }, + Expected: test.Expects(0, nil, test.Contains("foo")), + }, + } + + testCase.Run(t) } func TestCreateHyperVContainer(t *testing.T) { - base := testutil.NewBase(t) - tID := testutil.Identifier(t) - - if !testutil.HyperVSupported() { - t.Skip("HyperV is not enabled, skipping test") + testCase := nerdtest.Setup() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("create", "--isolation", "hyperv", "--name", data.Identifier("container"), testutil.CommonImage, "echo", "foo") + data.Set("cID", data.Identifier("container")) + } + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("container")) } - base.Cmd("create", "--isolation", "hyperv", "--name", tID, testutil.CommonImage, "echo", "foo").AssertOK() - defer base.Cmd("rm", "-f", tID).Run() - base.Cmd("ps", "-a").AssertOutContains("Created") - - base.Cmd("start", tID).AssertOK() - // hyperv containers take a few seconds to fire up, the test would fail without the sleep - // EnsureContainerStarted does not work - time.Sleep(10 * time.Second) + testCase.SubTests = []*test.Case{ + { + Description: "ps -a", + NoParallel: true, + Command: test.Command("ps", "-a"), + // FIXME: this might get a false positive if other tests have created a container + Expected: test.Expects(0, nil, test.Contains("Created")), + }, + { + Description: "start", + NoParallel: true, + Setup: func(data test.Data, helpers test.Helpers) test.TestableCommand { + helpers.Ensure("start", data.Get("cID")) + // hyperv containers take a few seconds to fire up, the test would fail without the sleep + // EnsureContainerStarted does not work + time.Sleep(10 * time.Second) + }, + }, + { + Description: "logs", + NoParallel: true, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("logs", data.Get("cID")) + }, + Expected: test.Expects(0, nil, test.Contains("foo")), + }, + } - base.Cmd("logs", tID).AssertOutContains("foo") + testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_diff_test.go b/cmd/nerdctl/container/container_diff_test.go index 6914dee5303..b47631dd600 100644 --- a/cmd/nerdctl/container/container_diff_test.go +++ b/cmd/nerdctl/container/container_diff_test.go @@ -17,11 +17,11 @@ package container import ( - "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" - "github.com/containerd/nerdctl/v2/pkg/testutil/test" "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestDiff(t *testing.T) { diff --git a/cmd/nerdctl/container/container_logs_test.go b/cmd/nerdctl/container/container_logs_test.go index ec9fbd2ce70..5f9e3d30aa6 100644 --- a/cmd/nerdctl/container/container_logs_test.go +++ b/cmd/nerdctl/container/container_logs_test.go @@ -95,6 +95,8 @@ func TestLogsWithInheritedFlags(t *testing.T) { base.Cmd("run", "-d", "--name", containerName, testutil.CommonImage, "sh", "-euxc", "echo foo; echo bar").AssertOK() + // NOTE: seen with Docker: there are circumstances where this happens too fast and we get foo + time.Sleep(1 * time.Second) // test rootCmd alias `-n` already used in logs subcommand base.Cmd("logs", "-n", "1", containerName).AssertOutWithFunc(func(stdout string) error { if !(stdout == "bar\n" || stdout == "") { diff --git a/cmd/nerdctl/container/container_prune_linux_test.go b/cmd/nerdctl/container/container_prune_linux_test.go index 8912e8fb8dd..84979c780a6 100644 --- a/cmd/nerdctl/container/container_prune_linux_test.go +++ b/cmd/nerdctl/container/container_prune_linux_test.go @@ -20,36 +20,36 @@ import ( "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestPruneContainer(t *testing.T) { - base := testutil.NewBase(t) - tID := testutil.Identifier(t) + testCase := nerdtest.Setup() - tearDown := func() { - defer base.Cmd("rm", "-f", tID+"-1").Run() - defer base.Cmd("rm", "-f", tID+"-2").Run() - } + testCase.Require = nerdtest.Private - tearUp := func() { - base.Cmd("run", "-d", "--name", tID+"-1", "-v", "/anonymous", testutil.CommonImage, "sleep", "infinity").AssertOK() - base.Cmd("exec", tID+"-1", "touch", "/anonymous/foo").AssertOK() - base.Cmd("create", "--name", tID+"-2", testutil.CommonImage, "sleep", "infinity").AssertOK() + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("1")) + helpers.Anyhow("rm", "-f", data.Identifier("2")) } - tearDown() - t.Cleanup(tearDown) - tearUp() - - base.Cmd("container", "prune", "-f").AssertOK() - // tID-1 is still running, tID-2 is not - base.Cmd("inspect", tID+"-1").AssertOK() - base.Cmd("inspect", tID+"-2").AssertFail() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("1"), "-v", "/anonymous", testutil.CommonImage, "sleep", "infinity") + helpers.Ensure("exec", data.Identifier("1"), "touch", "/anonymous/foo") + helpers.Ensure("create", "--name", data.Identifier("2"), testutil.CommonImage, "sleep", "infinity") + } - // https://github.com/containerd/nerdctl/issues/3134 - base.Cmd("exec", tID+"-1", "ls", "-lA", "/anonymous/foo").AssertOK() + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + helpers.Ensure("container", "prune", "-f") + helpers.Ensure("inspect", data.Identifier("1")) + helpers.Fail("inspect", data.Identifier("2")) + // https://github.com/containerd/nerdctl/issues/3134 + helpers.Ensure("exec", data.Identifier("1"), "ls", "-lA", "/anonymous/foo") + helpers.Ensure("kill", data.Identifier("1")) + helpers.Ensure("container", "prune", "-f") + return helpers.Command("inspect", data.Identifier("1")) + } - base.Cmd("kill", tID+"-1").AssertOK() - base.Cmd("container", "prune", "-f").AssertOK() - base.Cmd("inspect", tID+"-1").AssertFail() + testCase.Expected = test.Expects(1, nil, nil) } diff --git a/cmd/nerdctl/container/container_remove_test.go b/cmd/nerdctl/container/container_remove_test.go index 3f9eecfd679..626a4bead62 100644 --- a/cmd/nerdctl/container/container_remove_test.go +++ b/cmd/nerdctl/container/container_remove_test.go @@ -20,22 +20,29 @@ import ( "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestRemoveContainer(t *testing.T) { - t.Parallel() + testCase := nerdtest.Setup() - base := testutil.NewBase(t) - tID := testutil.Identifier(t) + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier(), testutil.CommonImage, "sleep", "inf") + } - // ignore error - base.Cmd("rm", tID, "-f").AssertOK() + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + } - base.Cmd("run", "-d", "--name", tID, testutil.NginxAlpineImage).AssertOK() - defer base.Cmd("rm", tID, "-f").AssertOK() - base.Cmd("rm", tID).AssertFail() + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + helpers.Fail("rm", data.Identifier()) - // `kill` does return before the container actually stops - base.Cmd("stop", tID).AssertOK() - base.Cmd("rm", tID).AssertOK() + // `kill` does return before the container actually stops + helpers.Ensure("stop", data.Identifier()) + + return helpers.Command("rm", data.Identifier()) + } + + testCase.Expected = test.Expects(0, nil, nil) } diff --git a/cmd/nerdctl/container/container_run_linux_test.go b/cmd/nerdctl/container/container_run_linux_test.go index aca549d9446..a177ec0864e 100644 --- a/cmd/nerdctl/container/container_run_linux_test.go +++ b/cmd/nerdctl/container/container_run_linux_test.go @@ -36,9 +36,10 @@ import ( "gotest.tools/v3/icmd" "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" - "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/strutil" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestRunCustomRootfs(t *testing.T) { @@ -458,64 +459,96 @@ func TestRunWithFluentdLogDriverWithLogOpt(t *testing.T) { } func TestRunWithOOMScoreAdj(t *testing.T) { - if rootlessutil.IsRootless() { - t.Skip("test skipped for rootless containers.") + nerdtest.Setup() + + testCase := &test.Case{ + Description: "TestStartDetachKeys", + Require: nerdtest.RootFul, + Command: test.Command("run", "--rm", "--oom-score-adj", "-42", testutil.AlpineImage, "cat", "/proc/self/oom_score_adj"), + Expected: test.Expects(0, nil, test.Contains("-42")), } - t.Parallel() - base := testutil.NewBase(t) - var score = "-42" - base.Cmd("run", "--rm", "--oom-score-adj", score, testutil.AlpineImage, "cat", "/proc/self/oom_score_adj").AssertOutContains(score) + testCase.Run(t) } -func TestRunWithDetachKeys(t *testing.T) { - t.Parallel() +func TestRunDetachKeys(t *testing.T) { + nerdtest.Setup() - if testutil.GetTarget() == testutil.Docker { - t.Skip("When detaching from a container, for a session started with 'docker attach'" + - ", it prints 'read escape sequence', but for one started with 'docker (run|start)', it prints nothing." + - " However, the flag is called '--detach-keys' in all cases" + - ", so nerdctl prints 'read detach keys' for all cases" + - ", and that's why this test is skipped for Docker.") + testCase := &test.Case{ + Description: "TestStartDetachKeys", + Require: test.Binary("unbuffer"), + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("container", "rm", "-f", data.Identifier()) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + si := testutil.NewDelayOnceReader(bytes.NewReader([]byte{1, 2})) + cmd := helpers. + Command("run", "-it", "--detach-keys=ctrl-a,ctrl-b", "--name", data.Identifier(), testutil.CommonImage) + cmd.WithStdin(si) + cmd.WithWrapper("unbuffer", "-p") + return cmd + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.Running, true, info) + }, + } + }, } - base := testutil.NewBase(t) - containerName := testutil.Identifier(t) - opts := []func(*testutil.Cmd){ - testutil.WithStdin(testutil.NewDelayOnceReader(bytes.NewReader([]byte{1, 2}))), // https://www.physics.udel.edu/~watson/scen103/ascii.html - } - defer base.Cmd("container", "rm", "-f", containerName).AssertOK() - // unbuffer(1) emulates tty, which is required by `nerdctl run -t`. - // unbuffer(1) can be installed with `apt-get install expect`. - // - // "-p" is needed because we need unbuffer to read from stdin, and from [1]: - // "Normally, unbuffer does not read from stdin. This simplifies use of unbuffer in some situations. - // To use unbuffer in a pipeline, use the -p flag." - // - // [1] https://linux.die.net/man/1/unbuffer - base.CmdWithHelper([]string{"unbuffer", "-p"}, "run", "-it", "--detach-keys=ctrl-a,ctrl-b", "--name", containerName, testutil.CommonImage). - CmdOption(opts...).AssertOutContains("read detach keys") - container := base.InspectContainer(containerName) - assert.Equal(base.T, container.State.Running, true) + testCase.Run(t) } func TestRunWithTtyAndDetached(t *testing.T) { - base := testutil.NewBase(t) - imageName := testutil.CommonImage - withoutTtyContainerName := "without-terminal-" + testutil.Identifier(t) - withTtyContainerName := "with-terminal-" + testutil.Identifier(t) - - // without -t, fail - base.Cmd("run", "-d", "--name", withoutTtyContainerName, imageName, "stty").AssertOK() - defer base.Cmd("container", "rm", "-f", withoutTtyContainerName).AssertOK() - base.Cmd("logs", withoutTtyContainerName).AssertCombinedOutContains("stty: standard input: Not a tty") - withoutTtyContainer := base.InspectContainer(withoutTtyContainerName) - assert.Equal(base.T, 1, withoutTtyContainer.State.ExitCode) - - // with -t, success - base.Cmd("run", "-d", "-t", "--name", withTtyContainerName, imageName, "stty").AssertOK() - defer base.Cmd("container", "rm", "-f", withTtyContainerName).AssertOK() - base.Cmd("logs", withTtyContainerName).AssertCombinedOutContains("speed 38400 baud; line = 0;") - withTtyContainer := base.InspectContainer(withTtyContainerName) - assert.Equal(base.T, 0, withTtyContainer.State.ExitCode) + testCase := nerdtest.Setup() + + testCase.SubTests = []*test.Case{ + { + Description: "without terminal", + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("container", "rm", "-f", data.Identifier()) + }, + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier(), testutil.CommonImage, "stty") + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("logs", data.Identifier()) + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Errors: []error{errors.New("stty: standard input: Not a tty")}, + Output: func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.ExitCode, 1, info) + }, + } + }, + }, + { + Description: "with terminal", + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("container", "rm", "-f", data.Identifier()) + }, + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "-t", "--name", data.Identifier(), testutil.CommonImage, "stty") + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("logs", data.Identifier()) + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.All( + test.Contains("speed 38400 baud; line = 0;"), + func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.ExitCode, 0, info) + }), + } + }, + }, + } + + testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_run_verify_linux_test.go b/cmd/nerdctl/container/container_run_verify_linux_test.go index 7d12342cbb3..9ec7256fc33 100644 --- a/cmd/nerdctl/container/container_run_verify_linux_test.go +++ b/cmd/nerdctl/container/container_run_verify_linux_test.go @@ -20,38 +20,56 @@ import ( "fmt" "testing" - "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" + testhelpers "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" "github.com/containerd/nerdctl/v2/pkg/testutil" - "github.com/containerd/nerdctl/v2/pkg/testutil/testregistry" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest/registry" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestRunVerifyCosign(t *testing.T) { - testutil.RequireExecutable(t, "cosign") - testutil.DockerIncompatible(t) - testutil.RequiresBuild(t) - testutil.RegisterBuildCacheCleanup(t) - t.Parallel() - - base := testutil.NewBase(t) - base.Env = append(base.Env, "COSIGN_PASSWORD=1") - - keyPair := helpers.NewCosignKeyPair(t, "cosign-key-pair", "1") - reg := testregistry.NewWithNoAuth(base, 0, false) - t.Cleanup(func() { - keyPair.Cleanup() - reg.Cleanup(nil) - }) - - tID := testutil.Identifier(t) - testImageRef := fmt.Sprintf("127.0.0.1:%d/%s", reg.Port, tID) - dockerfile := fmt.Sprintf(`FROM %s -CMD ["echo", "nerdctl-build-test-string"] - `, testutil.CommonImage) - - buildCtx := helpers.CreateBuildContext(t, dockerfile) - - base.Cmd("build", "-t", testImageRef, buildCtx).AssertOK() - base.Cmd("push", testImageRef, "--sign=cosign", "--cosign-key="+keyPair.PrivateKey).AssertOK() - base.Cmd("run", "--rm", "--verify=cosign", "--cosign-key="+keyPair.PublicKey, testImageRef).AssertOK() - base.Cmd("run", "--rm", "--verify=cosign", "--cosign-key=dummy", testImageRef).AssertFail() + var keyPair *testhelpers.CosignKeyPair + var reg *registry.Server + + testCase := nerdtest.Setup() + + testCase.Require = test.Require( + test.Binary("cosign"), + test.Not(nerdtest.Docker), + nerdtest.Build, + ) + + testCase.Env = map[string]string{ + "COSIGN_PASSWORD": "1", + } + + testCase.Setup = func(data test.Data, helpers test.Helpers) { + keyPair = testhelpers.NewCosignKeyPair(t, "cosign-key-pair", "1") + reg = nerdtest.RegistryWithNoAuth(data, helpers, 0, false) + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + if keyPair != nil { + keyPair.Cleanup() + } + if reg != nil { + reg.Cleanup(data, helpers) + } + } + + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + testImageRef := fmt.Sprintf("127.0.0.1:%d/%s", reg.Port, data.Identifier()) + dockerfile := fmt.Sprintf(`FROM %s + CMD ["echo", "nerdctl-build-test-string"] + `, testutil.CommonImage) + + buildCtx := testhelpers.CreateBuildContext(t, dockerfile) + + helpers.Ensure("build", "-t", testImageRef, buildCtx) + helpers.Ensure("push", testImageRef, "--sign=cosign", "--cosign-key="+keyPair.PrivateKey) + helpers.Ensure("run", "--rm", "--verify=cosign", "--cosign-key="+keyPair.PublicKey, testImageRef) + return helpers.Command("run", "--rm", "--verify=cosign", "--cosign-key=dummy", testImageRef) + } + + testCase.Expected = test.Expects(1, nil, nil) } diff --git a/cmd/nerdctl/container/container_start_linux_test.go b/cmd/nerdctl/container/container_start_linux_test.go index 4fe6f2d249c..ac2da9d90ae 100644 --- a/cmd/nerdctl/container/container_start_linux_test.go +++ b/cmd/nerdctl/container/container_start_linux_test.go @@ -24,41 +24,52 @@ import ( "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 TestStartDetachKeys(t *testing.T) { - t.Parallel() + nerdtest.Setup() - skipAttachForDocker(t) + testCase := &test.Case{ + Description: "TestStartDetachKeys", + Require: test.Binary("unbuffer"), + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("container", "rm", "-f", data.Identifier()) + }, + Setup: func(data test.Data, helpers test.Helpers) { + si := testutil.NewDelayOnceReader(strings.NewReader("exit\n")) - base := testutil.NewBase(t) - containerName := testutil.Identifier(t) - - defer base.Cmd("container", "rm", "-f", containerName).AssertOK() - opts := []func(*testutil.Cmd){ - // If NewDelayOnceReader is not used, - // the container state will be Created instead of Exited. - // Maybe `unbuffer` exits too early in that case? - testutil.WithStdin(testutil.NewDelayOnceReader(strings.NewReader("exit\n"))), + cmd := helpers. + Command("run", "-it", "--name", data.Identifier(), testutil.CommonImage) + cmd.WithWrapper("unbuffer", "-p") + cmd.WithStdin(si) + cmd.Run(&test.Expected{ + Output: test.All( + func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.Running, false, info) + }), + }) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + si := testutil.NewDelayOnceReader(bytes.NewReader([]byte{1, 2})) + cmd := helpers. + Command("start", "-a", "--detach-keys=ctrl-a,ctrl-b", data.Identifier()) + cmd.WithStdin(si) + cmd.WithWrapper("unbuffer", "-p") + return cmd + }, + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: func(stdout string, info string, t *testing.T) { + container := nerdtest.InspectContainer(helpers, data.Identifier()) + assert.Equal(t, container.State.Running, true, info) + }, + } + }, } - // unbuffer(1) emulates tty, which is required by `nerdctl run -t`. - // unbuffer(1) can be installed with `apt-get install expect`. - // - // "-p" is needed because we need unbuffer to read from stdin, and from [1]: - // "Normally, unbuffer does not read from stdin. This simplifies use of unbuffer in some situations. - // To use unbuffer in a pipeline, use the -p flag." - // - // [1] https://linux.die.net/man/1/unbuffer - base.CmdWithHelper([]string{"unbuffer", "-p"}, "run", "-it", "--name", containerName, testutil.CommonImage). - CmdOption(opts...).AssertOK() - container := base.InspectContainer(containerName) - assert.Equal(base.T, container.State.Running, false) - opts = []func(*testutil.Cmd){ - testutil.WithStdin(testutil.NewDelayOnceReader(bytes.NewReader([]byte{1, 2}))), // https://www.physics.udel.edu/~watson/scen103/ascii.html - } - base.CmdWithHelper([]string{"unbuffer", "-p"}, "start", "-a", "--detach-keys=ctrl-a,ctrl-b", containerName). - CmdOption(opts...).AssertOutContains("read detach keys") - container = base.InspectContainer(containerName) - assert.Equal(base.T, container.State.Running, true) + testCase.Run(t) + } diff --git a/cmd/nerdctl/container/container_stats_linux_test.go b/cmd/nerdctl/container/container_stats_linux_test.go index 5ea2017d949..b3f0969ca05 100644 --- a/cmd/nerdctl/container/container_stats_linux_test.go +++ b/cmd/nerdctl/container/container_stats_linux_test.go @@ -17,12 +17,13 @@ package container import ( - "fmt" "testing" "github.com/containerd/nerdctl/v2/pkg/infoutil" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestStats(t *testing.T) { @@ -31,17 +32,54 @@ func TestStats(t *testing.T) { if rootlessutil.IsRootless() && infoutil.CgroupsVersion() == "1" { t.Skip("test skipped for rootless containers on cgroup v1") } - testContainerName := testutil.Identifier(t)[:12] - exitedTestContainerName := fmt.Sprintf("%s-exited", testContainerName) - - base := testutil.NewBase(t) - defer base.Cmd("rm", "-f", testContainerName).Run() - defer base.Cmd("rm", "-f", exitedTestContainerName).Run() - base.Cmd("run", "--name", exitedTestContainerName, testutil.AlpineImage, "echo", "'exited'").AssertOK() - - base.Cmd("run", "-d", "--name", testContainerName, testutil.AlpineImage, "sleep", "10").AssertOK() - base.Cmd("stats", "--no-stream").AssertOutContains(testContainerName) - base.Cmd("stats", "--no-stream", testContainerName).AssertOK() - base.Cmd("container", "stats", "--no-stream").AssertOutContains(testContainerName) - base.Cmd("container", "stats", "--no-stream", testContainerName).AssertOK() + + testCase := nerdtest.Setup() + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()[:12]) + helpers.Anyhow("rm", "-f", data.Identifier()[:12]+"-exited") + } + + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "--name", data.Identifier()[:12], testutil.AlpineImage, "sleep", "10") + helpers.Ensure("run", "--name", data.Identifier()[:12]+"-exited", testutil.AlpineImage, "echo", "'exited'") + data.Set("id", data.Identifier()[:12]) + } + + testCase.SubTests = []*test.Case{ + { + Description: "stats", + Command: test.Command("stats", "--no-stream"), + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Identifier()[0:12]), + } + }, + }, + { + Description: "container stats", + Command: test.Command("container", "stats", "--no-stream"), + Expected: func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + Output: test.Contains(data.Identifier()[0:12]), + } + }, + }, + { + Description: "stats ID", + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("stats", "--no-stream", data.Get("id")) + }, + Expected: test.Expects(0, nil, nil), + }, + { + Description: "container stats ID", + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("container", "stats", "--no-stream", data.Get("id")) + }, + Expected: test.Expects(0, nil, nil), + }, + } + + testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_top_unix_test.go b/cmd/nerdctl/container/container_top_unix_test.go index d68d42302ee..5830c319033 100644 --- a/cmd/nerdctl/container/container_top_unix_test.go +++ b/cmd/nerdctl/container/container_top_unix_test.go @@ -24,20 +24,29 @@ import ( "github.com/containerd/nerdctl/v2/pkg/infoutil" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestTop(t *testing.T) { - t.Parallel() //more details https://github.com/containerd/nerdctl/pull/223#issuecomment-851395178 if rootlessutil.IsRootless() && infoutil.CgroupsVersion() == "1" { t.Skip("test skipped for rootless containers on cgroup v1") } - testContainerName := testutil.Identifier(t) - base := testutil.NewBase(t) - defer base.Cmd("rm", "-f", testContainerName).Run() + testCase := nerdtest.Setup() - base.Cmd("run", "-d", "--name", testContainerName, testutil.AlpineImage, "sleep", "5").AssertOK() - base.Cmd("top", testContainerName, "-o", "pid,user,cmd").AssertOK() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier(), testutil.CommonImage, "sleep", "5") + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + } + + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("top", data.Identifier(), "-o", "pid,user,cmd") + } + testCase.Expected = test.Expects(0, nil, nil) } diff --git a/cmd/nerdctl/container/container_top_windows_test.go b/cmd/nerdctl/container/container_top_windows_test.go index 690e52d50f4..bbd3925ce90 100644 --- a/cmd/nerdctl/container/container_top_windows_test.go +++ b/cmd/nerdctl/container/container_top_windows_test.go @@ -20,16 +20,28 @@ import ( "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestTopProcessContainer(t *testing.T) { - testContainerName := testutil.Identifier(t) + testCase := nerdtest.Setup() - base := testutil.NewBase(t) - defer base.Cmd("rm", "-f", testContainerName).Run() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier(), testutil.WindowsNano, "sleep", "5") + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + } + + testCase.Command = func(data test.Data, helpers test.Helpers) { + return helpers.Command("top", data.Identifier()) + } + + testCase.Execute = test.Expects(0, nil, nil) - base.Cmd("run", "-d", "--name", testContainerName, testutil.WindowsNano, "sleep", "5").AssertOK() - base.Cmd("top", testContainerName).AssertOK() + testCase.Run(t) } func TestTopHyperVContainer(t *testing.T) { @@ -37,11 +49,21 @@ func TestTopHyperVContainer(t *testing.T) { t.Skip("HyperV is not enabled, skipping test") } - testContainerName := testutil.Identifier(t) + testCase := nerdtest.Setup() + + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "--isolation", "hyperv", "-d", "--name", data.Identifier(), testutil.WindowsNano, "sleep", "5") + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + } + + testCase.Command = func(data test.Data, helpers test.Helpers) { + return helpers.Command("top", data.Identifier()) + } - base := testutil.NewBase(t) - defer base.Cmd("rm", "-f", testContainerName).Run() + testCase.Execute = test.Expects(0, nil, nil) - base.Cmd("run", "--isolation", "hyperv", "-d", "--name", testContainerName, testutil.WindowsNano, "sleep", "5").AssertOK() - base.Cmd("top", testContainerName).AssertOK() + testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_wait_test.go b/cmd/nerdctl/container/container_wait_test.go index d6a3203480a..ba24b0db70b 100644 --- a/cmd/nerdctl/container/container_wait_test.go +++ b/cmd/nerdctl/container/container_wait_test.go @@ -20,28 +20,31 @@ import ( "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" ) func TestWait(t *testing.T) { - t.Parallel() - tID := testutil.Identifier(t) - testContainerName1 := tID + "-1" - testContainerName2 := tID + "-2" - testContainerName3 := tID + "-3" + testCase := nerdtest.Setup() - const expected = `0 -0 -123 -` - base := testutil.NewBase(t) - defer base.Cmd("rm", "-f", testContainerName1, testContainerName2, testContainerName3).Run() - - base.Cmd("run", "-d", "--name", testContainerName1, testutil.CommonImage, "sleep", "1").AssertOK() + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("1"), data.Identifier("2"), data.Identifier("3")) + } - base.Cmd("run", "-d", "--name", testContainerName2, testutil.CommonImage, "sleep", "1").AssertOK() + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("1"), testutil.CommonImage, "sleep", "1") + helpers.Ensure("run", "-d", "--name", data.Identifier("2"), testutil.CommonImage, "sleep", "1") + helpers.Fail("run", "--name", data.Identifier("3"), testutil.CommonImage, "sh", "-euxc", "sleep 5; exit 123") + } - base.Cmd("run", "--name", testContainerName3, testutil.CommonImage, "sh", "-euxc", "sleep 5; exit 123").AssertExitCode(123) + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("wait", data.Identifier("1"), data.Identifier("2"), data.Identifier("3")) + } - base.Cmd("wait", testContainerName1, testContainerName2, testContainerName3).AssertOutExactly(expected) + testCase.Expected = test.Expects(0, nil, test.Equals(`0 +0 +123 +`)) + testCase.Run(t) } diff --git a/cmd/nerdctl/image/image_convert_linux_test.go b/cmd/nerdctl/image/image_convert_linux_test.go index 7e25b411c5a..46025e4305b 100644 --- a/cmd/nerdctl/image/image_convert_linux_test.go +++ b/cmd/nerdctl/image/image_convert_linux_test.go @@ -42,7 +42,7 @@ func TestImageConvert(t *testing.T) { { Description: "esgz", Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier("converted-image")) + helpers.Anyhow("rmi", "-f", data.Identifier("converted-image")) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("image", "convert", "--oci", "--estargz", @@ -56,7 +56,7 @@ func TestImageConvert(t *testing.T) { test.Binary("nydus-image"), ), Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier("converted-image")) + helpers.Anyhow("rmi", "-f", data.Identifier("converted-image")) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("image", "convert", "--oci", "--nydus", @@ -67,7 +67,7 @@ func TestImageConvert(t *testing.T) { { Description: "zstd", Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier("converted-image")) + helpers.Anyhow("rmi", "-f", data.Identifier("converted-image")) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("image", "convert", "--oci", "--zstd", "--zstd-compression-level", "3", @@ -78,7 +78,7 @@ func TestImageConvert(t *testing.T) { { Description: "zstdchunked", Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier("converted-image")) + helpers.Anyhow("rmi", "-f", data.Identifier("converted-image")) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("image", "convert", "--oci", "--zstdchunked", "--zstdchunked-compression-level", "3", @@ -120,10 +120,10 @@ func TestImageConvertNydusVerify(t *testing.T) { helpers.Ensure("push", data.Get(remoteImageKey)) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier("converted-image")) + helpers.Anyhow("rmi", "-f", data.Identifier("converted-image")) if registry != nil { registry.Cleanup(nil) - helpers.Anyhow("rmi", data.Get(remoteImageKey)) + helpers.Anyhow("rmi", "-f", data.Get(remoteImageKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { diff --git a/cmd/nerdctl/image/image_list_test.go b/cmd/nerdctl/image/image_list_test.go index 71e754484bf..2c12ebde535 100644 --- a/cmd/nerdctl/image/image_list_test.go +++ b/cmd/nerdctl/image/image_list_test.go @@ -143,9 +143,9 @@ RUN echo "actually creating a layer so that docker sets the createdAt time" data.Set("buildCtx", buildCtx) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", "taggedimage:one-fragment-one") - helpers.Anyhow("rmi", "taggedimage:two-fragment-two") - helpers.Anyhow("rmi", data.Identifier()) + helpers.Anyhow("rmi", "-f", "taggedimage:one-fragment-one") + helpers.Anyhow("rmi", "-f", "taggedimage:two-fragment-two") + helpers.Anyhow("rmi", "-f", data.Identifier()) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { data.Set("builtImageID", data.Identifier()) diff --git a/cmd/nerdctl/image/image_load_test.go b/cmd/nerdctl/image/image_load_test.go index 97f31c04b6e..452a0e18729 100644 --- a/cmd/nerdctl/image/image_load_test.go +++ b/cmd/nerdctl/image/image_load_test.go @@ -43,7 +43,7 @@ func TestLoadStdinFromPipe(t *testing.T) { helpers.Ensure("rmi", "-f", data.Identifier()) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { cmd := helpers.Command("load") diff --git a/cmd/nerdctl/image/image_prune_test.go b/cmd/nerdctl/image/image_prune_test.go index c6534253698..e3c66b8bf10 100644 --- a/cmd/nerdctl/image/image_prune_test.go +++ b/cmd/nerdctl/image/image_prune_test.go @@ -53,7 +53,7 @@ func TestImagePrune(t *testing.T) { nerdtest.Build, ), Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) }, Setup: func(data test.Data, helpers test.Helpers) { dockerfile := fmt.Sprintf(`FROM %s @@ -95,7 +95,7 @@ func TestImagePrune(t *testing.T) { // Cannot use a custom namespace with buildkitd right now, so, no parallel it is NoParallel: true, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) helpers.Anyhow("rm", "-f", data.Identifier()) }, Setup: func(data test.Data, helpers test.Helpers) { @@ -138,7 +138,7 @@ func TestImagePrune(t *testing.T) { // Cannot use a custom namespace with buildkitd right now, so, no parallel it is NoParallel: true, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) }, Setup: func(data test.Data, helpers test.Helpers) { dockerfile := fmt.Sprintf(`FROM %s @@ -177,7 +177,7 @@ LABEL version=0.1`, testutil.CommonImage) // Cannot use a custom namespace with buildkitd right now, so, no parallel it is NoParallel: true, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier()) + helpers.Anyhow("rmi", "-f", data.Identifier()) }, Setup: func(data test.Data, helpers test.Helpers) { dockerfile := fmt.Sprintf(`FROM %s diff --git a/cmd/nerdctl/image/image_pull_linux_test.go b/cmd/nerdctl/image/image_pull_linux_test.go index fb71ab3f7a1..228e88ea43a 100644 --- a/cmd/nerdctl/image/image_pull_linux_test.go +++ b/cmd/nerdctl/image/image_pull_linux_test.go @@ -176,7 +176,7 @@ func TestImagePullSoci(t *testing.T) { helpers.Ensure("--snapshotter=soci", "pull", testutil.FfmpegSociImage) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", testutil.FfmpegSociImage) + helpers.Anyhow("rmi", "-f", testutil.FfmpegSociImage) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Custom("mount") @@ -210,7 +210,7 @@ func TestImagePullSoci(t *testing.T) { helpers.Ensure("--snapshotter=soci", "pull", testutil.FfmpegSociImage) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", testutil.FfmpegSociImage) + helpers.Anyhow("rmi", "-f", testutil.FfmpegSociImage) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Custom("mount") diff --git a/cmd/nerdctl/image/image_push_linux_test.go b/cmd/nerdctl/image/image_push_linux_test.go index 9d3ae4d8598..1cd38bba7fd 100644 --- a/cmd/nerdctl/image/image_push_linux_test.go +++ b/cmd/nerdctl/image/image_push_linux_test.go @@ -72,7 +72,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -92,7 +92,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -126,7 +126,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -149,7 +149,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -172,7 +172,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -192,7 +192,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -224,7 +224,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -259,7 +259,7 @@ func TestPush(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get("testImageRef") != "" { - helpers.Anyhow("rmi", data.Get("testImageRef")) + helpers.Anyhow("rmi", "-f", data.Get("testImageRef")) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { diff --git a/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go b/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go index 10d56dd0d19..24fb696ebc9 100644 --- a/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go @@ -72,9 +72,8 @@ func TestIPFSCompNoBuild(t *testing.T) { if ipfsRegistry != nil { ipfsRegistry.Cleanup(data, helpers) } - // Speeding up repeat tests... - helpers.Anyhow("rmi", testutil.WordpressImage) - helpers.Anyhow("rmi", testutil.MariaDBImage) + helpers.Anyhow("rmi", "-f", testutil.WordpressImage) + helpers.Anyhow("rmi", "-f", testutil.MariaDBImage) } testCase.Run(t) @@ -128,8 +127,8 @@ func subtestTestIPFSCompNoB(t *testing.T, stargz bool, byAddr bool) *test.Case { // Deliberately electing to not remove them here so that we can parallelize and cut down the running time /* if data.Get(mariaImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mariaImageCIDKey)) - helpers.Anyhow("rmi", data.Get(wordpressImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mariaImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(wordpressImageCIDKey)) } */ } @@ -234,7 +233,7 @@ COPY index.html /usr/share/nginx/html/index.html testCase.Cleanup = func(data test.Data, helpers test.Helpers) { if ipfsServer != nil { // Close the server once done - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) ipfsServer.Run(nil) } if comp != nil { diff --git a/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go b/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go index 3738ceb4514..c65883e7681 100644 --- a/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go @@ -68,7 +68,7 @@ func TestIPFSAddrWithKubo(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get(mainImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -91,7 +91,7 @@ func TestIPFSAddrWithKubo(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get(mainImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { diff --git a/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go b/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go index 63a461361cc..b6b032dc965 100644 --- a/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go @@ -89,7 +89,7 @@ func TestIPFSNerdctlRegistry(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get(ipfsImageURLKey) != "" { - helpers.Anyhow("rmi", data.Get(ipfsImageURLKey)) + helpers.Anyhow("rmi", "-f", data.Get(ipfsImageURLKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -107,7 +107,7 @@ func TestIPFSNerdctlRegistry(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get(ipfsImageURLKey) != "" { - helpers.Anyhow("rmi", data.Get(ipfsImageURLKey)) + helpers.Anyhow("rmi", "-f", data.Get(ipfsImageURLKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -120,9 +120,9 @@ func TestIPFSNerdctlRegistry(t *testing.T) { NoParallel: true, Require: nerdtest.Build, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rmi", data.Identifier("built-image")) + helpers.Anyhow("rmi", "-f", data.Identifier("built-image")) if data.Get(ipfsImageURLKey) != "" { - helpers.Anyhow("rmi", data.Get(ipfsImageURLKey)) + helpers.Anyhow("rmi", "-f", data.Get(ipfsImageURLKey)) } }, Setup: func(data test.Data, helpers test.Helpers) { diff --git a/cmd/nerdctl/ipfs/ipfs_simple_linux_test.go b/cmd/nerdctl/ipfs/ipfs_simple_linux_test.go index e18acc332ee..5c7b5697464 100644 --- a/cmd/nerdctl/ipfs/ipfs_simple_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_simple_linux_test.go @@ -55,7 +55,7 @@ func TestIPFSSimple(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get(mainImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -76,7 +76,7 @@ func TestIPFSSimple(t *testing.T) { }, Cleanup: func(data test.Data, helpers test.Helpers) { if data.Get(mainImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) } }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { @@ -104,11 +104,11 @@ func TestIPFSSimple(t *testing.T) { helpers.Ensure("pull", "ipfs://"+data.Get(transformedImageCIDKey)) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rm", data.Identifier("commit-container")) - helpers.Anyhow("rmi", data.Identifier("commit-image")) + helpers.Anyhow("rm", "-f", data.Identifier("commit-container")) + helpers.Anyhow("rmi", "-f", data.Identifier("commit-image")) if data.Get(mainImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) - helpers.Anyhow("rmi", data.Get(transformedImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(transformedImageCIDKey)) } }, @@ -142,11 +142,11 @@ func TestIPFSSimple(t *testing.T) { helpers.Ensure("pull", "ipfs://"+data.Get(transformedImageCIDKey)) }, Cleanup: func(data test.Data, helpers test.Helpers) { - helpers.Anyhow("rm", data.Identifier("commit-container")) - helpers.Anyhow("rmi", data.Identifier("commit-image")) + helpers.Anyhow("rm", "-f", data.Identifier("commit-container")) + helpers.Anyhow("rmi", "-f", data.Identifier("commit-image")) if data.Get(mainImageCIDKey) != "" { - helpers.Anyhow("rmi", data.Get(mainImageCIDKey)) - helpers.Anyhow("rmi", data.Get(transformedImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(mainImageCIDKey)) + helpers.Anyhow("rmi", "-f", data.Get(transformedImageCIDKey)) } }, diff --git a/cmd/nerdctl/login/login_linux_test.go b/cmd/nerdctl/login/login_linux_test.go index 0a53a6a623e..2ac21fa374f 100644 --- a/cmd/nerdctl/login/login_linux_test.go +++ b/cmd/nerdctl/login/login_linux_test.go @@ -31,6 +31,7 @@ import ( "github.com/containerd/nerdctl/v2/pkg/imgutil/dockerconfigresolver" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/test" "github.com/containerd/nerdctl/v2/pkg/testutil/testca" "github.com/containerd/nerdctl/v2/pkg/testutil/testregistry" ) @@ -108,8 +109,8 @@ func TestLoginPersistence(t *testing.T) { t.Run(fmt.Sprintf("Server %s", tc.auth), func(t *testing.T) { t.Parallel() - username := testregistry.SafeRandomString(30) + "∞" - password := testregistry.SafeRandomString(30) + ":∞" + username := test.RandomStringBase64(30) + "∞" + password := test.RandomStringBase64(30) + ":∞" // Add the requested authentication var auth testregistry.Auth @@ -297,8 +298,8 @@ func TestLoginAgainstVariants(t *testing.T) { } // Generate credentials that are specific to each registry, so that we never cross hit another one - username := testregistry.SafeRandomString(30) + "∞" - password := testregistry.SafeRandomString(30) + ":∞" + username := test.RandomStringBase64(30) + "∞" + password := test.RandomStringBase64(30) + ":∞" // Get a CA if we want TLS var ca *testca.CA diff --git a/pkg/testutil/test/helpers.go b/pkg/testutil/test/helpers.go index 99d769d7c3e..06411df8e99 100644 --- a/pkg/testutil/test/helpers.go +++ b/pkg/testutil/test/helpers.go @@ -70,7 +70,7 @@ func (help *helpersInternal) Anyhow(args ...string) { // Fail will run a command and make sure it does fail func (help *helpersInternal) Fail(args ...string) { help.Command(args...).Run(&Expected{ - ExitCode: 1, + ExitCode: -1, }) }