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  }