github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/alertmanager/merger/v1_alerts_test.go (about) 1 package merger 2 3 import ( 4 "testing" 5 "time" 6 7 v1 "github.com/prometheus/alertmanager/api/v1" 8 "github.com/prometheus/alertmanager/types" 9 prom_model "github.com/prometheus/common/model" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestV1Alerts(t *testing.T) { 14 15 // This test is to check the parsing round-trip is working as expected, the merging logic is 16 // tested in TestMergeV1Alerts. The test data is based on captures from an actual Alertmanager. 17 18 in := [][]byte{ 19 []byte(`{"status":"success","data":[` + 20 `{"labels":{"group":"group_1","name":"alert_1"},` + 21 `"annotations":null,"startsAt":"2021-04-21T09:47:32.16145934+02:00",` + 22 `"endsAt":"2021-04-21T10:47:32.161462204+02:00","generatorURL":"",` + 23 `"status":{"state":"unprocessed","silencedBy":[],"inhibitedBy":[]},` + 24 `"receivers":["dummy"],"fingerprint":"c4b6b79a607b6ba0"},` + 25 `{"labels":{"group":"group_1","name":"alert_2"},` + 26 `"annotations":null,"startsAt":"2021-04-21T09:47:32.163797336+02:00",` + 27 `"endsAt":"2021-04-21T10:47:32.163800129+02:00","generatorURL":"",` + 28 `"status":{"state":"unprocessed","silencedBy":[],"inhibitedBy":[]},` + 29 `"receivers":["dummy"],"fingerprint":"c4b8b79a607bee77"}]}`), 30 []byte(`{"status":"success","data":[` + 31 `{"labels":{"group":"group_2","name":"alert_3"},` + 32 `"annotations":null,"startsAt":"2021-04-21T09:47:32.165939585+02:00",` + 33 `"endsAt":"2021-04-21T10:47:32.165942448+02:00","generatorURL":"",` + 34 `"status":{"state":"unprocessed","silencedBy":[],"inhibitedBy":[]},` + 35 `"receivers":["dummy"],"fingerprint":"465de60f606461c3"}]}`), 36 []byte(`{"status":"success","data":[]}`), 37 } 38 39 expected := []byte(`{"status":"success","data":[` + 40 `{"labels":{"group":"group_2","name":"alert_3"},"annotations":null,` + 41 `"startsAt":"2021-04-21T09:47:32.165939585+02:00",` + 42 `"endsAt":"2021-04-21T10:47:32.165942448+02:00","generatorURL":"",` + 43 `"status":{"state":"unprocessed","silencedBy":[],"inhibitedBy":[]},` + 44 `"receivers":["dummy"],"fingerprint":"465de60f606461c3"},` + 45 `{"labels":{"group":"group_1","name":"alert_1"},"annotations":null,` + 46 `"startsAt":"2021-04-21T09:47:32.16145934+02:00",` + 47 `"endsAt":"2021-04-21T10:47:32.161462204+02:00","generatorURL":"",` + 48 `"status":{"state":"unprocessed","silencedBy":[],"inhibitedBy":[]},` + 49 `"receivers":["dummy"],"fingerprint":"c4b6b79a607b6ba0"},` + 50 `{"labels":{"group":"group_1","name":"alert_2"},"annotations":null,` + 51 `"startsAt":"2021-04-21T09:47:32.163797336+02:00",` + 52 `"endsAt":"2021-04-21T10:47:32.163800129+02:00","generatorURL":"",` + 53 `"status":{"state":"unprocessed","silencedBy":[],"inhibitedBy":[]},` + 54 `"receivers":["dummy"],"fingerprint":"c4b8b79a607bee77"}]}`) 55 56 out, err := V1Alerts{}.MergeResponses(in) 57 require.NoError(t, err) 58 require.Equal(t, expected, out) 59 } 60 61 func v1ParseTime(s string) time.Time { 62 t, _ := time.Parse(time.RFC3339, s) 63 return t 64 } 65 66 // v1alert is a convenience function to create alert structures with certain important fields set 67 // and with sensible defaults for the remaining fields to test they are passed through. 68 func v1alert(fingerprint, annotation string) *v1.Alert { 69 return &v1.Alert{ 70 Alert: &prom_model.Alert{ 71 Labels: prom_model.LabelSet{ 72 "label1": "value1", 73 }, 74 Annotations: prom_model.LabelSet{ 75 "annotation1": prom_model.LabelValue(annotation), 76 }, 77 StartsAt: v1ParseTime("2020-01-01T12:00:00.000Z"), 78 EndsAt: v1ParseTime("2020-01-01T12:00:00.000Z"), 79 GeneratorURL: "something", 80 }, 81 Status: types.AlertStatus{}, 82 Receivers: []string{"dummy"}, 83 Fingerprint: fingerprint, 84 } 85 } 86 87 func v1alerts(alerts ...*v1.Alert) []*v1.Alert { 88 return alerts 89 } 90 91 func TestMergeV1Alerts(t *testing.T) { 92 var ( 93 alert1 = v1alert("1111111111111111", "a1") 94 alert1b = v1alert("1111111111111111", "a1b") 95 alert2 = v1alert("2222222222222222", "a2") 96 alert3 = v1alert("3333333333333333", "a3") 97 ) 98 cases := []struct { 99 name string 100 in []*v1.Alert 101 err error 102 out []*v1.Alert 103 }{ 104 { 105 name: "no alerts, should return an empty list", 106 in: v1alerts(), 107 out: []*v1.Alert{}, 108 }, 109 { 110 name: "one alert, should return the alert", 111 in: v1alerts(alert1), 112 out: v1alerts(alert1), 113 }, 114 { 115 name: "two alerts, should return two alerts", 116 in: v1alerts(alert1, alert2), 117 out: v1alerts(alert1, alert2), 118 }, 119 { 120 name: "three alerts, should return three alerts", 121 in: v1alerts(alert1, alert2, alert3), 122 out: v1alerts(alert1, alert2, alert3), 123 }, 124 { 125 name: "three alerts out of order, should return three alerts in fingerprint order", 126 in: v1alerts(alert3, alert2, alert1), 127 out: v1alerts(alert1, alert2, alert3), 128 }, 129 { 130 name: "two identical alerts, should return one alert", 131 in: v1alerts(alert1, alert1), 132 out: v1alerts(alert1), 133 }, 134 { 135 name: "two identical alerts plus another, should return two alerts", 136 in: v1alerts(alert1, alert1, alert2), 137 out: v1alerts(alert1, alert2), 138 }, 139 { 140 name: "two duplicates out of sync alerts, should return first seen alert", 141 in: v1alerts(alert1, alert1b), 142 out: v1alerts(alert1), 143 }, 144 { 145 name: "two duplicates plus others, should return first seen alert and others", 146 in: v1alerts(alert1b, alert3, alert1, alert2), 147 out: v1alerts(alert1b, alert2, alert3), 148 }, 149 } 150 151 for _, c := range cases { 152 t.Run(c.name, func(t *testing.T) { 153 out, err := mergeV1Alerts(c.in) 154 require.Equal(t, c.err, err) 155 require.Equal(t, c.out, out) 156 }) 157 } 158 }