@@ -91,16 +91,16 @@ func TestSilencesGC(t *testing.T) {
91
91
s .clock = clock .NewMock ()
92
92
now := s .nowUTC ()
93
93
94
- newSilence := func (exp time.Time ) * pb.MeshSilence {
95
- return & pb.MeshSilence {ExpiresAt : exp }
94
+ newSilence := func (id string , exp time.Time ) * pb.MeshSilence {
95
+ return & pb.MeshSilence {Silence : & pb. Silence { Id : id }, ExpiresAt : exp }
96
96
}
97
97
s .st = state {
98
- "1" : newSilence (now ),
99
- "2" : newSilence (now .Add (- time .Second )),
100
- "3" : newSilence (now .Add (time .Second )),
98
+ "1" : newSilence ("1" , now ),
99
+ "2" : newSilence ("2" , now .Add (- time .Second )),
100
+ "3" : newSilence ("3" , now .Add (time .Second )),
101
101
}
102
102
want := state {
103
- "3" : newSilence (now .Add (time .Second )),
103
+ "3" : newSilence ("3" , now .Add (time .Second )),
104
104
}
105
105
106
106
n , err := s .GC ()
@@ -109,6 +109,119 @@ func TestSilencesGC(t *testing.T) {
109
109
require .Equal (t , want , s .st )
110
110
}
111
111
112
+ func TestSilenceGCOverTime (t * testing.T ) {
113
+ type silenceEntry struct {
114
+ s * pb.Silence
115
+ expectPresentAfterGc bool
116
+ }
117
+ type testCase struct {
118
+ initialState []silenceEntry
119
+ updates []silenceEntry
120
+ expectedGCCount int
121
+ }
122
+
123
+ c := clock .NewMock ()
124
+ now := c .Now ().UTC ()
125
+
126
+ newSilence := func (id string , exp time.Time ) * pb.Silence {
127
+ return & pb.Silence {
128
+ Id : id ,
129
+ StartsAt : now .Add (- time .Second ),
130
+ EndsAt : exp ,
131
+ Matchers : []* pb.Matcher {
132
+ {Name : "foo" , Type : pb .Matcher_REGEXP , Pattern : "bar" },
133
+ }}
134
+ }
135
+
136
+ cases := map [string ]testCase {
137
+ "gc does not clean active silences" : {
138
+ initialState : []silenceEntry {
139
+ {s : newSilence ("1" , now ), expectPresentAfterGc : false },
140
+ {s : newSilence ("2" , now .Add (- time .Second )), expectPresentAfterGc : false },
141
+ {s : newSilence ("3" , now .Add (time .Second )), expectPresentAfterGc : true },
142
+ },
143
+ },
144
+ "silences added with Set are handled correctly" : {
145
+ initialState : []silenceEntry {
146
+ {s : newSilence ("1" , now ), expectPresentAfterGc : false },
147
+ },
148
+ updates : []silenceEntry {
149
+ {s : newSilence ("" , now .Add (time .Second )), expectPresentAfterGc : true },
150
+ {s : newSilence ("" , now .Add (- time .Second )), expectPresentAfterGc : false },
151
+ },
152
+ },
153
+ "silence update does not leak state" : {
154
+ initialState : []silenceEntry {
155
+ {s : newSilence ("1" , now ), expectPresentAfterGc : false },
156
+ },
157
+ updates : []silenceEntry {
158
+ {s : newSilence ("1" , now .Add (time .Second )), expectPresentAfterGc : true },
159
+ },
160
+ },
161
+ }
162
+
163
+ for name , tc := range cases {
164
+ t .Run (name , func (t * testing.T ) {
165
+ silences , err := New (Options {})
166
+ silClock := clock .NewMock ()
167
+ silences .clock = silClock
168
+ require .NoError (t , err )
169
+
170
+ expectedRemaining := []string {}
171
+ expectedGCCount := 0
172
+ for _ , sil := range tc .initialState {
173
+ silences .st [sil .s .Id ] = & pb.MeshSilence {
174
+ Silence : sil .s ,
175
+ ExpiresAt : sil .s .EndsAt ,
176
+ }
177
+ if sil .expectPresentAfterGc {
178
+ expectedRemaining = append (expectedRemaining , sil .s .Id )
179
+ } else {
180
+ expectedGCCount += 1
181
+ }
182
+ // simulate this silences being seen in a query
183
+ silences .mc .Get (silences .st [sil .s .Id ].Silence )
184
+ }
185
+ silClock .Add (- time .Second )
186
+ for _ , sil := range tc .updates {
187
+ if sil .s .Id != "" {
188
+ // we're replacing a silence which now will not get GC'd
189
+ expectedGCCount -= 1
190
+ }
191
+ err := silences .Set (sil .s )
192
+ require .NoError (t , err )
193
+ if sil .expectPresentAfterGc {
194
+ expectedRemaining = append (expectedRemaining , sil .s .Id )
195
+ } else {
196
+ expectedGCCount += 1
197
+ }
198
+ // simulate this silences being seen in a query
199
+ silences .mc .Get (silences .st [sil .s .Id ].Silence )
200
+ }
201
+
202
+ silClock .Add (time .Second )
203
+
204
+ n , err := silences .GC ()
205
+ require .NoError (t , err )
206
+ require .Equal (t , expectedGCCount , n )
207
+
208
+ for _ , id := range expectedRemaining {
209
+ foundSil , inState := silences .st [id ]
210
+ if ! inState {
211
+ require .Failf (t , "silence %s was missing from final state" , id )
212
+ }
213
+ if _ , ok := silences .mc [foundSil .Silence .Id ]; ! ok {
214
+ require .Failf (t , "silence %s's matchers were missing from the matcherCache" , id )
215
+ }
216
+ }
217
+ require .Equalf (t , len (expectedRemaining ), len (silences .st ), "there are extra silences in the final state" )
218
+ require .Equalf (t , len (expectedRemaining ), len (silences .mc ), "there are extra entries in the matcher cache" )
219
+
220
+ })
221
+ }
222
+
223
+ }
224
+
112
225
func TestSilencesSnapshot (t * testing.T ) {
113
226
// Check whether storing and loading the snapshot is symmetric.
114
227
now := clock .NewMock ().Now ().UTC ()
0 commit comments