@@ -271,3 +271,129 @@ receivers:
271271 require .EqualError (t , err , "exit status 1" )
272272 require .Equal (t , "amtool: error: Failed to parse labels: unexpected open or close brace: {foo=bar}\n \n " , string (out ))
273273}
274+
275+ func TestSilenceImport (t * testing.T ) {
276+ t .Parallel ()
277+
278+ conf := `
279+ route:
280+ receiver: "default"
281+ group_by: [alertname]
282+ group_wait: 1s
283+ group_interval: 1s
284+ repeat_interval: 1ms
285+
286+ receivers:
287+ - name: "default"
288+ webhook_configs:
289+ - url: 'http://%s'
290+ send_resolved: true
291+ `
292+
293+ at := NewAcceptanceTest (t , & AcceptanceOpts {
294+ Tolerance : 1 * time .Second ,
295+ })
296+ co := at .Collector ("webhook" )
297+ wh := NewWebhook (co )
298+
299+ amc := at .AlertmanagerCluster (fmt .Sprintf (conf , wh .Address ()), 1 )
300+ require .NoError (t , amc .Start ())
301+ defer amc .Terminate ()
302+
303+ am := amc .Members ()[0 ]
304+
305+ // Add some test silences
306+ silence1 := Silence (0 , 4 ).Match ("alertname=test1" , "severity=warning" ).Comment ("test silence 1" )
307+ silence2 := Silence (0 , 4 ).Match ("alertname=test2" , "severity=critical" ).Comment ("test silence 2" )
308+
309+ am .SetSilence (0 , silence1 )
310+ am .SetSilence (0 , silence2 )
311+
312+ // Export silences to JSON file
313+ tmpDir := t .TempDir ()
314+ exportFile := tmpDir + "/silences.json"
315+
316+ exportOut , err := am .ExportSilences ()
317+ require .NoError (t , err )
318+
319+ // Write to file
320+ err = os .WriteFile (exportFile , exportOut , 0o644 )
321+ require .NoError (t , err )
322+
323+ // Query current silences to get their IDs, then expire them
324+ sils , err := am .QuerySilence ()
325+ require .NoError (t , err )
326+ require .Len (t , sils , 2 )
327+ silIDs := make ([]string , 0 , len (sils ))
328+
329+ // Expire all silences by ID
330+ for _ , sil := range sils {
331+ id := sil .ID ()
332+ _ , err := am .ExpireSilenceByID (id )
333+ require .NoError (t , err )
334+ silIDs = append (silIDs , id )
335+ }
336+
337+ // Verify silences show as expired
338+ sils , err = am .QueryExpiredSilence ()
339+ require .NoError (t , err )
340+ // Silences should still be queryable but in expired state
341+ require .Len (t , sils , 2 , "expired silences should still be queryable" )
342+ // Check that the silences are actually expired (endsAt is in the past or equal to now)
343+ now := float64 (time .Now ().Unix ())
344+ for _ , sil := range sils {
345+ require .Contains (t , silIDs , sil .ID (), "silence ID should be in the expired list" )
346+ require .LessOrEqual (t , sil .EndsAt (), now , "silence %s should be expired" , sil .ID ())
347+ }
348+
349+ // Import silences back
350+ importOut , err := am .ImportSilences (exportFile )
351+ require .NoError (t , err , "import failed: %s" , string (importOut ))
352+
353+ // Verify silences were imported
354+ sils , err = am .QuerySilence ()
355+ require .NoError (t , err )
356+ require .GreaterOrEqual (t , len (sils ), 2 , "expected at least 2 silences after import" )
357+ }
358+
359+ func TestSilenceImportInvalidJSON (t * testing.T ) {
360+ t .Parallel ()
361+
362+ conf := `
363+ route:
364+ receiver: "default"
365+ group_by: [alertname]
366+ group_wait: 1s
367+ group_interval: 1s
368+ repeat_interval: 1ms
369+
370+ receivers:
371+ - name: "default"
372+ webhook_configs:
373+ - url: 'http://%s'
374+ send_resolved: true
375+ `
376+
377+ at := NewAcceptanceTest (t , & AcceptanceOpts {
378+ Tolerance : 1 * time .Second ,
379+ })
380+ co := at .Collector ("webhook" )
381+ wh := NewWebhook (co )
382+
383+ amc := at .AlertmanagerCluster (fmt .Sprintf (conf , wh .Address ()), 1 )
384+ require .NoError (t , amc .Start ())
385+ defer amc .Terminate ()
386+
387+ am := amc .Members ()[0 ]
388+
389+ // Create file with invalid JSON
390+ tmpDir := t .TempDir ()
391+ invalidFile := tmpDir + "/invalid.json"
392+ err := os .WriteFile (invalidFile , []byte (`[{"broken": "json"` ), 0o644 )
393+ require .NoError (t , err )
394+
395+ // Try to import - should fail
396+ out , err := am .ImportSilences (invalidFile )
397+ require .Error (t , err , "import should fail with invalid JSON" )
398+ require .Contains (t , string (out ), "couldn't unmarshal" , "error message should mention JSON parsing" )
399+ }
0 commit comments