diff --git a/cli/command/plugin/client_test.go b/cli/command/plugin/client_test.go index 436748da33..6dc4a0a625 100644 --- a/cli/command/plugin/client_test.go +++ b/cli/command/plugin/client_test.go @@ -17,6 +17,7 @@ type fakeClient struct { 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) + pluginInspectFunc func(name string) (*types.Plugin, []byte, error) } func (c *fakeClient) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error { @@ -61,3 +62,11 @@ func (c *fakeClient) PluginList(context context.Context, filter filters.Args) (t return types.PluginsListResponse{}, nil } + +func (c *fakeClient) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) { + if c.pluginInspectFunc != nil { + return c.pluginInspectFunc(name) + } + + return nil, nil, nil +} diff --git a/cli/command/plugin/inspect_test.go b/cli/command/plugin/inspect_test.go new file mode 100644 index 0000000000..ac892b5039 --- /dev/null +++ b/cli/command/plugin/inspect_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" + + "gotest.tools/assert" + "gotest.tools/golden" +) + +var pluginFoo = &types.Plugin{ + ID: "id-foo", + Name: "name-foo", + Config: types.PluginConfig{ + Description: "plugin foo description", + DockerVersion: "17.12.1-ce", + Documentation: "plugin foo documentation", + Entrypoint: []string{"/foo"}, + Interface: types.PluginConfigInterface{ + Socket: "pluginfoo.sock", + }, + Linux: types.PluginConfigLinux{ + Capabilities: []string{"CAP_SYS_ADMIN"}, + }, + WorkDir: "workdir-foo", + Rootfs: &types.PluginConfigRootfs{ + DiffIds: []string{"sha256:8603eedd4ea52cebb2f22b45405a3dc8f78ba3e31bf18f27b4547a9ff930e0bd"}, + Type: "layers", + }, + }, +} + +func TestInspectErrors(t *testing.T) { + testCases := []struct { + description string + args []string + flags map[string]string + expectedError string + inspectFunc func(name string) (*types.Plugin, []byte, error) + }{ + { + description: "too few arguments", + args: []string{}, + expectedError: "requires at least 1 argument", + }, + { + description: "error inspecting plugin", + args: []string{"foo"}, + expectedError: "error inspecting plugin", + inspectFunc: func(name string) (*types.Plugin, []byte, error) { + return nil, nil, fmt.Errorf("error inspecting plugin") + }, + }, + { + description: "invalid format", + args: []string{"foo"}, + flags: map[string]string{ + "format": "{{invalid format}}", + }, + expectedError: "Template parsing error", + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{pluginInspectFunc: tc.inspectFunc}) + cmd := newInspectCommand(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 TestInspect(t *testing.T) { + testCases := []struct { + description string + args []string + flags map[string]string + golden string + inspectFunc func(name string) (*types.Plugin, []byte, error) + }{ + { + description: "inspect single plugin with format", + args: []string{"foo"}, + flags: map[string]string{ + "format": "{{ .Name }}", + }, + golden: "plugin-inspect-single-with-format.golden", + inspectFunc: func(name string) (*types.Plugin, []byte, error) { + return &types.Plugin{ + ID: "id-foo", + Name: "name-foo", + }, []byte{}, nil + }, + }, + { + description: "inspect single plugin without format", + args: []string{"foo"}, + golden: "plugin-inspect-single-without-format.golden", + inspectFunc: func(name string) (*types.Plugin, []byte, error) { + return pluginFoo, nil, nil + }, + }, + { + description: "inspect multiple plugins with format", + args: []string{"foo", "bar"}, + flags: map[string]string{ + "format": "{{ .Name }}", + }, + golden: "plugin-inspect-multiple-with-format.golden", + inspectFunc: func(name string) (*types.Plugin, []byte, error) { + switch name { + case "foo": + return &types.Plugin{ + ID: "id-foo", + Name: "name-foo", + }, []byte{}, nil + case "bar": + return &types.Plugin{ + ID: "id-bar", + Name: "name-bar", + }, []byte{}, nil + default: + return nil, nil, fmt.Errorf("unexpected plugin name: %s", name) + } + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{pluginInspectFunc: tc.inspectFunc}) + cmd := newInspectCommand(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-inspect-multiple-with-format.golden b/cli/command/plugin/testdata/plugin-inspect-multiple-with-format.golden new file mode 100644 index 0000000000..3adb038a4c --- /dev/null +++ b/cli/command/plugin/testdata/plugin-inspect-multiple-with-format.golden @@ -0,0 +1,2 @@ +name-foo +name-bar diff --git a/cli/command/plugin/testdata/plugin-inspect-single-with-format.golden b/cli/command/plugin/testdata/plugin-inspect-single-with-format.golden new file mode 100644 index 0000000000..ab347b6919 --- /dev/null +++ b/cli/command/plugin/testdata/plugin-inspect-single-with-format.golden @@ -0,0 +1 @@ +name-foo diff --git a/cli/command/plugin/testdata/plugin-inspect-single-without-format.golden b/cli/command/plugin/testdata/plugin-inspect-single-without-format.golden new file mode 100644 index 0000000000..65c8d39ce9 --- /dev/null +++ b/cli/command/plugin/testdata/plugin-inspect-single-without-format.golden @@ -0,0 +1,54 @@ +[ + { + "Config": { + "Args": { + "Description": "", + "Name": "", + "Settable": null, + "Value": null + }, + "Description": "plugin foo description", + "DockerVersion": "17.12.1-ce", + "Documentation": "plugin foo documentation", + "Entrypoint": [ + "/foo" + ], + "Env": null, + "Interface": { + "Socket": "pluginfoo.sock", + "Types": null + }, + "IpcHost": false, + "Linux": { + "AllowAllDevices": false, + "Capabilities": [ + "CAP_SYS_ADMIN" + ], + "Devices": null + }, + "Mounts": null, + "Network": { + "Type": "" + }, + "PidHost": false, + "PropagatedMount": "", + "User": {}, + "WorkDir": "workdir-foo", + "rootfs": { + "diff_ids": [ + "sha256:8603eedd4ea52cebb2f22b45405a3dc8f78ba3e31bf18f27b4547a9ff930e0bd" + ], + "type": "layers" + } + }, + "Enabled": false, + "Id": "id-foo", + "Name": "name-foo", + "Settings": { + "Args": null, + "Devices": null, + "Env": null, + "Mounts": null + } + } +]