diff --git a/cli/command/plugin/client_test.go b/cli/command/plugin/client_test.go index a50b6b2ee9..436748da33 100644 --- a/cli/command/plugin/client_test.go +++ b/cli/command/plugin/client_test.go @@ -5,6 +5,7 @@ import ( "io" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" ) @@ -15,6 +16,7 @@ type fakeClient struct { pluginEnableFunc func(name string, options types.PluginEnableOptions) error pluginRemoveFunc func(name string, options types.PluginRemoveOptions) error pluginInstallFunc func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) + pluginListFunc func(filter filters.Args) (types.PluginsListResponse, error) } func (c *fakeClient) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error { @@ -51,3 +53,11 @@ func (c *fakeClient) PluginInstall(context context.Context, name string, install } return nil, nil } + +func (c *fakeClient) PluginList(context context.Context, filter filters.Args) (types.PluginsListResponse, error) { + if c.pluginListFunc != nil { + return c.pluginListFunc(filter) + } + + return types.PluginsListResponse{}, nil +} diff --git a/cli/command/plugin/list_test.go b/cli/command/plugin/list_test.go new file mode 100644 index 0000000000..03c23e51c7 --- /dev/null +++ b/cli/command/plugin/list_test.go @@ -0,0 +1,150 @@ +package plugin + +import ( + "fmt" + "io/ioutil" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + + "gotest.tools/assert" + is "gotest.tools/assert/cmp" + "gotest.tools/golden" +) + +func TestListErrors(t *testing.T) { + testCases := []struct { + description string + args []string + flags map[string]string + expectedError string + listFunc func(filter filters.Args) (types.PluginsListResponse, error) + }{ + { + description: "too many arguments", + args: []string{"foo"}, + expectedError: "accepts no arguments", + }, + { + description: "error listing plugins", + args: []string{}, + expectedError: "error listing plugins", + listFunc: func(filter filters.Args) (types.PluginsListResponse, error) { + return types.PluginsListResponse{}, fmt.Errorf("error listing plugins") + }, + }, + { + description: "invalid format", + args: []string{}, + flags: map[string]string{ + "format": "{{invalid format}}", + }, + expectedError: "Template parsing error", + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc}) + cmd := newListCommand(cli) + cmd.SetArgs(tc.args) + for key, value := range tc.flags { + cmd.Flags().Set(key, value) + } + cmd.SetOutput(ioutil.Discard) + assert.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestList(t *testing.T) { + singlePluginListFunc := func(filter filters.Args) (types.PluginsListResponse, error) { + return types.PluginsListResponse{ + { + ID: "id-foo", + Name: "name-foo", + Enabled: true, + Config: types.PluginConfig{ + Description: "desc-bar", + }, + }, + }, nil + } + + testCases := []struct { + description string + args []string + flags map[string]string + golden string + listFunc func(filter filters.Args) (types.PluginsListResponse, error) + }{ + { + description: "list with no additional flags", + args: []string{}, + golden: "plugin-list-without-format.golden", + listFunc: singlePluginListFunc, + }, + { + description: "list with filters", + args: []string{}, + flags: map[string]string{ + "filter": "foo=bar", + }, + golden: "plugin-list-without-format.golden", + listFunc: func(filter filters.Args) (types.PluginsListResponse, error) { + assert.Check(t, is.Equal("bar", filter.Get("foo")[0])) + return singlePluginListFunc(filter) + }, + }, + { + description: "list with quiet option", + args: []string{}, + flags: map[string]string{ + "quiet": "true", + }, + golden: "plugin-list-with-quiet-option.golden", + listFunc: singlePluginListFunc, + }, + { + description: "list with no-trunc option", + args: []string{}, + flags: map[string]string{ + "no-trunc": "true", + "format": "{{ .ID }}", + }, + golden: "plugin-list-with-no-trunc-option.golden", + listFunc: func(filter filters.Args) (types.PluginsListResponse, error) { + return types.PluginsListResponse{ + { + ID: "xyg4z2hiSLO5yTnBJfg4OYia9gKA6Qjd", + Name: "name-foo", + Enabled: true, + Config: types.PluginConfig{ + Description: "desc-bar", + }, + }, + }, nil + }, + }, + { + description: "list with format", + args: []string{}, + flags: map[string]string{ + "format": "{{ .Name }}", + }, + golden: "plugin-list-with-format.golden", + listFunc: singlePluginListFunc, + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc}) + cmd := newListCommand(cli) + cmd.SetArgs(tc.args) + for key, value := range tc.flags { + cmd.Flags().Set(key, value) + } + assert.NilError(t, cmd.Execute()) + golden.Assert(t, cli.OutBuffer().String(), tc.golden) + } +} diff --git a/cli/command/plugin/testdata/plugin-list-with-format.golden b/cli/command/plugin/testdata/plugin-list-with-format.golden new file mode 100644 index 0000000000..ab347b6919 --- /dev/null +++ b/cli/command/plugin/testdata/plugin-list-with-format.golden @@ -0,0 +1 @@ +name-foo diff --git a/cli/command/plugin/testdata/plugin-list-with-no-trunc-option.golden b/cli/command/plugin/testdata/plugin-list-with-no-trunc-option.golden new file mode 100644 index 0000000000..ac88922c7e --- /dev/null +++ b/cli/command/plugin/testdata/plugin-list-with-no-trunc-option.golden @@ -0,0 +1 @@ +xyg4z2hiSLO5yTnBJfg4OYia9gKA6Qjd diff --git a/cli/command/plugin/testdata/plugin-list-with-quiet-option.golden b/cli/command/plugin/testdata/plugin-list-with-quiet-option.golden new file mode 100644 index 0000000000..e2faeb6067 --- /dev/null +++ b/cli/command/plugin/testdata/plugin-list-with-quiet-option.golden @@ -0,0 +1 @@ +id-foo diff --git a/cli/command/plugin/testdata/plugin-list-without-format.golden b/cli/command/plugin/testdata/plugin-list-without-format.golden new file mode 100644 index 0000000000..a8398872cd --- /dev/null +++ b/cli/command/plugin/testdata/plugin-list-without-format.golden @@ -0,0 +1,2 @@ +ID NAME DESCRIPTION ENABLED +id-foo name-foo desc-bar true