Преглед на файлове

Merge pull request #32289 from adshmh/add-unit-tests-for-cli-command-secret-package

add unit tests for package cli/command/secret
Vincent Demeester преди 8 години
родител
ревизия
8b9d54c084

+ 44 - 0
cli/command/secret/client_test.go

@@ -0,0 +1,44 @@
+package secret
+
+import (
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/client"
+	"golang.org/x/net/context"
+)
+
+type fakeClient struct {
+	client.Client
+	secretCreateFunc  func(swarm.SecretSpec) (types.SecretCreateResponse, error)
+	secretInspectFunc func(string) (swarm.Secret, []byte, error)
+	secretListFunc    func(types.SecretListOptions) ([]swarm.Secret, error)
+	secretRemoveFunc  func(string) error
+}
+
+func (c *fakeClient) SecretCreate(ctx context.Context, spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
+	if c.secretCreateFunc != nil {
+		return c.secretCreateFunc(spec)
+	}
+	return types.SecretCreateResponse{}, nil
+}
+
+func (c *fakeClient) SecretInspectWithRaw(ctx context.Context, id string) (swarm.Secret, []byte, error) {
+	if c.secretInspectFunc != nil {
+		return c.secretInspectFunc(id)
+	}
+	return swarm.Secret{}, nil, nil
+}
+
+func (c *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
+	if c.secretListFunc != nil {
+		return c.secretListFunc(options)
+	}
+	return []swarm.Secret{}, nil
+}
+
+func (c *fakeClient) SecretRemove(ctx context.Context, name string) error {
+	if c.secretRemoveFunc != nil {
+		return c.secretRemoveFunc(name)
+	}
+	return nil
+}

+ 2 - 2
cli/command/secret/create.go

@@ -22,7 +22,7 @@ type createOptions struct {
 	labels opts.ListOpts
 }
 
-func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
+func newSecretCreateCommand(dockerCli command.Cli) *cobra.Command {
 	createOpts := createOptions{
 		labels: opts.NewListOpts(opts.ValidateEnv),
 	}
@@ -43,7 +43,7 @@ func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
 	return cmd
 }
 
