Files
docker-cli/components/engine/cli/command/formatter/stats_test.go
Yong Tang 190522d7df Fix Windows docker stats showing Linux headers
This fix is an attempt to fix issue raised in #28005 where
`docker stats` on Windows shows Linux headers if there is
no containers in stats.

The reason for the issue is that, in case there is no container,
a header is faked in:
https://github.com/docker/docker/blob/v1.13.0/cli/command/formatter/formatter.go#L74-L78
which does not know OS type information (as OS was stored with container stat entries)

This fix tries to fix the issue by moving OS type information
to stats context (instead of individual container stats entry).

Additional unit tests have been added.

This fix fixes #28005.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Upstream-commit: 0a3a3ba2b62a5720d949e93fd580d3cf797cfa9e
Component: engine
2017-02-05 08:55:30 -08:00

264 lines
6.2 KiB
Go

package formatter
import (
"bytes"
"testing"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/testutil/assert"
)
func TestContainerStatsContext(t *testing.T) {
containerID := stringid.GenerateRandomID()
var ctx containerStatsContext
tt := []struct {
stats StatsEntry
osType string
expValue string
expHeader string
call func() string
}{
{StatsEntry{Container: containerID}, "", containerID, containerHeader, ctx.Container},
{StatsEntry{CPUPercentage: 5.5}, "", "5.50%", cpuPercHeader, ctx.CPUPerc},
{StatsEntry{CPUPercentage: 5.5, IsInvalid: true}, "", "--", cpuPercHeader, ctx.CPUPerc},
{StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3}, "", "0.31 B / 12.3 B", netIOHeader, ctx.NetIO},
{StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3, IsInvalid: true}, "", "--", netIOHeader, ctx.NetIO},
{StatsEntry{BlockRead: 0.1, BlockWrite: 2.3}, "", "0.1 B / 2.3 B", blockIOHeader, ctx.BlockIO},
{StatsEntry{BlockRead: 0.1, BlockWrite: 2.3, IsInvalid: true}, "", "--", blockIOHeader, ctx.BlockIO},
{StatsEntry{MemoryPercentage: 10.2}, "", "10.20%", memPercHeader, ctx.MemPerc},
{StatsEntry{MemoryPercentage: 10.2, IsInvalid: true}, "", "--", memPercHeader, ctx.MemPerc},
{StatsEntry{MemoryPercentage: 10.2}, "windows", "--", memPercHeader, ctx.MemPerc},
{StatsEntry{Memory: 24, MemoryLimit: 30}, "", "24 B / 30 B", memUseHeader, ctx.MemUsage},
{StatsEntry{Memory: 24, MemoryLimit: 30, IsInvalid: true}, "", "-- / --", memUseHeader, ctx.MemUsage},
{StatsEntry{Memory: 24, MemoryLimit: 30}, "windows", "24 B", winMemUseHeader, ctx.MemUsage},
{StatsEntry{PidsCurrent: 10}, "", "10", pidsHeader, ctx.PIDs},
{StatsEntry{PidsCurrent: 10, IsInvalid: true}, "", "--", pidsHeader, ctx.PIDs},
{StatsEntry{PidsCurrent: 10}, "windows", "--", pidsHeader, ctx.PIDs},
}
for _, te := range tt {
ctx = containerStatsContext{s: te.stats, os: te.osType}
if v := te.call(); v != te.expValue {
t.Fatalf("Expected %q, got %q", te.expValue, v)
}
h := ctx.FullHeader()
if h != te.expHeader {
t.Fatalf("Expected %q, got %q", te.expHeader, h)
}
}
}
func TestContainerStatsContextWrite(t *testing.T) {
tt := []struct {
context Context
expected string
}{
{
Context{Format: "{{InvalidFunction}}"},
`Template parsing error: template: :1: function "InvalidFunction" not defined
`,
},
{
Context{Format: "{{nil}}"},
`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
`,
},
{
Context{Format: "table {{.MemUsage}}"},
`MEM USAGE / LIMIT
20 B / 20 B
-- / --
`,
},
{
Context{Format: "{{.Container}} {{.CPUPerc}}"},
`container1 20.00%
container2 --
`,
},
}
for _, te := range tt {
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,
},
}
var out bytes.Buffer
te.context.Output = &out
err := ContainerStatsWrite(te.context, stats, "linux")
if err != nil {
assert.Error(t, err, te.expected)
} else {
assert.Equal(t, out.String(), te.expected)
}
}
}
func TestContainerStatsContextWriteWindows(t *testing.T) {
tt := []struct {
context Context
expected string
}{
{
Context{Format: "table {{.MemUsage}}"},
`PRIV WORKING SET
20 B
-- / --
`,
},
{
Context{Format: "{{.Container}} {{.CPUPerc}}"},
`container1 20.00%
container2 --
`,
},
{
Context{Format: "{{.Container}} {{.MemPerc}} {{.PIDs}}"},
`container1 -- --
container2 -- --
`,
},
}
for _, te := range tt {
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,
},
}
var out bytes.Buffer
te.context.Output = &out
err := ContainerStatsWrite(te.context, stats, "windows")
if err != nil {
assert.Error(t, err, te.expected)
} else {
assert.Equal(t, out.String(), te.expected)
}
}
}
func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
var out bytes.Buffer
contexts := []struct {
context Context
expected string
}{
{
Context{
Format: "{{.Container}}",
Output: &out,
},
"",
},
{
Context{
Format: "table {{.Container}}",
Output: &out,
},
"CONTAINER\n",
},
{
Context{
Format: "table {{.Container}}\t{{.CPUPerc}}",
Output: &out,
},
"CONTAINER CPU %\n",
},
}
for _, context := range contexts {
ContainerStatsWrite(context.context, []StatsEntry{}, "linux")
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}
}
func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
var out bytes.Buffer
contexts := []struct {
context Context
expected string
}{
{
Context{
Format: "{{.Container}}",
Output: &out,
},
"",
},
{
Context{
Format: "table {{.Container}}\t{{.MemUsage}}",
Output: &out,
},
"CONTAINER PRIV WORKING SET\n",
},
{
Context{
Format: "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}",
Output: &out,
},
"CONTAINER CPU % PRIV WORKING SET\n",
},
}
for _, context := range contexts {
ContainerStatsWrite(context.context, []StatsEntry{}, "windows")
assert.Equal(t, out.String(), context.expected)
// Clean buffer
out.Reset()
}
}