@@ -19,6 +19,7 @@ import (
1919 "fmt"
2020 "io"
2121 "reflect"
22+ "strings"
2223 "testing"
2324 "time"
2425
@@ -936,97 +937,96 @@ func TestTimeMuteStage(t *testing.T) {
936937}
937938
938939func TestTimeActiveStage (t * testing.T ) {
939- // Route mutes alerts inside business hours if it is an active time interval
940- muteIn := `
941- ---
942- - weekdays: ['monday:friday']
943- times:
944- - start_time: '00:00'
945- end_time: '09:00'
946- - start_time: '17:00'
947- end_time: '24:00'
948- - weekdays: ['saturday', 'sunday']`
949-
950- cases := []struct {
951- fireTime string
952- labels model.LabelSet
953- shouldMute bool
954- }{
955- {
956- // Friday during business hours
957- fireTime : "01 Jan 21 09:00 +0000" ,
958- labels : model.LabelSet {"mute" : "me" },
959- shouldMute : true ,
960- },
961- {
962- fireTime : "02 Dec 20 16:59 +0000" ,
963- labels : model.LabelSet {"mute" : "me" },
964- shouldMute : true ,
965- },
966- {
967- // Tuesday before 5pm
968- fireTime : "01 Dec 20 16:59 +0000" ,
969- labels : model.LabelSet {"mute" : "me" },
970- shouldMute : true ,
971- },
972- {
973- // Saturday
974- fireTime : "17 Oct 20 10:00 +0000" ,
975- labels : model.LabelSet {"foo" : "bar" },
976- shouldMute : false ,
977- },
978- {
979- // Wednesday before 9am
980- fireTime : "14 Oct 20 05:00 +0000" ,
981- labels : model.LabelSet {"dont" : "mute" },
982- shouldMute : false ,
983- },
984- }
985- var intervals []timeinterval.TimeInterval
986- err := yaml .Unmarshal ([]byte (muteIn ), & intervals )
940+ sydney , err := time .LoadLocation ("Australia/Sydney" )
987941 if err != nil {
988- t .Fatalf ("Couldn't unmarshal time interval %s" , err )
989- }
990- m := map [string ][]timeinterval.TimeInterval {"test" : intervals }
991- intervener := timeinterval .NewIntervener (m )
992- metrics := NewMetrics (prometheus .NewRegistry (), featurecontrol.NoopFlags {})
993- stage := NewTimeActiveStage (intervener , metrics )
994-
995- outAlerts := []* types.Alert {}
996- nonMuteCount := 0
997- for _ , tc := range cases {
998- now , err := time .Parse (time .RFC822Z , tc .fireTime )
999- if err != nil {
1000- t .Fatalf ("Couldn't parse fire time %s %s" , tc .fireTime , err )
1001- }
1002- // Count alerts with shouldMute == false and compare to ensure none are muted incorrectly
1003- if ! tc .shouldMute {
1004- nonMuteCount ++
1005- }
1006- a := model.Alert {Labels : tc .labels }
1007- alerts := []* types.Alert {{Alert : a }}
1008- ctx := context .Background ()
1009- ctx = WithNow (ctx , now )
1010- ctx = WithActiveTimeIntervals (ctx , []string {"test" })
1011- ctx = WithMuteTimeIntervals (ctx , []string {})
942+ t .Fatalf ("Failed to load location Australia/Sydney: %s" , err )
943+ }
944+ weekdays := map [string ][]timeinterval.TimeInterval {
945+ "weekdays" : {{
946+ Weekdays : []timeinterval.WeekdayRange {{
947+ InclusiveRange : timeinterval.InclusiveRange {
948+ Begin : 1 , // Monday
949+ End : 5 , // Friday
950+ },
951+ }},
952+ Times : []timeinterval.TimeRange {{
953+ StartMinute : 540 , // 09:00
954+ EndMinute : 1020 , // 17:00
955+ }},
956+ Location : & timeinterval.Location {Location : sydney },
957+ }},
958+ }
959+
960+ tests := []struct {
961+ name string
962+ intervals map [string ][]timeinterval.TimeInterval
963+ now time.Time
964+ alerts []* types.Alert
965+ mutedBy []string
966+ }{{
967+ name : "Should be muted outside working hours" ,
968+ intervals : weekdays ,
969+ now : time .Date (2024 , 1 , 1 , 0 , 0 , 0 , 0 , sydney ),
970+ alerts : []* types.Alert {{Alert : model.Alert {Labels : model.LabelSet {"foo" : "bar" }}}},
971+ mutedBy : []string {"weekdays" },
972+ }, {
973+ name : "Should not be muted during workings hours" ,
974+ intervals : weekdays ,
975+ now : time .Date (2024 , 1 , 1 , 9 , 0 , 0 , 0 , sydney ),
976+ alerts : []* types.Alert {{Alert : model.Alert {Labels : model.LabelSet {"foo" : "bar" }}}},
977+ mutedBy : nil ,
978+ }, {
979+ name : "Should be muted during weekends" ,
980+ intervals : weekdays ,
981+ now : time .Date (2024 , 1 , 6 , 10 , 0 , 0 , 0 , sydney ),
982+ alerts : []* types.Alert {{Alert : model.Alert {Labels : model.LabelSet {"foo" : "bar" }}}},
983+ mutedBy : []string {"weekdays" },
984+ }, {
985+ name : "Should be muted at 12pm UTC" ,
986+ intervals : weekdays ,
987+ now : time .Date (2024 , 1 , 6 , 10 , 0 , 0 , 0 , time .UTC ),
988+ alerts : []* types.Alert {{Alert : model.Alert {Labels : model.LabelSet {"foo" : "bar" }}}},
989+ mutedBy : []string {"weekdays" },
990+ }}
991+
992+ for _ , test := range tests {
993+ t .Run (test .name , func (t * testing.T ) {
994+ r := prometheus .NewRegistry ()
995+ metrics := NewMetrics (r , featurecontrol.NoopFlags {})
996+ intervener := timeinterval .NewIntervener (test .intervals )
997+ st := NewTimeActiveStage (intervener , metrics )
998+
999+ // Get the names of all time intervals for the context.
1000+ activeTimeIntervalNames := make ([]string , 0 , len (test .intervals ))
1001+ for name := range test .intervals {
1002+ activeTimeIntervalNames = append (activeTimeIntervalNames , name )
1003+ }
10121004
1013- _ , out , err := stage .Exec (ctx , log .NewNopLogger (), alerts ... )
1014- if err != nil {
1015- t .Fatalf ("Unexpected error in time mute stage %s" , err )
1016- }
1017- outAlerts = append (outAlerts , out ... )
1018- }
1019- for _ , alert := range outAlerts {
1020- if _ , ok := alert .Alert .Labels ["mute" ]; ok {
1021- t .Fatalf ("Expected alert to be muted %+v" , alert .Alert )
1022- }
1023- }
1024- if len (outAlerts ) != nonMuteCount {
1025- t .Fatalf ("Expected %d alerts after time mute stage but got %d" , nonMuteCount , len (outAlerts ))
1026- }
1027- suppressed := int (prom_testutil .ToFloat64 (metrics .numNotificationSuppressedTotal ))
1028- if (len (cases ) - nonMuteCount ) != suppressed {
1029- t .Fatalf ("Expected %d alerts counted in suppressed metric but got %d" , (len (cases ) - nonMuteCount ), suppressed )
1005+ ctx := context .Background ()
1006+ ctx = WithNow (ctx , test .now )
1007+ ctx = WithActiveTimeIntervals (ctx , activeTimeIntervalNames )
1008+ ctx = WithMuteTimeIntervals (ctx , nil )
1009+
1010+ _ , active , err := st .Exec (ctx , log .NewNopLogger (), test .alerts ... )
1011+ require .NoError (t , err )
1012+
1013+ if len (test .mutedBy ) == 0 {
1014+ // All alerts should be active.
1015+ require .Equal (t , len (test .alerts ), len (active ))
1016+ // The metric for total suppressed notifications should not
1017+ // have been incremented, which means it will not be collected.
1018+ require .NoError (t , prom_testutil .GatherAndCompare (r , strings .NewReader ("" )))
1019+ } else {
1020+ // All alerts should be muted.
1021+ require .Empty (t , active )
1022+ // Gets the metric for total suppressed notifications.
1023+ require .NoError (t , prom_testutil .GatherAndCompare (r , strings .NewReader (fmt .Sprintf (`
1024+ # HELP alertmanager_notifications_suppressed_total The total number of notifications suppressed for being silenced, inhibited, outside of active time intervals or within muted time intervals.
1025+ # TYPE alertmanager_notifications_suppressed_total counter
1026+ alertmanager_notifications_suppressed_total{reason="active_time_interval"} %d
1027+ ` , len (test .alerts )))))
1028+ }
1029+ })
10301030 }
10311031}
10321032
0 commit comments