master
go 843 lines 40.5 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package docker
4
5 import (
6 "context"
7 "errors"
8 "os"
9 "testing"
10
11 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
12
13 "github.com/docker/docker/api/types"
14 typesContainer "github.com/docker/docker/api/types/container"
15 typesImage "github.com/docker/docker/api/types/image"
16 typesSystem "github.com/docker/docker/api/types/system"
17 "github.com/stretchr/testify/assert"
18 "github.com/stretchr/testify/require"
19 )
20
21 var (
22 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
23 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
24 )
25
26 func Test_testDataIsValid(t *testing.T) {
27 for name, data := range map[string][]byte{
28 "dataConfigJSON": dataConfigJSON,
29 "dataConfigYAML": dataConfigYAML,
30 } {
31 require.NotNil(t, data, name)
32 }
33 }
34
35 func TestCollector_ConfigurationSerialize(t *testing.T) {
36 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
37 }
38
39 func TestCollector_Init(t *testing.T) {
40 tests := map[string]struct {
41 config Config
42 wantFail bool
43 }{
44 "default config": {
45 wantFail: false,
46 config: New().Config,
47 },
48 "unset 'address'": {
49 wantFail: false,
50 config: Config{
51 Address: "",
52 },
53 },
54 }
55
56 for name, test := range tests {
57 t.Run(name, func(t *testing.T) {
58 collr := New()
59 collr.Config = test.config
60
61 if test.wantFail {
62 assert.Error(t, collr.Init(context.Background()))
63 } else {
64 assert.NoError(t, collr.Init(context.Background()))
65 }
66 })
67 }
68 }
69
70 func TestCollector_Charts(t *testing.T) {
71 assert.Equal(t, len(summaryCharts), len(*New().Charts()))
72 }
73
74 func TestCollector_Cleanup(t *testing.T) {
75 tests := map[string]struct {
76 prepare func(*Collector)
77 wantClose bool
78 }{
79 "after New": {
80 wantClose: false,
81 prepare: func(*Collector) {},
82 },
83 "after Init": {
84 wantClose: false,
85 prepare: func(c *Collector) { _ = c.Init(context.Background()) },
86 },
87 "after Check": {
88 wantClose: true,
89 prepare: func(c *Collector) { _ = c.Init(context.Background()); _ = c.Check(context.Background()) },
90 },
91 "after Collect": {
92 wantClose: true,
93 prepare: func(c *Collector) { _ = c.Init(context.Background()); c.Collect(context.Background()) },
94 },
95 }
96
97 for name, test := range tests {
98 t.Run(name, func(t *testing.T) {
99 m := &mockClient{}
100 collr := New()
101 collr.newClient = prepareNewClientFunc(m)
102
103 test.prepare(collr)
104
105 require.NotPanics(t, func() { collr.Cleanup(context.Background()) })
106
107 if test.wantClose {
108 assert.True(t, m.closeCalled)
109 } else {
110 assert.False(t, m.closeCalled)
111 }
112 })
113 }
114 }
115
116 func TestCollector_Check(t *testing.T) {
117 tests := map[string]struct {
118 prepare func() *Collector
119 wantFail bool
120 }{
121 "case success": {
122 wantFail: false,
123 prepare: func() *Collector {
124 return prepareCaseSuccess()
125 },
126 },
127 "case success without container size": {
128 wantFail: false,
129 prepare: func() *Collector {
130 return prepareCaseSuccessWithoutContainerSize()
131 },
132 },
133 "fail on case err on Info()": {
134 wantFail: true,
135 prepare: func() *Collector {
136 return prepareCaseErrOnInfo()
137 },
138 },
139 "fail on case err on ImageList()": {
140 wantFail: true,
141 prepare: func() *Collector {
142 return prepareCaseErrOnImageList()
143 },
144 },
145 "fail on case err on ContainerList()": {
146 wantFail: true,
147 prepare: func() *Collector {
148 return prepareCaseErrOnContainerList()
149 },
150 },
151 "fail on case err on creating Docker client": {
152 wantFail: true,
153 prepare: func() *Collector {
154 return prepareCaseErrCreatingClient()
155 },
156 },
157 }
158
159 for name, test := range tests {
160 t.Run(name, func(t *testing.T) {
161 collr := test.prepare()
162
163 require.NoError(t, collr.Init(context.Background()))
164
165 if test.wantFail {
166 assert.Error(t, collr.Check(context.Background()))
167 } else {
168 assert.NoError(t, collr.Check(context.Background()))
169 }
170 })
171 }
172 }
173
174 func TestCollector_Collect(t *testing.T) {
175 tests := map[string]struct {
176 prepare func() *Collector
177 expected map[string]int64
178 }{
179 "case success": {
180 prepare: prepareCaseSuccess,
181 expected: map[string]int64{
182 "container_container10_health_status_healthy": 0,
183 "container_container10_health_status_none": 0,
184 "container_container10_health_status_not_running_unhealthy": 1,
185 "container_container10_health_status_starting": 0,
186 "container_container10_health_status_unhealthy": 0,
187 "container_container10_size_root_fs": 0,
188 "container_container10_size_rw": 0,
189 "container_container10_state_created": 0,
190 "container_container10_state_dead": 1,
191 "container_container10_state_exited": 0,
192 "container_container10_state_paused": 0,
193 "container_container10_state_removing": 0,
194 "container_container10_state_restarting": 0,
195 "container_container10_state_running": 0,
196 "container_container11_health_status_healthy": 0,
197 "container_container11_health_status_none": 0,
198 "container_container11_health_status_not_running_unhealthy": 0,
199 "container_container11_health_status_starting": 1,
200 "container_container11_health_status_unhealthy": 0,
201 "container_container11_size_root_fs": 0,
202 "container_container11_size_rw": 0,
203 "container_container11_state_created": 0,
204 "container_container11_state_dead": 0,
205 "container_container11_state_exited": 0,
206 "container_container11_state_paused": 0,
207 "container_container11_state_removing": 1,
208 "container_container11_state_restarting": 0,
209 "container_container11_state_running": 0,
210 "container_container12_health_status_healthy": 0,
211 "container_container12_health_status_none": 0,
212 "container_container12_health_status_not_running_unhealthy": 0,
213 "container_container12_health_status_starting": 1,
214 "container_container12_health_status_unhealthy": 0,
215 "container_container12_size_root_fs": 0,
216 "container_container12_size_rw": 0,
217 "container_container12_state_created": 0,
218 "container_container12_state_dead": 0,
219 "container_container12_state_exited": 1,
220 "container_container12_state_paused": 0,
221 "container_container12_state_removing": 0,
222 "container_container12_state_restarting": 0,
223 "container_container12_state_running": 0,
224 "container_container13_health_status_healthy": 0,
225 "container_container13_health_status_none": 0,
226 "container_container13_health_status_not_running_unhealthy": 0,
227 "container_container13_health_status_starting": 1,
228 "container_container13_health_status_unhealthy": 0,
229 "container_container13_size_root_fs": 0,
230 "container_container13_size_rw": 0,
231 "container_container13_state_created": 0,
232 "container_container13_state_dead": 0,
233 "container_container13_state_exited": 1,
234 "container_container13_state_paused": 0,
235 "container_container13_state_removing": 0,
236 "container_container13_state_restarting": 0,
237 "container_container13_state_running": 0,
238 "container_container14_health_status_healthy": 0,
239 "container_container14_health_status_none": 1,
240 "container_container14_health_status_not_running_unhealthy": 0,
241 "container_container14_health_status_starting": 0,
242 "container_container14_health_status_unhealthy": 0,
243 "container_container14_size_root_fs": 0,
244 "container_container14_size_rw": 0,
245 "container_container14_state_created": 0,
246 "container_container14_state_dead": 1,
247 "container_container14_state_exited": 0,
248 "container_container14_state_paused": 0,
249 "container_container14_state_removing": 0,
250 "container_container14_state_restarting": 0,
251 "container_container14_state_running": 0,
252 "container_container15_health_status_healthy": 0,
253 "container_container15_health_status_none": 1,
254 "container_container15_health_status_not_running_unhealthy": 0,
255 "container_container15_health_status_starting": 0,
256 "container_container15_health_status_unhealthy": 0,
257 "container_container15_size_root_fs": 0,
258 "container_container15_size_rw": 0,
259 "container_container15_state_created": 0,
260 "container_container15_state_dead": 1,
261 "container_container15_state_exited": 0,
262 "container_container15_state_paused": 0,
263 "container_container15_state_removing": 0,
264 "container_container15_state_restarting": 0,
265 "container_container15_state_running": 0,
266 "container_container16_health_status_healthy": 0,
267 "container_container16_health_status_none": 1,
268 "container_container16_health_status_not_running_unhealthy": 0,
269 "container_container16_health_status_starting": 0,
270 "container_container16_health_status_unhealthy": 0,
271 "container_container16_size_root_fs": 0,
272 "container_container16_size_rw": 0,
273 "container_container16_state_created": 0,
274 "container_container16_state_dead": 1,
275 "container_container16_state_exited": 0,
276 "container_container16_state_paused": 0,
277 "container_container16_state_removing": 0,
278 "container_container16_state_restarting": 0,
279 "container_container16_state_running": 0,
280 "container_container1_health_status_healthy": 1,
281 "container_container1_health_status_none": 0,
282 "container_container1_health_status_not_running_unhealthy": 0,
283 "container_container1_health_status_starting": 0,
284 "container_container1_health_status_unhealthy": 0,
285 "container_container1_size_root_fs": 0,
286 "container_container1_size_rw": 0,
287 "container_container1_state_created": 1,
288 "container_container1_state_dead": 0,
289 "container_container1_state_exited": 0,
290 "container_container1_state_paused": 0,
291 "container_container1_state_removing": 0,
292 "container_container1_state_restarting": 0,
293 "container_container1_state_running": 0,
294 "container_container2_health_status_healthy": 1,
295 "container_container2_health_status_none": 0,
296 "container_container2_health_status_not_running_unhealthy": 0,
297 "container_container2_health_status_starting": 0,
298 "container_container2_health_status_unhealthy": 0,
299 "container_container2_size_root_fs": 0,
300 "container_container2_size_rw": 0,
301 "container_container2_state_created": 0,
302 "container_container2_state_dead": 0,
303 "container_container2_state_exited": 0,
304 "container_container2_state_paused": 0,
305 "container_container2_state_removing": 0,
306 "container_container2_state_restarting": 0,
307 "container_container2_state_running": 1,
308 "container_container3_health_status_healthy": 1,
309 "container_container3_health_status_none": 0,
310 "container_container3_health_status_not_running_unhealthy": 0,
311 "container_container3_health_status_starting": 0,
312 "container_container3_health_status_unhealthy": 0,
313 "container_container3_size_root_fs": 0,
314 "container_container3_size_rw": 0,
315 "container_container3_state_created": 0,
316 "container_container3_state_dead": 0,
317 "container_container3_state_exited": 0,
318 "container_container3_state_paused": 0,
319 "container_container3_state_removing": 0,
320 "container_container3_state_restarting": 0,
321 "container_container3_state_running": 1,
322 "container_container4_health_status_healthy": 0,
323 "container_container4_health_status_none": 0,
324 "container_container4_health_status_not_running_unhealthy": 1,
325 "container_container4_health_status_starting": 0,
326 "container_container4_health_status_unhealthy": 0,
327 "container_container4_size_root_fs": 0,
328 "container_container4_size_rw": 0,
329 "container_container4_state_created": 1,
330 "container_container4_state_dead": 0,
331 "container_container4_state_exited": 0,
332 "container_container4_state_paused": 0,
333 "container_container4_state_removing": 0,
334 "container_container4_state_restarting": 0,
335 "container_container4_state_running": 0,
336 "container_container5_health_status_healthy": 0,
337 "container_container5_health_status_none": 0,
338 "container_container5_health_status_not_running_unhealthy": 0,
339 "container_container5_health_status_starting": 0,
340 "container_container5_health_status_unhealthy": 1,
341 "container_container5_size_root_fs": 0,
342 "container_container5_size_rw": 0,
343 "container_container5_state_created": 0,
344 "container_container5_state_dead": 0,
345 "container_container5_state_exited": 0,
346 "container_container5_state_paused": 0,
347 "container_container5_state_removing": 0,
348 "container_container5_state_restarting": 0,
349 "container_container5_state_running": 1,
350 "container_container6_health_status_healthy": 0,
351 "container_container6_health_status_none": 0,
352 "container_container6_health_status_not_running_unhealthy": 1,
353 "container_container6_health_status_starting": 0,
354 "container_container6_health_status_unhealthy": 0,
355 "container_container6_size_root_fs": 0,
356 "container_container6_size_rw": 0,
357 "container_container6_state_created": 0,
358 "container_container6_state_dead": 0,
359 "container_container6_state_exited": 0,
360 "container_container6_state_paused": 1,
361 "container_container6_state_removing": 0,
362 "container_container6_state_restarting": 0,
363 "container_container6_state_running": 0,
364 "container_container7_health_status_healthy": 0,
365 "container_container7_health_status_none": 0,
366 "container_container7_health_status_not_running_unhealthy": 1,
367 "container_container7_health_status_starting": 0,
368 "container_container7_health_status_unhealthy": 0,
369 "container_container7_size_root_fs": 0,
370 "container_container7_size_rw": 0,
371 "container_container7_state_created": 0,
372 "container_container7_state_dead": 0,
373 "container_container7_state_exited": 0,
374 "container_container7_state_paused": 0,
375 "container_container7_state_removing": 0,
376 "container_container7_state_restarting": 1,
377 "container_container7_state_running": 0,
378 "container_container8_health_status_healthy": 0,
379 "container_container8_health_status_none": 0,
380 "container_container8_health_status_not_running_unhealthy": 1,
381 "container_container8_health_status_starting": 0,
382 "container_container8_health_status_unhealthy": 0,
383 "container_container8_size_root_fs": 0,
384 "container_container8_size_rw": 0,
385 "container_container8_state_created": 0,
386 "container_container8_state_dead": 0,
387 "container_container8_state_exited": 0,
388 "container_container8_state_paused": 0,
389 "container_container8_state_removing": 1,
390 "container_container8_state_restarting": 0,
391 "container_container8_state_running": 0,
392 "container_container9_health_status_healthy": 0,
393 "container_container9_health_status_none": 0,
394 "container_container9_health_status_not_running_unhealthy": 1,
395 "container_container9_health_status_starting": 0,
396 "container_container9_health_status_unhealthy": 0,
397 "container_container9_size_root_fs": 0,
398 "container_container9_size_rw": 0,
399 "container_container9_state_created": 0,
400 "container_container9_state_dead": 0,
401 "container_container9_state_exited": 1,
402 "container_container9_state_paused": 0,
403 "container_container9_state_removing": 0,
404 "container_container9_state_restarting": 0,
405 "container_container9_state_running": 0,
406 "containers_health_status_healthy": 3,
407 "containers_health_status_none": 4,
408 "containers_health_status_not_running_unhealthy": 6,
409 "containers_health_status_starting": 3,
410 "containers_health_status_unhealthy": 1,
411 "containers_state_exited": 6,
412 "containers_state_paused": 5,
413 "containers_state_running": 4,
414 "images_active": 1,
415 "images_dangling": 1,
416 "images_size": 300,
417 },
418 },
419 "case success without container size": {
420 prepare: prepareCaseSuccessWithoutContainerSize,
421 expected: map[string]int64{
422 "container_container10_health_status_healthy": 0,
423 "container_container10_health_status_none": 0,
424 "container_container10_health_status_not_running_unhealthy": 1,
425 "container_container10_health_status_starting": 0,
426 "container_container10_health_status_unhealthy": 0,
427 "container_container10_size_root_fs": 0,
428 "container_container10_size_rw": 0,
429 "container_container10_state_created": 0,
430 "container_container10_state_dead": 1,
431 "container_container10_state_exited": 0,
432 "container_container10_state_paused": 0,
433 "container_container10_state_removing": 0,
434 "container_container10_state_restarting": 0,
435 "container_container10_state_running": 0,
436 "container_container11_health_status_healthy": 0,
437 "container_container11_health_status_none": 0,
438 "container_container11_health_status_not_running_unhealthy": 0,
439 "container_container11_health_status_starting": 1,
440 "container_container11_health_status_unhealthy": 0,
441 "container_container11_size_root_fs": 0,
442 "container_container11_size_rw": 0,
443 "container_container11_state_created": 0,
444 "container_container11_state_dead": 0,
445 "container_container11_state_exited": 0,
446 "container_container11_state_paused": 0,
447 "container_container11_state_removing": 1,
448 "container_container11_state_restarting": 0,
449 "container_container11_state_running": 0,
450 "container_container12_health_status_healthy": 0,
451 "container_container12_health_status_none": 0,
452 "container_container12_health_status_not_running_unhealthy": 0,
453 "container_container12_health_status_starting": 1,
454 "container_container12_health_status_unhealthy": 0,
455 "container_container12_size_root_fs": 0,
456 "container_container12_size_rw": 0,
457 "container_container12_state_created": 0,
458 "container_container12_state_dead": 0,
459 "container_container12_state_exited": 1,
460 "container_container12_state_paused": 0,
461 "container_container12_state_removing": 0,
462 "container_container12_state_restarting": 0,
463 "container_container12_state_running": 0,
464 "container_container13_health_status_healthy": 0,
465 "container_container13_health_status_none": 0,
466 "container_container13_health_status_not_running_unhealthy": 0,
467 "container_container13_health_status_starting": 1,
468 "container_container13_health_status_unhealthy": 0,
469 "container_container13_size_root_fs": 0,
470 "container_container13_size_rw": 0,
471 "container_container13_state_created": 0,
472 "container_container13_state_dead": 0,
473 "container_container13_state_exited": 1,
474 "container_container13_state_paused": 0,
475 "container_container13_state_removing": 0,
476 "container_container13_state_restarting": 0,
477 "container_container13_state_running": 0,
478 "container_container14_health_status_healthy": 0,
479 "container_container14_health_status_none": 1,
480 "container_container14_health_status_not_running_unhealthy": 0,
481 "container_container14_health_status_starting": 0,
482 "container_container14_health_status_unhealthy": 0,
483 "container_container14_size_root_fs": 0,
484 "container_container14_size_rw": 0,
485 "container_container14_state_created": 0,
486 "container_container14_state_dead": 1,
487 "container_container14_state_exited": 0,
488 "container_container14_state_paused": 0,
489 "container_container14_state_removing": 0,
490 "container_container14_state_restarting": 0,
491 "container_container14_state_running": 0,
492 "container_container15_health_status_healthy": 0,
493 "container_container15_health_status_none": 1,
494 "container_container15_health_status_not_running_unhealthy": 0,
495 "container_container15_health_status_starting": 0,
496 "container_container15_health_status_unhealthy": 0,
497 "container_container15_size_root_fs": 0,
498 "container_container15_size_rw": 0,
499 "container_container15_state_created": 0,
500 "container_container15_state_dead": 1,
501 "container_container15_state_exited": 0,
502 "container_container15_state_paused": 0,
503 "container_container15_state_removing": 0,
504 "container_container15_state_restarting": 0,
505 "container_container15_state_running": 0,
506 "container_container16_health_status_healthy": 0,
507 "container_container16_health_status_none": 1,
508 "container_container16_health_status_not_running_unhealthy": 0,
509 "container_container16_health_status_starting": 0,
510 "container_container16_health_status_unhealthy": 0,
511 "container_container16_size_root_fs": 0,
512 "container_container16_size_rw": 0,
513 "container_container16_state_created": 0,
514 "container_container16_state_dead": 1,
515 "container_container16_state_exited": 0,
516 "container_container16_state_paused": 0,
517 "container_container16_state_removing": 0,
518 "container_container16_state_restarting": 0,
519 "container_container16_state_running": 0,
520 "container_container1_health_status_healthy": 1,
521 "container_container1_health_status_none": 0,
522 "container_container1_health_status_not_running_unhealthy": 0,
523 "container_container1_health_status_starting": 0,
524 "container_container1_health_status_unhealthy": 0,
525 "container_container1_size_root_fs": 0,
526 "container_container1_size_rw": 0,
527 "container_container1_state_created": 1,
528 "container_container1_state_dead": 0,
529 "container_container1_state_exited": 0,
530 "container_container1_state_paused": 0,
531 "container_container1_state_removing": 0,
532 "container_container1_state_restarting": 0,
533 "container_container1_state_running": 0,
534 "container_container2_health_status_healthy": 1,
535 "container_container2_health_status_none": 0,
536 "container_container2_health_status_not_running_unhealthy": 0,
537 "container_container2_health_status_starting": 0,
538 "container_container2_health_status_unhealthy": 0,
539 "container_container2_size_root_fs": 0,
540 "container_container2_size_rw": 0,
541 "container_container2_state_created": 0,
542 "container_container2_state_dead": 0,
543 "container_container2_state_exited": 0,
544 "container_container2_state_paused": 0,
545 "container_container2_state_removing": 0,
546 "container_container2_state_restarting": 0,
547 "container_container2_state_running": 1,
548 "container_container3_health_status_healthy": 1,
549 "container_container3_health_status_none": 0,
550 "container_container3_health_status_not_running_unhealthy": 0,
551 "container_container3_health_status_starting": 0,
552 "container_container3_health_status_unhealthy": 0,
553 "container_container3_size_root_fs": 0,
554 "container_container3_size_rw": 0,
555 "container_container3_state_created": 0,
556 "container_container3_state_dead": 0,
557 "container_container3_state_exited": 0,
558 "container_container3_state_paused": 0,
559 "container_container3_state_removing": 0,
560 "container_container3_state_restarting": 0,
561 "container_container3_state_running": 1,
562 "container_container4_health_status_healthy": 0,
563 "container_container4_health_status_none": 0,
564 "container_container4_health_status_not_running_unhealthy": 1,
565 "container_container4_health_status_starting": 0,
566 "container_container4_health_status_unhealthy": 0,
567 "container_container4_size_root_fs": 0,
568 "container_container4_size_rw": 0,
569 "container_container4_state_created": 1,
570 "container_container4_state_dead": 0,
571 "container_container4_state_exited": 0,
572 "container_container4_state_paused": 0,
573 "container_container4_state_removing": 0,
574 "container_container4_state_restarting": 0,
575 "container_container4_state_running": 0,
576 "container_container5_health_status_healthy": 0,
577 "container_container5_health_status_none": 0,
578 "container_container5_health_status_not_running_unhealthy": 0,
579 "container_container5_health_status_starting": 0,
580 "container_container5_health_status_unhealthy": 1,
581 "container_container5_size_root_fs": 0,
582 "container_container5_size_rw": 0,
583 "container_container5_state_created": 0,
584 "container_container5_state_dead": 0,
585 "container_container5_state_exited": 0,
586 "container_container5_state_paused": 0,
587 "container_container5_state_removing": 0,
588 "container_container5_state_restarting": 0,
589 "container_container5_state_running": 1,
590 "container_container6_health_status_healthy": 0,
591 "container_container6_health_status_none": 0,
592 "container_container6_health_status_not_running_unhealthy": 1,
593 "container_container6_health_status_starting": 0,
594 "container_container6_health_status_unhealthy": 0,
595 "container_container6_size_root_fs": 0,
596 "container_container6_size_rw": 0,
597 "container_container6_state_created": 0,
598 "container_container6_state_dead": 0,
599 "container_container6_state_exited": 0,
600 "container_container6_state_paused": 1,
601 "container_container6_state_removing": 0,
602 "container_container6_state_restarting": 0,
603 "container_container6_state_running": 0,
604 "container_container7_health_status_healthy": 0,
605 "container_container7_health_status_none": 0,
606 "container_container7_health_status_not_running_unhealthy": 1,
607 "container_container7_health_status_starting": 0,
608 "container_container7_health_status_unhealthy": 0,
609 "container_container7_size_root_fs": 0,
610 "container_container7_size_rw": 0,
611 "container_container7_state_created": 0,
612 "container_container7_state_dead": 0,
613 "container_container7_state_exited": 0,
614 "container_container7_state_paused": 0,
615 "container_container7_state_removing": 0,
616 "container_container7_state_restarting": 1,
617 "container_container7_state_running": 0,
618 "container_container8_health_status_healthy": 0,
619 "container_container8_health_status_none": 0,
620 "container_container8_health_status_not_running_unhealthy": 1,
621 "container_container8_health_status_starting": 0,
622 "container_container8_health_status_unhealthy": 0,
623 "container_container8_size_root_fs": 0,
624 "container_container8_size_rw": 0,
625 "container_container8_state_created": 0,
626 "container_container8_state_dead": 0,
627 "container_container8_state_exited": 0,
628 "container_container8_state_paused": 0,
629 "container_container8_state_removing": 1,
630 "container_container8_state_restarting": 0,
631 "container_container8_state_running": 0,
632 "container_container9_health_status_healthy": 0,
633 "container_container9_health_status_none": 0,
634 "container_container9_health_status_not_running_unhealthy": 1,
635 "container_container9_health_status_starting": 0,
636 "container_container9_health_status_unhealthy": 0,
637 "container_container9_size_root_fs": 0,
638 "container_container9_size_rw": 0,
639 "container_container9_state_created": 0,
640 "container_container9_state_dead": 0,
641 "container_container9_state_exited": 1,
642 "container_container9_state_paused": 0,
643 "container_container9_state_removing": 0,
644 "container_container9_state_restarting": 0,
645 "container_container9_state_running": 0,
646 "containers_health_status_healthy": 3,
647 "containers_health_status_none": 4,
648 "containers_health_status_not_running_unhealthy": 6,
649 "containers_health_status_starting": 3,
650 "containers_health_status_unhealthy": 1,
651 "containers_state_exited": 6,
652 "containers_state_paused": 5,
653 "containers_state_running": 4,
654 "images_active": 1,
655 "images_dangling": 1,
656 "images_size": 300,
657 },
658 },
659 "fail on case err on Info()": {
660 prepare: prepareCaseErrOnInfo,
661 expected: nil,
662 },
663 "fail on case err on ImageList()": {
664 prepare: prepareCaseErrOnImageList,
665 expected: nil,
666 },
667 "fail on case err on ContainerList()": {
668 prepare: prepareCaseErrOnContainerList,
669 expected: nil,
670 },
671 "fail on case err on creating Docker client": {
672 prepare: prepareCaseErrCreatingClient,
673 expected: nil,
674 },
675 }
676
677 for name, test := range tests {
678 t.Run(name, func(t *testing.T) {
679 collr := test.prepare()
680
681 require.NoError(t, collr.Init(context.Background()))
682
683 mx := collr.Collect(context.Background())
684
685 require.Equal(t, test.expected, mx)
686
687 if collr.client != nil {
688 m, ok := collr.client.(*mockClient)
689 require.True(t, ok)
690 require.True(t, m.negotiateAPIVersionCalled)
691 }
692
693 })
694 }
695 }
696
697 func prepareCaseSuccess() *Collector {
698 collr := New()
699 collr.CollectContainerSize = true
700 collr.newClient = prepareNewClientFunc(&mockClient{})
701 return collr
702 }
703
704 func prepareCaseSuccessWithoutContainerSize() *Collector {
705 collr := New()
706 collr.CollectContainerSize = false
707 collr.newClient = prepareNewClientFunc(&mockClient{})
708 return collr
709 }
710
711 func prepareCaseErrOnInfo() *Collector {
712 collr := New()
713 collr.newClient = prepareNewClientFunc(&mockClient{errOnInfo: true})
714 return collr
715 }
716
717 func prepareCaseErrOnImageList() *Collector {
718 collr := New()
719 collr.newClient = prepareNewClientFunc(&mockClient{errOnImageList: true})
720 return collr
721 }
722
723 func prepareCaseErrOnContainerList() *Collector {
724 collr := New()
725 collr.newClient = prepareNewClientFunc(&mockClient{errOnContainerList: true})
726 return collr
727 }
728
729 func prepareCaseErrCreatingClient() *Collector {
730 collr := New()
731 collr.newClient = prepareNewClientFunc(nil)
732 return collr
733 }
734
735 func prepareNewClientFunc(m *mockClient) func(_ Config) (dockerClient, error) {
736 if m == nil {
737 return func(_ Config) (dockerClient, error) { return nil, errors.New("mock.newClient() error") }
738 }
739 return func(_ Config) (dockerClient, error) { return m, nil }
740 }
741
742 type mockClient struct {
743 errOnInfo bool
744 errOnImageList bool
745 errOnContainerList bool
746 negotiateAPIVersionCalled bool
747 closeCalled bool
748 }
749
750 func (m *mockClient) Info(_ context.Context) (typesSystem.Info, error) {
751 if m.errOnInfo {
752 return typesSystem.Info{}, errors.New("mockClient.Info() error")
753 }
754
755 return typesSystem.Info{
756 ContainersRunning: 4,
757 ContainersPaused: 5,
758 ContainersStopped: 6,
759 }, nil
760 }
761
762 func (m *mockClient) ContainerList(_ context.Context, opts typesContainer.ListOptions) ([]types.Container, error) {
763 if m.errOnContainerList {
764 return nil, errors.New("mockClient.ContainerList() error")
765 }
766
767 v := opts.Filters.Get("health")
768
769 if len(v) == 0 {
770 return nil, errors.New("mockClient.ContainerList() error (expect 'health' filter)")
771 }
772
773 var containers []types.Container
774
775 switch v[0] {
776 case types.Healthy:
777 containers = []types.Container{
778 {Names: []string{"container1"}, State: "created", Image: "example/example:v1"},
779 {Names: []string{"container2"}, State: "running", Image: "example/example:v1"},
780 {Names: []string{"container3"}, State: "running", Image: "example/example:v1"},
781 }
782 case types.Unhealthy:
783 containers = []types.Container{
784 {Names: []string{"container4"}, State: "created", Image: "example/example:v2"},
785 {Names: []string{"container5"}, State: "running", Image: "example/example:v2"},
786 {Names: []string{"container6"}, State: "paused", Image: "example/example:v2"},
787 {Names: []string{"container7"}, State: "restarting", Image: "example/example:v2"},
788 {Names: []string{"container8"}, State: "removing", Image: "example/example:v2"},
789 {Names: []string{"container9"}, State: "exited", Image: "example/example:v2"},
790 {Names: []string{"container10"}, State: "dead", Image: "example/example:v2"},
791 }
792 case types.Starting:
793 containers = []types.Container{
794 {Names: []string{"container11"}, State: "removing", Image: "example/example:v3"},
795 {Names: []string{"container12"}, State: "exited", Image: "example/example:v3"},
796 {Names: []string{"container13"}, State: "exited", Image: "example/example:v3"},
797 }
798 case types.NoHealthcheck:
799 containers = []types.Container{
800 {Names: []string{"container14"}, State: "dead", Image: "example/example:v4"},
801 {Names: []string{"container15"}, State: "dead", Image: "example/example:v4"},
802 {Names: []string{"container16"}, State: "dead", Image: "example/example:v4"},
803 {Names: []string{"container17"}, State: "dead", Image: "example/example:v4",
804 Labels: map[string]string{"netdata.cloud/ignore": "true"},
805 },
806 }
807 }
808
809 if opts.Size {
810 for _, c := range containers {
811 c.SizeRw = 123
812 c.SizeRootFs = 321
813 }
814 }
815
816 return containers, nil
817 }
818
819 func (m *mockClient) ImageList(_ context.Context, _ typesImage.ListOptions) ([]typesImage.Summary, error) {
820 if m.errOnImageList {
821 return nil, errors.New("mockClient.ImageList() error")
822 }
823
824 return []typesImage.Summary{
825 {
826 Containers: 0,
827 Size: 100,
828 },
829 {
830 Containers: 1,
831 Size: 200,
832 },
833 }, nil
834 }
835
836 func (m *mockClient) NegotiateAPIVersion(_ context.Context) {
837 m.negotiateAPIVersionCalled = true
838 }
839
840 func (m *mockClient) Close() error {
841 m.closeCalled = true
842 return nil
843 }