add unit tests to stack package

Signed-off-by: Arash Deshmeh <adeshmeh@ca.ibm.com>
This commit is contained in:
Arash Deshmeh 2017-06-20 14:00:01 -04:00
parent 5dd30732a2
commit 535af2d868
25 changed files with 703 additions and 18 deletions

View File

@ -103,11 +103,11 @@ func TestNodePs(t *testing.T) {
}, },
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) { taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{ return []swarm.Task{
*Task(TaskID("taskID1"), ServiceID("failure"), *Task(TaskID("taskID1"), TaskServiceID("failure"),
WithStatus(Timestamp(time.Now().Add(-2*time.Hour)), StatusErr("a task error"))), WithStatus(Timestamp(time.Now().Add(-2*time.Hour)), StatusErr("a task error"))),
*Task(TaskID("taskID2"), ServiceID("failure"), *Task(TaskID("taskID2"), TaskServiceID("failure"),
WithStatus(Timestamp(time.Now().Add(-3*time.Hour)), StatusErr("a task error"))), WithStatus(Timestamp(time.Now().Add(-3*time.Hour)), StatusErr("a task error"))),
*Task(TaskID("taskID3"), ServiceID("failure"), *Task(TaskID("taskID3"), TaskServiceID("failure"),
WithStatus(Timestamp(time.Now().Add(-4*time.Hour)), StatusErr("a task error"))), WithStatus(Timestamp(time.Now().Add(-4*time.Hour)), StatusErr("a task error"))),
}, nil }, nil
}, },

View File

@ -25,14 +25,17 @@ type fakeClient struct {
removedSecrets []string removedSecrets []string
removedConfigs []string removedConfigs []string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error) serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
networkListFunc func(options types.NetworkListOptions) ([]types.NetworkResource, error) networkListFunc func(options types.NetworkListOptions) ([]types.NetworkResource, error)
secretListFunc func(options types.SecretListOptions) ([]swarm.Secret, error) secretListFunc func(options types.SecretListOptions) ([]swarm.Secret, error)
configListFunc func(options types.ConfigListOptions) ([]swarm.Config, error) configListFunc func(options types.ConfigListOptions) ([]swarm.Config, error)
serviceRemoveFunc func(serviceID string) error nodeListFunc func(options types.NodeListOptions) ([]swarm.Node, error)
networkRemoveFunc func(networkID string) error taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
secretRemoveFunc func(secretID string) error nodeInspectWithRaw func(ref string) (swarm.Node, []byte, error)
configRemoveFunc func(configID string) error serviceRemoveFunc func(serviceID string) error
networkRemoveFunc func(networkID string) error
secretRemoveFunc func(secretID string) error
configRemoveFunc func(configID string) error
} }
func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) { func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) {
@ -102,6 +105,27 @@ func (cli *fakeClient) ConfigList(ctx context.Context, options types.ConfigListO
return configsList, nil return configsList, nil
} }
func (cli *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
if cli.taskListFunc != nil {
return cli.taskListFunc(options)
}
return []swarm.Task{}, nil
}
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
if cli.nodeListFunc != nil {
return cli.nodeListFunc(options)
}
return []swarm.Node{}, nil
}
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
if cli.nodeInspectWithRaw != nil {
return cli.nodeInspectWithRaw(ref)
}
return swarm.Node{}, nil, nil
}
func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error { func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error {
if cli.serviceRemoveFunc != nil { if cli.serviceRemoveFunc != nil {
return cli.serviceRemoveFunc(serviceID) return cli.serviceRemoveFunc(serviceID)

View File

@ -18,7 +18,7 @@ type listOptions struct {
format string format string
} }
func newListCommand(dockerCli *command.DockerCli) *cobra.Command { func newListCommand(dockerCli command.Cli) *cobra.Command {
opts := listOptions{} opts := listOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -36,7 +36,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()
ctx := context.Background() ctx := context.Background()

View File

@ -0,0 +1,122 @@
package stack
import (
"bytes"
"io/ioutil"
"testing"
"github.com/docker/cli/cli/internal/test"
// Import builders to get the builder function as package function
. "github.com/docker/cli/cli/internal/test/builders"
"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/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestListErrors(t *testing.T) {
testCases := []struct {
args []string
flags map[string]string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
expectedError string
}{
{
args: []string{"foo"},
expectedError: "accepts no argument",
},
{
flags: map[string]string{
"format": "{{invalid format}}",
},
expectedError: "Template parsing error",
},
{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{}, errors.Errorf("error getting services")
},
expectedError: "error getting services",
},
{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*Service()}, nil
},
expectedError: "cannot get label",
},
}
for _, tc := range testCases {
cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: tc.serviceListFunc,
}, &bytes.Buffer{}))
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
}
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
func TestListWithFormat(t *testing.T) {
buf := new(bytes.Buffer)
cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*Service(
ServiceLabels(map[string]string{
"com.docker.stack.namespace": "service-name-foo",
}),
)}, nil
},
}, buf))
cmd.Flags().Set("format", "{{ .Name }}")
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-list-with-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestListWithoutFormat(t *testing.T) {
buf := new(bytes.Buffer)
cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*Service(
ServiceLabels(map[string]string{
"com.docker.stack.namespace": "service-name-foo",
}),
)}, nil
},
}, buf))
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-list-without-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestListOrder(t *testing.T) {
buf := new(bytes.Buffer)
cmd := newListCommand(test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*Service(
ServiceLabels(map[string]string{
"com.docker.stack.namespace": "service-name-foo",
}),
),
*Service(
ServiceLabels(map[string]string{
"com.docker.stack.namespace": "service-name-bar",
}),
),
}, nil
},
}, buf))
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-list-sort.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}

