Add some unit tests to the node and swarm cli code
Start work on adding unit tests to our cli code in order to have to write less costly integration test. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package node
|
||||
|
||||
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
|
||||
infoFunc func() (types.Info, error)
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeListFunc func() ([]swarm.Node, error)
|
||||
nodeRemoveFunc func() error
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
|
||||
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeInspectWithRaw(ctx context.Context, ref string) (swarm.Node, []byte, error) {
|
||||
if cli.nodeInspectFunc != nil {
|
||||
return cli.nodeInspectFunc()
|
||||
}
|
||||
return swarm.Node{}, []byte{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error) {
|
||||
if cli.nodeListFunc != nil {
|
||||
return cli.nodeListFunc()
|
||||
}
|
||||
return []swarm.Node{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeRemove(ctx context.Context, nodeID string, options types.NodeRemoveOptions) error {
|
||||
if cli.nodeRemoveFunc != nil {
|
||||
return cli.nodeRemoveFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if cli.nodeUpdateFunc != nil {
|
||||
return cli.nodeUpdateFunc(nodeID, version, node)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) Info(ctx context.Context) (types.Info, error) {
|
||||
if cli.infoFunc != nil {
|
||||
return cli.infoFunc()
|
||||
}
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error) {
|
||||
if cli.taskInspectFunc != nil {
|
||||
return cli.taskInspectFunc(taskID)
|
||||
}
|
||||
return swarm.Task{}, []byte{}, 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
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newDemoteCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newDemoteCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "demote NODE [NODE...]",
|
||||
Short: "Demote one or more nodes from manager in the swarm",
|
||||
@@ -20,7 +20,7 @@ func newDemoteCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
func runDemote(dockerCli *command.DockerCli, nodes []string) error {
|
||||
func runDemote(dockerCli command.Cli, nodes []string) error {
|
||||
demote := func(node *swarm.Node) error {
|
||||
if node.Spec.Role == swarm.NodeRoleWorker {
|
||||
fmt.Fprintf(dockerCli.Out(), "Node %s is already a worker.\n", node.ID)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestNodeDemoteErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
expectedError: "requires at least 1 argument",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, fmt.Errorf("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
return fmt.Errorf("error updating the node")
|
||||
},
|
||||
expectedError: "error updating the node",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newDemoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
nodeUpdateFunc: tc.nodeUpdateFunc,
|
||||
}, buf))
|
||||
cmd.SetArgs(tc.args)
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
assert.Error(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeDemoteNoChange(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newDemoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleWorker {
|
||||
return fmt.Errorf("expected role worker, got %s", node.Role)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}, buf))
|
||||
cmd.SetArgs([]string{"nodeID"})
|
||||
assert.NilError(t, cmd.Execute())
|
||||
}
|
||||
|
||||
func TestNodeDemoteMultipleNode(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newDemoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(Manager()), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleWorker {
|
||||
return fmt.Errorf("expected role worker, got %s", node.Role)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}, buf))
|
||||
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
|
||||
assert.NilError(t, cmd.Execute())
|
||||
}
|
||||
@@ -22,7 +22,7 @@ type inspectOptions struct {
|
||||
pretty bool
|
||||
}
|
||||
|
||||
func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newInspectCommand(dockerCli command.Cli) *cobra.Command {
|
||||
var opts inspectOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -41,7 +41,7 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
||||
func runInspect(dockerCli command.Cli, opts inspectOptions) error {
|
||||
client := dockerCli.Client()
|
||||
ctx := context.Background()
|
||||
getRef := func(ref string) (interface{}, []byte, error) {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"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 TestNodeInspectErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
infoFunc func() (types.Info, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
expectedError: "requires at least 1 argument",
|
||||
},
|
||||
{
|
||||
args: []string{"self"},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, fmt.Errorf("error asking for node info")
|
||||
},
|
||||
expectedError: "error asking for node info",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, fmt.Errorf("error inspecting the node")
|
||||
},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, fmt.Errorf("error asking for node info")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"self"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, fmt.Errorf("error inspecting the node")
|
||||
},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, nil
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"self"},
|
||||
flags: map[string]string{
|
||||
"pretty": "true",
|
||||
},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, fmt.Errorf("error asking for node info")
|
||||
},
|
||||
expectedError: "error asking for node info",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newInspectCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
infoFunc: tc.infoFunc,
|
||||
}, 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 TestNodeInspectPretty(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(NodeLabels(map[string]string{
|
||||
"lbl1": "value1",
|
||||
})), []byte{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manager",
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(Manager()), []byte{}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manager-leader",
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(Manager(Leader())), []byte{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newInspectCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
}, buf))
|
||||
cmd.SetArgs([]string{"nodeID"})
|
||||
cmd.Flags().Set("pretty", "true")
|
||||
assert.NilError(t, cmd.Execute())
|
||||
actual := buf.String()
|
||||
expected := golden.Get(t, []byte(actual), fmt.Sprintf("node-inspect-pretty.%s.golden", tc.name))
|
||||
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ type listOptions struct {
|
||||
filter opts.FilterOpt
|
||||
}
|
||||
|
||||
func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newListCommand(dockerCli command.Cli) *cobra.Command {
|
||||
opts := listOptions{filter: opts.NewFilterOpt()}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -43,7 +43,7 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runList(dockerCli *command.DockerCli, opts listOptions) error {
|
||||
func runList(dockerCli command.Cli, opts listOptions) error {
|
||||
client := dockerCli.Client()
|
||||
out := dockerCli.Out()
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestNodeListErrorOnAPIFailure(t *testing.T) {
|
||||
testCases := []struct {
|
||||
nodeListFunc func() ([]swarm.Node, error)
|
||||
infoFunc func() (types.Info, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{}, fmt.Errorf("error listing nodes")
|
||||
},
|
||||
expectedError: "error listing nodes",
|
||||
},
|
||||
{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
{
|
||||
ID: "nodeID",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, fmt.Errorf("error asking for node info")
|
||||
},
|
||||
expectedError: "error asking for node info",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newListCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: tc.nodeListFunc,
|
||||
infoFunc: tc.infoFunc,
|
||||
}, buf))
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
assert.Error(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeList(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newListCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
*Node(NodeID("nodeID1"), Hostname("nodeHostname1"), Manager(Leader())),
|
||||
*Node(NodeID("nodeID2"), Hostname("nodeHostname2"), Manager()),
|
||||
*Node(NodeID("nodeID3"), Hostname("nodeHostname3")),
|
||||
}, nil
|
||||
},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{
|
||||
Swarm: swarm.Info{
|
||||
NodeID: "nodeID1",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
}, buf))
|
||||
assert.NilError(t, cmd.Execute())
|
||||
assert.Contains(t, buf.String(), `nodeID1 * nodeHostname1 Ready Active Leader`)
|
||||
assert.Contains(t, buf.String(), `nodeID2 nodeHostname2 Ready Active Reachable`)
|
||||
assert.Contains(t, buf.String(), `nodeID3 nodeHostname3 Ready Active`)
|
||||
}
|
||||
|
||||
func TestNodeListQuietShouldOnlyPrintIDs(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newListCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeListFunc: func() ([]swarm.Node, error) {
|
||||
return []swarm.Node{
|
||||
*Node(),
|
||||
}, nil
|
||||
},
|
||||
}, buf))
|
||||
cmd.Flags().Set("quiet", "true")
|
||||
assert.NilError(t, cmd.Execute())
|
||||
assert.Contains(t, buf.String(), "nodeID")
|
||||
}
|
||||
|
||||
// Test case for #24090
|
||||
func TestNodeListContainsHostname(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newListCommand(test.NewFakeCli(&fakeClient{}, buf))
|
||||
assert.NilError(t, cmd.Execute())
|
||||
assert.Contains(t, buf.String(), "HOSTNAME")
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/opts"
|
||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||
)
|
||||
|
||||
type nodeOptions struct {
|
||||
@@ -27,34 +22,3 @@ func newNodeOptions() *nodeOptions {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (opts *nodeOptions) ToNodeSpec() (swarm.NodeSpec, error) {
|
||||
var spec swarm.NodeSpec
|
||||
|
||||
spec.Annotations.Name = opts.annotations.name
|
||||
spec.Annotations.Labels = runconfigopts.ConvertKVStringsToMap(opts.annotations.labels.GetAll())
|
||||
|
||||
switch swarm.NodeRole(strings.ToLower(opts.role)) {
|
||||
case swarm.NodeRoleWorker:
|
||||
spec.Role = swarm.NodeRoleWorker
|
||||
case swarm.NodeRoleManager:
|
||||
spec.Role = swarm.NodeRoleManager
|
||||
case "":
|
||||
default:
|
||||
return swarm.NodeSpec{}, fmt.Errorf("invalid role %q, only worker and manager are supported", opts.role)
|
||||
}
|
||||
|
||||
switch swarm.NodeAvailability(strings.ToLower(opts.availability)) {
|
||||
case swarm.NodeAvailabilityActive:
|
||||
spec.Availability = swarm.NodeAvailabilityActive
|
||||
case swarm.NodeAvailabilityPause:
|
||||
spec.Availability = swarm.NodeAvailabilityPause
|
||||
case swarm.NodeAvailabilityDrain:
|
||||
spec.Availability = swarm.NodeAvailabilityDrain
|
||||
case "":
|
||||
default:
|
||||
return swarm.NodeSpec{}, fmt.Errorf("invalid availability %q, only active, pause and drain are supported", opts.availability)
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newPromoteCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newPromoteCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "promote NODE [NODE...]",
|
||||
Short: "Promote one or more nodes to manager in the swarm",
|
||||
@@ -20,7 +20,7 @@ func newPromoteCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
func runPromote(dockerCli *command.DockerCli, nodes []string) error {
|
||||
func runPromote(dockerCli command.Cli, nodes []string) error {
|
||||
promote := func(node *swarm.Node) error {
|
||||
if node.Spec.Role == swarm.NodeRoleManager {
|
||||
fmt.Fprintf(dockerCli.Out(), "Node %s is already a manager.\n", node.ID)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestNodePromoteErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
expectedError: "requires at least 1 argument",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, fmt.Errorf("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
return fmt.Errorf("error updating the node")
|
||||
},
|
||||
expectedError: "error updating the node",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newPromoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
nodeUpdateFunc: tc.nodeUpdateFunc,
|
||||
}, buf))
|
||||
cmd.SetArgs(tc.args)
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
assert.Error(t, cmd.Execute(), tc.expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodePromoteNoChange(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newPromoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(Manager()), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleManager {
|
||||
return fmt.Errorf("expected role manager, got %s", node.Role)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}, buf))
|
||||
cmd.SetArgs([]string{"nodeID"})
|
||||
assert.NilError(t, cmd.Execute())
|
||||
}
|
||||
|
||||
func TestNodePromoteMultipleNode(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newPromoteCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleManager {
|
||||
return fmt.Errorf("expected role manager, got %s", node.Role)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}, buf))
|
||||
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
|
||||
assert.NilError(t, cmd.Execute())
|
||||
}
|
||||
+2
-2
@@ -22,7 +22,7 @@ type psOptions struct {
|
||||
filter opts.FilterOpt
|
||||
}
|
||||
|
||||
func newPsCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newPsCommand(dockerCli command.Cli) *cobra.Command {
|
||||
opts := psOptions{filter: opts.NewFilterOpt()}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -47,7 +47,7 @@ func newPsCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPs(dockerCli *command.DockerCli, opts psOptions) error {
|
||||
func runPs(dockerCli command.Cli, opts psOptions) error {
|
||||
client := dockerCli.Client()
|
||||
ctx := context.Background()
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"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 TestNodePsErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
infoFunc func() (types.Info, error)
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
|
||||
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, fmt.Errorf("error asking for node info")
|
||||
},
|
||||
expectedError: "error asking for node info",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, fmt.Errorf("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
return []swarm.Task{}, fmt.Errorf("error returning the task list")
|
||||
},
|
||||
expectedError: "error returning the task list",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newPsCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
infoFunc: tc.infoFunc,
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
taskInspectFunc: tc.taskInspectFunc,
|
||||
taskListFunc: tc.taskListFunc,
|
||||
}, 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 TestNodePs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args []string
|
||||
flags map[string]string
|
||||
infoFunc func() (types.Info, error)
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
taskListFunc func(options types.TaskListOptions) ([]swarm.Task, error)
|
||||
taskInspectFunc func(taskID string) (swarm.Task, []byte, error)
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
return []swarm.Task{
|
||||
*Task(WithStatus(Timestamp(time.Now().Add(-2*time.Hour)), PortStatus([]swarm.PortConfig{
|
||||
{
|
||||
TargetPort: 80,
|
||||
PublishedPort: 80,
|
||||
Protocol: "tcp",
|
||||
},
|
||||
}))),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with-errors",
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
taskListFunc: func(options types.TaskListOptions) ([]swarm.Task, error) {
|
||||
return []swarm.Task{
|
||||
*Task(TaskID("taskID1"), ServiceID("failure"),
|
||||
WithStatus(Timestamp(time.Now().Add(-2*time.Hour)), StatusErr("a task error"))),
|
||||
*Task(TaskID("taskID2"), ServiceID("failure"),
|
||||
WithStatus(Timestamp(time.Now().Add(-3*time.Hour)), StatusErr("a task error"))),
|
||||
*Task(TaskID("taskID3"), ServiceID("failure"),
|
||||
WithStatus(Timestamp(time.Now().Add(-4*time.Hour)), StatusErr("a task error"))),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newPsCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
infoFunc: tc.infoFunc,
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
taskInspectFunc: tc.taskInspectFunc,
|
||||
taskListFunc: tc.taskListFunc,
|
||||
}, buf))
|
||||
cmd.SetArgs(tc.args)
|
||||
for key, value := range tc.flags {
|
||||
cmd.Flags().Set(key, value)
|
||||
}
|
||||
assert.NilError(t, cmd.Execute())
|
||||
actual := buf.String()
|
||||
expected := golden.Get(t, []byte(actual), fmt.Sprintf("node-ps.%s.golden", tc.name))
|
||||
assert.EqualNormalizedString(t, assert.RemoveSpace, actual, string(expected))
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type removeOptions struct {
|
||||
force bool
|
||||
}
|
||||
|
||||
func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
|
||||
opts := removeOptions{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -33,7 +33,7 @@ func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runRemove(dockerCli *command.DockerCli, args []string, opts removeOptions) error {
|
||||
func runRemove(dockerCli command.Cli, args []string, opts removeOptions) error {
|
||||
client := dockerCli.Client()
|
||||
ctx := context.Background()
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/cli/internal/test"
|
||||
"github.com/docker/docker/pkg/testutil/assert"
|
||||
)
|
||||
|
||||
func TestNodeRemoveErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
nodeRemoveFunc func() error
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
expectedError: "requires at least 1 argument",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeRemoveFunc: func() error {
|
||||
return fmt.Errorf("error removing the node")
|
||||
},
|
||||
expectedError: "error removing the node",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newRemoveCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeRemoveFunc: tc.nodeRemoveFunc,
|
||||
}, 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{"nodeID1", "nodeID2"})
|
||||
assert.NilError(t, cmd.Execute())
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
ID: nodeID
|
||||
Name: defaultNodeName
|
||||
Hostname: defaultNodeHostname
|
||||
Joined at: 2009-11-10 23:00:00 +0000 utc
|
||||
Status:
|
||||
State: Ready
|
||||
Availability: Active
|
||||
Address: 127.0.0.1
|
||||
Manager Status:
|
||||
Address: 127.0.0.1
|
||||
Raft Status: Reachable
|
||||
Leader: Yes
|
||||
Platform:
|
||||
Operating System: linux
|
||||
Architecture: x86_64
|
||||
Resources:
|
||||
CPUs: 0
|
||||
Memory: 20 MiB
|
||||
Plugins:
|
||||
Network: bridge, overlay
|
||||
Volume: local
|
||||
Engine Version: 1.13.0
|
||||
Engine Labels:
|
||||
- engine = label
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
ID: nodeID
|
||||
Name: defaultNodeName
|
||||
Hostname: defaultNodeHostname
|
||||
Joined at: 2009-11-10 23:00:00 +0000 utc
|
||||
Status:
|
||||
State: Ready
|
||||
Availability: Active
|
||||
Address: 127.0.0.1
|
||||
Manager Status:
|
||||
Address: 127.0.0.1
|
||||
Raft Status: Reachable
|
||||
Leader: No
|
||||
Platform:
|
||||
Operating System: linux
|
||||
Architecture: x86_64
|
||||
Resources:
|
||||
CPUs: 0
|
||||
Memory: 20 MiB
|
||||
Plugins:
|
||||
Network: bridge, overlay
|
||||
Volume: local
|
||||
Engine Version: 1.13.0
|
||||
Engine Labels:
|
||||
- engine = label
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
ID: nodeID
|
||||
Name: defaultNodeName
|
||||
Labels:
|
||||
- lbl1 = value1
|
||||
Hostname: defaultNodeHostname
|
||||
Joined at: 2009-11-10 23:00:00 +0000 utc
|
||||
Status:
|
||||
State: Ready
|
||||
Availability: Active
|
||||
Address: 127.0.0.1
|
||||
Platform:
|
||||
Operating System: linux
|
||||
Architecture: x86_64
|
||||
Resources:
|
||||
CPUs: 0
|
||||
Memory: 20 MiB
|
||||
Plugins:
|
||||
Network: bridge, overlay
|
||||
Volume: local
|
||||
Engine Version: 1.13.0
|
||||
Engine Labels:
|
||||
- engine = label
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
||||
taskID rl02d5gwz6chzu7il5fhtb8be.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago *:80->80/tcp
|
||||
@@ -0,0 +1,4 @@
|
||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
||||
taskID1 failure.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago "a task error"
|
||||
taskID2 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 3 hours ago "a task error"
|
||||
taskID3 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 4 hours ago "a task error"
|
||||
@@ -18,7 +18,7 @@ var (
|
||||
errNoRoleChange = errors.New("role was already set to the requested value")
|
||||
)
|
||||
|
||||
func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
|
||||
nodeOpts := newNodeOptions()
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -39,14 +39,14 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runUpdate(dockerCli *command.DockerCli, flags *pflag.FlagSet, nodeID string) error {
|
||||
func runUpdate(dockerCli command.Cli, flags *pflag.FlagSet, nodeID string) error {
|
||||
success := func(_ string) {
|
||||
fmt.Fprintln(dockerCli.Out(), nodeID)
|
||||
}
|
||||
return updateNodes(dockerCli, []string{nodeID}, mergeNodeUpdate(flags), success)
|
||||
}
|
||||
|
||||
func updateNodes(dockerCli *command.DockerCli, nodes []string, mergeNode func(node *swarm.Node) error, success func(nodeID string)) error {
|
||||
func updateNodes(dockerCli command.Cli, nodes []string, mergeNode func(node *swarm.Node) error, success func(nodeID string)) error {
|
||||
client := dockerCli.Client()
|
||||
ctx := context.Background()
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestNodeUpdateErrors(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
expectedError: "requires exactly 1 argument",
|
||||
},
|
||||
{
|
||||
args: []string{"node1", "node2"},
|
||||
expectedError: "requires exactly 1 argument",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return swarm.Node{}, []byte{}, fmt.Errorf("error inspecting the node")
|
||||
},
|
||||
expectedError: "error inspecting the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
return fmt.Errorf("error updating the node")
|
||||
},
|
||||
expectedError: "error updating the node",
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(NodeLabels(map[string]string{
|
||||
"key": "value",
|
||||
})), []byte{}, nil
|
||||
},
|
||||
flags: map[string]string{
|
||||
"label-rm": "notpresent",
|
||||
},
|
||||
expectedError: "key notpresent doesn't exist in node's labels",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newUpdateCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
nodeUpdateFunc: tc.nodeUpdateFunc,
|
||||
}, 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 TestNodeUpdate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
flags map[string]string
|
||||
nodeInspectFunc func() (swarm.Node, []byte, error)
|
||||
nodeUpdateFunc func(nodeID string, version swarm.Version, node swarm.NodeSpec) error
|
||||
}{
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
flags: map[string]string{
|
||||
"role": "manager",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Role != swarm.NodeRoleManager {
|
||||
return fmt.Errorf("expected role manager, got %s", node.Role)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
flags: map[string]string{
|
||||
"availability": "drain",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if node.Availability != swarm.NodeAvailabilityDrain {
|
||||
return fmt.Errorf("expected drain availability, got %s", node.Availability)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
flags: map[string]string{
|
||||
"label-add": "lbl",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if _, present := node.Annotations.Labels["lbl"]; !present {
|
||||
return fmt.Errorf("expected 'lbl' label, got %v", node.Annotations.Labels)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
flags: map[string]string{
|
||||
"label-add": "key=value",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if value, present := node.Annotations.Labels["key"]; !present || value != "value" {
|
||||
return fmt.Errorf("expected 'key' label to be 'value', got %v", node.Annotations.Labels)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"nodeID"},
|
||||
flags: map[string]string{
|
||||
"label-rm": "key",
|
||||
},
|
||||
nodeInspectFunc: func() (swarm.Node, []byte, error) {
|
||||
return *Node(NodeLabels(map[string]string{
|
||||
"key": "value",
|
||||
})), []byte{}, nil
|
||||
},
|
||||
nodeUpdateFunc: func(nodeID string, version swarm.Version, node swarm.NodeSpec) error {
|
||||
if len(node.Annotations.Labels) > 0 {
|
||||
return fmt.Errorf("expected no labels, got %v", node.Annotations.Labels)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cmd := newUpdateCommand(
|
||||
test.NewFakeCli(&fakeClient{
|
||||
nodeInspectFunc: tc.nodeInspectFunc,
|
||||
nodeUpdateFunc: tc.nodeUpdateFunc,
|
||||
}, buf))
|
||||
cmd.SetArgs(tc.args)
|
||||
for key, value := range tc.flags {
|
||||
cmd.Flags().Set(key, value)
|
||||
}
|
||||
assert.NilError(t, cmd.Execute())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user