Repository: prometheus/alertmanager
File: silence/silence_test.go (Go)

Code before:

func TestSilenceGCOverTime(t *testing.T) {
	type silenceEntry struct {
		s                    *pb.Silence
		expectPresentAfterGc bool
	}
	type testCase struct {
		initialState    []silenceEntry
		updates         []silenceEntry
		expectedGCCount int
	}

	c := clock.NewMock()
	now := c.Now().UTC()

	newSilence := func(id string, exp time.Time) *pb.Silence {
		return &pb.Silence{
			Id:       id,
			StartsAt: now.Add(-time.Second),
			EndsAt:   exp,
			Matchers: []*pb.Matcher{
				{Name: "foo", Type: pb.Matcher_REGEXP, Pattern: "bar"},
			}}
	}

	cases := map[string]testCase{
		"gc does not clean active silences": {
			initialState: []silenceEntry{
				{s: newSilence("1", now), expectPresentAfterGc: false},
				{s: newSilence("2", now.Add(-time.Second)), expectPresentAfterGc: false},
				{s: newSilence("3", now.Add(time.Second)), expectPresentAfterGc: true},
			},
		},
		"silences added with Set are handled correctly": {
			initialState: []silenceEntry{
				{s: newSilence("1", now), expectPresentAfterGc: false},
			},
			updates: []silenceEntry{
				{s: newSilence("", now.Add(time.Second)), expectPresentAfterGc: true},
				{s: newSilence("", now.Add(-time.Second)), expectPresentAfterGc: false},
			},
		},
		"silence update does not leak state": {
			initialState: []silenceEntry{
				{s: newSilence("1", now), expectPresentAfterGc: false},
			},
			updates: []silenceEntry{
				{s: newSilence("1", now.Add(time.Second)), expectPresentAfterGc: true},
			},
		},
	}

Review comment (suggestion):
It's more idiomatic to write test cases like this 

```diff
diff --git a/silence/silence_test.go b/silence/silence_test.go
index c290522a..7a1bf335 100644
--- a/silence/silence_test.go
+++ b/silence/silence_test.go
@@ -114,11 +114,6 @@ func TestSilenceGCOverTime(t *testing.T) {
                s                    *pb.Silence
                expectPresentAfterGc bool
        }
-       type testCase struct {
-               initialState    []silenceEntry
-               updates         []silenceEntry
-               expectedGCCount int
-       }

        c := clock.NewMock()
        now := c.Now().UTC()
@@ -133,35 +128,39 @@ func TestSilenceGCOverTime(t *testing.T) {
                        }}
        }

-       cases := map[string]testCase{
-               "gc does not clean active silences": {
-                       initialState: []silenceEntry{
-                               {s: newSilence("1", now), expectPresentAfterGc: false},
-                               {s: newSilence("2", now.Add(-time.Second)), expectPresentAfterGc: false},
-                               {s: newSilence("3", now.Add(time.Second)), expectPresentAfterGc: true},
-                       },
+       cases := []struct {
+               name            string
+               initialState    []silenceEntry
+               updates         []silenceEntry
+               expectedGCCount int
+       }{{
+               name: "gc does not clean active silences",
+               initialState: []silenceEntry{
+                       {s: newSilence("1", now), expectPresentAfterGc: false},
+                       {s: newSilence("2", now.Add(-time.Second)), expectPresentAfterGc: false},
+                       {s: newSilence("3", now.Add(time.Second)), expectPresentAfterGc: true},
                },
-               "silences added with Set are handled correctly": {
-                       initialState: []silenceEntry{
-                               {s: newSilence("1", now), expectPresentAfterGc: false},
-                       },
-                       updates: []silenceEntry{
-                               {s: newSilence("", now.Add(time.Second)), expectPresentAfterGc: true},
-                               {s: newSilence("", now.Add(-time.Second)), expectPresentAfterGc: false},
-                       },
+       }, {
+               name: "silences added with Set are handled correctly",
+               initialState: []silenceEntry{
+                       {s: newSilence("1", now), expectPresentAfterGc: false},
                },
-               "silence update does not leak state": {
-                       initialState: []silenceEntry{
-                               {s: newSilence("1", now), expectPresentAfterGc: false},
-                       },
-                       updates: []silenceEntry{
-                               {s: newSilence("1", now.Add(time.Second)), expectPresentAfterGc: true},
-                       },
+               updates: []silenceEntry{
+                       {s: newSilence("", now.Add(time.Second)), expectPresentAfterGc: true},
+                       {s: newSilence("", now.Add(-time.Second)), expectPresentAfterGc: false},
                },
-       }
+       }, {
+               name: "silence update does not leak state",
+               initialState: []silenceEntry{
+                       {s: newSilence("1", now), expectPresentAfterGc: false},
+               },
+               updates: []silenceEntry{
+                       {s: newSilence("1", now.Add(time.Second)), expectPresentAfterGc: true},
+               },
+       }}

-       for name, tc := range cases {
-               t.Run(name, func(t *testing.T) {
+       for _, tc := range cases {
+               t.Run(tc.name, func(t *testing.T) {
                        silences, err := New(Options{})
                        silClock := clock.NewMock()
                        silences.clock = silClock
```


Code after:
		s.clock = clock
		sil1 := &pb.Silence{
			Matchers: []*pb.Matcher{{
				Type:    pb.Matcher_EQUAL,
				Name:    "foo",
				Pattern: "bar",
			}},
			StartsAt: clock.Now(),
			EndsAt:   clock.Now().Add(time.Minute),
		}
		require.NoError(t, s.Set(sil1))
		// Need to query the silence to populate the matcher cache.
		s.Query(QMatches(model.LabelSet{"foo": "bar"}))
		require.Len(t, s.st, 1)
		require.Len(t, s.mc, 1)
		// Move time forward and both silence and cache entry should be garbage
		// collected.
		clock.Add(time.Minute)
		n, err := s.GC()
		require.NoError(t, err)
		require.Equal(t, 1, n)
		require.Empty(t, s.st)
		require.Empty(t, s.mc)
	})

	t.Run("replacing a silences does not leak cache entries", func(t *testing.T) {
		s, err := New(Options{})
		require.NoError(t, err)
		clock := clock.NewMock()
		s.clock = clock
		sil1 := &pb.Silence{
			Matchers: []*pb.Matcher{{
				Type:    pb.Matcher_EQUAL,
				Name:    "foo",
				Pattern: "bar",
			}},
			StartsAt: clock.Now(),
			EndsAt:   clock.Now().Add(time.Minute),
		}
		require.NoError(t, s.Set(sil1))
		// Need to query the silence to populate the matcher cache.
		s.Query(QMatches(model.LabelSet{"foo": "bar"}))
		require.Len(t, s.st, 1)
		require.Len(t, s.mc, 1)
		// must clone sil1 before replacing it.
		sil2 := cloneSilence(sil1)
		sil2.Matchers = []*pb.Matcher{{
			Type:    pb.Matcher_EQUAL,
			Name:    "bar",
			Pattern: "baz",
		}}