View File

@ -0,0 +1,49 @@
package stack
import (
"bytes"
"fmt"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestLoadBundlefileErrors(t *testing.T) {
testCases := []struct {
namespace string
path string
expectedError error
}{
{
namespace: "namespace_foo",
expectedError: fmt.Errorf("Bundle %s.dab not found", "namespace_foo"),
},
{
namespace: "namespace_foo",
path: "invalid_path",
expectedError: fmt.Errorf("Bundle %s not found", "invalid_path"),
},
{
namespace: "namespace_foo",
path: filepath.Join("testdata", "bundlefile_with_invalid_syntax"),
expectedError: fmt.Errorf("Error reading"),
},
}
for _, tc := range testCases {
_, err := loadBundlefile(&bytes.Buffer{}, tc.namespace, tc.path)
assert.Error(t, err, tc.expectedError)
}
}
func TestLoadBundlefile(t *testing.T) {
buf := new(bytes.Buffer)
namespace := ""
path := filepath.Join("testdata", "bundlefile_with_two_services.dab")
bundleFile, err := loadBundlefile(buf, namespace, path)
assert.NoError(t, err)
assert.Equal(t, len(bundleFile.Services), 2)
}

View File

@ -0,0 +1,185 @@
package stack
import (
"bytes"
"io/ioutil"
"testing"
"time"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/internal/test"
// Import builders to get the builder function as package function
. "github.com/docker/cli/cli/internal/test/builders"
"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/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestStackPsErrors(t *testing.T) {
testCases := []struct {
args []string
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
expectedError string
}{
{
args: []string{},
expectedError: "requires exactly 1 argument",
},
{
args: []string{"foo", "bar"},
expectedError: "requires exactly 1 argument",
},
{
args: []string{"foo"},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return nil, errors.Errorf("error getting tasks")
},
expectedError: "error getting tasks",
},
}
for _, tc := range testCases {
cmd := newPsCommand(test.NewFakeCli(&fakeClient{
taskListFunc: tc.taskListFunc,
}, &bytes.Buffer{}))
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
func TestStackPsEmptyStack(t *testing.T) {
buf := new(bytes.Buffer)
cmd := newPsCommand(test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{}, nil
},
}, buf))
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
testutil.EqualNormalizedString(t, testutil.RemoveSpace, buf.String(), "Nothing found in stack: foo")
}
func TestStackPsWithQuietOption(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*Task(TaskID("id-foo"))}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newPsCommand(cli)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("quiet", "true")
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-ps-with-quiet-option.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackPsWithNoTruncOption(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*Task(TaskID("xn4cypcov06f2w8gsbaf2lst3"))}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newPsCommand(cli)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("no-trunc", "true")
cmd.Flags().Set("format", "{{ .ID }}")
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-ps-with-no-trunc-option.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackPsWithNoResolveOption(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*Task(
TaskNodeID("id-node-foo"),
)}, nil
},
nodeInspectWithRaw: func(ref string) (swarm.Node, []byte, error) {
return *Node(NodeName("node-name-bar")), nil, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newPsCommand(cli)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("no-resolve", "true")
cmd.Flags().Set("format", "{{ .Node }}")
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-ps-with-no-resolve-option.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackPsWithFormat(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*Task(TaskServiceID("service-id-foo"))}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newPsCommand(cli)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("format", "{{ .Name }}")
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-ps-with-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackPsWithConfigFormat(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*Task(TaskServiceID("service-id-foo"))}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{
TasksFormat: "{{ .Name }}",
})
cmd := newPsCommand(cli)
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-ps-with-config-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackPsWithoutFormat(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{*Task(
TaskID("id-foo"),
TaskServiceID("service-id-foo"),
TaskNodeID("id-node"),
WithTaskSpec(TaskImage("myimage:mytag")),
TaskDesiredState(swarm.TaskStateReady),
WithStatus(TaskState(swarm.TaskStateFailed), Timestamp(time.Now().Add(-2*time.Hour))),
)}, nil
},
nodeInspectWithRaw: func(ref string) (swarm.Node, []byte, error) {
return *Node(NodeName("node-name-bar")), nil, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newPsCommand(cli)
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-ps-without-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}

