github.com/cspotcode/docker-cli@v20.10.0-rc1.0.20201201121459-3faad7acc5b8+incompatible/cli/command/container/formatter_stats_test.go (about) 1 package container 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/docker/cli/cli/command/formatter" 8 "github.com/docker/docker/pkg/stringid" 9 "gotest.tools/v3/assert" 10 is "gotest.tools/v3/assert/cmp" 11 ) 12 13 func TestContainerStatsContext(t *testing.T) { 14 containerID := stringid.GenerateRandomID() 15 16 var ctx statsContext 17 tt := []struct { 18 stats StatsEntry 19 osType string 20 expValue string 21 expHeader string 22 call func() string 23 }{ 24 {StatsEntry{Container: containerID}, "", containerID, containerHeader, ctx.Container}, 25 {StatsEntry{CPUPercentage: 5.5}, "", "5.50%", cpuPercHeader, ctx.CPUPerc}, 26 {StatsEntry{CPUPercentage: 5.5, IsInvalid: true}, "", "--", cpuPercHeader, ctx.CPUPerc}, 27 {StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3}, "", "0.31B / 12.3B", netIOHeader, ctx.NetIO}, 28 {StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3, IsInvalid: true}, "", "--", netIOHeader, ctx.NetIO}, 29 {StatsEntry{BlockRead: 0.1, BlockWrite: 2.3}, "", "0.1B / 2.3B", blockIOHeader, ctx.BlockIO}, 30 {StatsEntry{BlockRead: 0.1, BlockWrite: 2.3, IsInvalid: true}, "", "--", blockIOHeader, ctx.BlockIO}, 31 {StatsEntry{MemoryPercentage: 10.2}, "", "10.20%", memPercHeader, ctx.MemPerc}, 32 {StatsEntry{MemoryPercentage: 10.2, IsInvalid: true}, "", "--", memPercHeader, ctx.MemPerc}, 33 {StatsEntry{MemoryPercentage: 10.2}, "windows", "--", memPercHeader, ctx.MemPerc}, 34 {StatsEntry{Memory: 24, MemoryLimit: 30}, "", "24B / 30B", memUseHeader, ctx.MemUsage}, 35 {StatsEntry{Memory: 24, MemoryLimit: 30, IsInvalid: true}, "", "-- / --", memUseHeader, ctx.MemUsage}, 36 {StatsEntry{Memory: 24, MemoryLimit: 30}, "windows", "24B", winMemUseHeader, ctx.MemUsage}, 37 {StatsEntry{PidsCurrent: 10}, "", "10", pidsHeader, ctx.PIDs}, 38 {StatsEntry{PidsCurrent: 10, IsInvalid: true}, "", "--", pidsHeader, ctx.PIDs}, 39 {StatsEntry{PidsCurrent: 10}, "windows", "--", pidsHeader, ctx.PIDs}, 40 } 41 42 for _, te := range tt { 43 ctx = statsContext{s: te.stats, os: te.osType} 44 if v := te.call(); v != te.expValue { 45 t.Fatalf("Expected %q, got %q", te.expValue, v) 46 } 47 } 48 } 49 50 func TestContainerStatsContextWrite(t *testing.T) { 51 tt := []struct { 52 context formatter.Context 53 expected string 54 }{ 55 { 56 formatter.Context{Format: "{{InvalidFunction}}"}, 57 `Template parsing error: template: :1: function "InvalidFunction" not defined 58 `, 59 }, 60 { 61 formatter.Context{Format: "{{nil}}"}, 62 `Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command 63 `, 64 }, 65 { 66 formatter.Context{Format: "table {{.MemUsage}}"}, 67 `MEM USAGE / LIMIT 68 20B / 20B 69 -- / -- 70 `, 71 }, 72 { 73 formatter.Context{Format: "{{.Container}} {{.ID}} {{.Name}}"}, 74 `container1 abcdef foo 75 container2 -- 76 `, 77 }, 78 { 79 formatter.Context{Format: "{{.Container}} {{.CPUPerc}}"}, 80 `container1 20.00% 81 container2 -- 82 `, 83 }, 84 } 85 86 for _, te := range tt { 87 stats := []StatsEntry{ 88 { 89 Container: "container1", 90 ID: "abcdef", 91 Name: "/foo", 92 CPUPercentage: 20, 93 Memory: 20, 94 MemoryLimit: 20, 95 MemoryPercentage: 20, 96 NetworkRx: 20, 97 NetworkTx: 20, 98 BlockRead: 20, 99 BlockWrite: 20, 100 PidsCurrent: 2, 101 IsInvalid: false, 102 }, 103 { 104 Container: "container2", 105 CPUPercentage: 30, 106 Memory: 30, 107 MemoryLimit: 30, 108 MemoryPercentage: 30, 109 NetworkRx: 30, 110 NetworkTx: 30, 111 BlockRead: 30, 112 BlockWrite: 30, 113 PidsCurrent: 3, 114 IsInvalid: true, 115 }, 116 } 117 var out bytes.Buffer 118 te.context.Output = &out 119 err := statsFormatWrite(te.context, stats, "linux", false) 120 if err != nil { 121 assert.Error(t, err, te.expected) 122 } else { 123 assert.Check(t, is.Equal(te.expected, out.String())) 124 } 125 } 126 } 127 128 func TestContainerStatsContextWriteWindows(t *testing.T) { 129 cases := []struct { 130 context formatter.Context 131 expected string 132 }{ 133 { 134 formatter.Context{Format: "table {{.MemUsage}}"}, 135 `PRIV WORKING SET 136 20B 137 -- / -- 138 `, 139 }, 140 { 141 formatter.Context{Format: "{{.Container}} {{.CPUPerc}}"}, 142 `container1 20.00% 143 container2 -- 144 `, 145 }, 146 { 147 formatter.Context{Format: "{{.Container}} {{.MemPerc}} {{.PIDs}}"}, 148 `container1 -- -- 149 container2 -- -- 150 `, 151 }, 152 } 153 stats := []StatsEntry{ 154 { 155 Container: "container1", 156 CPUPercentage: 20, 157 Memory: 20, 158 MemoryLimit: 20, 159 MemoryPercentage: 20, 160 NetworkRx: 20, 161 NetworkTx: 20, 162 BlockRead: 20, 163 BlockWrite: 20, 164 PidsCurrent: 2, 165 IsInvalid: false, 166 }, 167 { 168 Container: "container2", 169 CPUPercentage: 30, 170 Memory: 30, 171 MemoryLimit: 30, 172 MemoryPercentage: 30, 173 NetworkRx: 30, 174 NetworkTx: 30, 175 BlockRead: 30, 176 BlockWrite: 30, 177 PidsCurrent: 3, 178 IsInvalid: true, 179 }, 180 } 181 182 for _, tc := range cases { 183 tc := tc 184 t.Run(string(tc.context.Format), func(t *testing.T) { 185 var out bytes.Buffer 186 tc.context.Output = &out 187 err := statsFormatWrite(tc.context, stats, "windows", false) 188 if err != nil { 189 assert.Error(t, err, tc.expected) 190 } else { 191 assert.Equal(t, out.String(), tc.expected) 192 } 193 }) 194 } 195 } 196 197 func TestContainerStatsContextWriteWithNoStats(t *testing.T) { 198 var out bytes.Buffer 199 200 cases := []struct { 201 context formatter.Context 202 expected string 203 }{ 204 { 205 formatter.Context{ 206 Format: "{{.Container}}", 207 Output: &out, 208 }, 209 "", 210 }, 211 { 212 formatter.Context{ 213 Format: "table {{.Container}}", 214 Output: &out, 215 }, 216 "CONTAINER\n", 217 }, 218 { 219 formatter.Context{ 220 Format: "table {{.Container}}\t{{.CPUPerc}}", 221 Output: &out, 222 }, 223 "CONTAINER CPU %\n", 224 }, 225 } 226 227 for _, tc := range cases { 228 tc := tc 229 t.Run(string(tc.context.Format), func(t *testing.T) { 230 err := statsFormatWrite(tc.context, []StatsEntry{}, "linux", false) 231 assert.NilError(t, err) 232 assert.Equal(t, out.String(), tc.expected) 233 // Clean buffer 234 out.Reset() 235 }) 236 } 237 } 238 239 func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) { 240 var out bytes.Buffer 241 242 cases := []struct { 243 context formatter.Context 244 expected string 245 }{ 246 { 247 formatter.Context{ 248 Format: "{{.Container}}", 249 Output: &out, 250 }, 251 "", 252 }, 253 { 254 formatter.Context{ 255 Format: "table {{.Container}}\t{{.MemUsage}}", 256 Output: &out, 257 }, 258 "CONTAINER PRIV WORKING SET\n", 259 }, 260 { 261 formatter.Context{ 262 Format: "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}", 263 Output: &out, 264 }, 265 "CONTAINER CPU % PRIV WORKING SET\n", 266 }, 267 } 268 269 for _, tc := range cases { 270 tc := tc 271 t.Run(string(tc.context.Format), func(t *testing.T) { 272 err := statsFormatWrite(tc.context, []StatsEntry{}, "windows", false) 273 assert.NilError(t, err) 274 assert.Equal(t, out.String(), tc.expected) 275 out.Reset() 276 }) 277 } 278 } 279 280 func TestContainerStatsContextWriteTrunc(t *testing.T) { 281 var out bytes.Buffer 282 283 contexts := []struct { 284 context formatter.Context 285 trunc bool 286 expected string 287 }{ 288 { 289 formatter.Context{ 290 Format: "{{.ID}}", 291 Output: &out, 292 }, 293 false, 294 "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc\n", 295 }, 296 { 297 formatter.Context{ 298 Format: "{{.ID}}", 299 Output: &out, 300 }, 301 true, 302 "b95a83497c91\n", 303 }, 304 } 305 306 for _, context := range contexts { 307 statsFormatWrite(context.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", context.trunc) 308 assert.Check(t, is.Equal(context.expected, out.String())) 309 // Clean buffer 310 out.Reset() 311 } 312 }