package web import ( "io" "log" "strings" "testing" ) // fix-3: a deployed-not-running app produces a self-clearing WARN dashboard banner; an empty list // clears it. COMPANION red-proof: skip SetDeadAppAlerts entirely (the pre-fix-3 silence) → GetAlerts // has no dead-app banner → the "not fut" assertion fails. func TestDeadAppAlerts_PresentAndSelfClearing(t *testing.T) { am := NewAlertManager(log.New(io.Discard, "", 0)) am.SetDeadAppAlerts([]DeadApp{{Name: "cwa", DisplayName: "Calibre-Web", State: "stopped"}}) got := am.GetAlerts() if len(got) != 1 || got[0].Level != "warning" || !strings.Contains(got[0].Message, "Telepített alkalmazás nem fut: Calibre-Web") { t.Fatalf("expected a WARN dead-app banner, got %+v", got) } if !strings.Contains(got[0].Message, "stopped") { t.Errorf("banner should carry the state: %q", got[0].Message) } // The app recovers → an empty set clears the banner (state-based, no manual dismissal). am.SetDeadAppAlerts(nil) if got := am.GetAlerts(); len(got) != 0 { t.Fatalf("dead-app banner must self-clear when the app recovers, got %+v", got) } } // Above the group threshold, many dead apps collapse to ONE grouped banner (a reboot storm must not // paper the dashboard). func TestDeadAppAlerts_GroupedAboveThreshold(t *testing.T) { am := NewAlertManager(log.New(io.Discard, "", 0)) var many []DeadApp for _, n := range []string{"radarr", "jellyfin", "navidrome", "calibre", "seerr"} { many = append(many, DeadApp{Name: n, DisplayName: n, State: "stopped"}) } am.SetDeadAppAlerts(many) got := am.GetAlerts() if len(got) != 1 || !strings.Contains(got[0].Message, "5 telepített alkalmazás nem fut") { t.Fatalf("expected one grouped banner for %d dead apps, got %+v", len(many), got) } }