View File

@ -87,7 +87,7 @@ func TestSkipEmptyStack(t *testing.T) {
assert.Equal(t, allConfigIDs, cli.removedConfigs) assert.Equal(t, allConfigIDs, cli.removedConfigs)
} }
func TestContinueAfterError(t *testing.T) { func TestRemoveContinueAfterError(t *testing.T) {
allServices := []string{objectName("foo", "service1"), objectName("bar", "service1")} allServices := []string{objectName("foo", "service1"), objectName("bar", "service1")}
allServiceIDs := buildObjectIDs(allServices) allServiceIDs := buildObjectIDs(allServices)

View File

@ -21,7 +21,7 @@ type servicesOptions struct {
namespace string namespace string
} }
func newServicesCommand(dockerCli *command.DockerCli) *cobra.Command { func newServicesCommand(dockerCli command.Cli) *cobra.Command {
options := servicesOptions{filter: opts.NewFilterOpt()} options := servicesOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -41,7 +41,7 @@ func newServicesCommand(dockerCli *command.DockerCli) *cobra.Command {
return cmd return cmd
} }
func runServices(dockerCli *command.DockerCli, options servicesOptions) error { func runServices(dockerCli command.Cli, options servicesOptions) error {
ctx := context.Background() ctx := context.Background()
client := dockerCli.Client() client := dockerCli.Client()

View File

@ -0,0 +1,180 @@
package stack
import (
"bytes"
"io/ioutil"
"testing"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/internal/test"
// Import builders to get the builder function as package function
. "github.com/docker/cli/cli/internal/test/builders"
"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/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestStackServicesErrors(t *testing.T) {
testCases := []struct {
args []string
flags map[string]string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
nodeListFunc func(options types.NodeListOptions) ([]swarm.Node, error)
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
expectedError string
}{
{
args: []string{"foo"},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return nil, errors.Errorf("error getting services")
},
expectedError: "error getting services",
},
{
args: []string{"foo"},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*Service()}, nil
},
nodeListFunc: func(options types.NodeListOptions) ([]swarm.Node, error) {
return nil, errors.Errorf("error getting nodes")
},
expectedError: "error getting nodes",
},
{
args: []string{"foo"},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*Service()}, nil
},
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
return nil, errors.Errorf("error getting tasks")
},
expectedError: "error getting tasks",
},
{
args: []string{"foo"},
flags: map[string]string{
"format": "{{invalid format}}",
},
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*Service()}, nil
},
expectedError: "Template parsing error",
},
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: tc.serviceListFunc,
nodeListFunc: tc.nodeListFunc,
taskListFunc: tc.taskListFunc,
}, &bytes.Buffer{})
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newServicesCommand(cli)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
func TestStackServicesEmptyServiceList(t *testing.T) {
buf := new(bytes.Buffer)
cmd := newServicesCommand(
test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{}, nil
},
}, buf),
)
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
testutil.EqualNormalizedString(t, testutil.RemoveSpace, buf.String(), "Nothing found in stack: foo")
}
func TestStackServicesWithQuietOption(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*Service(ServiceID("id-foo"))}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newServicesCommand(cli)
cmd.Flags().Set("quiet", "true")
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-services-with-quiet-option.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackServicesWithFormat(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*Service(ServiceName("service-name-foo")),
}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newServicesCommand(cli)
cmd.SetArgs([]string{"foo"})
cmd.Flags().Set("format", "{{ .Name }}")
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-services-with-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackServicesWithConfigFormat(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{
*Service(ServiceName("service-name-foo")),
}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{
ServicesFormat: "{{ .Name }}",
})
cmd := newServicesCommand(cli)
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-services-with-config-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}
func TestStackServicesWithoutFormat(t *testing.T) {
buf := new(bytes.Buffer)
cli := test.NewFakeCli(&fakeClient{
serviceListFunc: func(options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{*Service(
ServiceName("name-foo"),
ServiceID("id-foo"),
ReplicatedService(2),
ServiceImage("busybox:latest"),
ServicePort(swarm.PortConfig{
PublishMode: swarm.PortConfigPublishModeIngress,
PublishedPort: 0,
TargetPort: 3232,
Protocol: swarm.PortConfigProtocolTCP,
}),
)}, nil
},
}, buf)
cli.SetConfigfile(&configfile.ConfigFile{})
cmd := newServicesCommand(cli)
cmd.SetArgs([]string{"foo"})
assert.NoError(t, cmd.Execute())
actual := buf.String()
expected := golden.Get(t, []byte(actual), "stack-services-without-format.golden")
testutil.EqualNormalizedString(t, testutil.RemoveSpace, actual, string(expected))
}

