mirror of https://github.com/docker/cli.git
Add unit tests to cli/command/volume package
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
798ed3eb6c
commit
407d65df9d
|
@ -38,6 +38,7 @@ type Cli interface {
|
||||||
Out() *OutStream
|
Out() *OutStream
|
||||||
Err() io.Writer
|
Err() io.Writer
|
||||||
In() *InStream
|
In() *InStream
|
||||||
|
ConfigFile() *configfile.ConfigFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// DockerCli is an instance the docker command line client.
|
// DockerCli is an instance the docker command line client.
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
volumetypes "github.com/docker/docker/api/types/volume"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeClient struct {
|
||||||
|
client.Client
|
||||||
|
volumeCreateFunc func(volumetypes.VolumesCreateBody) (types.Volume, error)
|
||||||
|
volumeInspectFunc func(volumeID string) (types.Volume, error)
|
||||||
|
volumeListFunc func(filter filters.Args) (volumetypes.VolumesListOKBody, error)
|
||||||
|
volumeRemoveFunc func(volumeID string, force bool) error
|
||||||
|
volumePruneFunc func(filter filters.Args) (types.VolumesPruneReport, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) VolumeCreate(ctx context.Context, options volumetypes.VolumesCreateBody) (types.Volume, error) {
|
||||||
|
if c.volumeCreateFunc != nil {
|
||||||
|
return c.volumeCreateFunc(options)
|
||||||
|
}
|
||||||
|
return types.Volume{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error) {
|
||||||
|
if c.volumeInspectFunc != nil {
|
||||||
|
return c.volumeInspectFunc(volumeID)
|
||||||
|
}
|
||||||
|
return types.Volume{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
||||||
|
if c.volumeListFunc != nil {
|
||||||
|
return c.volumeListFunc(filter)
|
||||||
|
}
|
||||||
|
return volumetypes.VolumesListOKBody{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) VolumesPrune(ctx context.Context, filter filters.Args) (types.VolumesPruneReport, error) {
|
||||||
|
if c.volumePruneFunc != nil {
|
||||||
|
return c.volumePruneFunc(filter)
|
||||||
|
}
|
||||||
|
return types.VolumesPruneReport{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeClient) VolumeRemove(ctx context.Context, volumeID string, force bool) error {
|
||||||
|
if c.volumeRemoveFunc != nil {
|
||||||
|
return c.volumeRemoveFunc(volumeID, force)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,10 +1,9 @@
|
||||||
package volume
|
package volume
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewVolumeCommand returns a cobra command for `volume` subcommands
|
// NewVolumeCommand returns a cobra command for `volume` subcommands
|
||||||
|
|
|
@ -19,7 +19,7 @@ type createOptions struct {
|
||||||
labels opts.ListOpts
|
labels opts.ListOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
func newCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
opts := createOptions{
|
opts := createOptions{
|
||||||
driverOpts: *opts.NewMapOpts(nil, nil),
|
driverOpts: *opts.NewMapOpts(nil, nil),
|
||||||
labels: opts.NewListOpts(opts.ValidateEnv),
|
labels: opts.NewListOpts(opts.ValidateEnv),
|
||||||
|
@ -32,8 +32,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
if opts.name != "" {
|
if opts.name != "" {
|
||||||
fmt.Fprint(dockerCli.Err(), "Conflicting options: either specify --name or provide positional arg, not both\n")
|
return fmt.Errorf("Conflicting options: either specify --name or provide positional arg, not both\n")
|
||||||
return cli.StatusError{StatusCode: 1}
|
|
||||||
}
|
}
|
||||||
opts.name = args[0]
|
opts.name = args[0]
|
||||||
}
|
}
|
||||||
|
@ -50,7 +49,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCreate(dockerCli *command.DockerCli, opts createOptions) error {
|
func runCreate(dockerCli command.Cli, opts createOptions) error {
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
|
|
||||||
volReq := volumetypes.VolumesCreateBody{
|
volReq := volumetypes.VolumesCreateBody{
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
volumetypes "github.com/docker/docker/api/types/volume"
|
||||||
|
"github.com/docker/docker/cli/internal/test"
|
||||||
|
"github.com/docker/docker/pkg/testutil/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVolumeCreateErrors(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
flags map[string]string
|
||||||
|
volumeCreateFunc func(volumetypes.VolumesCreateBody) (types.Volume, error)
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: []string{"volumeName"},
|
||||||
|
flags: map[string]string{
|
||||||
|
"name": "volumeName",
|
||||||
|
},
|
||||||
|
expectedError: "Conflicting options: either specify --name or provide positional arg, not both",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"too", "many"},
|
||||||
|
expectedError: "requires at most 1 argument(s)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
volumeCreateFunc: func(createBody volumetypes.VolumesCreateBody) (types.Volume, error) {
|
||||||
|
return types.Volume{}, fmt.Errorf("error creating volume")
|
||||||
|
},
|
||||||
|
expectedError: "error creating volume",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newCreateCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumeCreateFunc: tc.volumeCreateFunc,
|
||||||
|
}, 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 TestVolumeCreateWithName(t *testing.T) {
|
||||||
|
name := "foo"
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumeCreateFunc: func(body volumetypes.VolumesCreateBody) (types.Volume, error) {
|
||||||
|
if body.Name != name {
|
||||||
|
return types.Volume{}, fmt.Errorf("expected name %q, got %q", name, body.Name)
|
||||||
|
}
|
||||||
|
return types.Volume{
|
||||||
|
Name: body.Name,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}, buf)
|
||||||
|
|
||||||
|
// Test by flags
|
||||||
|
cmd := newCreateCommand(cli)
|
||||||
|
cmd.Flags().Set("name", name)
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
assert.Equal(t, strings.TrimSpace(buf.String()), name)
|
||||||
|
|
||||||
|
// Then by args
|
||||||
|
buf.Reset()
|
||||||
|
cmd = newCreateCommand(cli)
|
||||||
|
cmd.SetArgs([]string{name})
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
assert.Equal(t, strings.TrimSpace(buf.String()), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVolumeCreateWithFlags(t *testing.T) {
|
||||||
|
expectedDriver := "foo"
|
||||||
|
expectedOpts := map[string]string{
|
||||||
|
"bar": "1",
|
||||||
|
"baz": "baz",
|
||||||
|
}
|
||||||
|
expectedLabels := map[string]string{
|
||||||
|
"lbl1": "v1",
|
||||||
|
"lbl2": "v2",
|
||||||
|
}
|
||||||
|
name := "banana"
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumeCreateFunc: func(body volumetypes.VolumesCreateBody) (types.Volume, error) {
|
||||||
|
if body.Name != "" {
|
||||||
|
return types.Volume{}, fmt.Errorf("expected empty name, got %q", body.Name)
|
||||||
|
}
|
||||||
|
if body.Driver != expectedDriver {
|
||||||
|
return types.Volume{}, fmt.Errorf("expected driver %q, got %q", expectedDriver, body.Driver)
|
||||||
|
}
|
||||||
|
if !compareMap(body.DriverOpts, expectedOpts) {
|
||||||
|
return types.Volume{}, fmt.Errorf("expected drivers opts %v, got %v", expectedOpts, body.DriverOpts)
|
||||||
|
}
|
||||||
|
if !compareMap(body.Labels, expectedLabels) {
|
||||||
|
return types.Volume{}, fmt.Errorf("expected labels %v, got %v", expectedLabels, body.Labels)
|
||||||
|
}
|
||||||
|
return types.Volume{
|
||||||
|
Name: name,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}, buf)
|
||||||
|
|
||||||
|
cmd := newCreateCommand(cli)
|
||||||
|
cmd.Flags().Set("driver", "foo")
|
||||||
|
cmd.Flags().Set("opt", "bar=1")
|
||||||
|
cmd.Flags().Set("opt", "baz=baz")
|
||||||
|
cmd.Flags().Set("label", "lbl1=v1")
|
||||||
|
cmd.Flags().Set("label", "lbl2=v2")
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
assert.Equal(t, strings.TrimSpace(buf.String()), 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
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
package volume
|
package volume
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/cli/command/inspect"
|
"github.com/docker/docker/cli/command/inspect"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type inspectOptions struct {
|
type inspectOptions struct {
|
||||||
|
@ -14,7 +13,7 @@ type inspectOptions struct {
|
||||||
names []string
|
names []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
func newInspectCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
var opts inspectOptions
|
var opts inspectOptions
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -32,7 +31,7 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
func runInspect(dockerCli command.Cli, opts inspectOptions) error {
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/cli/internal/test"
|
||||||
|
// 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 TestVolumeInspectErrors(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
flags map[string]string
|
||||||
|
volumeInspectFunc func(volumeID string) (types.Volume, error)
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
expectedError: "requires at least 1 argument",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo"},
|
||||||
|
volumeInspectFunc: func(volumeID string) (types.Volume, error) {
|
||||||
|
return types.Volume{}, fmt.Errorf("error while inspecting the volume")
|
||||||
|
},
|
||||||
|
expectedError: "error while inspecting the volume",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo"},
|
||||||
|
flags: map[string]string{
|
||||||
|
"format": "{{invalid format}}",
|
||||||
|
},
|
||||||
|
expectedError: "Template parsing error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"foo", "bar"},
|
||||||
|
volumeInspectFunc: func(volumeID string) (types.Volume, error) {
|
||||||
|
if volumeID == "foo" {
|
||||||
|
return types.Volume{
|
||||||
|
Name: "foo",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return types.Volume{}, fmt.Errorf("error while inspecting the volume")
|
||||||
|
},
|
||||||
|
expectedError: "error while inspecting the volume",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newInspectCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumeInspectFunc: tc.volumeInspectFunc,
|
||||||
|
}, 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 TestVolumeInspectWithoutFormat(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
volumeInspectFunc func(volumeID string) (types.Volume, error)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single-volume",
|
||||||
|
args: []string{"foo"},
|
||||||
|
volumeInspectFunc: func(volumeID string) (types.Volume, error) {
|
||||||
|
if volumeID != "foo" {
|
||||||
|
return types.Volume{}, fmt.Errorf("Invalid volumeID, expected %s, got %s", "foo", volumeID)
|
||||||
|
}
|
||||||
|
return *Volume(), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple-volume-with-labels",
|
||||||
|
args: []string{"foo", "bar"},
|
||||||
|
volumeInspectFunc: func(volumeID string) (types.Volume, error) {
|
||||||
|
return *Volume(VolumeName(volumeID), VolumeLabels(map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
})), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newInspectCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumeInspectFunc: tc.volumeInspectFunc,
|
||||||
|
}, buf),
|
||||||
|
)
|
||||||
|
cmd.SetArgs(tc.args)
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), fmt.Sprintf("volume-inspect-without-format.%s.golden", tc.name))
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVolumeInspectWithFormat(t *testing.T) {
|
||||||
|
volumeInspectFunc := func(volumeID string) (types.Volume, error) {
|
||||||
|
return *Volume(VolumeLabels(map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
})), nil
|
||||||
|
}
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
format string
|
||||||
|
args []string
|
||||||
|
volumeInspectFunc func(volumeID string) (types.Volume, error)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple-template",
|
||||||
|
format: "{{.Name}}",
|
||||||
|
args: []string{"foo"},
|
||||||
|
volumeInspectFunc: volumeInspectFunc,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "json-template",
|
||||||
|
format: "{{json .Labels}}",
|
||||||
|
args: []string{"foo"},
|
||||||
|
volumeInspectFunc: volumeInspectFunc,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newInspectCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumeInspectFunc: tc.volumeInspectFunc,
|
||||||
|
}, 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("volume-inspect-with-format.%s.golden", tc.name))
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,14 +3,13 @@ package volume
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/cli/command/formatter"
|
"github.com/docker/docker/cli/command/formatter"
|
||||||
"github.com/docker/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type byVolumeName []*types.Volume
|
type byVolumeName []*types.Volume
|
||||||
|
@ -27,7 +26,7 @@ type listOptions struct {
|
||||||
filter opts.FilterOpt
|
filter opts.FilterOpt
|
||||||
}
|
}
|
||||||
|
|
||||||
func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
func newListCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
opts := listOptions{filter: opts.NewFilterOpt()}
|
opts := listOptions{filter: opts.NewFilterOpt()}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -48,7 +47,7 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runList(dockerCli *command.DockerCli, opts listOptions) error {
|
func runList(dockerCli command.Cli, opts listOptions) error {
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
volumes, err := client.VolumeList(context.Background(), opts.filter.Value())
|
volumes, err := client.VolumeList(context.Background(), opts.filter.Value())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
volumetypes "github.com/docker/docker/api/types/volume"
|
||||||
|
"github.com/docker/docker/cli/config/configfile"
|
||||||
|
"github.com/docker/docker/cli/internal/test"
|
||||||
|
// 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 TestVolumeListErrors(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
flags map[string]string
|
||||||
|
volumeListFunc func(filter filters.Args) (volumetypes.VolumesListOKBody, error)
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: []string{"foo"},
|
||||||
|
expectedError: "accepts no argument",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
||||||
|
return volumetypes.VolumesListOKBody{}, fmt.Errorf("error listing volumes")
|
||||||
|
},
|
||||||
|
expectedError: "error listing volumes",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newListCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumeListFunc: tc.volumeListFunc,
|
||||||
|
}, 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 TestVolumeListWithoutFormat(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
||||||
|
return volumetypes.VolumesListOKBody{
|
||||||
|
Volumes: []*types.Volume{
|
||||||
|
Volume(),
|
||||||
|
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
||||||
|
Volume(VolumeName("baz"), VolumeLabels(map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}, buf)
|
||||||
|
cli.SetConfigfile(&configfile.ConfigFile{})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), "volume-list-without-format.golden")
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVolumeListWithConfigFormat(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
||||||
|
return volumetypes.VolumesListOKBody{
|
||||||
|
Volumes: []*types.Volume{
|
||||||
|
Volume(),
|
||||||
|
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
||||||
|
Volume(VolumeName("baz"), VolumeLabels(map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}, buf)
|
||||||
|
cli.SetConfigfile(&configfile.ConfigFile{
|
||||||
|
VolumesFormat: "{{ .Name }} {{ .Driver }} {{ .Labels }}",
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), "volume-list-with-config-format.golden")
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVolumeListWithFormat(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
||||||
|
return volumetypes.VolumesListOKBody{
|
||||||
|
Volumes: []*types.Volume{
|
||||||
|
Volume(),
|
||||||
|
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
||||||
|
Volume(VolumeName("baz"), VolumeLabels(map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}, buf)
|
||||||
|
cli.SetConfigfile(&configfile.ConfigFile{})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
cmd.Flags().Set("format", "{{ .Name }} {{ .Driver }} {{ .Labels }}")
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), "volume-list-with-format.golden")
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
|
@ -3,13 +3,12 @@ package volume
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pruneOptions struct {
|
type pruneOptions struct {
|
||||||
|
@ -17,7 +16,7 @@ type pruneOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPruneCommand returns a new cobra prune command for volumes
|
// NewPruneCommand returns a new cobra prune command for volumes
|
||||||
func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command {
|
func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
var opts pruneOptions
|
var opts pruneOptions
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -47,7 +46,7 @@ func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
const warning = `WARNING! This will remove all volumes not used by at least one container.
|
const warning = `WARNING! This will remove all volumes not used by at least one container.
|
||||||
Are you sure you want to continue?`
|
Are you sure you want to continue?`
|
||||||
|
|
||||||
func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
|
func runPrune(dockerCli command.Cli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
|
||||||
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
|
if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/cli/internal/test"
|
||||||
|
"github.com/docker/docker/pkg/testutil/assert"
|
||||||
|
"github.com/docker/docker/pkg/testutil/golden"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVolumePruneErrors(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
flags map[string]string
|
||||||
|
volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error)
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: []string{"foo"},
|
||||||
|
expectedError: "accepts no argument",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flags: map[string]string{
|
||||||
|
"force": "true",
|
||||||
|
},
|
||||||
|
volumePruneFunc: func(args filters.Args) (types.VolumesPruneReport, error) {
|
||||||
|
return types.VolumesPruneReport{}, fmt.Errorf("error pruning volumes")
|
||||||
|
},
|
||||||
|
expectedError: "error pruning volumes",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
cmd := NewPruneCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumePruneFunc: tc.volumePruneFunc,
|
||||||
|
}, ioutil.Discard),
|
||||||
|
)
|
||||||
|
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 TestVolumePruneForce(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deletedVolumes",
|
||||||
|
volumePruneFunc: simplePruneFunc,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := NewPruneCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumePruneFunc: tc.volumePruneFunc,
|
||||||
|
}, buf),
|
||||||
|
)
|
||||||
|
cmd.Flags().Set("force", "true")
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), fmt.Sprintf("volume-prune.%s.golden", tc.name))
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestVolumePrunePromptYes(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// FIXME(vdemeester) make it work..
|
||||||
|
t.Skip("skipping this test on Windows")
|
||||||
|
}
|
||||||
|
for _, input := range []string{"y", "Y"} {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumePruneFunc: simplePruneFunc,
|
||||||
|
}, buf)
|
||||||
|
|
||||||
|
cli.SetIn(ioutil.NopCloser(strings.NewReader(input)))
|
||||||
|
cmd := NewPruneCommand(
|
||||||
|
cli,
|
||||||
|
)
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), "volume-prune-yes.golden")
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVolumePrunePromptNo(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// FIXME(vdemeester) make it work..
|
||||||
|
t.Skip("skipping this test on Windows")
|
||||||
|
}
|
||||||
|
for _, input := range []string{"n", "N", "no", "anything", "really"} {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
volumePruneFunc: simplePruneFunc,
|
||||||
|
}, buf)
|
||||||
|
|
||||||
|
cli.SetIn(ioutil.NopCloser(strings.NewReader(input)))
|
||||||
|
cmd := NewPruneCommand(
|
||||||
|
cli,
|
||||||
|
)
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
actual := buf.String()
|
||||||
|
expected := golden.Get(t, []byte(actual), "volume-prune-no.golden")
|
||||||
|
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func simplePruneFunc(args filters.Args) (types.VolumesPruneReport, error) {
|
||||||
|
return types.VolumesPruneReport{
|
||||||
|
VolumesDeleted: []string{
|
||||||
|
"foo", "bar", "baz",
|
||||||
|
},
|
||||||
|
SpaceReclaimed: 2000,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -2,12 +2,12 @@ package volume
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type removeOptions struct {
|
type removeOptions struct {
|
||||||
|
@ -16,7 +16,7 @@ type removeOptions struct {
|
||||||
volumes []string
|
volumes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
|
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
var opts removeOptions
|
var opts removeOptions
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -38,22 +38,22 @@ func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRemove(dockerCli *command.DockerCli, opts *removeOptions) error {
|
func runRemove(dockerCli command.Cli, opts *removeOptions) error {
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
status := 0
|
|
||||||
|
var errs []string
|
||||||
|
|
||||||
for _, name := range opts.volumes {
|
for _, name := range opts.volumes {
|
||||||
if err := client.VolumeRemove(ctx, name, opts.force); err != nil {
|
if err := client.VolumeRemove(ctx, name, opts.force); err != nil {
|
||||||
fmt.Fprintf(dockerCli.Err(), "%s\n", err)
|
errs = append(errs, err.Error())
|
||||||
status = 1
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Fprintf(dockerCli.Out(), "%s\n", name)
|
fmt.Fprintf(dockerCli.Out(), "%s\n", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if status != 0 {
|
if len(errs) > 0 {
|
||||||
return cli.StatusError{StatusCode: status}
|
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package volume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/cli/internal/test"
|
||||||
|
"github.com/docker/docker/pkg/testutil/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVolumeRemoveErrors(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
volumeRemoveFunc func(volumeID string, force bool) error
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
expectedError: "requires at least 1 argument",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"nodeID"},
|
||||||
|
volumeRemoveFunc: func(volumeID string, force bool) error {
|
||||||
|
return fmt.Errorf("error removing the volume")
|
||||||
|
},
|
||||||
|
expectedError: "error removing the volume",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newRemoveCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
volumeRemoveFunc: tc.volumeRemoveFunc,
|
||||||
|
}, buf))
|
||||||
|
cmd.SetArgs(tc.args)
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.Error(t, cmd.Execute(), tc.expectedError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNodeRemoveMultiple(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}, buf))
|
||||||
|
cmd.SetArgs([]string{"volume1", "volume2"})
|
||||||
|
assert.NilError(t, cmd.Execute())
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
{"foo":"bar"}
|
|
@ -0,0 +1 @@
|
||||||
|
volume
|
22
command/volume/testdata/volume-inspect-without-format.multiple-volume-with-labels.golden
vendored
Normal file
22
command/volume/testdata/volume-inspect-without-format.multiple-volume-with-labels.golden
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Driver": "local",
|
||||||
|
"Labels": {
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"Mountpoint": "/data/volume",
|
||||||
|
"Name": "foo",
|
||||||
|
"Options": null,
|
||||||
|
"Scope": "local"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Driver": "local",
|
||||||
|
"Labels": {
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"Mountpoint": "/data/volume",
|
||||||
|
"Name": "bar",
|
||||||
|
"Options": null,
|
||||||
|
"Scope": "local"
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,10 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Driver": "local",
|
||||||
|
"Labels": null,
|
||||||
|
"Mountpoint": "/data/volume",
|
||||||
|
"Name": "volume",
|
||||||
|
"Options": null,
|
||||||
|
"Scope": "local"
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,3 @@
|
||||||
|
baz local foo=bar
|
||||||
|
foo bar
|
||||||
|
volume local
|
|
@ -0,0 +1,3 @@
|
||||||
|
baz local foo=bar
|
||||||
|
foo bar
|
||||||
|
volume local
|
|
@ -0,0 +1,4 @@
|
||||||
|
DRIVER VOLUME NAME
|
||||||
|
local baz
|
||||||
|
bar foo
|
||||||
|
local volume
|
|
@ -0,0 +1,2 @@
|
||||||
|
WARNING! This will remove all volumes not used by at least one container.
|
||||||
|
Are you sure you want to continue? [y/N] Total reclaimed space: 0B
|
|
@ -0,0 +1,7 @@
|
||||||
|
WARNING! This will remove all volumes not used by at least one container.
|
||||||
|
Are you sure you want to continue? [y/N] Deleted Volumes:
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
baz
|
||||||
|
|
||||||
|
Total reclaimed space: 2kB
|
|
@ -0,0 +1,6 @@
|
||||||
|
Deleted Volumes:
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
baz
|
||||||
|
|
||||||
|
Total reclaimed space: 2kB
|
|
@ -0,0 +1 @@
|
||||||
|
Total reclaimed space: 0B
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Package builders helps you create struct for your unit test while keeping them expressive.
|
||||||
|
//
|
||||||
|
package builders
|
|
@ -8,6 +8,9 @@ import (
|
||||||
|
|
||||||
// Node creates a node with default values.
|
// Node creates a node with default values.
|
||||||
// Any number of node function builder can be pass to augment it.
|
// Any number of node function builder can be pass to augment it.
|
||||||
|
//
|
||||||
|
// n1 := Node() // Returns a default node
|
||||||
|
// n2 := Node(NodeID("foo"), NodeHostname("bar"), Leader())
|
||||||
func Node(builders ...func(*swarm.Node)) *swarm.Node {
|
func Node(builders ...func(*swarm.Node)) *swarm.Node {
|
||||||
t1 := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
t1 := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||||
node := &swarm.Node{
|
node := &swarm.Node{
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Volume creates a volume with default values.
|
||||||
|
// Any number of volume function builder can be pass to augment it.
|
||||||
|
func Volume(builders ...func(volume *types.Volume)) *types.Volume {
|
||||||
|
volume := &types.Volume{
|
||||||
|
Name: "volume",
|
||||||
|
Driver: "local",
|
||||||
|
Mountpoint: "/data/volume",
|
||||||
|
Scope: "local",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, builder := range builders {
|
||||||
|
builder(volume)
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeLabels sets the volume labels
|
||||||
|
func VolumeLabels(labels map[string]string) func(volume *types.Volume) {
|
||||||
|
return func(volume *types.Volume) {
|
||||||
|
volume.Labels = labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeName sets the volume labels
|
||||||
|
func VolumeName(name string) func(volume *types.Volume) {
|
||||||
|
return func(volume *types.Volume) {
|
||||||
|
volume.Name = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeDriver sets the volume driver
|
||||||
|
func VolumeDriver(name string) func(volume *types.Volume) {
|
||||||
|
return func(volume *types.Volume) {
|
||||||
|
volume.Driver = name
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,23 @@
|
||||||
// Package test is a test-only package that can be used by other cli package to write unit test
|
|
||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
|
"github.com/docker/docker/cli/config/configfile"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FakeCli emulates the default DockerCli
|
// FakeCli emulates the default DockerCli
|
||||||
type FakeCli struct {
|
type FakeCli struct {
|
||||||
command.DockerCli
|
command.DockerCli
|
||||||
client client.APIClient
|
client client.APIClient
|
||||||
out io.Writer
|
configfile *configfile.ConfigFile
|
||||||
in io.ReadCloser
|
out io.Writer
|
||||||
|
err io.Writer
|
||||||
|
in io.ReadCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFakeCli returns a Cli backed by the fakeCli
|
// NewFakeCli returns a Cli backed by the fakeCli
|
||||||
|
@ -23,6 +25,7 @@ func NewFakeCli(client client.APIClient, out io.Writer) *FakeCli {
|
||||||
return &FakeCli{
|
return &FakeCli{
|
||||||
client: client,
|
client: client,
|
||||||
out: out,
|
out: out,
|
||||||
|
err: ioutil.Discard,
|
||||||
in: ioutil.NopCloser(strings.NewReader("")),
|
in: ioutil.NopCloser(strings.NewReader("")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,17 +35,37 @@ func (c *FakeCli) SetIn(in io.ReadCloser) {
|
||||||
c.in = in
|
c.in = in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetErr sets the standard error stream th cli should write on
|
||||||
|
func (c *FakeCli) SetErr(err io.Writer) {
|
||||||
|
c.err = err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConfigfile sets the "fake" config file
|
||||||
|
func (c *FakeCli) SetConfigfile(configfile *configfile.ConfigFile) {
|
||||||
|
c.configfile = configfile
|
||||||
|
}
|
||||||
|
|
||||||
// Client returns a docker API client
|
// Client returns a docker API client
|
||||||
func (c *FakeCli) Client() client.APIClient {
|
func (c *FakeCli) Client() client.APIClient {
|
||||||
return c.client
|
return c.client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Out returns the output stream the cli should write on
|
// Out returns the output stream (stdout) the cli should write on
|
||||||
func (c *FakeCli) Out() *command.OutStream {
|
func (c *FakeCli) Out() *command.OutStream {
|
||||||
return command.NewOutStream(c.out)
|
return command.NewOutStream(c.out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// In returns thi input stream the cli will use
|
// Err returns the output stream (stderr) the cli should write on
|
||||||
|
func (c *FakeCli) Err() io.Writer {
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// In returns the input stream the cli will use
|
||||||
func (c *FakeCli) In() *command.InStream {
|
func (c *FakeCli) In() *command.InStream {
|
||||||
return command.NewInStream(c.in)
|
return command.NewInStream(c.in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigFile returns the cli configfile object (to get client configuration)
|
||||||
|
func (c *FakeCli) ConfigFile() *configfile.ConfigFile {
|
||||||
|
return c.configfile
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
// Package test is a test-only package that can be used by other cli package to write unit test.
|
||||||
|
//
|
||||||
|
// It as an internal package and cannot be used outside of github.com/docker/docker/cli package.
|
||||||
|
//
|
||||||
|
package test
|
Loading…
Reference in New Issue