-func runSecretCreate(dockerCli *command.DockerCli, options createOptions) error {
+func runSecretCreate(dockerCli command.Cli, options createOptions) error {
 	client := dockerCli.Client()
 	ctx := context.Background()
 

+ 126 - 0
cli/command/secret/create_test.go

@@ -0,0 +1,126 @@
+package secret
+
+import (
+	"bytes"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/cli/internal/test"
+	"github.com/docker/docker/pkg/testutil/assert"
+	"github.com/docker/docker/pkg/testutil/golden"
+	"github.com/pkg/errors"
+)
+
+const secretDataFile = "secret-create-with-name.golden"
+
+func TestSecretCreateErrors(t *testing.T) {
+	testCases := []struct {
+		args             []string
+		secretCreateFunc func(swarm.SecretSpec) (types.SecretCreateResponse, error)
+		expectedError    string
+	}{
+		{
+			args:          []string{"too_few"},
+			expectedError: "requires exactly 2 argument(s)",
+		},
+		{args: []string{"too", "many", "arguments"},
+			expectedError: "requires exactly 2 argument(s)",
+		},
+		{
+			args: []string{"name", filepath.Join("testdata", secretDataFile)},
+			secretCreateFunc: func(secretSpec swarm.SecretSpec) (types.SecretCreateResponse, error) {
+				return types.SecretCreateResponse{}, errors.Errorf("error creating secret")
+			},
+			expectedError: "error creating secret",
+		},
+	}
+	for _, tc := range testCases {
+		buf := new(bytes.Buffer)
+		cmd := newSecretCreateCommand(
+			test.NewFakeCli(&fakeClient{
+				secretCreateFunc: tc.secretCreateFunc,
+			}, buf),
+		)
+		cmd.SetArgs(tc.args)
+		cmd.SetOutput(ioutil.Discard)
+		assert.Error(t, cmd.Execute(), tc.expectedError)
+	}
+}
+
+func TestSecretCreateWithName(t *testing.T) {
+	name := "foo"
+	buf := new(bytes.Buffer)
+	var actual []byte
+	cli := test.NewFakeCli(&fakeClient{
+		secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
+			if spec.Name != name {
+				return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
+			}
+
+			actual = spec.Data
+
+			return types.SecretCreateResponse{
+				ID: "ID-" + spec.Name,
+			}, nil
+		},
+	}, buf)
+
+	cmd := newSecretCreateCommand(cli)
+	cmd.SetArgs([]string{name, filepath.Join("testdata", secretDataFile)})
+	assert.NilError(t, cmd.Execute())
+	expected := golden.Get(t, actual, secretDataFile)
+	assert.Equal(t, string(actual), string(expected))
+	assert.Equal(t, strings.TrimSpace(buf.String()), "ID-"+name)
+}
+
+func TestSecretCreateWithLabels(t *testing.T) {
+	expectedLabels := map[string]string{
+		"lbl1": "Label-foo",
+		"lbl2": "Label-bar",
+	}
+	name := "foo"
+
+	buf := new(bytes.Buffer)
+	cli := test.NewFakeCli(&fakeClient{
+		secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
+			if spec.Name != name {
+				return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
+			}
+
+			if !compareMap(spec.Labels, expectedLabels) {
+				return types.SecretCreateResponse{}, errors.Errorf("expected labels %v, got %v", expectedLabels, spec.Labels)
+			}
+
+			return types.SecretCreateResponse{
+				ID: "ID-" + spec.Name,
+			}, nil
+		},
+	}, buf)
+
+	cmd := newSecretCreateCommand(cli)
+	cmd.SetArgs([]string{name, filepath.Join("testdata", secretDataFile)})
+	cmd.Flags().Set("label", "lbl1=Label-foo")
+	cmd.Flags().Set("label", "lbl2=Label-bar")
+	assert.NilError(t, cmd.Execute())
+	assert.Equal(t, strings.TrimSpace(buf.String()), "ID-"+name)
+}
+
+func compareMap(actual map[string]string, expected map[string]string) bool {
+	if len(actual) != len(expected) {
+		return false
+	}
+	for key, value := range actual {
+		if expectedValue, ok := expected[key]; ok {
+			if expectedValue != value {
+				return false
+			}
+		} else {
+			return false
+		}
+	}
+	return true
+}

+ 2 - 2
cli/command/secret/inspect.go

@@ -13,7 +13,7 @@ type inspectOptions struct {
 	format string
 }
 