View File

@ -0,0 +1,29 @@
{
"Services": {
"visualizer": {
"Image": "busybox@sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f",
"Networks": [
"webnet"
],
"Ports": [
{
"Port": 8080,
"Protocol": "tcp"
}
]
},
"web": {
"Image": "busybox@sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f",
"Networks": [
"webnet"
],
"Ports": [
{
"Port": 80,
"Protocol": "tcp"
}
]
}
},
"Version": "0.1"
}

View File

@ -0,0 +1,3 @@
NAME SERVICES
service-name-bar 1
service-name-foo 1

View File

@ -0,0 +1 @@
service-name-foo

View File

@ -0,0 +1,2 @@
NAME SERVICES
service-name-foo 1

View File

@ -0,0 +1 @@
service-id-foo.1

View File

@ -0,0 +1 @@
service-id-foo.1

View File

@ -0,0 +1 @@
id-node-foo

View File

@ -0,0 +1 @@
xn4cypcov06f2w8gsbaf2lst3

View File

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

View File

@ -0,0 +1,2 @@
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
id-foo service-id-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago

View File

@ -0,0 +1 @@
service-name-foo

View File

@ -0,0 +1 @@
service-name-foo

View File

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

View File

@ -0,0 +1,2 @@
ID NAME MODE REPLICAS IMAGE PORTS
id-foo name-foo replicated 0/2 busybox:latest *:0->3232/tcp

View File

