From 8cb9f25f46ba92a0d8ca99403dddc0466f23223b Mon Sep 17 00:00:00 2001 From: apostasie Date: Fri, 6 Sep 2024 21:11:02 -0700 Subject: [PATCH] Migrating cmd/nerdctl to the new framework Signed-off-by: apostasie --- cmd/nerdctl/main_linux_test.go | 38 ++++++-- cmd/nerdctl/main_test.go | 141 +++++++++++++++++++----------- pkg/testutil/testcase/command.go | 16 ++++ pkg/testutil/testcase/testcase.go | 7 +- 4 files changed, 141 insertions(+), 61 deletions(-) diff --git a/cmd/nerdctl/main_linux_test.go b/cmd/nerdctl/main_linux_test.go index a0e82861a84..2d34a7f0fc4 100644 --- a/cmd/nerdctl/main_linux_test.go +++ b/cmd/nerdctl/main_linux_test.go @@ -20,17 +20,39 @@ import ( "testing" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/testcase" ) // TestIssue108 tests https://github.com/containerd/nerdctl/issues/108 // ("`nerdctl run --net=host -it` fails while `nerdctl run -it --net=host` works") func TestIssue108(t *testing.T) { - base := testutil.NewBase(t) - // unbuffer(1) emulates tty, which is required by `nerdctl run -t`. - // unbuffer(1) can be installed with `apt-get install expect`. - unbuffer := []string{"unbuffer"} - base.CmdWithHelper(unbuffer, "run", "-it", "--rm", "--net=host", testutil.AlpineImage, - "echo", "this was always working").AssertOK() - base.CmdWithHelper(unbuffer, "run", "--rm", "--net=host", "-it", testutil.AlpineImage, - "echo", "this was not working due to issue #108").AssertOK() + t.Parallel() + testutil.RequireExecutable(t, "unbuffer") + + testCases := []*testcase.TestCase{ + { + Description: "-it --net=host", + Command: func(data *testcase.Data) testcase.Command { + c := &testcase.BaseCommand{} + c.WithHelper("unbuffer") + c.WithArgs("run", "-it", "--rm", "--net=host", testutil.AlpineImage, "echo", "this was always working") + return c + }, + Expected: testcase.Expects(0, nil, nil), + }, + { + Description: "--net=host -it", + Command: func(data *testcase.Data) testcase.Command { + c := &testcase.BaseCommand{} + c.WithHelper("unbuffer") + c.WithArgs("run", "--rm", "--net=host", "-it", testutil.AlpineImage, "echo", "this was not working due to issue #108") + return c + }, + Expected: testcase.Expects(0, nil, nil), + }, + } + + for _, tc := range testCases { + tc.Run(t) + } } diff --git a/cmd/nerdctl/main_test.go b/cmd/nerdctl/main_test.go index a450c963bf5..3fbb7ea522d 100644 --- a/cmd/nerdctl/main_test.go +++ b/cmd/nerdctl/main_test.go @@ -17,15 +17,13 @@ package main import ( - "os" - "path/filepath" + "errors" "testing" - "gotest.tools/v3/assert" - "github.com/containerd/containerd/v2/defaults" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/testcase" ) func TestMain(m *testing.M) { @@ -35,55 +33,98 @@ func TestMain(m *testing.M) { // TestUnknownCommand tests https://github.com/containerd/nerdctl/issues/487 func TestUnknownCommand(t *testing.T) { t.Parallel() - base := testutil.NewBase(t) - base.Cmd("non-existent-command").AssertFail() - base.Cmd("non-existent-command", "info").AssertFail() - base.Cmd("system", "non-existent-command").AssertFail() - base.Cmd("system", "non-existent-command", "info").AssertFail() - base.Cmd("system").AssertOK() // show help without error - base.Cmd("system", "info").AssertOutContains("Kernel Version:") - base.Cmd("info").AssertOutContains("Kernel Version:") + + testCases := []*testcase.TestCase{ + { + Description: "non-existent-command", + NoParallel: true, + Command: testcase.NewCommand("non-existent-command"), + Expected: testcase.Expects(1, []error{errors.New("unknown subcommand")}, nil), + }, + { + Description: "non-existent-command info", + Command: testcase.NewCommand("non-existent-command", "info"), + Expected: testcase.Expects(1, []error{errors.New("unknown subcommand")}, nil), + }, + { + Description: "system non-existent-command", + Command: testcase.NewCommand("system", "non-existent-command"), + Expected: testcase.Expects(1, []error{errors.New("unknown subcommand")}, nil), + }, + { + Description: "system non-existent-command info", + Command: testcase.NewCommand("system", "non-existent-command", "info"), + Expected: testcase.Expects(1, []error{errors.New("unknown subcommand")}, nil), + }, + { + Description: "system", + Command: testcase.NewCommand("system"), + Expected: testcase.Expects(0, nil, nil), + }, + { + Description: "system info", + Command: testcase.NewCommand("system", "info"), + Expected: testcase.Expects(0, nil, testcase.Contains("Kernel Version:")), + }, + { + Description: "info", + Command: testcase.NewCommand("info"), + Expected: testcase.Expects(0, nil, testcase.Contains("Kernel Version:")), + }, + } + + for _, tc := range testCases { + tc.Run(t) + } } -// TestNerdctlConfig validates the configuration precedence [CLI, Env, TOML, Default]. +// TestNerdctlConfig validates the configuration precedence [CLI, Env, TOML, Default] and broken config rejection func TestNerdctlConfig(t *testing.T) { - testutil.DockerIncompatible(t) t.Parallel() - tomlPath := filepath.Join(t.TempDir(), "nerdctl.toml") - err := os.WriteFile(tomlPath, []byte(` -snapshotter = "dummy-snapshotter-via-toml" -`), 0400) - assert.NilError(t, err) - base := testutil.NewBase(t) - - // [Default] - base.Cmd("info", "-f", "{{.Driver}}").AssertOutExactly(defaults.DefaultSnapshotter + "\n") - - // [TOML, Default] - base.Env = append(base.Env, "NERDCTL_TOML="+tomlPath) - base.Cmd("info", "-f", "{{.Driver}}").AssertOutExactly("dummy-snapshotter-via-toml\n") - - // [CLI, TOML, Default] - base.Cmd("info", "-f", "{{.Driver}}", "--snapshotter=dummy-snapshotter-via-cli").AssertOutExactly("dummy-snapshotter-via-cli\n") - - // [Env, TOML, Default] - base.Env = append(base.Env, "CONTAINERD_SNAPSHOTTER=dummy-snapshotter-via-env") - base.Cmd("info", "-f", "{{.Driver}}").AssertOutExactly("dummy-snapshotter-via-env\n") - - // [CLI, Env, TOML, Default] - base.Cmd("info", "-f", "{{.Driver}}", "--snapshotter=dummy-snapshotter-via-cli").AssertOutExactly("dummy-snapshotter-via-cli\n") -} - -func TestNerdctlConfigBad(t *testing.T) { testutil.DockerIncompatible(t) - t.Parallel() - tomlPath := filepath.Join(t.TempDir(), "config.toml") - err := os.WriteFile(tomlPath, []byte(` -# containerd config, not nerdctl config -version = 2 -`), 0400) - assert.NilError(t, err) - base := testutil.NewBase(t) - base.Env = append(base.Env, "NERDCTL_TOML="+tomlPath) - base.Cmd("info").AssertFail() + + testCases := []*testcase.TestCase{ + { + Description: "Default", + Command: testcase.NewCommand("info", "-f", "{{.Driver}}"), + Expected: testcase.Expects(0, nil, testcase.Equals(defaults.DefaultSnapshotter+"\n")), + }, + { + Description: "TOML > Default", + NerdctlToml: `snapshotter = "dummy-snapshotter-via-toml"`, + Command: testcase.NewCommand("info", "-f", "{{.Driver}}"), + Expected: testcase.Expects(0, nil, testcase.Equals("dummy-snapshotter-via-toml\n")), + }, + { + Description: "Cli > TOML > Default", + NerdctlToml: `snapshotter = "dummy-snapshotter-via-toml"`, + Command: testcase.NewCommand("info", "-f", "{{.Driver}}", "--snapshotter=dummy-snapshotter-via-cli"), + Expected: testcase.Expects(0, nil, testcase.Equals("dummy-snapshotter-via-cli\n")), + }, + { + Description: "Env > TOML > Default", + NerdctlToml: `snapshotter = "dummy-snapshotter-via-toml"`, + Command: testcase.NewCommand("info", "-f", "{{.Driver}}"), + Env: map[string]string{"CONTAINERD_SNAPSHOTTER": "dummy-snapshotter-via-env"}, + Expected: testcase.Expects(0, nil, testcase.Equals("dummy-snapshotter-via-env\n")), + }, + { + Description: "Cli > Env > TOML > Default", + NerdctlToml: `snapshotter = "dummy-snapshotter-via-toml"`, + Command: testcase.NewCommand("info", "-f", "{{.Driver}}", "--snapshotter=dummy-snapshotter-via-cli"), + Env: map[string]string{"CONTAINERD_SNAPSHOTTER": "dummy-snapshotter-via-env"}, + Expected: testcase.Expects(0, nil, testcase.Equals("dummy-snapshotter-via-cli\n")), + }, + { + Description: "Broken config", + NerdctlToml: `# containerd config, not nerdctl config +version = 2`, + Command: testcase.NewCommand("info"), + Expected: testcase.Expects(1, []error{errors.New("failed to load nerdctl config")}, nil), + }, + } + + for _, tc := range testCases { + tc.Run(t) + } } diff --git a/pkg/testutil/testcase/command.go b/pkg/testutil/testcase/command.go index 438e9252b8e..ff757136940 100644 --- a/pkg/testutil/testcase/command.go +++ b/pkg/testutil/testcase/command.go @@ -144,6 +144,22 @@ func (cc *GenericCommand) WithBase(base *testutil.Base) Command { return cc } +func Ensure(t *testing.T, args ...string) { + (func() Command { + bc := &BaseCommand{} + bc.WithArgs(args...) + return bc + })().Run(t, &Expected{}) +} + +func Anyway(t *testing.T, args ...string) { + (func() Command { + bc := &BaseCommand{} + bc.WithArgs(args...) + return bc + })().Run(t, nil) +} + func NewCommand(args ...string) func(data *Data) Command { return func(data *Data) Command { bc := &BaseCommand{} diff --git a/pkg/testutil/testcase/testcase.go b/pkg/testutil/testcase/testcase.go index c68260a34fc..03ad5366001 100644 --- a/pkg/testutil/testcase/testcase.go +++ b/pkg/testutil/testcase/testcase.go @@ -119,10 +119,9 @@ func (test *TestCase) Run(t *testing.T) { var base *testutil.Base // If private, set hosts-dir, data-root, and DOCKER_CONFIG to tempDir, create a dedicated namespace, and make // sure we clean it up - for nerdctl - // Docker does not have these facilities to isolate as much, so, disable parallel if test.PrivateMode { pvNamespace := "nerdctl-test-" + test.Data.testID - base = testutil.NewBaseWithNamespace(t, pvNamespace) + base = testutil.NewBaseWithNamespace(tt, pvNamespace) test.Env["DOCKER_CONFIG"] = test.Data.tempDir if base.Target == testutil.Nerdctl { test.Env["NERDCTL_TOML"] = filepath.Join(test.Data.tempDir, "nerdctl.toml") @@ -137,10 +136,12 @@ func (test *TestCase) Run(t *testing.T) { cleanup() tt.Cleanup(cleanup) } else { + // Docker does not have these facilities to isolate as much, so, just disable parallel + // NOTE there then may be side effects to other tests. Obviously use caution. test.NoParallel = true } } else { - base = testutil.NewBase(t) + base = testutil.NewBase(tt) } if test.NerdctlToml != "" {