From bc9b42ea9bf569d68a1486979c8daa2bf6c71980 Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Sat, 23 Jun 2018 10:21:17 -0400 Subject: [PATCH] added unit tests covering content trust for plugin install command Signed-off-by: Arash Deshmeh --- cli/command/plugin/client_test.go | 8 ++ cli/command/plugin/install.go | 2 +- cli/command/plugin/install_test.go | 141 +++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 cli/command/plugin/install_test.go diff --git a/cli/command/plugin/client_test.go b/cli/command/plugin/client_test.go index 07b4a06e28..a50b6b2ee9 100644 --- a/cli/command/plugin/client_test.go +++ b/cli/command/plugin/client_test.go @@ -14,6 +14,7 @@ type fakeClient struct { pluginDisableFunc func(name string, disableOptions types.PluginDisableOptions) error 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) } func (c *fakeClient) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error { @@ -43,3 +44,10 @@ func (c *fakeClient) PluginRemove(context context.Context, name string, removeOp } return nil } + +func (c *fakeClient) PluginInstall(context context.Context, name string, installOptions types.PluginInstallOptions) (io.ReadCloser, error) { + if c.pluginInstallFunc != nil { + return c.pluginInstallFunc(name, installOptions) + } + return nil, nil +} diff --git a/cli/command/plugin/install.go b/cli/command/plugin/install.go index 44e007f66d..7b3f508a24 100644 --- a/cli/command/plugin/install.go +++ b/cli/command/plugin/install.go @@ -151,7 +151,7 @@ func runInstall(dockerCli command.Cli, opts pluginOptions) error { responseBody, err := dockerCli.Client().PluginInstall(ctx, localName, options) if err != nil { if strings.Contains(err.Error(), "(image) when fetching") { - return errors.New(err.Error() + " - Use `docker image pull`") + return errors.New(err.Error() + " - Use \"docker image pull\"") } return err } diff --git a/cli/command/plugin/install_test.go b/cli/command/plugin/install_test.go new file mode 100644 index 0000000000..ccd5294ec2 --- /dev/null +++ b/cli/command/plugin/install_test.go @@ -0,0 +1,141 @@ +package plugin + +import ( + "fmt" + "io" + "io/ioutil" + "strings" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/notary" + "github.com/docker/docker/api/types" + + "gotest.tools/assert" +) + +func TestInstallErrors(t *testing.T) { + testCases := []struct { + description string + args []string + expectedError string + installFunc func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) + }{ + { + description: "insufficient number of arguments", + args: []string{}, + expectedError: "requires at least 1 argument", + }, + { + description: "invalid alias", + args: []string{"foo", "--alias", "UPPERCASE_ALIAS"}, + expectedError: "invalid", + }, + { + description: "invalid plugin name", + args: []string{"UPPERCASE_REPONAME"}, + expectedError: "invalid", + }, + { + description: "installation error", + args: []string{"foo"}, + expectedError: "Error installing plugin", + installFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) { + return nil, fmt.Errorf("Error installing plugin") + }, + }, + { + description: "installation error due to missing image", + args: []string{"foo"}, + expectedError: "docker image pull", + installFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) { + return nil, fmt.Errorf("(image) when fetching") + }, + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{pluginInstallFunc: tc.installFunc}) + cmd := newInstallCommand(cli) + cmd.SetArgs(tc.args) + cmd.SetOutput(ioutil.Discard) + assert.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestInstallContentTrustErrors(t *testing.T) { + testCases := []struct { + description string + args []string + expectedError string + notaryFunc test.NotaryClientFuncType + }{ + { + description: "install plugin, offline notary server", + args: []string{"plugin:tag"}, + expectedError: "client is offline", + notaryFunc: notary.GetOfflineNotaryRepository, + }, + { + description: "install plugin, uninitialized notary server", + args: []string{"plugin:tag"}, + expectedError: "remote trust data does not exist", + notaryFunc: notary.GetUninitializedNotaryRepository, + }, + { + description: "install plugin, empty notary server", + args: []string{"plugin:tag"}, + expectedError: "No valid trust data for tag", + notaryFunc: notary.GetEmptyTargetsNotaryRepository, + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{ + pluginInstallFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) { + return nil, fmt.Errorf("should not try to install plugin") + + }, + }, test.EnableContentTrust) + cli.SetNotaryClient(tc.notaryFunc) + cmd := newInstallCommand(cli) + cmd.SetArgs(tc.args) + cmd.SetOutput(ioutil.Discard) + assert.ErrorContains(t, cmd.Execute(), tc.expectedError) + } +} + +func TestInstall(t *testing.T) { + testCases := []struct { + description string + args []string + expectedOutput string + installFunc func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) + }{ + { + description: "install with no additional flags", + args: []string{"foo"}, + expectedOutput: "Installed plugin foo\n", + installFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) { + return ioutil.NopCloser(strings.NewReader("")), nil + }, + }, + { + description: "install with disable flag", + args: []string{"--disable", "foo"}, + expectedOutput: "Installed plugin foo\n", + installFunc: func(name string, options types.PluginInstallOptions) (io.ReadCloser, error) { + assert.Check(t, options.Disabled) + return ioutil.NopCloser(strings.NewReader("")), nil + }, + }, + } + + for _, tc := range testCases { + cli := test.NewFakeCli(&fakeClient{pluginInstallFunc: tc.installFunc}) + cmd := newInstallCommand(cli) + cmd.SetArgs(tc.args) + assert.NilError(t, cmd.Execute()) + assert.Check(t, strings.Contains(cli.OutBuffer().String(), tc.expectedOutput)) + } +}