diff --git a/cli/command/system/client_test.go b/cli/command/system/client_test.go index b6eeb3bd9294..55a6a6d474fe 100644 --- a/cli/command/system/client_test.go +++ b/cli/command/system/client_test.go @@ -3,6 +3,13 @@ package system import ( "context" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/volume" + + "github.com/docker/docker/api/types/image" + + "github.com/docker/docker/api/types/system" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/events" @@ -19,6 +26,12 @@ type fakeClient struct { eventsFn func(context.Context, events.ListOptions) (<-chan events.Message, <-chan error) containerPruneFunc func(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) networkPruneFunc func(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) + containerListFunc func(context.Context, container.ListOptions) ([]container.Summary, error) + infoFunc func(ctx context.Context) (system.Info, error) + networkListFunc func(ctx context.Context, options network.ListOptions) ([]network.Summary, error) + imageListFunc func(ctx context.Context, options image.ListOptions) ([]image.Summary, error) + nodeListFunc func(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) + volumeListFunc func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) } func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) { @@ -46,3 +59,45 @@ func (cli *fakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Ar } return network.PruneReport{}, nil } + +func (cli *fakeClient) ContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error) { + if cli.containerListFunc != nil { + return cli.containerListFunc(ctx, options) + } + return []container.Summary{}, nil +} + +func (cli *fakeClient) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) { + if cli.imageListFunc != nil { + return cli.imageListFunc(ctx, options) + } + return []image.Summary{}, nil +} + +func (cli *fakeClient) Info(ctx context.Context) (system.Info, error) { + if cli.infoFunc != nil { + return cli.infoFunc(ctx) + } + return system.Info{}, nil +} + +func (cli *fakeClient) NetworkList(ctx context.Context, options network.ListOptions) ([]network.Summary, error) { + if cli.networkListFunc != nil { + return cli.networkListFunc(ctx, options) + } + return []network.Summary{}, nil +} + +func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { + if cli.nodeListFunc != nil { + return cli.nodeListFunc(ctx, options) + } + return []swarm.Node{}, nil +} + +func (cli *fakeClient) VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) { + if cli.volumeListFunc != nil { + return cli.volumeListFunc(ctx, options) + } + return volume.ListResponse{}, nil +} diff --git a/cli/command/system/completion_test.go b/cli/command/system/completion_test.go new file mode 100644 index 000000000000..0e4aa8d5ce8e --- /dev/null +++ b/cli/command/system/completion_test.go @@ -0,0 +1,165 @@ +package system + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/docker/cli/internal/test" + "github.com/docker/cli/internal/test/builders" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/system" + "github.com/docker/docker/api/types/volume" + "github.com/spf13/cobra" + "gotest.tools/v3/assert" +) + +func TestCompleteEventFilter(t *testing.T) { + tests := []struct { + client *fakeClient + toComplete string + expected []string + }{ + { + client: &fakeClient{ + containerListFunc: func(_ context.Context, _ container.ListOptions) ([]container.Summary, error) { + return []container.Summary{ + *builders.Container("c1"), + *builders.Container("c2"), + }, nil + }, + }, + toComplete: "container=", + expected: []string{"container=c1", "container=c2"}, + }, + { + client: &fakeClient{ + containerListFunc: func(_ context.Context, _ container.ListOptions) ([]container.Summary, error) { + return nil, errors.New("API error") + }, + }, + toComplete: "container=", + expected: []string{}, + }, + { + client: &fakeClient{ + infoFunc: func(ctx context.Context) (system.Info, error) { + return system.Info{ + ID: "daemon-id", + Name: "daemon-name", + }, nil + }, + }, + toComplete: "daemon=", + expected: []string{"daemon=daemon-name", "daemon=daemon-id"}, + }, + { + client: &fakeClient{ + infoFunc: func(ctx context.Context) (system.Info, error) { + return system.Info{}, errors.New("API error") + }, + }, + toComplete: "daemon=", + expected: []string{}, + }, + { + client: &fakeClient{ + imageListFunc: func(_ context.Context, _ image.ListOptions) ([]image.Summary, error) { + return []image.Summary{ + {RepoTags: []string{"img:1"}}, + {RepoTags: []string{"img:2"}}, + }, nil + }, + }, + toComplete: "image=", + expected: []string{"image=img:1", "image=img:2"}, + }, + { + client: &fakeClient{ + imageListFunc: func(_ context.Context, _ image.ListOptions) ([]image.Summary, error) { + return []image.Summary{}, errors.New("API error") + }, + }, + toComplete: "image=", + expected: []string{}, + }, + { + client: &fakeClient{ + networkListFunc: func(_ context.Context, _ network.ListOptions) ([]network.Summary, error) { + return []network.Summary{ + *builders.NetworkResource(builders.NetworkResourceName("nw1")), + *builders.NetworkResource(builders.NetworkResourceName("nw2")), + }, nil + }, + }, + toComplete: "network=", + expected: []string{"network=nw1", "network=nw2"}, + }, + { + client: &fakeClient{ + networkListFunc: func(_ context.Context, _ network.ListOptions) ([]network.Summary, error) { + return nil, errors.New("API error") + }, + }, + toComplete: "network=", + expected: []string{}, + }, + { + client: &fakeClient{ + nodeListFunc: func(_ context.Context, _ types.NodeListOptions) ([]swarm.Node, error) { + return []swarm.Node{ + *builders.Node(builders.Hostname("n1")), + }, nil + }, + }, + toComplete: "node=", + expected: []string{"node=n1"}, + }, + { + client: &fakeClient{ + nodeListFunc: func(_ context.Context, _ types.NodeListOptions) ([]swarm.Node, error) { + return []swarm.Node{}, errors.New("API error") + }, + }, + toComplete: "node=", + expected: []string{}, + }, + { + client: &fakeClient{ + volumeListFunc: func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) { + return volume.ListResponse{ + Volumes: []*volume.Volume{ + builders.Volume(builders.VolumeName("v1")), + builders.Volume(builders.VolumeName("v2")), + }, + }, nil + }, + }, + toComplete: "volume=", + expected: []string{"volume=v1", "volume=v2"}, + }, + { + client: &fakeClient{ + volumeListFunc: func(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) { + return volume.ListResponse{}, errors.New("API error") + }, + }, + toComplete: "volume=", + expected: []string{}, + }, + } + + for _, tc := range tests { + cli := test.NewFakeCli(tc.client) + + completions, directive := completeFilters(cli)(NewEventsCommand(cli), nil, tc.toComplete) + + assert.DeepEqual(t, completions, tc.expected) + assert.Equal(t, directive, cobra.ShellCompDirectiveNoFileComp, fmt.Sprintf("wrong directive in completion for '%s'", tc.toComplete)) + } +}