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