-func newSecretInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
+func newSecretInspectCommand(dockerCli command.Cli) *cobra.Command {
 	opts := inspectOptions{}
 	cmd := &cobra.Command{
 		Use:   "inspect [OPTIONS] SECRET [SECRET...]",
@@ -29,7 +29,7 @@ func newSecretInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
 	return cmd
 }
 
-func runSecretInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
+func runSecretInspect(dockerCli command.Cli, opts inspectOptions) error {
 	client := dockerCli.Client()
 	ctx := context.Background()
 

+ 149 - 0
cli/command/secret/inspect_test.go

@@ -0,0 +1,149 @@
+package secret
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"testing"
+
+	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/cli/internal/test"
+	"github.com/pkg/errors"
+	// Import builders to get the builder function as package function
+	. "github.com/docker/docker/cli/internal/test/builders"
+	"github.com/docker/docker/pkg/testutil/assert"
+	"github.com/docker/docker/pkg/testutil/golden"
+)
+
+func TestSecretInspectErrors(t *testing.T) {
+	testCases := []struct {
+		args              []string
+		flags             map[string]string
+		secretInspectFunc func(secretID string) (swarm.Secret, []byte, error)
+		expectedError     string
+	}{
+		{
+			expectedError: "requires at least 1 argument",
+		},
+		{
+			args: []string{"foo"},
+			secretInspectFunc: func(secretID string) (swarm.Secret, []byte, error) {
+				return swarm.Secret{}, nil, errors.Errorf("error while inspecting the secret")
+			},
+			expectedError: "error while inspecting the secret",
+		},
+		{
+			args: []string{"foo"},
+			flags: map[string]string{
+				"format": "{{invalid format}}",
+			},
+			expectedError: "Template parsing error",
+		},
+		{
+			args: []string{"foo", "bar"},
+			secretInspectFunc: func(secretID string) (swarm.Secret, []byte, error) {
+				if secretID == "foo" {
+					return *Secret(SecretName("foo")), nil, nil
+				}
+				return swarm.Secret{}, nil, errors.Errorf("error while inspecting the secret")
+			},
+			expectedError: "error while inspecting the secret",
+		},
+	}
+	for _, tc := range testCases {
+		buf := new(bytes.Buffer)
+		cmd := newSecretInspectCommand(
+			test.NewFakeCli(&fakeClient{
+				secretInspectFunc: tc.secretInspectFunc,
+			}, buf),
+		)
+		cmd.SetArgs(tc.args)
+		for key, value := range tc.flags {
+			cmd.Flags().Set(key, value)
+		}
+		cmd.SetOutput(ioutil.Discard)
+		assert.Error(t, cmd.Execute(), tc.expectedError)
+	}
+}
+
+func TestSecretInspectWithoutFormat(t *testing.T) {
+	testCases := []struct {
+		name              string
+		args              []string
+		secretInspectFunc func(secretID string) (swarm.Secret, []byte, error)
+	}{
+		{
+			name: "single-secret",
+			args: []string{"foo"},
+			secretInspectFunc: func(name string) (swarm.Secret, []byte, error) {
+				if name != "foo" {
+					return swarm.Secret{}, nil, errors.Errorf("Invalid name, expected %s, got %s", "foo", name)
+				}
+				return *Secret(SecretID("ID-foo"), SecretName("foo")), nil, nil
+			},
+		},
+		{
+			name: "multiple-secrets-with-labels",
+			args: []string{"foo", "bar"},
+			secretInspectFunc: func(name string) (swarm.Secret, []byte, error) {
+				return *Secret(SecretID("ID-"+name), SecretName(name), SecretLabels(map[string]string{
+					"label1": "label-foo",
+				})), nil, nil
+			},
+		},
+	}
+	for _, tc := range testCases {
+		buf := new(bytes.Buffer)
+		cmd := newSecretInspectCommand(
+			test.NewFakeCli(&fakeClient{
+				secretInspectFunc: tc.secretInspectFunc,
+			}, buf),
+		)
+		cmd.SetArgs(tc.args)
+		assert.NilError(t, cmd.Execute())
+		actual := buf.String()
+		expected := golden.Get(t, []byte(actual), fmt.Sprintf("secret-inspect-without-format.%s.golden", tc.name))
+		assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+	}
+}
+
+func TestSecretInspectWithFormat(t *testing.T) {
+	secretInspectFunc := func(name string) (swarm.Secret, []byte, error) {
+		return *Secret(SecretName("foo"), SecretLabels(map[string]string{
+			"label1": "label-foo",
+		})), nil, nil
+	}
+	testCases := []struct {
+		name              string
+		format            string
+		args              []string
+		secretInspectFunc func(name string) (swarm.Secret, []byte, error)
+	}{
+		{
+			name:              "simple-template",
+			format:            "{{.Spec.Name}}",
+			args:              []string{"foo"},
+			secretInspectFunc: secretInspectFunc,
+		},
+		{
+			name:              "json-template",
+			format:            "{{json .Spec.Labels}}",
+			args:              []string{"foo"},
+			secretInspectFunc: secretInspectFunc,
+		},
+	}
+	for _, tc := range testCases {
+		buf := new(bytes.Buffer)
+		cmd := newSecretInspectCommand(
+			test.NewFakeCli(&fakeClient{
+				secretInspectFunc: tc.secretInspectFunc,
+			}, buf),
+		)
+		cmd.SetArgs(tc.args)
+		cmd.Flags().Set("format", tc.format)
+		assert.NilError(t, cmd.Execute())
+		actual := buf.String()
+		expected := golden.Get(t, []byte(actual), fmt.Sprintf("secret-inspect-with-format.%s.golden", tc.name))
+		assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+	}
+}

+ 2 - 2
cli/command/secret/ls.go

@@ -16,7 +16,7 @@ type listOptions struct {
 	filter opts.FilterOpt
 }
 
-func newSecretListCommand(dockerCli *command.DockerCli) *cobra.Command {
+func newSecretListCommand(dockerCli command.Cli) *cobra.Command {
 	opts := listOptions{filter: opts.NewFilterOpt()}
 
 	cmd := &cobra.Command{
@@ -37,7 +37,7 @@ func newSecretListCommand(dockerCli *command.DockerCli) *cobra.Command {
 	return cmd
 }
 
-func runSecretList(dockerCli *command.DockerCli, opts listOptions) error {
+func runSecretList(dockerCli command.Cli, opts listOptions) error {
 	client := dockerCli.Client()
 	ctx := context.Background()
 

+ 172 - 0
cli/command/secret/ls_test.go

@@ -0,0 +1,172 @@
+package secret
+
+import (
+	"bytes"
+	"io/ioutil"
+	"testing"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/swarm"
+	"github.com/docker/docker/cli/config/configfile"
+	"github.com/docker/docker/cli/internal/test"
+	"github.com/pkg/errors"
+	// Import builders to get the builder function as package function
+	. "github.com/docker/docker/cli/internal/test/builders"
+	"github.com/docker/docker/pkg/testutil/assert"
+	"github.com/docker/docker/pkg/testutil/golden"
+)
+
+func TestSecretListErrors(t *testing.T) {
+	testCases := []struct {
+		args           []string
+		secretListFunc func(types.SecretListOptions) ([]swarm.Secret, error)
+		expectedError  string
+	}{
+		{
+			args:          []string{"foo"},
+			expectedError: "accepts no argument",
+		},
+		{
+			secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
+				return []swarm.Secret{}, errors.Errorf("error listing secrets")
+			},
+			expectedError: "error listing secrets",
+		},
+	}
+	for _, tc := range testCases {
+		buf := new(bytes.Buffer)
+		cmd := newSecretListCommand(
+			test.NewFakeCli(&fakeClient{
+				secretListFunc: tc.secretListFunc,
+			}, buf),
+		)
+		cmd.SetArgs(tc.args)
+		cmd.SetOutput(ioutil.Discard)
+		assert.Error(t, cmd.Execute(), tc.expectedError)
+	}
+}
+
+func TestSecretList(t *testing.T) {
+	buf := new(bytes.Buffer)
+	cli := test.NewFakeCli(&fakeClient{
+		secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
+			return []swarm.Secret{
+				*Secret(SecretID("ID-foo"),
+					SecretName("foo"),
+					SecretVersion(swarm.Version{Index: 10}),
+					SecretCreatedAt(time.Now().Add(-2*time.Hour)),
+					SecretUpdatedAt(time.Now().Add(-1*time.Hour)),
+				),
+				*Secret(SecretID("ID-bar"),
+					SecretName("bar"),
+					SecretVersion(swarm.Version{Index: 11}),
+					SecretCreatedAt(time.Now().Add(-2*time.Hour)),
+					SecretUpdatedAt(time.Now().Add(-1*time.Hour)),
+				),
+			}, nil
+		},
+	}, buf)
+	cli.SetConfigfile(&configfile.ConfigFile{})
+	cmd := newSecretListCommand(cli)
+	cmd.SetOutput(buf)
+	assert.NilError(t, cmd.Execute())
+	actual := buf.String()
+	expected := golden.Get(t, []byte(actual), "secret-list.golden")
+	assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+}
+
+func TestSecretListWithQuietOption(t *testing.T) {
+	buf := new(bytes.Buffer)
+	cli := test.NewFakeCli(&fakeClient{
+		secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
+			return []swarm.Secret{
+				*Secret(SecretID("ID-foo"), SecretName("foo")),
+				*Secret(SecretID("ID-bar"), SecretName("bar"), SecretLabels(map[string]string{
+					"label": "label-bar",
+				})),
+			}, nil
+		},
+	}, buf)
+	cli.SetConfigfile(&configfile.ConfigFile{})
+	cmd := newSecretListCommand(cli)
+	cmd.Flags().Set("quiet", "true")
+	assert.NilError(t, cmd.Execute())
+	actual := buf.String()
+	expected := golden.Get(t, []byte(actual), "secret-list-with-quiet-option.golden")
+	assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+}
+
+func TestSecretListWithConfigFormat(t *testing.T) {
+	buf := new(bytes.Buffer)
+	cli := test.NewFakeCli(&fakeClient{
+		secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
+			return []swarm.Secret{
+				*Secret(SecretID("ID-foo"), SecretName("foo")),
+				*Secret(SecretID("ID-bar"), SecretName("bar"), SecretLabels(map[string]string{
+					"label": "label-bar",
+				})),
+			}, nil
+		},
+	}, buf)
+	cli.SetConfigfile(&configfile.ConfigFile{
+		SecretFormat: "{{ .Name }} {{ .Labels }}",
+	})
+	cmd := newSecretListCommand(cli)
+	assert.NilError(t, cmd.Execute())
+	actual := buf.String()
+	expected := golden.Get(t, []byte(actual), "secret-list-with-config-format.golden")
+	assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+}
+
+func TestSecretListWithFormat(t *testing.T) {
+	buf := new(bytes.Buffer)
+	cli := test.NewFakeCli(&fakeClient{
+		secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
+			return []swarm.Secret{
+				*Secret(SecretID("ID-foo"), SecretName("foo")),
+				*Secret(SecretID("ID-bar"), SecretName("bar"), SecretLabels(map[string]string{
+					"label": "label-bar",
+				})),
+			}, nil
+		},
+	}, buf)
+	cmd := newSecretListCommand(cli)
+	cmd.Flags().Set("format", "{{ .Name }} {{ .Labels }}")
+	assert.NilError(t, cmd.Execute())
+	actual := buf.String()
+	expected := golden.Get(t, []byte(actual), "secret-list-with-format.golden")
+	assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+}
+
+func TestSecretListWithFilter(t *testing.T) {
+	buf := new(bytes.Buffer)
+	cli := test.NewFakeCli(&fakeClient{
+		secretListFunc: func(options types.SecretListOptions) ([]swarm.Secret, error) {
+			assert.Equal(t, options.Filters.Get("name")[0], "foo")
+			assert.Equal(t, options.Filters.Get("label")[0], "lbl1=Label-bar")
+			return []swarm.Secret{
+				*Secret(SecretID("ID-foo"),
+					SecretName("foo"),
+					SecretVersion(swarm.Version{Index: 10}),
+					SecretCreatedAt(time.Now().Add(-2*time.Hour)),
+					SecretUpdatedAt(time.Now().Add(-1*time.Hour)),
+				),
+				*Secret(SecretID("ID-bar"),
+					SecretName("bar"),
+					SecretVersion(swarm.Version{Index: 11}),
+					SecretCreatedAt(time.Now().Add(-2*time.Hour)),
+					SecretUpdatedAt(time.Now().Add(-1*time.Hour)),
+				),
+			}, nil
+		},
+	}, buf)
+	cli.SetConfigfile(&configfile.ConfigFile{})
+	cmd := newSecretListCommand(cli)
+	cmd.Flags().Set("filter", "name=foo")
+	cmd.Flags().Set("filter", "label=lbl1=Label-bar")
+	assert.NilError(t, cmd.Execute())
+	actual := buf.String()
+	expected := golden.Get(t, []byte(actual), "secret-list-with-filter.golden")
+	assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
+}

+ 2 - 2
cli/command/secret/remove.go

@@ -15,7 +15,7 @@ type removeOptions struct {
 	names []string
 }
 
-func newSecretRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
+func newSecretRemoveCommand(dockerCli command.Cli) *cobra.Command {
 	return &cobra.Command{
 		Use:     "rm SECRET [SECRET...]",
 		Aliases: []string{"remove"},
@@ -30,7 +30,7 @@ func newSecretRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
 	}
 }
 
-func runSecretRemove(dockerCli *command.DockerCli, opts removeOptions) error {
+func runSecretRemove(dockerCli command.Cli, opts removeOptions) error {
 	client := dockerCli.Client()
 	ctx := context.Background()
 

+ 81 - 0
cli/command/secret/remove_test.go

@@ -0,0 +1,81 @@
+package secret
+
+import (
+	"bytes"
+	"io/ioutil"
+	"strings"
+	"testing"
+
+	"github.com/docker/docker/cli/internal/test"
+	"github.com/docker/docker/pkg/testutil/assert"
+	"github.com/pkg/errors"
+)
+
+func TestSecretRemoveErrors(t *testing.T) {
+	testCases := []struct {
+		args             []string
+		secretRemoveFunc func(string) error
+		expectedError    string
+	}{
+		{
+			args:          []string{},
+			expectedError: "requires at least 1 argument(s).",
+		},
+		{
+			args: []string{"foo"},
+			secretRemoveFunc: func(name string) error {
+				return errors.Errorf("error removing secret")
+			},
+			expectedError: "error removing secret",
+		},
+	}
+	for _, tc := range testCases {
+		buf := new(bytes.Buffer)
+		cmd := newSecretRemoveCommand(
+			test.NewFakeCli(&fakeClient{
+				secretRemoveFunc: tc.secretRemoveFunc,
+			}, buf),
+		)
+		cmd.SetArgs(tc.args)
+		cmd.SetOutput(ioutil.Discard)
+		assert.Error(t, cmd.Execute(), tc.expectedError)
+	}
+}
+
+func TestSecretRemoveWithName(t *testing.T) {
+	names := []string{"foo", "bar"}
+	buf := new(bytes.Buffer)
+	var removedSecrets []string
+	cli := test.NewFakeCli(&fakeClient{
+		secretRemoveFunc: func(name string) error {
+			removedSecrets = append(removedSecrets, name)
+			return nil
+		},
+	}, buf)
+	cmd := newSecretRemoveCommand(cli)
+	cmd.SetArgs(names)
+	assert.NilError(t, cmd.Execute())
+	assert.EqualStringSlice(t, strings.Split(strings.TrimSpace(buf.String()), "\n"), names)
+	assert.EqualStringSlice(t, removedSecrets, names)
+}
+
+func TestSecretRemoveContinueAfterError(t *testing.T) {
+	names := []string{"foo", "bar"}
+	buf := new(bytes.Buffer)
+	var removedSecrets []string
+
+	cli := test.NewFakeCli(&fakeClient{
+		secretRemoveFunc: func(name string) error {
+			removedSecrets = append(removedSecrets, name)
+			if name == "foo" {
+				return errors.Errorf("error removing secret: %s", name)
+			}
+			return nil
+		},
+	}, buf)
+
+	cmd := newSecretRemoveCommand(cli)
+	cmd.SetArgs(names)
+	assert.Error(t, cmd.Execute(), "error removing secret: foo")
+	assert.EqualStringSlice(t, removedSecrets, names)
+}

+ 1 - 0
cli/command/secret/testdata/secret-create-with-name.golden

@@ -0,0 +1 @@
+secret_foo_bar

+ 1 - 0
cli/command/secret/testdata/secret-inspect-with-format.json-template.golden

@@ -0,0 +1 @@
+{"label1":"label-foo"}

+ 1 - 0
cli/command/secret/testdata/secret-inspect-with-format.simple-template.golden

@@ -0,0 +1 @@
+foo

+ 26 - 0
cli/command/secret/testdata/secret-inspect-without-format.multiple-secrets-with-labels.golden

@@ -0,0 +1,26 @@
+[
+    {
+        "ID": "ID-foo",
+	"Version": {},
+        "CreatedAt": "0001-01-01T00:00:00Z",
+        "UpdatedAt": "0001-01-01T00:00:00Z",
+        "Spec": {
+            "Name": "foo",
+            "Labels": {
+                "label1": "label-foo"
+            }
+        }
+    },
+    {
+        "ID": "ID-bar",
+	"Version": {},
+        "CreatedAt": "0001-01-01T00:00:00Z",
+        "UpdatedAt": "0001-01-01T00:00:00Z",
+        "Spec": {
+            "Name": "bar",
+            "Labels": {
+                "label1": "label-foo"
+            }
+        }
+    }
+]

+ 12 - 0
cli/command/secret/testdata/secret-inspect-without-format.single-secret.golden

@@ -0,0 +1,12 @@
+[
+    {
+        "ID": "ID-foo",
+	"Version": {},
+	"CreatedAt": "0001-01-01T00:00:00Z",
+	"UpdatedAt": "0001-01-01T00:00:00Z",
+        "Spec": {
+            "Name": "foo",
+            "Labels": null
+        }
+    }
+]

+ 2 - 0
cli/command/secret/testdata/secret-list-with-config-format.golden

@@ -0,0 +1,2 @@
+foo
+bar label=label-bar

+ 3 - 0
cli/command/secret/testdata/secret-list-with-filter.golden

@@ -0,0 +1,3 @@
+ID                  NAME                CREATED             UPDATED
+ID-foo              foo                 2 hours ago         About an hour ago
+ID-bar              bar                 2 hours ago         About an hour ago

+ 2 - 0
cli/command/secret/testdata/secret-list-with-format.golden

@@ -0,0 +1,2 @@
+foo
+bar label=label-bar

+ 2 - 0
cli/command/secret/testdata/secret-list-with-quiet-option.golden

@@ -0,0 +1,2 @@
+ID-foo
+ID-bar

+ 3 - 0
cli/command/secret/testdata/secret-list.golden

@@ -0,0 +1,3 @@
+ID                  NAME                CREATED             UPDATED
+ID-foo              foo                 2 hours ago         About an hour ago
+ID-bar              bar                 2 hours ago         About an hour ago

+ 61 - 0
cli/internal/test/builders/secret.go

@@ -0,0 +1,61 @@
+package builders
+
+import (
+	"time"
+
+	"github.com/docker/docker/api/types/swarm"
+)
+
+// Secret creates a secret with default values.
+// Any number of secret builder functions can be passed to augment it.
+func Secret(builders ...func(secret *swarm.Secret)) *swarm.Secret {
+	secret := &swarm.Secret{}
+
+	for _, builder := range builders {
+		builder(secret)
+	}
+
+	return secret
+}
+
+// SecretLabels sets the secret's labels
+func SecretLabels(labels map[string]string) func(secret *swarm.Secret) {
+	return func(secret *swarm.Secret) {
+		secret.Spec.Labels = labels
+	}
+}
+
+// SecretName sets the secret's name
+func SecretName(name string) func(secret *swarm.Secret) {
+	return func(secret *swarm.Secret) {
+		secret.Spec.Name = name
+	}
+}
+
+// SecretID sets the secret's ID
+func SecretID(ID string) func(secret *swarm.Secret) {
+	return func(secret *swarm.Secret) {
+		secret.ID = ID
+	}
+}
+
+// SecretVersion sets the version for the secret
+func SecretVersion(v swarm.Version) func(*swarm.Secret) {
+	return func(secret *swarm.Secret) {
+		secret.Version = v
+	}
+}
+
+// SecretCreatedAt sets the creation time for the secret
+func SecretCreatedAt(t time.Time) func(*swarm.Secret) {
+	return func(secret *swarm.Secret) {
+		secret.CreatedAt = t
+	}
+}
+
+// SecretUpdatedAt sets the update time for the secret
+func SecretUpdatedAt(t time.Time) func(*swarm.Secret) {
+	return func(secret *swarm.Secret) {
+		secret.UpdatedAt = t
+	}
+}