mirror of https://github.com/docker/cli.git
Add unit tests to docker container ls
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
3e5f2f29ad
commit
581b8d9d72
|
@ -22,9 +22,17 @@ type fakeClient struct {
|
||||||
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
||||||
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
|
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
|
||||||
waitFunc func(string) (<-chan container.ContainerWaitOKBody, <-chan error)
|
waitFunc func(string) (<-chan container.ContainerWaitOKBody, <-chan error)
|
||||||
|
containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
|
||||||
Version string
|
Version string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fakeClient) ContainerList(_ context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
if f.containerListFunc != nil {
|
||||||
|
return f.containerListFunc(options)
|
||||||
|
}
|
||||||
|
return []types.Container{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (types.ContainerJSON, error) {
|
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (types.ContainerJSON, error) {
|
||||||
if f.inspectFunc != nil {
|
if f.inspectFunc != nil {
|
||||||
return f.inspectFunc(containerID)
|
return f.inspectFunc(containerID)
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
|
"github.com/docker/cli/internal/test"
|
||||||
|
"github.com/docker/cli/internal/test/testutil"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
// Import builders to get the builder function as package function
|
||||||
|
. "github.com/docker/cli/internal/test/builders"
|
||||||
|
"github.com/gotestyourself/gotestyourself/golden"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContainerListErrors(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
flags map[string]string
|
||||||
|
containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
flags: map[string]string{
|
||||||
|
"format": "{{invalid}}",
|
||||||
|
},
|
||||||
|
expectedError: `function "invalid" not defined`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flags: map[string]string{
|
||||||
|
"format": "{{join}}",
|
||||||
|
},
|
||||||
|
expectedError: `wrong number of args for join`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return nil, fmt.Errorf("error listing containers")
|
||||||
|
},
|
||||||
|
expectedError: "error listing containers",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
cmd := newListCommand(
|
||||||
|
test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: tc.containerListFunc,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
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 TestContainerListWithoutFormat(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return []types.Container{
|
||||||
|
*Container("c1"),
|
||||||
|
*Container("c2", WithName("foo")),
|
||||||
|
*Container("c3", WithPort(80, 80, TCP), WithPort(81, 81, TCP), WithPort(82, 82, TCP)),
|
||||||
|
*Container("c4", WithPort(81, 81, UDP)),
|
||||||
|
*Container("c5", WithPort(82, 82, IP("8.8.8.8"), TCP)),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "container-list-without-format.golden")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerListNoTrunc(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return []types.Container{
|
||||||
|
*Container("c1"),
|
||||||
|
*Container("c2", WithName("foo/bar")),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
cmd.Flags().Set("no-trunc", "true")
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "container-list-without-format-no-trunc.golden")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for GitHub issue docker/docker#21772
|
||||||
|
func TestContainerListNamesMultipleTime(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return []types.Container{
|
||||||
|
*Container("c1"),
|
||||||
|
*Container("c2", WithName("foo/bar")),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
cmd.Flags().Set("format", "{{.Names}} {{.Names}}")
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "container-list-format-name-name.golden")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for GitHub issue docker/docker#30291
|
||||||
|
func TestContainerListFormatTemplateWithArg(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return []types.Container{
|
||||||
|
*Container("c1", WithLabel("some.label", "value")),
|
||||||
|
*Container("c2", WithName("foo/bar"), WithLabel("foo", "bar")),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
cmd.Flags().Set("format", `{{.Names}} {{.Label "some.label"}}`)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "container-list-format-with-arg.golden")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerListFormatSizeSetsOption(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(options types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
assert.True(t, options.Size)
|
||||||
|
return []types.Container{}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
cmd.Flags().Set("format", `{{.Size}}`)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerListWithConfigFormat(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return []types.Container{
|
||||||
|
*Container("c1", WithLabel("some.label", "value")),
|
||||||
|
*Container("c2", WithName("foo/bar"), WithLabel("foo", "bar")),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cli.SetConfigFile(&configfile.ConfigFile{
|
||||||
|
PsFormat: "{{ .Names }} {{ .Image }} {{ .Labels }}",
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "container-list-with-config-format.golden")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerListWithFormat(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: func(_ types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
return []types.Container{
|
||||||
|
*Container("c1", WithLabel("some.label", "value")),
|
||||||
|
*Container("c2", WithName("foo/bar"), WithLabel("foo", "bar")),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
cmd := newListCommand(cli)
|
||||||
|
cmd.Flags().Set("format", "{{ .Names }} {{ .Image }} {{ .Labels }}")
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
golden.Assert(t, cli.OutBuffer().String(), "container-list-with-format.golden")
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
c1 c1
|
||||||
|
c2 c2
|
|
@ -0,0 +1,2 @@
|
||||||
|
c1 value
|
||||||
|
c2
|
|
@ -0,0 +1,2 @@
|
||||||
|
c1 busybox:latest some.label=value
|
||||||
|
c2 busybox:latest foo=bar
|
|
@ -0,0 +1,2 @@
|
||||||
|
c1 busybox:latest some.label=value
|
||||||
|
c2 busybox:latest foo=bar
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second c1
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second c2,foo/bar
|
|
@ -0,0 +1,6 @@
|
||||||
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second c1
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second c2
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second 80-82/tcp c3
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second 81/udp c4
|
||||||
|
container_id busybox:latest "top" Less than a second ago Up 1 second 8.8.8.8:82->82/tcp c5
|
|
@ -0,0 +1,79 @@
|
||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Container creates a container with default values.
|
||||||
|
// Any number of container function builder can be passed to augment it.
|
||||||
|
func Container(name string, builders ...func(container *types.Container)) *types.Container {
|
||||||
|
// now := time.Now()
|
||||||
|
// onehourago := now.Add(-120 * time.Minute)
|
||||||
|
container := &types.Container{
|
||||||
|
ID: "container_id",
|
||||||
|
Names: []string{"/" + name},
|
||||||
|
Command: "top",
|
||||||
|
Image: "busybox:latest",
|
||||||
|
Status: "Up 1 second",
|
||||||
|
Created: time.Now().UnixNano(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, builder := range builders {
|
||||||
|
builder(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLabel adds a label to the container
|
||||||
|
func WithLabel(key, value string) func(*types.Container) {
|
||||||
|
return func(c *types.Container) {
|
||||||
|
if c.Labels == nil {
|
||||||
|
c.Labels = map[string]string{}
|
||||||
|
}
|
||||||
|
c.Labels[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithName adds a name to the container
|
||||||
|
func WithName(name string) func(*types.Container) {
|
||||||
|
return func(c *types.Container) {
|
||||||
|
c.Names = append(c.Names, "/"+name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPort adds a port mapping to the container
|
||||||
|
func WithPort(privateport, publicport uint16, builders ...func(*types.Port)) func(*types.Container) {
|
||||||
|
return func(c *types.Container) {
|
||||||
|
if c.Ports == nil {
|
||||||
|
c.Ports = []types.Port{}
|
||||||
|
}
|
||||||
|
port := &types.Port{
|
||||||
|
PrivatePort: privateport,
|
||||||
|
PublicPort: publicport,
|
||||||
|
}
|
||||||
|
for _, builder := range builders {
|
||||||
|
builder(port)
|
||||||
|
}
|
||||||
|
c.Ports = append(c.Ports, *port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IP sets the ip of the port
|
||||||
|
func IP(ip string) func(*types.Port) {
|
||||||
|
return func(p *types.Port) {
|
||||||
|
p.IP = ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TCP sets the port to tcp
|
||||||
|
func TCP(p *types.Port) {
|
||||||
|
p.Type = "tcp"
|
||||||
|
}
|
||||||
|
|
||||||
|
// UDP sets the port to udp
|
||||||
|
func UDP(p *types.Port) {
|
||||||
|
p.Type = "udp"
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Volume creates a volume with default values.
|
// Volume creates a volume with default values.
|
||||||
// Any number of volume function builder can be pass to augment it.
|
// Any number of volume function builder can be passed to augment it.
|
||||||
func Volume(builders ...func(volume *types.Volume)) *types.Volume {
|
func Volume(builders ...func(volume *types.Volume)) *types.Volume {
|
||||||
volume := &types.Volume{
|
volume := &types.Volume{
|
||||||
Name: "volume",
|
Name: "volume",
|
||||||
|
|
Loading…
Reference in New Issue