Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/metrics/instance/group_manager_test.go
4094 views
1
package instance
2
3
import (
4
"fmt"
5
"strings"
6
"testing"
7
8
"github.com/stretchr/testify/require"
9
)
10
11
func TestGroupManager_ListInstances_Configs(t *testing.T) {
12
gm := NewGroupManager(newFakeManager())
13
14
// Create two configs in the same group and one in another
15
// group.
16
configs := []string{
17
`
18
name: configA
19
scrape_configs: []
20
remote_write: []`,
21
`
22
name: configB
23
scrape_configs: []
24
remote_write: []`,
25
`
26
name: configC
27
scrape_configs: []
28
remote_write:
29
- url: http://localhost:9090`,
30
}
31
32
for _, cfg := range configs {
33
c := testUnmarshalConfig(t, cfg)
34
err := gm.ApplyConfig(c)
35
require.NoError(t, err)
36
}
37
38
// ListInstances should return our grouped instances
39
insts := gm.ListInstances()
40
require.Equal(t, 2, len(insts))
41
42
// ...but ListConfigs should return the ungrouped configs.
43
confs := gm.ListConfigs()
44
require.Equal(t, 3, len(confs))
45
require.Containsf(t, confs, "configA", "configA not in confs")
46
require.Containsf(t, confs, "configB", "configB not in confs")
47
require.Containsf(t, confs, "configC", "configC not in confs")
48
}
49
50
func testUnmarshalConfig(t *testing.T, cfg string) Config {
51
c, err := UnmarshalConfig(strings.NewReader(cfg))
52
require.NoError(t, err)
53
return *c
54
}
55
56
func TestGroupManager_ApplyConfig(t *testing.T) {
57
t.Run("combining configs", func(t *testing.T) {
58
inner := newFakeManager()
59
gm := NewGroupManager(inner)
60
err := gm.ApplyConfig(testUnmarshalConfig(t, `
61
name: configA
62
scrape_configs: []
63
remote_write: []
64
`))
65
require.NoError(t, err)
66
67
err = gm.ApplyConfig(testUnmarshalConfig(t, `
68
name: configB
69
scrape_configs:
70
- job_name: test_job
71
static_configs:
72
- targets: [127.0.0.1:12345]
73
remote_write: []
74
`))
75
require.NoError(t, err)
76
77
require.Equal(t, 1, len(gm.groups))
78
require.Equal(t, 2, len(gm.groupLookup))
79
80
// Check the underlying grouped config and make sure it was updated.
81
expect := testUnmarshalConfig(t, fmt.Sprintf(`
82
name: %s
83
scrape_configs:
84
- job_name: test_job
85
static_configs:
86
- targets: [127.0.0.1:12345]
87
remote_write: []
88
`, gm.groupLookup["configA"]))
89
90
innerConfigs := inner.ListConfigs()
91
require.Equal(t, 1, len(innerConfigs))
92
require.Equal(t, expect, innerConfigs[gm.groupLookup["configA"]])
93
})
94
95
t.Run("updating existing config within group", func(t *testing.T) {
96
inner := newFakeManager()
97
gm := NewGroupManager(inner)
98
err := gm.ApplyConfig(testUnmarshalConfig(t, `
99
name: configA
100
scrape_configs: []
101
remote_write: []
102
`))
103
require.NoError(t, err)
104
require.Equal(t, 1, len(gm.groups))
105
require.Equal(t, 1, len(gm.groupLookup))
106
107
err = gm.ApplyConfig(testUnmarshalConfig(t, `
108
name: configA
109
scrape_configs:
110
- job_name: test_job
111
static_configs:
112
- targets: [127.0.0.1:12345]
113
remote_write: []
114
`))
115
require.NoError(t, err)
116
require.Equal(t, 1, len(gm.groups))
117
require.Equal(t, 1, len(gm.groupLookup))
118
119
// Check the underlying grouped config and make sure it was updated.
120
expect := testUnmarshalConfig(t, fmt.Sprintf(`
121
name: %s
122
scrape_configs:
123
- job_name: test_job
124
static_configs:
125
- targets: [127.0.0.1:12345]
126
remote_write: []
127
`, gm.groupLookup["configA"]))
128
actual := inner.ListConfigs()[gm.groupLookup["configA"]]
129
require.Equal(t, expect, actual)
130
})
131
132
t.Run("updating existing config to new group", func(t *testing.T) {
133
inner := newFakeManager()
134
gm := NewGroupManager(inner)
135
err := gm.ApplyConfig(testUnmarshalConfig(t, `
136
name: configA
137
scrape_configs: []
138
remote_write: []
139
`))
140
require.NoError(t, err)
141
require.Equal(t, 1, len(gm.groups))
142
require.Equal(t, 1, len(gm.groupLookup))
143
oldGroup := gm.groupLookup["configA"]
144
145
// Reapply the config but give it a setting change that would
146
// force it into a new group. We should still have only one
147
// group and only one entry in the group lookup table.
148
err = gm.ApplyConfig(testUnmarshalConfig(t, `
149
name: configA
150
host_filter: true
151
scrape_configs: []
152
remote_write: []
153
`))
154
require.NoError(t, err)
155
require.Equal(t, 1, len(gm.groups))
156
require.Equal(t, 1, len(gm.groupLookup))
157
newGroup := gm.groupLookup["configA"]
158
159
// Check the underlying grouped config and make sure it was updated.
160
expect := testUnmarshalConfig(t, fmt.Sprintf(`
161
name: %s
162
host_filter: true
163
scrape_configs: []
164
remote_write: []
165
`, gm.groupLookup["configA"]))
166
actual := inner.ListConfigs()[newGroup]
167
require.Equal(t, expect, actual)
168
169
// The old underlying ngroup should be gone.
170
require.NotContains(t, inner.ListConfigs(), oldGroup)
171
require.Equal(t, 1, len(inner.ListConfigs()))
172
})
173
}
174
175
func TestGroupManager_ApplyConfig_RemoteWriteName(t *testing.T) {
176
inner := newFakeManager()
177
gm := NewGroupManager(inner)
178
err := gm.ApplyConfig(testUnmarshalConfig(t, `
179
name: configA
180
scrape_configs: []
181
remote_write:
182
- name: rw-cfg-a
183
url: http://localhost:9009/api/prom/push
184
`))
185
require.NoError(t, err)
186
187
require.Equal(t, 1, len(gm.groups))
188
require.Equal(t, 1, len(gm.groupLookup))
189
190
// Check the underlying grouped config and make sure the group_name
191
// didn't get copied from the remote_name of A.
192
innerConfigs := inner.ListConfigs()
193
require.Equal(t, 1, len(innerConfigs))
194
195
cfg := innerConfigs[gm.groupLookup["configA"]]
196
require.NotEqual(t, "rw-cfg-a", cfg.RemoteWrite[0].Name)
197
}
198
199
func TestGroupManager_DeleteConfig(t *testing.T) {
200
t.Run("partial delete", func(t *testing.T) {
201
inner := newFakeManager()
202
gm := NewGroupManager(inner)
203
204
// Apply two configs in the same group and then delete one. The group
205
// should still be active with the one config inside of it.
206
err := gm.ApplyConfig(testUnmarshalConfig(t, `
207
name: configA
208
scrape_configs:
209
- job_name: test_job
210
static_configs:
211
- targets: [127.0.0.1:12345]
212
remote_write: []
213
`))
214
require.NoError(t, err)
215
216
err = gm.ApplyConfig(testUnmarshalConfig(t, `
217
name: configB
218
scrape_configs:
219
- job_name: test_job2
220
static_configs:
221
- targets: [127.0.0.1:12345]
222
remote_write: []
223
`))
224
require.NoError(t, err)
225
226
err = gm.DeleteConfig("configA")
227
require.NoError(t, err)
228
229
expect := testUnmarshalConfig(t, fmt.Sprintf(`
230
name: %s
231
scrape_configs:
232
- job_name: test_job2
233
static_configs:
234
- targets: [127.0.0.1:12345]
235
remote_write: []`, gm.groupLookup["configB"]))
236
actual := inner.ListConfigs()[gm.groupLookup["configB"]]
237
require.Equal(t, expect, actual)
238
require.Equal(t, 1, len(gm.groups))
239
require.Equal(t, 1, len(gm.groupLookup))
240
})
241
242
t.Run("full delete", func(t *testing.T) {
243
inner := newFakeManager()
244
gm := NewGroupManager(inner)
245
246
// Apply a single config but delete the entire group.
247
err := gm.ApplyConfig(testUnmarshalConfig(t, `
248
name: configA
249
scrape_configs:
250
- job_name: test_job
251
static_configs:
252
- targets: [127.0.0.1:12345]
253
remote_write: []
254
`))
255
require.NoError(t, err)
256
257
err = gm.DeleteConfig("configA")
258
require.NoError(t, err)
259
require.Equal(t, 0, len(inner.ListConfigs()))
260
require.Equal(t, 0, len(inner.ListInstances()))
261
require.Equal(t, 0, len(gm.groups))
262
require.Equal(t, 0, len(gm.groupLookup))
263
})
264
}
265
266
func newFakeManager() Manager {
267
instances := make(map[string]ManagedInstance)
268
configs := make(map[string]Config)
269
270
return &MockManager{
271
ListInstancesFunc: func() map[string]ManagedInstance {
272
return instances
273
},
274
ListConfigsFunc: func() map[string]Config {
275
return configs
276
},
277
ApplyConfigFunc: func(c Config) error {
278
instances[c.Name] = &mockInstance{}
279
configs[c.Name] = c
280
return nil
281
},
282
DeleteConfigFunc: func(name string) error {
283
delete(instances, name)
284
delete(configs, name)
285
return nil
286
},
287
StopFunc: func() {},
288
}
289
}
290
291
func Test_hashConfig(t *testing.T) {
292
t.Run("name and scrape configs are ignored", func(t *testing.T) {
293
configAText := `
294
name: configA
295
scrape_configs: []
296
remote_write: []`
297
298
configBText := `
299
name: configB
300
scrape_configs:
301
- job_name: test_job
302
static_configs:
303
- targets: [127.0.0.1:12345]
304
remote_write: []`
305
306
hashA, hashB := getHashesFromConfigs(t, configAText, configBText)
307
require.Equal(t, hashA, hashB)
308
})
309
310
t.Run("remote_writes are unordered", func(t *testing.T) {
311
configAText := `
312
name: configA
313
scrape_configs: []
314
remote_write:
315
- url: http://localhost:9009/api/prom/push1
316
- url: http://localhost:9009/api/prom/push2`
317
318
configBText := `
319
name: configB
320
scrape_configs: []
321
remote_write:
322
- url: http://localhost:9009/api/prom/push2
323
- url: http://localhost:9009/api/prom/push1`
324
325
hashA, hashB := getHashesFromConfigs(t, configAText, configBText)
326
require.Equal(t, hashA, hashB)
327
})
328
329
t.Run("remote_writes must match", func(t *testing.T) {
330
configAText := `
331
name: configA
332
scrape_configs: []
333
remote_write:
334
- url: http://localhost:9009/api/prom/push1
335
- url: http://localhost:9009/api/prom/push2`
336
337
configBText := `
338
name: configB
339
scrape_configs: []
340
remote_write:
341
- url: http://localhost:9009/api/prom/push1
342
- url: http://localhost:9009/api/prom/push1`
343
344
hashA, hashB := getHashesFromConfigs(t, configAText, configBText)
345
require.NotEqual(t, hashA, hashB)
346
})
347
348
t.Run("other fields must match", func(t *testing.T) {
349
configAText := `
350
name: configA
351
host_filter: true
352
scrape_configs: []
353
remote_write: []`
354
355
configBText := `
356
name: configB
357
host_filter: false
358
scrape_configs: []
359
remote_write: []`
360
361
hashA, hashB := getHashesFromConfigs(t, configAText, configBText)
362
require.NotEqual(t, hashA, hashB)
363
})
364
}
365
366
func getHashesFromConfigs(t *testing.T, configAText, configBText string) (string, string) {
367
configA := testUnmarshalConfig(t, configAText)
368
configB := testUnmarshalConfig(t, configBText)
369
370
hashA, err := hashConfig(configA)
371
require.NoError(t, err)
372
373
hashB, err := hashConfig(configB)
374
require.NoError(t, err)
375
376
return hashA, hashB
377
}
378
379
func Test_groupConfigs(t *testing.T) {
380
configAText := `
381
name: configA
382
scrape_configs:
383
- job_name: test_job
384
static_configs:
385
- targets: [127.0.0.1:12345]
386
remote_write:
387
- url: http://localhost:9009/api/prom/push1
388
- url: http://localhost:9009/api/prom/push2`
389
390
configBText := `
391
name: configB
392
scrape_configs:
393
- job_name: test_job2
394
static_configs:
395
- targets: [127.0.0.1:12345]
396
remote_write:
397
- url: http://localhost:9009/api/prom/push2
398
- url: http://localhost:9009/api/prom/push1`
399
400
configA := testUnmarshalConfig(t, configAText)
401
configB := testUnmarshalConfig(t, configBText)
402
403
groupName, err := hashConfig(configA)
404
require.NoError(t, err)
405
406
expectText := fmt.Sprintf(`
407
name: %s
408
scrape_configs:
409
- job_name: test_job
410
static_configs:
411
- targets: [127.0.0.1:12345]
412
- job_name: test_job2
413
static_configs:
414
- targets: [127.0.0.1:12345]
415
remote_write:
416
- url: http://localhost:9009/api/prom/push1
417
- url: http://localhost:9009/api/prom/push2`, groupName)
418
419
expect, err := UnmarshalConfig(strings.NewReader(expectText))
420
require.NoError(t, err)
421
422
// Generate expected remote_write names
423
for _, rwConfig := range expect.RemoteWrite {
424
hash, err := getHash(rwConfig)
425
require.NoError(t, err)
426
rwConfig.Name = groupName[:6] + "-" + hash[:6]
427
}
428
429
group := groupedConfigs{
430
"configA": configA,
431
"configB": configB,
432
}
433
actual, err := groupConfigs(groupName, group)
434
require.NoError(t, err)
435
require.Equal(t, *expect, actual)
436
437
// Consistency check: groupedConfigs is a map and we want to always have
438
// groupConfigs return the same thing regardless of how the map
439
// is iterated over. Run through groupConfigs a bunch of times and
440
// make sure it always returns the same thing.
441
for i := 0; i < 100; i++ {
442
actual, err = groupConfigs(groupName, group)
443
require.NoError(t, err)
444
require.Equal(t, *expect, actual)
445
}
446
}
447
448