diff --git a/cli/command/plugin/client_test.go b/cli/command/plugin/client_test.go new file mode 100644 index 0000000000..b543542764 --- /dev/null +++ b/cli/command/plugin/client_test.go @@ -0,0 +1,45 @@ +package plugin + +import ( + "io" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" + "golang.org/x/net/context" +) + +type fakeClient struct { + client.Client + pluginCreateFunc func(createContext io.Reader, createOptions types.PluginCreateOptions) error + pluginDisableFunc func(name string, disableOptions types.PluginDisableOptions) error + pluginEnableFunc func(name string, options types.PluginEnableOptions) error + pluginRemoveFunc func(name string, options types.PluginRemoveOptions) error +} + +func (c *fakeClient) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error { + if c.pluginCreateFunc != nil { + return c.pluginCreateFunc(createContext, createOptions) + } + return nil +} + +func (c *fakeClient) PluginEnable(ctx context.Context, name string, enableOptions types.PluginEnableOptions) error { + if c.pluginEnableFunc != nil { + return c.pluginEnableFunc(name, enableOptions) + } + return nil +} + +func (c *fakeClient) PluginDisable(context context.Context, name string, disableOptions types.PluginDisableOptions) error { + if c.pluginDisableFunc != nil { + return c.pluginDisableFunc(name, disableOptions) + } + return nil +} + +func (c *fakeClient) PluginRemove(context context.Context, name string, removeOptions types.PluginRemoveOptions) error { + if c.pluginRemoveFunc != nil { + return c.pluginRemoveFunc(name, removeOptions) + } + return nil +} diff --git a/cli/command/plugin/create_test.go b/cli/command/plugin/create_test.go new file mode 100644 index 0000000000..739e4197eb --- /dev/null +++ b/cli/command/plugin/create_test.go @@ -0,0 +1,114 @@ +package plugin + +import ( + "fmt" + "io" + "io/ioutil" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" + "github.com/docker/docker/api/types" + "github.com/gotestyourself/gotestyourself/fs" + "github.com/stretchr/testify/assert" +) + +func TestCreateErrors(t *testing.T) { + + testCases := []struct { + args []string + expectedError string + }{ + { + args: []string{}, + expectedError: "requires at least 2 arguments", + }, + { + args: []string{"INVALID_TAG", "context-dir"}, + expectedError: "invalid", + }, + { + args: []string{"plugin-foo", "nonexistent_context_dir"}, + expectedError: "no such file or directory", + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{}) + cmd := newCreateCommand(cli) + cmd.SetArgs(tc.args) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestCreateErrorOnFileAsContextDir(t *testing.T) { + tmpFile := fs.NewFile(t, "file-as-context-dir") + defer tmpFile.Remove() + + cli := test.NewFakeCli(&fakeClient{}) + cmd := newCreateCommand(cli) + cmd.SetArgs([]string{"plugin-foo", tmpFile.Path()}) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), "context must be a directory") +} + +func TestCreateErrorOnContextDirWithoutConfig(t *testing.T) { + tmpDir := fs.NewDir(t, "plugin-create-test") + defer tmpDir.Remove() + + cli := test.NewFakeCli(&fakeClient{}) + cmd := newCreateCommand(cli) + cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()}) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), "config.json: no such file or directory") +} + +func TestCreateErrorOnInvalidConfig(t *testing.T) { + tmpDir := fs.NewDir(t, "plugin-create-test", + fs.WithDir("rootfs"), + fs.WithFile("config.json", "invalid-config-contents")) + defer tmpDir.Remove() + + cli := test.NewFakeCli(&fakeClient{}) + cmd := newCreateCommand(cli) + cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()}) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), "invalid") +} + +func TestCreateErrorFromDaemon(t *testing.T) { + tmpDir := fs.NewDir(t, "plugin-create-test", + fs.WithDir("rootfs"), + fs.WithFile("config.json", `{ "Name": "plugin-foo" }`)) + defer tmpDir.Remove() + + cli := test.NewFakeCli(&fakeClient{ + pluginCreateFunc: func(createContext io.Reader, createOptions types.PluginCreateOptions) error { + return fmt.Errorf("Error creating plugin") + }, + }) + + cmd := newCreateCommand(cli) + cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()}) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), "Error creating plugin") +} + +func TestCreatePlugin(t *testing.T) { + tmpDir := fs.NewDir(t, "plugin-create-test", + fs.WithDir("rootfs"), + fs.WithFile("config.json", `{ "Name": "plugin-foo" }`)) + defer tmpDir.Remove() + + cli := test.NewFakeCli(&fakeClient{ + pluginCreateFunc: func(createContext io.Reader, createOptions types.PluginCreateOptions) error { + return nil + }, + }) + + cmd := newCreateCommand(cli) + cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()}) + assert.NoError(t, cmd.Execute()) + assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String()) +} diff --git a/cli/command/plugin/disable_test.go b/cli/command/plugin/disable_test.go new file mode 100644 index 0000000000..96fce34646 --- /dev/null +++ b/cli/command/plugin/disable_test.go @@ -0,0 +1,58 @@ +package plugin + +import ( + "fmt" + "io/ioutil" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" + "github.com/docker/docker/api/types" + "github.com/stretchr/testify/assert" +) + +func TestPluginDisableErrors(t *testing.T) { + testCases := []struct { + args []string + expectedError string + pluginDisableFunc func(name string, disableOptions types.PluginDisableOptions) error + }{ + { + args: []string{}, + expectedError: "requires exactly 1 argument", + }, + { + args: []string{"too", "many", "arguments"}, + expectedError: "requires exactly 1 argument", + }, + { + args: []string{"plugin-foo"}, + expectedError: "Error disabling plugin", + pluginDisableFunc: func(name string, disableOptions types.PluginDisableOptions) error { + return fmt.Errorf("Error disabling plugin") + }, + }, + } + + for _, tc := range testCases { + cmd := newDisableCommand( + test.NewFakeCli(&fakeClient{ + pluginDisableFunc: tc.pluginDisableFunc, + })) + cmd.SetArgs(tc.args) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestPluginDisable(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{ + pluginDisableFunc: func(name string, disableOptions types.PluginDisableOptions) error { + return nil + }, + }) + cmd := newDisableCommand(cli) + cmd.SetArgs([]string{"plugin-foo"}) + assert.NoError(t, cmd.Execute()) + assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String()) +} diff --git a/cli/command/plugin/enable_test.go b/cli/command/plugin/enable_test.go new file mode 100644 index 0000000000..68b50eae6f --- /dev/null +++ b/cli/command/plugin/enable_test.go @@ -0,0 +1,70 @@ +package plugin + +import ( + "fmt" + "io/ioutil" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" + "github.com/docker/docker/api/types" + "github.com/stretchr/testify/assert" +) + +func TestPluginEnableErrors(t *testing.T) { + testCases := []struct { + args []string + flags map[string]string + pluginEnableFunc func(name string, options types.PluginEnableOptions) error + expectedError string + }{ + { + args: []string{}, + expectedError: "requires exactly 1 argument", + }, + { + args: []string{"too-many", "arguments"}, + expectedError: "requires exactly 1 argument", + }, + { + args: []string{"plugin-foo"}, + pluginEnableFunc: func(name string, options types.PluginEnableOptions) error { + return fmt.Errorf("failed to enable plugin") + }, + expectedError: "failed to enable plugin", + }, + { + args: []string{"plugin-foo"}, + flags: map[string]string{ + "timeout": "-1", + }, + expectedError: "negative timeout -1 is invalid", + }, + } + + for _, tc := range testCases { + cmd := newEnableCommand( + test.NewFakeCli(&fakeClient{ + pluginEnableFunc: tc.pluginEnableFunc, + })) + cmd.SetArgs(tc.args) + for key, value := range tc.flags { + cmd.Flags().Set(key, value) + } + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestPluginEnable(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{ + pluginEnableFunc: func(name string, options types.PluginEnableOptions) error { + return nil + }, + }) + + cmd := newEnableCommand(cli) + cmd.SetArgs([]string{"plugin-foo"}) + assert.NoError(t, cmd.Execute()) + assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String()) +} diff --git a/cli/command/plugin/remove_test.go b/cli/command/plugin/remove_test.go new file mode 100644 index 0000000000..cc179091b9 --- /dev/null +++ b/cli/command/plugin/remove_test.go @@ -0,0 +1,71 @@ +package plugin + +import ( + "fmt" + "io/ioutil" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/testutil" + "github.com/docker/docker/api/types" + "github.com/stretchr/testify/assert" +) + +func TestRemoveErrors(t *testing.T) { + + testCases := []struct { + args []string + pluginRemoveFunc func(name string, options types.PluginRemoveOptions) error + expectedError string + }{ + { + args: []string{}, + expectedError: "requires at least 1 argument", + }, + { + args: []string{"plugin-foo"}, + pluginRemoveFunc: func(name string, options types.PluginRemoveOptions) error { + return fmt.Errorf("Error removing plugin") + }, + expectedError: "Error removing plugin", + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{ + pluginRemoveFunc: tc.pluginRemoveFunc, + }) + cmd := newRemoveCommand(cli) + cmd.SetArgs(tc.args) + cmd.SetOutput(ioutil.Discard) + testutil.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestRemove(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{ + pluginRemoveFunc: func(name string, options types.PluginRemoveOptions) error { + return nil + }, + }) + cmd := newRemoveCommand(cli) + cmd.SetArgs([]string{"plugin-foo"}) + assert.NoError(t, cmd.Execute()) + assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String()) +} + +func TestRemoveWithForceOption(t *testing.T) { + force := false + cli := test.NewFakeCli(&fakeClient{ + pluginRemoveFunc: func(name string, options types.PluginRemoveOptions) error { + force = options.Force + return nil + }, + }) + cmd := newRemoveCommand(cli) + cmd.SetArgs([]string{"plugin-foo"}) + cmd.Flags().Set("force", "true") + assert.NoError(t, cmd.Execute()) + assert.True(t, force) + assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String()) +}