mirror of https://github.com/docker/cli.git
Merge pull request #2699 from thaJeztah/reduce_table_width
formatter: reduce minimum width for columns in table-view
This commit is contained in:
commit
ed8ce81d58
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigContextFormatWrite(t *testing.T) {
|
func TestConfigContextFormatWrite(t *testing.T) {
|
||||||
|
@ -30,9 +29,9 @@ func TestConfigContextFormatWrite(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Table format
|
// Table format
|
||||||
{formatter.Context{Format: NewFormat("table", false)},
|
{formatter.Context{Format: NewFormat("table", false)},
|
||||||
`ID NAME CREATED UPDATED
|
`ID NAME CREATED UPDATED
|
||||||
1 passwords Less than a second ago Less than a second ago
|
1 passwords Less than a second ago Less than a second ago
|
||||||
2 id_rsa Less than a second ago Less than a second ago
|
2 id_rsa Less than a second ago Less than a second ago
|
||||||
`},
|
`},
|
||||||
{formatter.Context{Format: NewFormat("table {{.Name}}", true)},
|
{formatter.Context{Format: NewFormat("table {{.Name}}", true)},
|
||||||
`NAME
|
`NAME
|
||||||
|
@ -53,13 +52,16 @@ id_rsa
|
||||||
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||||
Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "id_rsa"}}},
|
Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "id_rsa"}}},
|
||||||
}
|
}
|
||||||
for _, testcase := range cases {
|
for _, tc := range cases {
|
||||||
out := bytes.NewBufferString("")
|
tc := tc
|
||||||
testcase.context.Output = out
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err := FormatWrite(testcase.context, configs); err != nil {
|
var out bytes.Buffer
|
||||||
assert.ErrorContains(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
if err := FormatWrite(tc.context, configs); err != nil {
|
||||||
assert.Check(t, is.Equal(out.String(), testcase.expected))
|
assert.ErrorContains(t, err, tc.expected)
|
||||||
}
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ID NAME CREATED UPDATED
|
ID NAME CREATED UPDATED
|
||||||
ID-1-foo 1-foo 2 hours ago About an hour ago
|
ID-1-foo 1-foo 2 hours ago About an hour ago
|
||||||
ID-2-foo 2-foo 2 hours ago About an hour ago
|
ID-2-foo 2-foo 2 hours ago About an hour ago
|
||||||
ID-10-foo 10-foo 2 hours ago About an hour ago
|
ID-10-foo 10-foo 2 hours ago About an hour ago
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
ID NAME CREATED UPDATED
|
ID NAME CREATED UPDATED
|
||||||
ID-bar bar 2 hours ago About an hour ago
|
ID-bar bar 2 hours ago About an hour ago
|
||||||
ID-foo foo 2 hours ago About an hour ago
|
ID-foo foo 2 hours ago About an hour ago
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDiffContextFormatWrite(t *testing.T) {
|
func TestDiffContextFormatWrite(t *testing.T) {
|
||||||
|
@ -19,10 +18,10 @@ func TestDiffContextFormatWrite(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
formatter.Context{Format: NewDiffFormat("table")},
|
formatter.Context{Format: NewDiffFormat("table")},
|
||||||
`CHANGE TYPE PATH
|
`CHANGE TYPE PATH
|
||||||
C /var/log/app.log
|
C /var/log/app.log
|
||||||
A /usr/app/app.js
|
A /usr/app/app.js
|
||||||
D /usr/app/old_app.js
|
D /usr/app/old_app.js
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -48,14 +47,17 @@ D: /usr/app/old_app.js
|
||||||
{Kind: archive.ChangeDelete, Path: "/usr/app/old_app.js"},
|
{Kind: archive.ChangeDelete, Path: "/usr/app/old_app.js"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
for _, tc := range cases {
|
||||||
out := bytes.NewBufferString("")
|
tc := tc
|
||||||
testcase.context.Output = out
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
err := DiffFormatWrite(testcase.context, diffs)
|
out := bytes.NewBufferString("")
|
||||||
if err != nil {
|
tc.context.Output = out
|
||||||
assert.Error(t, err, testcase.expected)
|
err := DiffFormatWrite(tc.context, diffs)
|
||||||
} else {
|
if err != nil {
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
assert.Error(t, err, tc.expected)
|
||||||
}
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ container2 --
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerStatsContextWriteWindows(t *testing.T) {
|
func TestContainerStatsContextWriteWindows(t *testing.T) {
|
||||||
tt := []struct {
|
cases := []struct {
|
||||||
context formatter.Context
|
context formatter.Context
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
@ -150,51 +150,54 @@ container2 -- --
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
stats := []StatsEntry{
|
||||||
|
{
|
||||||
|
Container: "container1",
|
||||||
|
CPUPercentage: 20,
|
||||||
|
Memory: 20,
|
||||||
|
MemoryLimit: 20,
|
||||||
|
MemoryPercentage: 20,
|
||||||
|
NetworkRx: 20,
|
||||||
|
NetworkTx: 20,
|
||||||
|
BlockRead: 20,
|
||||||
|
BlockWrite: 20,
|
||||||
|
PidsCurrent: 2,
|
||||||
|
IsInvalid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Container: "container2",
|
||||||
|
CPUPercentage: 30,
|
||||||
|
Memory: 30,
|
||||||
|
MemoryLimit: 30,
|
||||||
|
MemoryPercentage: 30,
|
||||||
|
NetworkRx: 30,
|
||||||
|
NetworkTx: 30,
|
||||||
|
BlockRead: 30,
|
||||||
|
BlockWrite: 30,
|
||||||
|
PidsCurrent: 3,
|
||||||
|
IsInvalid: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
for _, te := range tt {
|
for _, tc := range cases {
|
||||||
stats := []StatsEntry{
|
tc := tc
|
||||||
{
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
Container: "container1",
|
var out bytes.Buffer
|
||||||
CPUPercentage: 20,
|
tc.context.Output = &out
|
||||||
Memory: 20,
|
err := statsFormatWrite(tc.context, stats, "windows", false)
|
||||||
MemoryLimit: 20,
|
if err != nil {
|
||||||
MemoryPercentage: 20,
|
assert.Error(t, err, tc.expected)
|
||||||
NetworkRx: 20,
|
} else {
|
||||||
NetworkTx: 20,
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
BlockRead: 20,
|
}
|
||||||
BlockWrite: 20,
|
})
|
||||||
PidsCurrent: 2,
|
|
||||||
IsInvalid: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Container: "container2",
|
|
||||||
CPUPercentage: 30,
|
|
||||||
Memory: 30,
|
|
||||||
MemoryLimit: 30,
|
|
||||||
MemoryPercentage: 30,
|
|
||||||
NetworkRx: 30,
|
|
||||||
NetworkTx: 30,
|
|
||||||
BlockRead: 30,
|
|
||||||
BlockWrite: 30,
|
|
||||||
PidsCurrent: 3,
|
|
||||||
IsInvalid: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
var out bytes.Buffer
|
|
||||||
te.context.Output = &out
|
|
||||||
err := statsFormatWrite(te.context, stats, "windows", false)
|
|
||||||
if err != nil {
|
|
||||||
assert.Error(t, err, te.expected)
|
|
||||||
} else {
|
|
||||||
assert.Check(t, is.Equal(te.expected, out.String()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
|
func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
|
|
||||||
contexts := []struct {
|
cases := []struct {
|
||||||
context formatter.Context
|
context formatter.Context
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
@ -217,22 +220,26 @@ func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
|
||||||
Format: "table {{.Container}}\t{{.CPUPerc}}",
|
Format: "table {{.Container}}\t{{.CPUPerc}}",
|
||||||
Output: &out,
|
Output: &out,
|
||||||
},
|
},
|
||||||
"CONTAINER CPU %\n",
|
"CONTAINER CPU %\n",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, context := range contexts {
|
for _, tc := range cases {
|
||||||
statsFormatWrite(context.context, []StatsEntry{}, "linux", false)
|
tc := tc
|
||||||
assert.Check(t, is.Equal(context.expected, out.String()))
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
// Clean buffer
|
err := statsFormatWrite(tc.context, []StatsEntry{}, "linux", false)
|
||||||
out.Reset()
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
// Clean buffer
|
||||||
|
out.Reset()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
|
func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
|
|
||||||
contexts := []struct {
|
cases := []struct {
|
||||||
context formatter.Context
|
context formatter.Context
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
@ -248,22 +255,25 @@ func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
|
||||||
Format: "table {{.Container}}\t{{.MemUsage}}",
|
Format: "table {{.Container}}\t{{.MemUsage}}",
|
||||||
Output: &out,
|
Output: &out,
|
||||||
},
|
},
|
||||||
"CONTAINER PRIV WORKING SET\n",
|
"CONTAINER PRIV WORKING SET\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
formatter.Context{
|
formatter.Context{
|
||||||
Format: "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}",
|
Format: "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}",
|
||||||
Output: &out,
|
Output: &out,
|
||||||
},
|
},
|
||||||
"CONTAINER CPU % PRIV WORKING SET\n",
|
"CONTAINER CPU % PRIV WORKING SET\n",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, context := range contexts {
|
for _, tc := range cases {
|
||||||
statsFormatWrite(context.context, []StatsEntry{}, "windows", false)
|
tc := tc
|
||||||
assert.Check(t, is.Equal(context.expected, out.String()))
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
// Clean buffer
|
err := statsFormatWrite(tc.context, []StatsEntry{}, "windows", false)
|
||||||
out.Reset()
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
out.Reset()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
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 c1
|
||||||
container_id busybox:latest "top" Less than a second ago Up 1 second c2,foo/bar
|
container_id busybox:latest "top" Less than a second ago Up 1 second c2,foo/bar
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
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 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 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 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 81/udp c4
|
||||||
container_id busybox:latest "top" Less than a second ago Up 1 second 8.8.8.8:82->82/tcp c5
|
container_id busybox:latest "top" Less than a second ago Up 1 second 8.8.8.8:82->82/tcp c5
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
|
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
|
||||||
current * description of current https://someswarmserver https://someserver (default) all
|
current * description of current https://someswarmserver https://someserver (default) all
|
||||||
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
|
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
|
||||||
other description of other https://someswarmserver https://someserver (default) all
|
other description of other https://someswarmserver https://someserver (default) all
|
||||||
unset description of unset https://someswarmserver https://someserver (default)
|
unset description of unset https://someswarmserver https://someserver (default)
|
||||||
|
|
|
@ -141,16 +141,16 @@ func TestContainerContextWrite(t *testing.T) {
|
||||||
// Table Format
|
// Table Format
|
||||||
{
|
{
|
||||||
Context{Format: NewContainerFormat("table", false, true)},
|
Context{Format: NewContainerFormat("table", false, true)},
|
||||||
`CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
|
`CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
|
||||||
containerID1 ubuntu "" 24 hours ago foobar_baz 0B
|
containerID1 ubuntu "" 24 hours ago foobar_baz 0B
|
||||||
containerID2 ubuntu "" 24 hours ago foobar_bar 0B
|
containerID2 ubuntu "" 24 hours ago foobar_bar 0B
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Context{Format: NewContainerFormat("table", false, false)},
|
Context{Format: NewContainerFormat("table", false, false)},
|
||||||
`CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
`CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
containerID1 ubuntu "" 24 hours ago foobar_baz
|
containerID1 ubuntu "" 24 hours ago foobar_baz
|
||||||
containerID2 ubuntu "" 24 hours ago foobar_bar
|
containerID2 ubuntu "" 24 hours ago foobar_bar
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -248,19 +248,24 @@ size: 0B
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
containers := []types.Container{
|
||||||
containers := []types.Container{
|
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime, State: "running"},
|
||||||
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime, State: "running"},
|
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime, State: "running"},
|
||||||
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime, State: "running"},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := ContainerWrite(testcase.context, containers)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
err := ContainerWrite(tc.context, containers)
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +273,7 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
|
||||||
out := bytes.NewBufferString("")
|
out := bytes.NewBufferString("")
|
||||||
containers := []types.Container{}
|
containers := []types.Container{}
|
||||||
|
|
||||||
contexts := []struct {
|
cases := []struct {
|
||||||
context Context
|
context Context
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
@ -305,23 +310,26 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
|
||||||
Format: "table {{.Image}}\t{{.Size}}",
|
Format: "table {{.Image}}\t{{.Size}}",
|
||||||
Output: out,
|
Output: out,
|
||||||
},
|
},
|
||||||
"IMAGE SIZE\n",
|
"IMAGE SIZE\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Context{
|
Context{
|
||||||
Format: NewContainerFormat("table {{.Image}}\t{{.Size}}", false, true),
|
Format: NewContainerFormat("table {{.Image}}\t{{.Size}}", false, true),
|
||||||
Output: out,
|
Output: out,
|
||||||
},
|
},
|
||||||
"IMAGE SIZE\n",
|
"IMAGE SIZE\n",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, context := range contexts {
|
for _, tc := range cases {
|
||||||
err := ContainerWrite(context.context, containers)
|
tc := tc
|
||||||
assert.NilError(t, err)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
assert.Check(t, is.Equal(context.expected, out.String()))
|
err := ContainerWrite(tc.context, containers)
|
||||||
// Clean buffer
|
assert.NilError(t, err)
|
||||||
out.Reset()
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
// Clean buffer
|
||||||
|
out.Reset()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
"gotest.tools/v3/golden"
|
"gotest.tools/v3/golden"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,30 +20,30 @@ func TestDiskUsageContextFormatWrite(t *testing.T) {
|
||||||
Format: NewDiskUsageFormat("table", false),
|
Format: NewDiskUsageFormat("table", false),
|
||||||
},
|
},
|
||||||
Verbose: false},
|
Verbose: false},
|
||||||
`TYPE TOTAL ACTIVE SIZE RECLAIMABLE
|
`TYPE TOTAL ACTIVE SIZE RECLAIMABLE
|
||||||
Images 0 0 0B 0B
|
Images 0 0 0B 0B
|
||||||
Containers 0 0 0B 0B
|
Containers 0 0 0B 0B
|
||||||
Local Volumes 0 0 0B 0B
|
Local Volumes 0 0 0B 0B
|
||||||
Build Cache 0 0 0B 0B
|
Build Cache 0 0 0B 0B
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
DiskUsageContext{Verbose: true, Context: Context{Format: NewDiskUsageFormat("table", true)}},
|
DiskUsageContext{Verbose: true, Context: Context{Format: NewDiskUsageFormat("table", true)}},
|
||||||
`Images space usage:
|
`Images space usage:
|
||||||
|
|
||||||
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
|
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
|
||||||
|
|
||||||
Containers space usage:
|
Containers space usage:
|
||||||
|
|
||||||
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
|
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
|
||||||
|
|
||||||
Local Volumes space usage:
|
Local Volumes space usage:
|
||||||
|
|
||||||
VOLUME NAME LINKS SIZE
|
VOLUME NAME LINKS SIZE
|
||||||
|
|
||||||
Build cache usage: 0B
|
Build cache usage: 0B
|
||||||
|
|
||||||
CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
|
CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -81,11 +80,11 @@ CACHE ID CACHE TYPE SIZE CREATED
|
||||||
Format: NewDiskUsageFormat("table", false),
|
Format: NewDiskUsageFormat("table", false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
`TYPE TOTAL ACTIVE SIZE RECLAIMABLE
|
`TYPE TOTAL ACTIVE SIZE RECLAIMABLE
|
||||||
Images 0 0 0B 0B
|
Images 0 0 0B 0B
|
||||||
Containers 0 0 0B 0B
|
Containers 0 0 0B 0B
|
||||||
Local Volumes 0 0 0B 0B
|
Local Volumes 0 0 0B 0B
|
||||||
Build Cache 0 0 0B 0B
|
Build Cache 0 0 0B 0B
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -107,13 +106,16 @@ Build Cache 0 0 0B
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
for _, tc := range cases {
|
||||||
out := bytes.NewBufferString("")
|
tc := tc
|
||||||
testcase.context.Output = out
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err := testcase.context.Write(); err != nil {
|
var out bytes.Buffer
|
||||||
assert.Check(t, is.Equal(testcase.expected, err.Error()))
|
tc.context.Output = &out
|
||||||
} else {
|
if err := tc.context.Write(); err != nil {
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
assert.Error(t, err, tc.expected)
|
||||||
}
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ func (c *Context) parseFormat() (*template.Template, error) {
|
||||||
|
|
||||||
func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
|
func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
|
||||||
if c.Format.IsTable() {
|
if c.Format.IsTable() {
|
||||||
t := tabwriter.NewWriter(c.Output, 20, 1, 3, ' ', 0)
|
t := tabwriter.NewWriter(c.Output, 10, 1, 3, ' ', 0)
|
||||||
buffer := bytes.NewBufferString("")
|
buffer := bytes.NewBufferString("")
|
||||||
tmpl.Funcs(templates.HeaderFunctions).Execute(buffer, subContext.FullHeader())
|
tmpl.Funcs(templates.HeaderFunctions).Execute(buffer, subContext.FullHeader())
|
||||||
buffer.WriteTo(t)
|
buffer.WriteTo(t)
|
||||||
|
|
|
@ -138,10 +138,10 @@ func TestImageContextWrite(t *testing.T) {
|
||||||
Format: NewImageFormat("table", false, false),
|
Format: NewImageFormat("table", false, false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
`REPOSITORY TAG IMAGE ID CREATED SIZE
|
`REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
image tag1 imageID1 24 hours ago 0B
|
image tag1 imageID1 24 hours ago 0B
|
||||||
image tag2 imageID2 N/A 0B
|
image tag2 imageID2 N/A 0B
|
||||||
<none> <none> imageID3 24 hours ago 0B
|
<none> <none> imageID3 24 hours ago 0B
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -159,10 +159,10 @@ image tag2 imageID2 N/A
|
||||||
},
|
},
|
||||||
Digest: true,
|
Digest: true,
|
||||||
},
|
},
|
||||||
`REPOSITORY DIGEST
|
`REPOSITORY DIGEST
|
||||||
image sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
|
image sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
|
||||||
image <none>
|
image <none>
|
||||||
<none> <none>
|
<none> <none>
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -196,10 +196,10 @@ image <none>
|
||||||
},
|
},
|
||||||
Digest: true,
|
Digest: true,
|
||||||
},
|
},
|
||||||
`REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
|
`REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
|
||||||
image tag1 sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf imageID1 24 hours ago 0B
|
image tag1 sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf imageID1 24 hours ago 0B
|
||||||
image tag2 <none> imageID2 N/A 0B
|
image tag2 <none> imageID2 N/A 0B
|
||||||
<none> <none> <none> imageID3 24 hours ago 0B
|
<none> <none> <none> imageID3 24 hours ago 0B
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -299,20 +299,24 @@ image_id: imageID3
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
images := []types.ImageSummary{
|
||||||
images := []types.ImageSummary{
|
{ID: "imageID1", RepoTags: []string{"image:tag1"}, RepoDigests: []string{"image@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"}, Created: unixTime},
|
||||||
{ID: "imageID1", RepoTags: []string{"image:tag1"}, RepoDigests: []string{"image@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"}, Created: unixTime},
|
{ID: "imageID2", RepoTags: []string{"image:tag2"}, Created: zeroTime},
|
||||||
{ID: "imageID2", RepoTags: []string{"image:tag2"}, Created: zeroTime},
|
{ID: "imageID3", RepoTags: []string{"<none>:<none>"}, RepoDigests: []string{"<none>@<none>"}, Created: unixTime},
|
||||||
{ID: "imageID3", RepoTags: []string{"<none>:<none>"}, RepoDigests: []string{"<none>@<none>"}, Created: unixTime},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := ImageWrite(testcase.context, images)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
err := ImageWrite(tc.context, images)
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +324,7 @@ func TestImageContextWriteWithNoImage(t *testing.T) {
|
||||||
out := bytes.NewBufferString("")
|
out := bytes.NewBufferString("")
|
||||||
images := []types.ImageSummary{}
|
images := []types.ImageSummary{}
|
||||||
|
|
||||||
contexts := []struct {
|
cases := []struct {
|
||||||
context ImageContext
|
context ImageContext
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
@ -358,15 +362,18 @@ func TestImageContextWriteWithNoImage(t *testing.T) {
|
||||||
Output: out,
|
Output: out,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"REPOSITORY DIGEST\n",
|
"REPOSITORY DIGEST\n",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, context := range contexts {
|
for _, tc := range cases {
|
||||||
err := ImageWrite(context.context, images)
|
tc := tc
|
||||||
assert.NilError(t, err)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
assert.Check(t, is.Equal(context.expected, out.String()))
|
err := ImageWrite(tc.context, images)
|
||||||
// Clean buffer
|
assert.NilError(t, err)
|
||||||
out.Reset()
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
// Clean buffer
|
||||||
|
out.Reset()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
CONTAINER ID IMAGE CREATED/STATUS/ PORTS .NAMES STATUS
|
CONTAINER ID IMAGE CREATED/STATUS/ PORTS .NAMES STATUS
|
||||||
conta "ubuntu" 24 hours ago//.FOOBAR_BAZ
|
conta "ubuntu" 24 hours ago//.FOOBAR_BAZ
|
||||||
conta "ubuntu" 24 hours ago//.FOOBAR_BAR
|
conta "ubuntu" 24 hours ago//.FOOBAR_BAR
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TYPE ACTIVE
|
TYPE ACTIVE
|
||||||
Images 0
|
Images 0
|
||||||
Containers 0
|
Containers 0
|
||||||
Local Volumes 0
|
Local Volumes 0
|
||||||
Build Cache 0
|
Build Cache 0
|
||||||
|
|
|
@ -59,7 +59,6 @@ func TestVolumeContextWrite(t *testing.T) {
|
||||||
context Context
|
context Context
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
{
|
{
|
||||||
Context{Format: "{{InvalidFunction}}"},
|
Context{Format: "{{InvalidFunction}}"},
|
||||||
|
@ -74,9 +73,9 @@ func TestVolumeContextWrite(t *testing.T) {
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
Context{Format: NewVolumeFormat("table", false)},
|
Context{Format: NewVolumeFormat("table", false)},
|
||||||
`DRIVER VOLUME NAME
|
`DRIVER VOLUME NAME
|
||||||
foo foobar_baz
|
foo foobar_baz
|
||||||
bar foobar_bar
|
bar foobar_bar
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -125,19 +124,23 @@ foobar_bar
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
volumes := []*types.Volume{
|
||||||
volumes := []*types.Volume{
|
{Name: "foobar_baz", Driver: "foo"},
|
||||||
{Name: "foobar_baz", Driver: "foo"},
|
{Name: "foobar_bar", Driver: "bar"},
|
||||||
{Name: "foobar_bar", Driver: "bar"},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := VolumeWrite(testcase.context, volumes)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
err := VolumeWrite(tc.context, volumes)
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
"gotest.tools/v3/skip"
|
"gotest.tools/v3/skip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -188,20 +187,20 @@ func TestHistoryContext_Table(t *testing.T) {
|
||||||
{ID: "imageID4", Created: unixTime, CreatedBy: "/bin/bash grep", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
{ID: "imageID4", Created: unixTime, CreatedBy: "/bin/bash grep", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}},
|
||||||
}
|
}
|
||||||
// nolint: lll
|
// nolint: lll
|
||||||
expectedNoTrunc := `IMAGE CREATED CREATED BY SIZE COMMENT
|
expectedNoTrunc := `IMAGE CREATED CREATED BY SIZE COMMENT
|
||||||
imageID1 24 hours ago /bin/bash ls && npm i && npm run test && karma -c karma.conf.js start && npm start && more commands here && the list goes on 183MB Hi
|
imageID1 24 hours ago /bin/bash ls && npm i && npm run test && karma -c karma.conf.js start && npm start && more commands here && the list goes on 183MB Hi
|
||||||
imageID2 24 hours ago /bin/bash echo 183MB Hi
|
imageID2 24 hours ago /bin/bash echo 183MB Hi
|
||||||
imageID3 24 hours ago /bin/bash ls 183MB Hi
|
imageID3 24 hours ago /bin/bash ls 183MB Hi
|
||||||
imageID4 24 hours ago /bin/bash grep 183MB Hi
|
imageID4 24 hours ago /bin/bash grep 183MB Hi
|
||||||
`
|
`
|
||||||
expectedTrunc := `IMAGE CREATED CREATED BY SIZE COMMENT
|
expectedTrunc := `IMAGE CREATED CREATED BY SIZE COMMENT
|
||||||
imageID1 24 hours ago /bin/bash ls && npm i && npm run test && kar… 183MB Hi
|
imageID1 24 hours ago /bin/bash ls && npm i && npm run test && kar… 183MB Hi
|
||||||
imageID2 24 hours ago /bin/bash echo 183MB Hi
|
imageID2 24 hours ago /bin/bash echo 183MB Hi
|
||||||
imageID3 24 hours ago /bin/bash ls 183MB Hi
|
imageID3 24 hours ago /bin/bash ls 183MB Hi
|
||||||
imageID4 24 hours ago /bin/bash grep 183MB Hi
|
imageID4 24 hours ago /bin/bash grep 183MB Hi
|
||||||
`
|
`
|
||||||
|
|
||||||
contexts := []struct {
|
cases := []struct {
|
||||||
context formatter.Context
|
context formatter.Context
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
@ -221,10 +220,14 @@ imageID4 24 hours ago /bin/bash grep
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, context := range contexts {
|
for _, tc := range cases {
|
||||||
HistoryWrite(context.context, true, histories)
|
tc := tc
|
||||||
assert.Check(t, is.Equal(context.expected, out.String()))
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
// Clean buffer
|
err := HistoryWrite(tc.context, true, histories)
|
||||||
out.Reset()
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
// Clean buffer
|
||||||
|
out.Reset()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||||
|
|
|
@ -90,9 +90,9 @@ func TestNetworkContextWrite(t *testing.T) {
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
formatter.Context{Format: NewFormat("table", false)},
|
formatter.Context{Format: NewFormat("table", false)},
|
||||||
`NETWORK ID NAME DRIVER SCOPE
|
`NETWORK ID NAME DRIVER SCOPE
|
||||||
networkID1 foobar_baz foo local
|
networkID1 foobar_baz foo local
|
||||||
networkID2 foobar_bar bar local
|
networkID2 foobar_bar bar local
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -155,19 +155,23 @@ foobar_bar 2017-01-01 00:00:00 +0000 UTC
|
||||||
timestamp1, _ := time.Parse("2006-01-02", "2016-01-01")
|
timestamp1, _ := time.Parse("2006-01-02", "2016-01-01")
|
||||||
timestamp2, _ := time.Parse("2006-01-02", "2017-01-01")
|
timestamp2, _ := time.Parse("2006-01-02", "2017-01-01")
|
||||||
|
|
||||||
for _, testcase := range cases {
|
networks := []types.NetworkResource{
|
||||||
networks := []types.NetworkResource{
|
{ID: "networkID1", Name: "foobar_baz", Driver: "foo", Scope: "local", Created: timestamp1},
|
||||||
{ID: "networkID1", Name: "foobar_baz", Driver: "foo", Scope: "local", Created: timestamp1},
|
{ID: "networkID2", Name: "foobar_bar", Driver: "bar", Scope: "local", Created: timestamp2},
|
||||||
{ID: "networkID2", Name: "foobar_bar", Driver: "bar", Scope: "local", Created: timestamp2},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := FormatWrite(testcase.context, networks)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
err := FormatWrite(tc.context, networks)
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
NETWORK ID NAME DRIVER SCOPE
|
NETWORK ID NAME DRIVER SCOPE
|
||||||
123454321 network_1 09.7.01 global
|
123454321 network_1 09.7.01 global
|
||||||
|
|
|
@ -76,10 +76,10 @@ func TestNodeContextWrite(t *testing.T) {
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
context: formatter.Context{Format: NewFormat("table", false)},
|
context: formatter.Context{Format: NewFormat("table", false)},
|
||||||
expected: `ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
expected: `ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
||||||
nodeID1 foobar_baz Foo Drain Leader 18.03.0-ce
|
nodeID1 foobar_baz Foo Drain Leader 18.03.0-ce
|
||||||
nodeID2 foobar_bar Bar Active Reachable 1.2.3
|
nodeID2 foobar_bar Bar Active Reachable 1.2.3
|
||||||
nodeID3 foobar_boo Boo Active ` + "\n", // (to preserve whitespace)
|
nodeID3 foobar_boo Boo Active ` + "\n", // (to preserve whitespace)
|
||||||
clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}},
|
clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -110,19 +110,19 @@ foobar_boo
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
context: formatter.Context{Format: NewFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)},
|
context: formatter.Context{Format: NewFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)},
|
||||||
expected: `ID HOSTNAME TLS STATUS
|
expected: `ID HOSTNAME TLS STATUS
|
||||||
nodeID1 foobar_baz Needs Rotation
|
nodeID1 foobar_baz Needs Rotation
|
||||||
nodeID2 foobar_bar Ready
|
nodeID2 foobar_bar Ready
|
||||||
nodeID3 foobar_boo Unknown
|
nodeID3 foobar_boo Unknown
|
||||||
`,
|
`,
|
||||||
clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}},
|
clusterInfo: swarm.ClusterInfo{TLSInfo: swarm.TLSInfo{TrustRoot: "hi"}},
|
||||||
},
|
},
|
||||||
{ // no cluster TLS status info, TLS status for all nodes is unknown
|
{ // no cluster TLS status info, TLS status for all nodes is unknown
|
||||||
context: formatter.Context{Format: NewFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)},
|
context: formatter.Context{Format: NewFormat("table {{.ID}}\t{{.Hostname}}\t{{.TLSStatus}}", false)},
|
||||||
expected: `ID HOSTNAME TLS STATUS
|
expected: `ID HOSTNAME TLS STATUS
|
||||||
nodeID1 foobar_baz Unknown
|
nodeID1 foobar_baz Unknown
|
||||||
nodeID2 foobar_bar Unknown
|
nodeID2 foobar_bar Unknown
|
||||||
nodeID3 foobar_boo Unknown
|
nodeID3 foobar_boo Unknown
|
||||||
`,
|
`,
|
||||||
clusterInfo: swarm.ClusterInfo{},
|
clusterInfo: swarm.ClusterInfo{},
|
||||||
},
|
},
|
||||||
|
@ -167,48 +167,53 @@ foobar_boo Unknown
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
nodes := []swarm.Node{
|
||||||
nodes := []swarm.Node{
|
{
|
||||||
{
|
ID: "nodeID1",
|
||||||
ID: "nodeID1",
|
Description: swarm.NodeDescription{
|
||||||
Description: swarm.NodeDescription{
|
Hostname: "foobar_baz",
|
||||||
Hostname: "foobar_baz",
|
TLSInfo: swarm.TLSInfo{TrustRoot: "no"},
|
||||||
TLSInfo: swarm.TLSInfo{TrustRoot: "no"},
|
Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"},
|
||||||
Engine: swarm.EngineDescription{EngineVersion: "18.03.0-ce"},
|
|
||||||
},
|
|
||||||
Status: swarm.NodeStatus{State: swarm.NodeState("foo")},
|
|
||||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("drain")},
|
|
||||||
ManagerStatus: &swarm.ManagerStatus{Leader: true},
|
|
||||||
},
|
},
|
||||||
{
|
Status: swarm.NodeStatus{State: swarm.NodeState("foo")},
|
||||||
ID: "nodeID2",
|
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("drain")},
|
||||||
Description: swarm.NodeDescription{
|
ManagerStatus: &swarm.ManagerStatus{Leader: true},
|
||||||
Hostname: "foobar_bar",
|
},
|
||||||
TLSInfo: swarm.TLSInfo{TrustRoot: "hi"},
|
{
|
||||||
Engine: swarm.EngineDescription{EngineVersion: "1.2.3"},
|
ID: "nodeID2",
|
||||||
},
|
Description: swarm.NodeDescription{
|
||||||
Status: swarm.NodeStatus{State: swarm.NodeState("bar")},
|
Hostname: "foobar_bar",
|
||||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
TLSInfo: swarm.TLSInfo{TrustRoot: "hi"},
|
||||||
ManagerStatus: &swarm.ManagerStatus{
|
Engine: swarm.EngineDescription{EngineVersion: "1.2.3"},
|
||||||
Leader: false,
|
|
||||||
Reachability: swarm.Reachability("Reachable"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
Status: swarm.NodeStatus{State: swarm.NodeState("bar")},
|
||||||
ID: "nodeID3",
|
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
||||||
Description: swarm.NodeDescription{Hostname: "foobar_boo"},
|
ManagerStatus: &swarm.ManagerStatus{
|
||||||
Status: swarm.NodeStatus{State: swarm.NodeState("boo")},
|
Leader: false,
|
||||||
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
Reachability: swarm.Reachability("Reachable"),
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
out := bytes.NewBufferString("")
|
{
|
||||||
testcase.context.Output = out
|
ID: "nodeID3",
|
||||||
err := FormatWrite(testcase.context, nodes, types.Info{Swarm: swarm.Info{Cluster: &testcase.clusterInfo}})
|
Description: swarm.NodeDescription{Hostname: "foobar_boo"},
|
||||||
if err != nil {
|
Status: swarm.NodeStatus{State: swarm.NodeState("boo")},
|
||||||
assert.Error(t, err, testcase.expected)
|
Spec: swarm.NodeSpec{Availability: swarm.NodeAvailability("active")},
|
||||||
} else {
|
},
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
}
|
||||||
}
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
tc.context.Output = &out
|
||||||
|
|
||||||
|
err := FormatWrite(tc.context, nodes, types.Info{Swarm: swarm.Info{Cluster: &tc.clusterInfo}})
|
||||||
|
if err != nil {
|
||||||
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
||||||
nodeID3 node-1-foo Ready Active 1.13.0
|
nodeID3 node-1-foo Ready Active 1.13.0
|
||||||
nodeID1 * node-2-foo Ready Active Leader .
|
nodeID1 * node-2-foo Ready Active Leader .
|
||||||
nodeID2 node-10-foo Ready Active Reachable 18.03.0-ce
|
nodeID2 node-10-foo Ready Active Reachable 18.03.0-ce
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
||||||
taskID rl02d5gwz6chzu7il5fhtb8be.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago *:80->80/tcp
|
taskID rl02d5gwz6chzu7il5fhtb8be.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago *:80->80/tcp
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
||||||
taskID1 failure.1 myimage:mytag defaultNodeName Ready Ready 2 hours ago "a task error"
|
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"
|
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"
|
taskID3 \_ failure.1 myimage:mytag defaultNodeName Ready Ready 4 hours ago "a task error"
|
||||||
|
|
|
@ -70,9 +70,9 @@ func TestPluginContextWrite(t *testing.T) {
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
formatter.Context{Format: NewFormat("table", false)},
|
formatter.Context{Format: NewFormat("table", false)},
|
||||||
`ID NAME DESCRIPTION ENABLED
|
`ID NAME DESCRIPTION ENABLED
|
||||||
pluginID1 foobar_baz description 1 true
|
pluginID1 foobar_baz description 1 true
|
||||||
pluginID2 foobar_bar description 2 false
|
pluginID2 foobar_bar description 2 false
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -125,19 +125,24 @@ foobar_bar
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
plugins := []*types.Plugin{
|
||||||
plugins := []*types.Plugin{
|
{ID: "pluginID1", Name: "foobar_baz", Config: types.PluginConfig{Description: "description 1"}, Enabled: true},
|
||||||
{ID: "pluginID1", Name: "foobar_baz", Config: types.PluginConfig{Description: "description 1"}, Enabled: true},
|
{ID: "pluginID2", Name: "foobar_bar", Config: types.PluginConfig{Description: "description 2"}, Enabled: false},
|
||||||
{ID: "pluginID2", Name: "foobar_bar", Config: types.PluginConfig{Description: "description 2"}, Enabled: false},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := FormatWrite(testcase.context, plugins)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
err := FormatWrite(tc.context, plugins)
|
||||||
}
|
if err != nil {
|
||||||
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
ID NAME DESCRIPTION ENABLED
|
ID NAME DESCRIPTION ENABLED
|
||||||
id-foo name-foo desc-bar true
|
id-foo name-foo desc-bar true
|
||||||
|
|
|
@ -148,19 +148,24 @@ result2 5
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
results := []registrytypes.SearchResult{
|
||||||
results := []registrytypes.SearchResult{
|
{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false},
|
||||||
{Name: "result1", Description: "Official build", StarCount: 5000, IsOfficial: true, IsAutomated: false},
|
{Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true},
|
||||||
{Name: "result2", Description: "Not official", StarCount: 5, IsOfficial: false, IsAutomated: true},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := SearchWrite(testcase.context, results)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Check(t, is.ErrorContains(err, testcase.expected))
|
tc.context.Output = &out
|
||||||
} else {
|
|
||||||
assert.Check(t, is.Equal(out.String(), testcase.expected))
|
err := SearchWrite(tc.context, results)
|
||||||
}
|
if err != nil {
|
||||||
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
|
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
|
||||||
result1 Official build 5000 [OK]
|
result1 Official build 5000 [OK]
|
||||||
result2 Not official 5 [OK]
|
result2 Not official 5 [OK]
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSecretContextFormatWrite(t *testing.T) {
|
func TestSecretContextFormatWrite(t *testing.T) {
|
||||||
|
@ -30,9 +29,9 @@ func TestSecretContextFormatWrite(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Table format
|
// Table format
|
||||||
{formatter.Context{Format: NewFormat("table", false)},
|
{formatter.Context{Format: NewFormat("table", false)},
|
||||||
`ID NAME DRIVER CREATED UPDATED
|
`ID NAME DRIVER CREATED UPDATED
|
||||||
1 passwords Less than a second ago Less than a second ago
|
1 passwords Less than a second ago Less than a second ago
|
||||||
2 id_rsa Less than a second ago Less than a second ago
|
2 id_rsa Less than a second ago Less than a second ago
|
||||||
`},
|
`},
|
||||||
{formatter.Context{Format: NewFormat("table {{.Name}}", true)},
|
{formatter.Context{Format: NewFormat("table {{.Name}}", true)},
|
||||||
`NAME
|
`NAME
|
||||||
|
@ -53,13 +52,17 @@ id_rsa
|
||||||
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
Meta: swarm.Meta{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||||
Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "id_rsa"}}},
|
Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "id_rsa"}}},
|
||||||
}
|
}
|
||||||
for _, testcase := range cases {
|
for _, tc := range cases {
|
||||||
out := bytes.NewBufferString("")
|
tc := tc
|
||||||
testcase.context.Output = out
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err := FormatWrite(testcase.context, secrets); err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err := FormatWrite(tc.context, secrets); err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
ID NAME DRIVER CREATED UPDATED
|
ID NAME DRIVER CREATED UPDATED
|
||||||
ID-1-foo 1-foo 2 hours ago About an hour ago
|
ID-1-foo 1-foo 2 hours ago About an hour ago
|
||||||
ID-2-foo 2-foo driver 2 hours ago About an hour ago
|
ID-2-foo 2-foo driver 2 hours ago About an hour ago
|
||||||
ID-10-foo 10-foo driver 2 hours ago About an hour ago
|
ID-10-foo 10-foo driver 2 hours ago About an hour ago
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
ID NAME DRIVER CREATED UPDATED
|
ID NAME DRIVER CREATED UPDATED
|
||||||
ID-bar bar 2 hours ago About an hour ago
|
ID-bar bar 2 hours ago About an hour ago
|
||||||
ID-foo foo 2 hours ago About an hour ago
|
ID-foo foo 2 hours ago About an hour ago
|
||||||
|
|
|
@ -40,13 +40,13 @@ func TestServiceContextWrite(t *testing.T) {
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
formatter.Context{Format: NewListFormat("table", false)},
|
formatter.Context{Format: NewListFormat("table", false)},
|
||||||
`ID NAME MODE REPLICAS IMAGE PORTS
|
`ID NAME MODE REPLICAS IMAGE PORTS
|
||||||
02_bar bar replicated 2/4 *:80->8090/udp
|
02_bar bar replicated 2/4 *:80->8090/udp
|
||||||
01_baz baz global 1/3 *:80->8080/tcp
|
01_baz baz global 1/3 *:80->8080/tcp
|
||||||
04_qux2 qux2 replicated 3/3 (max 2 per node)
|
04_qux2 qux2 replicated 3/3 (max 2 per node)
|
||||||
03_qux10 qux10 replicated 2/3 (max 1 per node)
|
03_qux10 qux10 replicated 2/3 (max 1 per node)
|
||||||
05_job1 zarp1 replicated job 2/3 (5/10 completed)
|
05_job1 zarp1 replicated job 2/3 (5/10 completed)
|
||||||
06_job2 zarp2 global job 1/1 (3/4 completed)
|
06_job2 zarp2 global job 1/1 (3/4 completed)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -61,13 +61,13 @@ func TestServiceContextWrite(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
formatter.Context{Format: NewListFormat("table {{.Name}}\t{{.Mode}}", false)},
|
formatter.Context{Format: NewListFormat("table {{.Name}}\t{{.Mode}}", false)},
|
||||||
`NAME MODE
|
`NAME MODE
|
||||||
bar replicated
|
bar replicated
|
||||||
baz global
|
baz global
|
||||||
qux2 replicated
|
qux2 replicated
|
||||||
qux10 replicated
|
qux10 replicated
|
||||||
zarp1 replicated job
|
zarp1 replicated job
|
||||||
zarp2 global job
|
zarp2 global job
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -109,126 +109,130 @@ zarp2
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
services := []swarm.Service{
|
||||||
services := []swarm.Service{
|
{
|
||||||
{
|
ID: "01_baz",
|
||||||
ID: "01_baz",
|
Spec: swarm.ServiceSpec{
|
||||||
Spec: swarm.ServiceSpec{
|
Annotations: swarm.Annotations{Name: "baz"},
|
||||||
Annotations: swarm.Annotations{Name: "baz"},
|
Mode: swarm.ServiceMode{
|
||||||
Mode: swarm.ServiceMode{
|
Global: &swarm.GlobalService{},
|
||||||
Global: &swarm.GlobalService{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Endpoint: swarm.Endpoint{
|
|
||||||
Ports: []swarm.PortConfig{
|
|
||||||
{
|
|
||||||
PublishMode: "ingress",
|
|
||||||
PublishedPort: 80,
|
|
||||||
TargetPort: 8080,
|
|
||||||
Protocol: "tcp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ServiceStatus: &swarm.ServiceStatus{
|
|
||||||
RunningTasks: 1,
|
|
||||||
DesiredTasks: 3,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
Endpoint: swarm.Endpoint{
|
||||||
ID: "02_bar",
|
Ports: []swarm.PortConfig{
|
||||||
Spec: swarm.ServiceSpec{
|
{
|
||||||
Annotations: swarm.Annotations{Name: "bar"},
|
PublishMode: "ingress",
|
||||||
Mode: swarm.ServiceMode{
|
PublishedPort: 80,
|
||||||
Replicated: &swarm.ReplicatedService{},
|
TargetPort: 8080,
|
||||||
|
Protocol: "tcp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Endpoint: swarm.Endpoint{
|
|
||||||
Ports: []swarm.PortConfig{
|
|
||||||
{
|
|
||||||
PublishMode: "ingress",
|
|
||||||
PublishedPort: 80,
|
|
||||||
TargetPort: 8090,
|
|
||||||
Protocol: "udp",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ServiceStatus: &swarm.ServiceStatus{
|
|
||||||
RunningTasks: 2,
|
|
||||||
DesiredTasks: 4,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
ServiceStatus: &swarm.ServiceStatus{
|
||||||
ID: "03_qux10",
|
RunningTasks: 1,
|
||||||
Spec: swarm.ServiceSpec{
|
DesiredTasks: 3,
|
||||||
Annotations: swarm.Annotations{Name: "qux10"},
|
},
|
||||||
Mode: swarm.ServiceMode{
|
},
|
||||||
Replicated: &swarm.ReplicatedService{},
|
{
|
||||||
},
|
ID: "02_bar",
|
||||||
TaskTemplate: swarm.TaskSpec{
|
Spec: swarm.ServiceSpec{
|
||||||
Placement: &swarm.Placement{MaxReplicas: 1},
|
Annotations: swarm.Annotations{Name: "bar"},
|
||||||
},
|
Mode: swarm.ServiceMode{
|
||||||
},
|
Replicated: &swarm.ReplicatedService{},
|
||||||
ServiceStatus: &swarm.ServiceStatus{
|
|
||||||
RunningTasks: 2,
|
|
||||||
DesiredTasks: 3,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
Endpoint: swarm.Endpoint{
|
||||||
ID: "04_qux2",
|
Ports: []swarm.PortConfig{
|
||||||
Spec: swarm.ServiceSpec{
|
{
|
||||||
Annotations: swarm.Annotations{Name: "qux2"},
|
PublishMode: "ingress",
|
||||||
Mode: swarm.ServiceMode{
|
PublishedPort: 80,
|
||||||
Replicated: &swarm.ReplicatedService{},
|
TargetPort: 8090,
|
||||||
|
Protocol: "udp",
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
|
||||||
Placement: &swarm.Placement{MaxReplicas: 2},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ServiceStatus: &swarm.ServiceStatus{
|
|
||||||
RunningTasks: 3,
|
|
||||||
DesiredTasks: 3,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
ServiceStatus: &swarm.ServiceStatus{
|
||||||
ID: "05_job1",
|
RunningTasks: 2,
|
||||||
Spec: swarm.ServiceSpec{
|
DesiredTasks: 4,
|
||||||
Annotations: swarm.Annotations{Name: "zarp1"},
|
},
|
||||||
Mode: swarm.ServiceMode{
|
},
|
||||||
ReplicatedJob: &swarm.ReplicatedJob{
|
{
|
||||||
MaxConcurrent: &varThree,
|
ID: "03_qux10",
|
||||||
TotalCompletions: &varTen,
|
Spec: swarm.ServiceSpec{
|
||||||
},
|
Annotations: swarm.Annotations{Name: "qux10"},
|
||||||
},
|
Mode: swarm.ServiceMode{
|
||||||
|
Replicated: &swarm.ReplicatedService{},
|
||||||
},
|
},
|
||||||
ServiceStatus: &swarm.ServiceStatus{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
RunningTasks: 2,
|
Placement: &swarm.Placement{MaxReplicas: 1},
|
||||||
DesiredTasks: 3,
|
|
||||||
CompletedTasks: 5,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
ServiceStatus: &swarm.ServiceStatus{
|
||||||
ID: "06_job2",
|
RunningTasks: 2,
|
||||||
Spec: swarm.ServiceSpec{
|
DesiredTasks: 3,
|
||||||
Annotations: swarm.Annotations{Name: "zarp2"},
|
},
|
||||||
Mode: swarm.ServiceMode{
|
},
|
||||||
GlobalJob: &swarm.GlobalJob{},
|
{
|
||||||
},
|
ID: "04_qux2",
|
||||||
|
Spec: swarm.ServiceSpec{
|
||||||
|
Annotations: swarm.Annotations{Name: "qux2"},
|
||||||
|
Mode: swarm.ServiceMode{
|
||||||
|
Replicated: &swarm.ReplicatedService{},
|
||||||
},
|
},
|
||||||
ServiceStatus: &swarm.ServiceStatus{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
RunningTasks: 1,
|
Placement: &swarm.Placement{MaxReplicas: 2},
|
||||||
DesiredTasks: 1,
|
|
||||||
CompletedTasks: 3,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
ServiceStatus: &swarm.ServiceStatus{
|
||||||
out := bytes.NewBufferString("")
|
RunningTasks: 3,
|
||||||
testcase.context.Output = out
|
DesiredTasks: 3,
|
||||||
err := ListFormatWrite(testcase.context, services)
|
},
|
||||||
if err != nil {
|
},
|
||||||
assert.Error(t, err, testcase.expected)
|
{
|
||||||
} else {
|
ID: "05_job1",
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
Spec: swarm.ServiceSpec{
|
||||||
}
|
Annotations: swarm.Annotations{Name: "zarp1"},
|
||||||
|
Mode: swarm.ServiceMode{
|
||||||
|
ReplicatedJob: &swarm.ReplicatedJob{
|
||||||
|
MaxConcurrent: &varThree,
|
||||||
|
TotalCompletions: &varTen,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceStatus: &swarm.ServiceStatus{
|
||||||
|
RunningTasks: 2,
|
||||||
|
DesiredTasks: 3,
|
||||||
|
CompletedTasks: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "06_job2",
|
||||||
|
Spec: swarm.ServiceSpec{
|
||||||
|
Annotations: swarm.Annotations{Name: "zarp2"},
|
||||||
|
Mode: swarm.ServiceMode{
|
||||||
|
GlobalJob: &swarm.GlobalJob{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceStatus: &swarm.ServiceStatus{
|
||||||
|
RunningTasks: 1,
|
||||||
|
DesiredTasks: 1,
|
||||||
|
CompletedTasks: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
tc := tc
|
||||||
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
tc.context.Output = &out
|
||||||
|
|
||||||
|
if err := ListFormatWrite(tc.context, services); err != nil {
|
||||||
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStackContextWrite(t *testing.T) {
|
func TestStackContextWrite(t *testing.T) {
|
||||||
|
@ -28,17 +27,17 @@ func TestStackContextWrite(t *testing.T) {
|
||||||
// Table format
|
// Table format
|
||||||
{
|
{
|
||||||
formatter.Context{Format: SwarmStackTableFormat},
|
formatter.Context{Format: SwarmStackTableFormat},
|
||||||
`NAME SERVICES ORCHESTRATOR
|
`NAME SERVICES ORCHESTRATOR
|
||||||
baz 2 orchestrator1
|
baz 2 orchestrator1
|
||||||
bar 1 orchestrator2
|
bar 1 orchestrator2
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
// Kubernetes table format adds Namespace column
|
// Kubernetes table format adds Namespace column
|
||||||
{
|
{
|
||||||
formatter.Context{Format: KubernetesStackTableFormat},
|
formatter.Context{Format: KubernetesStackTableFormat},
|
||||||
`NAME SERVICES ORCHESTRATOR NAMESPACE
|
`NAME SERVICES ORCHESTRATOR NAMESPACE
|
||||||
baz 2 orchestrator1 namespace1
|
baz 2 orchestrator1 namespace1
|
||||||
bar 1 orchestrator2 namespace2
|
bar 1 orchestrator2 namespace2
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -61,14 +60,17 @@ bar
|
||||||
{Name: "baz", Services: 2, Orchestrator: "orchestrator1", Namespace: "namespace1"},
|
{Name: "baz", Services: 2, Orchestrator: "orchestrator1", Namespace: "namespace1"},
|
||||||
{Name: "bar", Services: 1, Orchestrator: "orchestrator2", Namespace: "namespace2"},
|
{Name: "bar", Services: 1, Orchestrator: "orchestrator2", Namespace: "namespace2"},
|
||||||
}
|
}
|
||||||
for _, testcase := range cases {
|
for _, tc := range cases {
|
||||||
out := bytes.NewBufferString("")
|
tc := tc
|
||||||
testcase.context.Output = out
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
err := StackWrite(testcase.context, stacks)
|
var out bytes.Buffer
|
||||||
if err != nil {
|
tc.context.Output = &out
|
||||||
assert.Check(t, is.ErrorContains(err, testcase.expected))
|
|
||||||
} else {
|
if err := StackWrite(tc.context, stacks); err != nil {
|
||||||
assert.Check(t, is.Equal(out.String(), testcase.expected))
|
assert.Error(t, err, tc.expected)
|
||||||
}
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
NAME SERVICES ORCHESTRATOR
|
NAME SERVICES ORCHESTRATOR
|
||||||
service-name-1-foo 1 Swarm
|
service-name-1-foo 1 Swarm
|
||||||
service-name-2-foo 1 Swarm
|
service-name-2-foo 1 Swarm
|
||||||
service-name-10-foo 1 Swarm
|
service-name-10-foo 1 Swarm
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME SERVICES ORCHESTRATOR
|
NAME SERVICES ORCHESTRATOR
|
||||||
service-name-bar 1 Swarm
|
service-name-bar 1 Swarm
|
||||||
service-name-foo 1 Swarm
|
service-name-foo 1 Swarm
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
NAME SERVICES ORCHESTRATOR
|
NAME SERVICES ORCHESTRATOR
|
||||||
service-name-foo 1 Swarm
|
service-name-foo 1 Swarm
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
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
|
id-foo service-id-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
ID NAME MODE REPLICAS IMAGE PORTS
|
ID NAME MODE REPLICAS IMAGE PORTS
|
||||||
id-foo name-foo replicated 0/2 busybox:latest *:30000->3232/tcp
|
id-foo name-foo replicated 0/2 busybox:latest *:30000->3232/tcp
|
||||||
|
|
|
@ -59,27 +59,31 @@ foobar_bar foo2
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
tasks := []swarm.Task{
|
||||||
tasks := []swarm.Task{
|
{ID: "taskID1"},
|
||||||
{ID: "taskID1"},
|
{ID: "taskID2"},
|
||||||
{ID: "taskID2"},
|
}
|
||||||
}
|
names := map[string]string{
|
||||||
names := map[string]string{
|
"taskID1": "foobar_baz",
|
||||||
"taskID1": "foobar_baz",
|
"taskID2": "foobar_bar",
|
||||||
"taskID2": "foobar_bar",
|
}
|
||||||
}
|
nodes := map[string]string{
|
||||||
nodes := map[string]string{
|
"taskID1": "foo1",
|
||||||
"taskID1": "foo1",
|
"taskID2": "foo2",
|
||||||
"taskID2": "foo2",
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := FormatWrite(testcase.context, tasks, names, nodes)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err := FormatWrite(tc.context, tasks, names, nodes); err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME NODE PORTS
|
NAME NODE PORTS
|
||||||
foobar_baz foo1
|
foobar_baz foo1
|
||||||
foobar_bar foo2
|
foobar_bar foo2
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
||||||
id-bar service-name-1.1 myimage:mytag id-node Ready Failed 2 hours ago
|
id-bar service-name-1.1 myimage:mytag id-node Ready Failed 2 hours ago
|
||||||
id-foo service-name-10.1 myimage:mytag id-node Ready Failed 2 hours ago
|
id-foo service-name-10.1 myimage:mytag id-node Ready Failed 2 hours ago
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
|
||||||
id-foo service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago
|
id-foo service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago
|
||||||
id-bar \_ service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago
|
id-bar \_ service-name-foo.1 myimage:mytag node-name-bar Ready Failed 2 hours ago
|
||||||
|
|
|
@ -110,28 +110,32 @@ func TestTrustTagContextWrite(t *testing.T) {
|
||||||
formatter.Context{
|
formatter.Context{
|
||||||
Format: NewTrustTagFormat(),
|
Format: NewTrustTagFormat(),
|
||||||
},
|
},
|
||||||
`SIGNED TAG DIGEST SIGNERS
|
`SIGNED TAG DIGEST SIGNERS
|
||||||
tag1 deadbeef alice
|
tag1 deadbeef alice
|
||||||
tag2 aaaaaaaa alice, bob
|
tag2 aaaaaaaa alice, bob
|
||||||
tag3 bbbbbbbb
|
tag3 bbbbbbbb
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
signedTags := []SignedTagInfo{
|
||||||
signedTags := []SignedTagInfo{
|
{Name: "tag1", Digest: "deadbeef", Signers: []string{"alice"}},
|
||||||
{Name: "tag1", Digest: "deadbeef", Signers: []string{"alice"}},
|
{Name: "tag2", Digest: "aaaaaaaa", Signers: []string{"alice", "bob"}},
|
||||||
{Name: "tag2", Digest: "aaaaaaaa", Signers: []string{"alice", "bob"}},
|
{Name: "tag3", Digest: "bbbbbbbb", Signers: []string{}},
|
||||||
{Name: "tag3", Digest: "bbbbbbbb", Signers: []string{}},
|
}
|
||||||
}
|
|
||||||
out := bytes.NewBufferString("")
|
for _, tc := range cases {
|
||||||
testcase.context.Output = out
|
tc := tc
|
||||||
err := TagWrite(testcase.context, signedTags)
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
if err != nil {
|
var out bytes.Buffer
|
||||||
assert.Error(t, err, testcase.expected)
|
tc.context.Output = &out
|
||||||
} else {
|
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
if err := TagWrite(tc.context, signedTags); err != nil {
|
||||||
}
|
assert.Error(t, err, tc.expected)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +150,7 @@ func TestTrustTagContextEmptyWrite(t *testing.T) {
|
||||||
formatter.Context{
|
formatter.Context{
|
||||||
Format: NewTrustTagFormat(),
|
Format: NewTrustTagFormat(),
|
||||||
},
|
},
|
||||||
`SIGNED TAG DIGEST SIGNERS
|
`SIGNED TAG DIGEST SIGNERS
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +170,7 @@ func TestSignerInfoContextEmptyWrite(t *testing.T) {
|
||||||
formatter.Context{
|
formatter.Context{
|
||||||
Format: NewSignerInfoFormat(),
|
Format: NewSignerInfoFormat(),
|
||||||
},
|
},
|
||||||
`SIGNER KEYS
|
`SIGNER KEYS
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
emptySignerInfo := []SignerInfo{}
|
emptySignerInfo := []SignerInfo{}
|
||||||
|
@ -203,10 +207,10 @@ func TestSignerInfoContextWrite(t *testing.T) {
|
||||||
Format: NewSignerInfoFormat(),
|
Format: NewSignerInfoFormat(),
|
||||||
Trunc: true,
|
Trunc: true,
|
||||||
},
|
},
|
||||||
`SIGNER KEYS
|
`SIGNER KEYS
|
||||||
alice key11, key12
|
alice key11, key12
|
||||||
bob key21
|
bob key21
|
||||||
eve foobarbazqux, key31, key32
|
eve foobarbazqux, key31, key32
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
// No truncation
|
// No truncation
|
||||||
|
@ -214,27 +218,30 @@ eve foobarbazqux, key31, key32
|
||||||
formatter.Context{
|
formatter.Context{
|
||||||
Format: NewSignerInfoFormat(),
|
Format: NewSignerInfoFormat(),
|
||||||
},
|
},
|
||||||
`SIGNER KEYS
|
`SIGNER KEYS
|
||||||
alice key11, key12
|
alice key11, key12
|
||||||
bob key21
|
bob key21
|
||||||
eve foobarbazquxquux, key31, key32
|
eve foobarbazquxquux, key31, key32
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range cases {
|
signerInfo := []SignerInfo{
|
||||||
signerInfo := []SignerInfo{
|
{Name: "alice", Keys: []string{"key11", "key12"}},
|
||||||
{Name: "alice", Keys: []string{"key11", "key12"}},
|
{Name: "bob", Keys: []string{"key21"}},
|
||||||
{Name: "bob", Keys: []string{"key21"}},
|
{Name: "eve", Keys: []string{"key31", "key32", "foobarbazquxquux"}},
|
||||||
{Name: "eve", Keys: []string{"key31", "key32", "foobarbazquxquux"}},
|
}
|
||||||
}
|
for _, tc := range cases {
|
||||||
out := bytes.NewBufferString("")
|
tc := tc
|
||||||
testcase.context.Output = out
|
t.Run(string(tc.context.Format), func(t *testing.T) {
|
||||||
err := SignerInfoWrite(testcase.context, signerInfo)
|
var out bytes.Buffer
|
||||||
if err != nil {
|
tc.context.Output = &out
|
||||||
assert.Error(t, err, testcase.expected)
|
|
||||||
} else {
|
if err := SignerInfoWrite(tc.context, signerInfo); err != nil {
|
||||||
assert.Check(t, is.Equal(testcase.expected, out.String()))
|
assert.Error(t, err, tc.expected)
|
||||||
}
|
} else {
|
||||||
|
assert.Equal(t, out.String(), tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -460,10 +460,10 @@ func TestPrintSignerInfoSortOrder(t *testing.T) {
|
||||||
"signer1-foo": {"A"},
|
"signer1-foo": {"A"},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `SIGNER KEYS
|
expected := `SIGNER KEYS
|
||||||
signer1-foo A
|
signer1-foo A
|
||||||
signer2-foo B
|
signer2-foo B
|
||||||
signer10-foo C
|
signer10-foo C
|
||||||
`
|
`
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
assert.NilError(t, printSignerInfo(buf, roleToKeyIDs))
|
assert.NilError(t, printSignerInfo(buf, roleToKeyIDs))
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
Signatures for signed-repo
|
Signatures for signed-repo
|
||||||
|
|
||||||
SIGNED TAG DIGEST SIGNERS
|
SIGNED TAG DIGEST SIGNERS
|
||||||
green 677265656e2d646967657374 (Repo Admin)
|
green 677265656e2d646967657374 (Repo Admin)
|
||||||
|
|
||||||
Administrative keys for signed-repo
|
Administrative keys for signed-repo
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
Signatures for signed-repo
|
Signatures for signed-repo
|
||||||
|
|
||||||
SIGNED TAG DIGEST SIGNERS
|
SIGNED TAG DIGEST SIGNERS
|
||||||
blue 626c75652d646967657374 alice
|
blue 626c75652d646967657374 alice
|
||||||
green 677265656e2d646967657374 (Repo Admin)
|
green 677265656e2d646967657374 (Repo Admin)
|
||||||
red 7265642d646967657374 alice, bob
|
red 7265642d646967657374 alice, bob
|
||||||
|
|
||||||
List of signers and their keys for signed-repo
|
List of signers and their keys for signed-repo
|
||||||
|
|
||||||
SIGNER KEYS
|
SIGNER KEYS
|
||||||
alice A
|
alice A
|
||||||
bob B
|
bob B
|
||||||
|
|
||||||
Administrative keys for signed-repo
|
Administrative keys for signed-repo
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
Signatures for signed-repo:green
|
Signatures for signed-repo:green
|
||||||
|
|
||||||
SIGNED TAG DIGEST SIGNERS
|
SIGNED TAG DIGEST SIGNERS
|
||||||
green 677265656e2d646967657374 (Repo Admin)
|
green 677265656e2d646967657374 (Repo Admin)
|
||||||
|
|
||||||
Administrative keys for signed-repo:green
|
Administrative keys for signed-repo:green
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ No signatures for signed-repo:unsigned
|
||||||
|
|
||||||
List of signers and their keys for signed-repo:unsigned
|
List of signers and their keys for signed-repo:unsigned
|
||||||
|
|
||||||
SIGNER KEYS
|
SIGNER KEYS
|
||||||
alice A
|
alice A
|
||||||
bob B
|
bob B
|
||||||
|
|
||||||
Administrative keys for signed-repo:unsigned
|
Administrative keys for signed-repo:unsigned
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
DRIVER VOLUME NAME
|
DRIVER VOLUME NAME
|
||||||
local baz
|
local baz
|
||||||
bar foo
|
bar foo
|
||||||
local volume
|
local volume
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
|
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
|
||||||
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock https://someserver (zoinx) swarm
|
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock https://someserver (zoinx) swarm
|
||||||
remote my remote cluster ssh://someserver https://someserver (default) kubernetes
|
remote my remote cluster ssh://someserver https://someserver (default) kubernetes
|
||||||
|
|
Loading…
Reference in New Issue