package monitoring import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" ) func TestAlertmanagerClient_ListAlerts(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/v2/alerts" { t.Errorf("unexpected path: %s", r.URL.Path) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`[ { "annotations": {"summary": "Target is down"}, "endsAt": "2024-01-01T01:00:00Z", "fingerprint": "abc123", "receivers": [{"name": "default"}], "startsAt": "2024-01-01T00:00:00Z", "status": {"inhibitedBy": [], "silencedBy": [], "state": "active"}, "updatedAt": "2024-01-01T00:00:00Z", "generatorURL": "http://prometheus:9090/graph", "labels": {"alertname": "TargetDown", "severity": "critical", "instance": "node1:9100"} } ]`)) })) defer srv.Close() client := NewAlertmanagerClient(srv.URL) alerts, err := client.ListAlerts(context.Background(), AlertFilters{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(alerts) != 1 { t.Fatalf("expected 1 alert, got %d", len(alerts)) } if alerts[0].Fingerprint != "abc123" { t.Errorf("expected fingerprint=abc123, got %s", alerts[0].Fingerprint) } if alerts[0].Labels["alertname"] != "TargetDown" { t.Errorf("expected alertname=TargetDown, got %s", alerts[0].Labels["alertname"]) } if alerts[0].Status.State != "active" { t.Errorf("expected state=active, got %s", alerts[0].Status.State) } } func TestAlertmanagerClient_ListAlertsWithFilters(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() if q.Get("active") != "true" { t.Errorf("expected active=true, got %s", q.Get("active")) } if q.Get("silenced") != "false" { t.Errorf("expected silenced=false, got %s", q.Get("silenced")) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`[]`)) })) defer srv.Close() client := NewAlertmanagerClient(srv.URL) active := true silenced := false _, err := client.ListAlerts(context.Background(), AlertFilters{ Active: &active, Silenced: &silenced, }) if err != nil { t.Fatalf("unexpected error: %v", err) } } func TestAlertmanagerClient_ListSilences(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/v2/silences" { t.Errorf("unexpected path: %s", r.URL.Path) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`[ { "id": "silence-1", "matchers": [{"name": "alertname", "value": "TargetDown", "isRegex": false}], "startsAt": "2024-01-01T00:00:00Z", "endsAt": "2024-01-01T02:00:00Z", "createdBy": "admin", "comment": "Maintenance window", "status": {"state": "active"} } ]`)) })) defer srv.Close() client := NewAlertmanagerClient(srv.URL) silences, err := client.ListSilences(context.Background()) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(silences) != 1 { t.Fatalf("expected 1 silence, got %d", len(silences)) } if silences[0].ID != "silence-1" { t.Errorf("expected id=silence-1, got %s", silences[0].ID) } if silences[0].CreatedBy != "admin" { t.Errorf("expected createdBy=admin, got %s", silences[0].CreatedBy) } } func TestAlertmanagerClient_CreateSilence(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { t.Errorf("expected POST, got %s", r.Method) } if r.URL.Path != "/api/v2/silences" { t.Errorf("unexpected path: %s", r.URL.Path) } if r.Header.Get("Content-Type") != "application/json" { t.Errorf("expected Content-Type=application/json, got %s", r.Header.Get("Content-Type")) } var silence Silence if err := json.NewDecoder(r.Body).Decode(&silence); err != nil { t.Fatalf("failed to decode request body: %v", err) } if silence.CreatedBy != "admin" { t.Errorf("expected createdBy=admin, got %s", silence.CreatedBy) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"silenceID": "new-silence-id"}`)) })) defer srv.Close() client := NewAlertmanagerClient(srv.URL) id, err := client.CreateSilence(context.Background(), Silence{ Matchers: []Matcher{ {Name: "alertname", Value: "TargetDown", IsRegex: false}, }, StartsAt: time.Now(), EndsAt: time.Now().Add(2 * time.Hour), CreatedBy: "admin", Comment: "Test silence", }) if err != nil { t.Fatalf("unexpected error: %v", err) } if id != "new-silence-id" { t.Errorf("expected id=new-silence-id, got %s", id) } } func TestAlertmanagerClient_HTTPError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte("internal error")) })) defer srv.Close() client := NewAlertmanagerClient(srv.URL) _, err := client.ListAlerts(context.Background(), AlertFilters{}) if err == nil { t.Fatal("expected error, got nil") } }