@ -14,6 +14,7 @@ func Service(builders ...func(*swarm.Service)) *swarm.Service {
Annotations: swarm.Annotations{ Annotations: swarm.Annotations{
Name: "defaultServiceName", Name: "defaultServiceName",
}, },
EndpointSpec: &swarm.EndpointSpec{},
}, },
} }
@ -24,9 +25,44 @@ func Service(builders ...func(*swarm.Service)) *swarm.Service {
return service return service
} }
// ServiceID sets the service ID
func ServiceID(ID string) func(*swarm.Service) {
return func(service *swarm.Service) {
service.ID = ID
}
}
// ServiceName sets the service name // ServiceName sets the service name
func ServiceName(name string) func(*swarm.Service) { func ServiceName(name string) func(*swarm.Service) {
return func(service *swarm.Service) { return func(service *swarm.Service) {
service.Spec.Annotations.Name = name service.Spec.Annotations.Name = name
} }
} }
// ServiceLabels sets the service's labels
func ServiceLabels(labels map[string]string) func(*swarm.Service) {
return func(service *swarm.Service) {
service.Spec.Annotations.Labels = labels
}
}
// ReplicatedService sets the number of replicas for the service
func ReplicatedService(replicas uint64) func(*swarm.Service) {
return func(service *swarm.Service) {
service.Spec.Mode = swarm.ServiceMode{Replicated: &swarm.ReplicatedService{Replicas: &replicas}}
}
}
// ServiceImage sets the service's image
func ServiceImage(image string) func(*swarm.Service) {
return func(service *swarm.Service) {
service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: swarm.ContainerSpec{Image: image}}
}
}
// ServicePort sets the service's port
func ServicePort(port swarm.PortConfig) func(*swarm.Service) {
return func(service *swarm.Service) {
service.Spec.EndpointSpec.Ports = append(service.Spec.EndpointSpec.Ports, port)
}
}

View File

@ -42,13 +42,34 @@ func TaskID(id string) func(*swarm.Task) {
} }
} }
// ServiceID sets the task service's ID // TaskName sets the task name
func ServiceID(id string) func(*swarm.Task) { func TaskName(name string) func(*swarm.Task) {
return func(task *swarm.Task) {
task.Annotations.Name = name
}
}
// TaskServiceID sets the task service's ID
func TaskServiceID(id string) func(*swarm.Task) {
return func(task *swarm.Task) { return func(task *swarm.Task) {
task.ServiceID = id task.ServiceID = id
} }
} }
// TaskNodeID sets the task's node id
func TaskNodeID(id string) func(*swarm.Task) {
return func(task *swarm.Task) {
task.NodeID = id
}
}
// TaskDesiredState sets the task's desired state
func TaskDesiredState(state swarm.TaskState) func(*swarm.Task) {
return func(task *swarm.Task) {
task.DesiredState = state
}
}
// WithStatus sets the task status // WithStatus sets the task status
func WithStatus(statusBuilders ...func(*swarm.TaskStatus)) func(*swarm.Task) { func WithStatus(statusBuilders ...func(*swarm.TaskStatus)) func(*swarm.Task) {
return func(task *swarm.Task) { return func(task *swarm.Task) {
@ -86,6 +107,13 @@ func StatusErr(err string) func(*swarm.TaskStatus) {
} }
} }
// TaskState sets the task's current state
func TaskState(state swarm.TaskState) func(*swarm.TaskStatus) {
return func(taskStatus *swarm.TaskStatus) {
taskStatus.State = state
}
}
// PortStatus sets the tasks port config status // PortStatus sets the tasks port config status
// FIXME(vdemeester) should be a sub builder 👼 // FIXME(vdemeester) should be a sub builder 👼
func PortStatus(portConfigs []swarm.PortConfig) func(*swarm.TaskStatus) { func PortStatus(portConfigs []swarm.PortConfig) func(*swarm.TaskStatus) {
@ -94,6 +122,13 @@ func PortStatus(portConfigs []swarm.PortConfig) func(*swarm.TaskStatus) {
} }
} }
// WithTaskSpec sets the task spec
func WithTaskSpec(specBuilders ...func(*swarm.TaskSpec)) func(*swarm.Task) {
return func(task *swarm.Task) {
task.Spec = *TaskSpec(specBuilders...)
}
}
// TaskSpec creates a task spec with default values . // TaskSpec creates a task spec with default values .
// Any number of taskSpec function builder can be pass to augment it. // Any number of taskSpec function builder can be pass to augment it.
func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec { func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec {
@ -109,3 +144,10 @@ func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec {
return taskSpec return taskSpec
} }
// TaskImage sets the task's image
func TaskImage(image string) func(*swarm.TaskSpec) {
return func(taskSpec *swarm.TaskSpec) {
taskSpec.ContainerSpec.Image = image
}
}