@@ -25,11 +25,13 @@ import (
25
25
26
26
"github.com/go-kit/kit/log"
27
27
"github.com/kylelemons/godebug/pretty"
28
- "github.com/prometheus/alertmanager/store"
29
- "github.com/prometheus/alertmanager/types"
30
28
"github.com/prometheus/client_golang/prometheus"
31
29
"github.com/prometheus/common/model"
32
30
"github.com/stretchr/testify/require"
31
+ "go.uber.org/atomic"
32
+
33
+ "github.com/prometheus/alertmanager/store"
34
+ "github.com/prometheus/alertmanager/types"
33
35
)
34
36
35
37
var (
@@ -85,7 +87,7 @@ func init() {
85
87
// a listener can not unsubscribe as the lock is hold by `alerts.Lock`.
86
88
func TestAlertsSubscribePutStarvation (t * testing.T ) {
87
89
marker := types .NewMarker (prometheus .NewRegistry ())
88
- alerts , err := NewAlerts (context .Background (), marker , 30 * time .Minute , log .NewNopLogger ())
90
+ alerts , err := NewAlerts (context .Background (), marker , 30 * time .Minute , noopCallback {}, log .NewNopLogger ())
89
91
if err != nil {
90
92
t .Fatal (err )
91
93
}
@@ -136,7 +138,7 @@ func TestAlertsSubscribePutStarvation(t *testing.T) {
136
138
137
139
func TestAlertsPut (t * testing.T ) {
138
140
marker := types .NewMarker (prometheus .NewRegistry ())
139
- alerts , err := NewAlerts (context .Background (), marker , 30 * time .Minute , log .NewNopLogger ())
141
+ alerts , err := NewAlerts (context .Background (), marker , 30 * time .Minute , noopCallback {}, log .NewNopLogger ())
140
142
if err != nil {
141
143
t .Fatal (err )
142
144
}
@@ -164,7 +166,7 @@ func TestAlertsSubscribe(t *testing.T) {
164
166
165
167
ctx , cancel := context .WithCancel (context .Background ())
166
168
defer cancel ()
167
- alerts , err := NewAlerts (ctx , marker , 30 * time .Minute , log .NewNopLogger ())
169
+ alerts , err := NewAlerts (ctx , marker , 30 * time .Minute , noopCallback {}, log .NewNopLogger ())
168
170
if err != nil {
169
171
t .Fatal (err )
170
172
}
@@ -241,7 +243,7 @@ func TestAlertsSubscribe(t *testing.T) {
241
243
242
244
func TestAlertsGetPending (t * testing.T ) {
243
245
marker := types .NewMarker (prometheus .NewRegistry ())
244
- alerts , err := NewAlerts (context .Background (), marker , 30 * time .Minute , log .NewNopLogger ())
246
+ alerts , err := NewAlerts (context .Background (), marker , 30 * time .Minute , noopCallback {}, log .NewNopLogger ())
245
247
if err != nil {
246
248
t .Fatal (err )
247
249
}
@@ -284,7 +286,7 @@ func TestAlertsGetPending(t *testing.T) {
284
286
285
287
func TestAlertsGC (t * testing.T ) {
286
288
marker := types .NewMarker (prometheus .NewRegistry ())
287
- alerts , err := NewAlerts (context .Background (), marker , 200 * time .Millisecond , log .NewNopLogger ())
289
+ alerts , err := NewAlerts (context .Background (), marker , 200 * time .Millisecond , noopCallback {}, log .NewNopLogger ())
288
290
if err != nil {
289
291
t .Fatal (err )
290
292
}
@@ -316,6 +318,71 @@ func TestAlertsGC(t *testing.T) {
316
318
}
317
319
}
318
320
321
+ func TestAlertsStoreCallback (t * testing.T ) {
322
+ cb := & limitCountCallback {limit : 3 }
323
+
324
+ marker := types .NewMarker (prometheus .NewRegistry ())
325
+ alerts , err := NewAlerts (context .Background (), marker , 200 * time .Millisecond , cb , log .NewNopLogger ())
326
+ if err != nil {
327
+ t .Fatal (err )
328
+ }
329
+
330
+ err = alerts .Put (alert1 , alert2 , alert3 )
331
+ if err != nil {
332
+ t .Fatal (err )
333
+ }
334
+ if num := cb .alerts .Load (); num != 3 {
335
+ t .Fatalf ("unexpected number of alerts in the store, expected %v, got %v" , 3 , num )
336
+ }
337
+
338
+ alert1Mod := * alert1
339
+ alert1Mod .Annotations = model.LabelSet {"foo" : "bar" , "new" : "test" } // Update annotations for alert1
340
+
341
+ alert4 := & types.Alert {
342
+ Alert : model.Alert {
343
+ Labels : model.LabelSet {"bar4" : "foo4" },
344
+ Annotations : model.LabelSet {"foo4" : "bar4" },
345
+ StartsAt : t0 ,
346
+ EndsAt : t1 ,
347
+ GeneratorURL : "http://example.com/prometheus" ,
348
+ },
349
+ UpdatedAt : t0 ,
350
+ Timeout : false ,
351
+ }
352
+
353
+ err = alerts .Put (& alert1Mod , alert4 )
354
+ // Verify that we failed to put new alert into store (not reported via error, only checked using Load)
355
+ if err != nil {
356
+ t .Fatalf ("unexpected error %v" , err )
357
+ }
358
+
359
+ if num := cb .alerts .Load (); num != 3 {
360
+ t .Fatalf ("unexpected number of alerts in the store, expected %v, got %v" , 3 , num )
361
+ }
362
+
363
+ // But we still managed to update alert1, since callback doesn't report error when updating existing alert.
364
+ a , err := alerts .Get (alert1 .Fingerprint ())
365
+ if err != nil {
366
+ t .Fatal (err )
367
+ }
368
+ if ! alertsEqual (a , & alert1Mod ) {
369
+ t .Errorf ("Unexpected alert" )
370
+ t .Fatalf (pretty .Compare (a , & alert1Mod ))
371
+ }
372
+
373
+ // Now wait until existing alerts are GC-ed, and make sure that callback was called.
374
+ time .Sleep (300 * time .Millisecond )
375
+
376
+ if num := cb .alerts .Load (); num != 0 {
377
+ t .Fatalf ("unexpected number of alerts in the store, expected %v, got %v" , 0 , num )
378
+ }
379
+
380
+ err = alerts .Put (alert4 )
381
+ if err != nil {
382
+ t .Fatal (err )
383
+ }
384
+ }
385
+
319
386
func alertsEqual (a1 , a2 * types.Alert ) bool {
320
387
if a1 == nil || a2 == nil {
321
388
return false
@@ -340,3 +407,32 @@ func alertsEqual(a1, a2 *types.Alert) bool {
340
407
}
341
408
return a1 .Timeout == a2 .Timeout
342
409
}
410
+
411
+ type limitCountCallback struct {
412
+ alerts atomic.Int32
413
+ limit int
414
+ }
415
+
416
+ var errTooManyAlerts = fmt .Errorf ("too many alerts" )
417
+
418
+ func (l * limitCountCallback ) PreStore (_ * types.Alert , existing bool ) error {
419
+ if existing {
420
+ return nil
421
+ }
422
+
423
+ if int (l .alerts .Load ())+ 1 > l .limit {
424
+ return errTooManyAlerts
425
+ }
426
+
427
+ return nil
428
+ }
429
+
430
+ func (l * limitCountCallback ) PostStore (_ * types.Alert , existing bool ) {
431
+ if ! existing {
432
+ l .alerts .Inc ()
433
+ }
434
+ }
435
+
436
+ func (l * limitCountCallback ) PostDelete (_ * types.Alert ) {
437
+ l .alerts .Dec ()
438
+ }
0 commit comments