66 lines
2.8 KiB
Go
66 lines
2.8 KiB
Go
package notify
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// R-1287: a D47 set-aside reaches the hub as backup_run_failures, leg `unit-set-aside`, severity error, Failed 1 —
|
|
// the payload controller 0.343.0 sends (cmd/controller/main.go SetUnitSetAsideNotify). Measured 2026-10-25 on Tester 1:
|
|
// two mails „🔴 tester-1: 1 of 1 apps failed to back up (backup run)" while nothing failed. The consequence asserted:
|
|
// the operator's mail says set aside / nothing failed, as a warning; a run with a real failure keeps its red subject.
|
|
// RED-PROOF: drop the setAsideApps branch in renderBackupRunFailures and the severity override in processEvent → the
|
|
// subject is the red „failed to back up" and the record reads error.
|
|
const setAsidePayload = `{"run_id":"unit-set-aside-tandoor-20261025T173155Z","run_kind":"backup","failed":1,"attempted":1,` +
|
|
`"apps":[{"app":"tandoor","leg":"unit-set-aside","reason":"the backup of an earlier install was set aside whole (D47)"}]}`
|
|
|
|
func r1287Dispatch(t *testing.T, details string) (subjects []string, severity string) {
|
|
t.Helper()
|
|
st := opOnlyStore(t)
|
|
d := opOnlyDispatcher(t, st, &sentTo{})
|
|
d.sendEmailFn = func(to, subject, body string, headers map[string]string) error {
|
|
if to == "operator@felhom.eu" {
|
|
subjects = append(subjects, subject)
|
|
}
|
|
return nil
|
|
}
|
|
d.ProcessEvent("c1", "backup_run_failures", "error", `App "tandoor": its backup belonged to an earlier install`, details, "controller")
|
|
logs, err := st.GetRecentNotifications("c1", 10)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, l := range logs {
|
|
if l.EventType == "backup_run_failures" {
|
|
severity = l.Severity
|
|
}
|
|
}
|
|
return subjects, severity
|
|
}
|
|
|
|
func TestR1287_ASetAsideMailsAsSetAsideNotAsAFailure(t *testing.T) {
|
|
subjects, sev := r1287Dispatch(t, setAsidePayload)
|
|
if len(subjects) != 1 {
|
|
t.Fatalf("the operator got %d mail(s), want 1: %v", len(subjects), subjects)
|
|
}
|
|
s := subjects[0]
|
|
if strings.Contains(s, "failed to back up") || strings.Contains(s, "🔴") {
|
|
t.Fatalf("a set-aside is dressed as a red backup failure: %q", s)
|
|
}
|
|
if !strings.Contains(s, "set aside — nothing failed") || !strings.Contains(s, "tandoor") || !strings.Contains(s, "⚠️") {
|
|
t.Fatalf("the subject must say set aside / nothing failed and name the app: %q", s)
|
|
}
|
|
if sev != "warning" {
|
|
t.Fatalf("the record reads %q, want warning", sev)
|
|
}
|
|
}
|
|
|
|
func TestR1287_ARunWithARealFailureKeepsItsRedSubject(t *testing.T) {
|
|
mixed := `{"run_kind":"backup","failed":2,"attempted":5,"apps":[` +
|
|
`{"app":"tandoor","leg":"unit-set-aside","reason":"set aside (D47)"},` +
|
|
`{"app":"immich","leg":"recovery-unit","reason":"disk full"}]}`
|
|
subjects, sev := r1287Dispatch(t, mixed)
|
|
if len(subjects) != 1 || !strings.Contains(subjects[0], "2 of 5 apps failed to back up") || sev != "error" {
|
|
t.Fatalf("a run with a real failure must stay red and error: %v %q", subjects, sev)
|
|
}
|
|
}
|