diff --git a/cli/command/service/client_test.go b/cli/command/service/client_test.go new file mode 100644 index 0000000000..b4f8905159 --- /dev/null +++ b/cli/command/service/client_test.go @@ -0,0 +1,35 @@ +package service + +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 + serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) +} + +func (f *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { + if f.serviceListFunc != nil { + return f.serviceListFunc(ctx, options) + } + return nil, nil +} + +func (f *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) { + return nil, nil +} + +func (f *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) { + return nil, nil +} + +func newService(id string, name string) swarm.Service { + return swarm.Service{ + ID: id, + Spec: swarm.ServiceSpec{Annotations: swarm.Annotations{Name: name}}, + } +} diff --git a/cli/command/service/list.go b/cli/command/service/list.go index 5b359d307a..63adce1ec1 100644 --- a/cli/command/service/list.go +++ b/cli/command/service/list.go @@ -2,6 +2,9 @@ package service import ( "fmt" + "sort" + + "vbom.ml/util/sortorder" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -20,7 +23,7 @@ type listOptions struct { filter opts.FilterOpt } -func newListCommand(dockerCli *command.DockerCli) *cobra.Command { +func newListCommand(dockerCli command.Cli) *cobra.Command { options := listOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ @@ -41,7 +44,13 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command { return cmd } -func runList(dockerCli *command.DockerCli, options listOptions) error { +type byName []swarm.Service + +func (n byName) Len() int { return len(n) } +func (n byName) Swap(i, j int) { n[i], n[j] = n[j], n[i] } +func (n byName) Less(i, j int) bool { return sortorder.NaturalLess(n[i].Spec.Name, n[j].Spec.Name) } + +func runList(dockerCli command.Cli, options listOptions) error { ctx := context.Background() client := dockerCli.Client() @@ -51,6 +60,7 @@ func runList(dockerCli *command.DockerCli, options listOptions) error { return err } + sort.Sort(byName(services)) info := map[string]formatter.ServiceListInfo{} if len(services) > 0 && !options.quiet { // only non-empty services and not quiet, should we call TaskList and NodeList api diff --git a/cli/command/service/list_test.go b/cli/command/service/list_test.go new file mode 100644 index 0000000000..85ccd1fb79 --- /dev/null +++ b/cli/command/service/list_test.go @@ -0,0 +1,32 @@ +package service + +import ( + "testing" + + "golang.org/x/net/context" + + "github.com/docker/cli/cli/internal/test" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/pkg/testutil" + "github.com/docker/docker/pkg/testutil/golden" + "github.com/stretchr/testify/assert" +) + +func TestServiceListOrder(t *testing.T) { + cli := test.NewFakeCli(&fakeClient{ + serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { + return []swarm.Service{ + newService("a57dbe8", "service-1-foo"), + newService("a57dbdd", "service-10-foo"), + newService("aaaaaaa", "service-2-foo"), + }, nil + }, + }) + cmd := newListCommand(cli) + cmd.Flags().Set("format", "{{.Name}}") + assert.NoError(t, cmd.Execute()) + actual := cli.OutBuffer().String() + expected := golden.Get(t, []byte(actual), "service-list-sort.golden") + testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected)) +} diff --git a/cli/command/service/ps_test.go b/cli/command/service/ps_test.go index 0e1bcb438b..dac79ab50a 100644 --- a/cli/command/service/ps_test.go +++ b/cli/command/service/ps_test.go @@ -10,35 +10,11 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/client" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/net/context" ) -type fakeClient struct { - client.Client - serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) -} - -func (f *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { - if f.serviceListFunc != nil { - return f.serviceListFunc(ctx, options) - } - return nil, nil -} - -func (f *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) { - return nil, nil -} - -func newService(id string, name string) swarm.Service { - return swarm.Service{ - ID: id, - Spec: swarm.ServiceSpec{Annotations: swarm.Annotations{Name: name}}, - } -} - func TestCreateFilter(t *testing.T) { client := &fakeClient{ serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) { diff --git a/cli/command/service/testdata/service-list-sort.golden b/cli/command/service/testdata/service-list-sort.golden new file mode 100644 index 0000000000..3b0cb2144d --- /dev/null +++ b/cli/command/service/testdata/service-list-sort.golden @@ -0,0 +1,3 @@ +service-1-foo +service-2-foo +service-10-foo