master
go 443 lines 11 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package file
4
5 import (
6 "fmt"
7 "testing"
8 "time"
9
10 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
11 "github.com/netdata/netdata/go/plugins/plugin/framework/confgroup"
12
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
15 )
16
17 func TestWatcher_New(t *testing.T) {
18 tests := map[string]struct {
19 run func(t *testing.T)
20 }{
21 "string is not empty": {
22 run: func(t *testing.T) {
23 assert.NotEmpty(t, NewWatcher(confgroup.Registry{}, nil))
24 },
25 },
26 "empty inputs create watcher": {
27 run: func(t *testing.T) {
28 assert.NotNil(t, NewWatcher(confgroup.Registry{}, []string{}))
29 },
30 },
31 }
32
33 for name, tc := range tests {
34 t.Run(name, func(t *testing.T) {
35 tc.run(t)
36 })
37 }
38 }
39
40 func TestWatcher_Run(t *testing.T) {
41 tests := map[string]struct {
42 createSim func(tmp *tmpDir) discoverySim
43 }{
44 "file exists before start": {
45 createSim: func(tmp *tmpDir) discoverySim {
46 reg := confgroup.Registry{
47 "module": {},
48 }
49 cfg := sdConfig{
50 {
51 "name": "name",
52 "module": "module",
53 },
54 }
55 filename := tmp.join("module.conf")
56 discovery := prepareDiscovery(t, Config{
57 Registry: reg,
58 Watch: []string{tmp.join("*.conf")},
59 })
60 expected := []*confgroup.Group{
61 {
62 Source: filename,
63 Configs: []confgroup.Config{
64 {
65 "name": "name",
66 "module": "module",
67 "update_every": collectorapi.UpdateEvery,
68 "autodetection_retry": collectorapi.AutoDetectionRetry,
69 "priority": collectorapi.Priority,
70 "__provider__": "file watcher",
71 "__source_type__": confgroup.TypeStock,
72 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
73 },
74 },
75 },
76 }
77
78 sim := discoverySim{
79 discovery: discovery,
80 beforeRun: func() {
81 tmp.writeYAML(filename, cfg)
82 },
83 expectedGroups: expected,
84 }
85 return sim
86 },
87 },
88 "empty file": {
89 createSim: func(tmp *tmpDir) discoverySim {
90 reg := confgroup.Registry{
91 "module": {},
92 }
93 filename := tmp.join("module.conf")
94 discovery := prepareDiscovery(t, Config{
95 Registry: reg,
96 Watch: []string{tmp.join("*.conf")},
97 })
98 expected := []*confgroup.Group{
99 {
100 Source: filename,
101 },
102 }
103
104 sim := discoverySim{
105 discovery: discovery,
106 beforeRun: func() {
107 tmp.writeString(filename, "")
108 },
109 expectedGroups: expected,
110 }
111 return sim
112 },
113 },
114 "only comments, no data": {
115 createSim: func(tmp *tmpDir) discoverySim {
116 reg := confgroup.Registry{
117 "module": {},
118 }
119 filename := tmp.join("module.conf")
120 discovery := prepareDiscovery(t, Config{
121 Registry: reg,
122 Watch: []string{tmp.join("*.conf")},
123 })
124 expected := []*confgroup.Group{
125 {
126 Source: filename,
127 },
128 }
129
130 sim := discoverySim{
131 discovery: discovery,
132 beforeRun: func() {
133 tmp.writeString(filename, "# a comment")
134 },
135 expectedGroups: expected,
136 }
137 return sim
138 },
139 },
140 "add file": {
141 createSim: func(tmp *tmpDir) discoverySim {
142 reg := confgroup.Registry{
143 "module": {},
144 }
145 cfg := sdConfig{
146 {
147 "name": "name",
148 "module": "module",
149 },
150 }
151 filename := tmp.join("module.conf")
152 discovery := prepareDiscovery(t, Config{
153 Registry: reg,
154 Watch: []string{tmp.join("*.conf")},
155 })
156 expected := []*confgroup.Group{
157 {
158 Source: filename,
159 Configs: []confgroup.Config{
160 {
161 "name": "name",
162 "module": "module",
163 "update_every": collectorapi.UpdateEvery,
164 "autodetection_retry": collectorapi.AutoDetectionRetry,
165 "priority": collectorapi.Priority,
166 "__provider__": "file watcher",
167 "__source_type__": confgroup.TypeStock,
168 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
169 },
170 },
171 },
172 }
173
174 sim := discoverySim{
175 discovery: discovery,
176 afterRun: func() {
177 tmp.writeYAML(filename, cfg)
178 },
179 expectedGroups: expected,
180 }
181 return sim
182 },
183 },
184 "add file while write is still settling": {
185 createSim: func(tmp *tmpDir) discoverySim {
186 reg := confgroup.Registry{
187 "module": {},
188 }
189 cfg := sdConfig{
190 {
191 "name": "name",
192 "module": "module",
193 },
194 }
195 filename := tmp.join("module.conf")
196 discovery := prepareDiscovery(t, Config{
197 Registry: reg,
198 Watch: []string{tmp.join("*.conf")},
199 })
200 setWatcherEventSettle(t, discovery, 50*time.Millisecond)
201 expected := []*confgroup.Group{
202 {
203 Source: filename,
204 Configs: []confgroup.Config{
205 {
206 "name": "name",
207 "module": "module",
208 "update_every": collectorapi.UpdateEvery,
209 "autodetection_retry": collectorapi.AutoDetectionRetry,
210 "priority": collectorapi.Priority,
211 "__provider__": "file watcher",
212 "__source_type__": confgroup.TypeStock,
213 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
214 },
215 },
216 },
217 }
218
219 sim := discoverySim{
220 discovery: discovery,
221 afterRun: func() {
222 tmp.writeString(filename, "")
223 go func() {
224 time.Sleep(10 * time.Millisecond)
225 tmp.writeYAML(filename, cfg)
226 }()
227 time.Sleep(250 * time.Millisecond)
228 },
229 expectedGroups: expected,
230 }
231 return sim
232 },
233 },
234 "remove file": {
235 createSim: func(tmp *tmpDir) discoverySim {
236 reg := confgroup.Registry{
237 "module": {},
238 }
239 cfg := sdConfig{
240 {
241 "name": "name",
242 "module": "module",
243 },
244 }
245 filename := tmp.join("module.conf")
246 discovery := prepareDiscovery(t, Config{
247 Registry: reg,
248 Watch: []string{tmp.join("*.conf")},
249 })
250 expected := []*confgroup.Group{
251 {
252 Source: filename,
253 Configs: []confgroup.Config{
254 {
255 "name": "name",
256 "module": "module",
257 "update_every": collectorapi.UpdateEvery,
258 "autodetection_retry": collectorapi.AutoDetectionRetry,
259 "priority": collectorapi.Priority,
260 "__provider__": "file watcher",
261 "__source_type__": confgroup.TypeStock,
262 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
263 },
264 },
265 },
266 {
267 Source: filename,
268 Configs: nil,
269 },
270 }
271
272 sim := discoverySim{
273 discovery: discovery,
274 beforeRun: func() {
275 tmp.writeYAML(filename, cfg)
276 },
277 afterRun: func() {
278 tmp.removeFile(filename)
279 },
280 expectedGroups: expected,
281 }
282 return sim
283 },
284 },
285 "change file": {
286 createSim: func(tmp *tmpDir) discoverySim {
287 reg := confgroup.Registry{
288 "module": {},
289 }
290 cfgOrig := sdConfig{
291 {
292 "name": "name",
293 "module": "module",
294 },
295 }
296 cfgChanged := sdConfig{
297 {
298 "name": "name_changed",
299 "module": "module",
300 },
301 }
302 filename := tmp.join("module.conf")
303 discovery := prepareDiscovery(t, Config{
304 Registry: reg,
305 Watch: []string{tmp.join("*.conf")},
306 })
307 expected := []*confgroup.Group{
308 {
309 Source: filename,
310 Configs: []confgroup.Config{
311 {
312 "name": "name",
313 "module": "module",
314 "update_every": collectorapi.UpdateEvery,
315 "autodetection_retry": collectorapi.AutoDetectionRetry,
316 "priority": collectorapi.Priority,
317 "__provider__": "file watcher",
318 "__source_type__": confgroup.TypeStock,
319 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
320 },
321 },
322 },
323 {
324 Source: filename,
325 Configs: []confgroup.Config{
326 {
327 "name": "name_changed",
328 "module": "module",
329 "update_every": collectorapi.UpdateEvery,
330 "autodetection_retry": collectorapi.AutoDetectionRetry,
331 "priority": collectorapi.Priority,
332 "__provider__": "file watcher",
333 "__source_type__": confgroup.TypeStock,
334 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
335 },
336 },
337 },
338 }
339
340 sim := discoverySim{
341 discovery: discovery,
342 beforeRun: func() {
343 tmp.writeYAML(filename, cfgOrig)
344 },
345 afterRun: func() {
346 tmp.writeYAML(filename, cfgChanged)
347 time.Sleep(time.Millisecond * 500)
348 },
349 expectedGroups: expected,
350 }
351 return sim
352 },
353 },
354 "vim 'backupcopy=no' (writing to a file and backup)": {
355 createSim: func(tmp *tmpDir) discoverySim {
356 reg := confgroup.Registry{
357 "module": {},
358 }
359 cfg := sdConfig{
360 {
361 "name": "name",
362 "module": "module",
363 },
364 }
365 filename := tmp.join("module.conf")
366 discovery := prepareDiscovery(t, Config{
367 Registry: reg,
368 Watch: []string{tmp.join("*.conf")},
369 })
370 expected := []*confgroup.Group{
371 {
372 Source: filename,
373 Configs: []confgroup.Config{
374 {
375 "name": "name",
376 "module": "module",
377 "update_every": collectorapi.UpdateEvery,
378 "autodetection_retry": collectorapi.AutoDetectionRetry,
379 "priority": collectorapi.Priority,
380 "__provider__": "file watcher",
381 "__source_type__": confgroup.TypeStock,
382 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
383 },
384 },
385 },
386 {
387 Source: filename,
388 Configs: []confgroup.Config{
389 {
390 "name": "name",
391 "module": "module",
392 "update_every": collectorapi.UpdateEvery,
393 "autodetection_retry": collectorapi.AutoDetectionRetry,
394 "priority": collectorapi.Priority,
395 "__provider__": "file watcher",
396 "__source_type__": "stock",
397 "__source__": fmt.Sprintf("discoverer=file_watcher,file=%s", filename),
398 },
399 },
400 },
401 }
402
403 sim := discoverySim{
404 discovery: discovery,
405 beforeRun: func() {
406 tmp.writeYAML(filename, cfg)
407 },
408 afterRun: func() {
409 newFilename := filename + ".swp"
410 tmp.renameFile(filename, newFilename)
411 tmp.writeYAML(filename, cfg)
412 tmp.removeFile(newFilename)
413 time.Sleep(time.Millisecond * 500)
414 },
415 expectedGroups: expected,
416 }
417 return sim
418 },
419 },
420 }
421
422 for name, test := range tests {
423 t.Run(name, func(t *testing.T) {
424 tmp := newTmpDir(t, "watch-run-*")
425 defer tmp.cleanup()
426
427 test.createSim(tmp).run(t)
428 })
429 }
430 }
431
432 func setWatcherEventSettle(t *testing.T, discovery *Discovery, delay time.Duration) {
433 t.Helper()
434 require.NotNil(t, discovery)
435
436 for _, dd := range discovery.discoverers {
437 w, ok := dd.(*Watcher)
438 if !ok {
439 continue
440 }
441 w.eventSettle = delay
442 }
443 }