package notify import ( "io" "log" "testing" ) // R-339, Group G — THE WIRING TEST, and it is not optional. // // The recovery leg spans two packages: internal/monitor emits, internal/notify routes. A fake-injected // test in monitor proves the checker emits and proves NOTHING about whether the operator receives the // mail. Both `*_box_recovered` events carry severity "info", and severityNotifies drops "info" — so // without an entry in recoveredPairedDownTypes they are stored and never mailed, and the operator is // told the off-site tier went blind and never told it came back. // // Precedent for why this test exists at all: agent v0.91.0 shipped fully green with SetAuthSink never // called from main.go, and the entire auth-honesty leg was inert. A green unit test on one side of a // seam is not evidence that the seam is connected. // // These drive ProcessEvent end-to-end and assert a MAIL, not a map entry. A map assertion would pass // on a correctly-populated map that nothing reads. func TestBoxRecovery_ReachesTheOperatorDespiteInfoSeverity(t *testing.T) { if severityNotifies("info") { t.Fatal("premise changed: \"info\" now notifies, so the pairing entries may be unnecessary — re-check") } for _, et := range []string{"pbsdr_box_recovered", "offsite_box_recovered"} { st := newDispStore(t) d := NewDispatcher(st, "test-key", "hub@felhom.eu", "op@felhom.eu", true, log.New(io.Discard, "", 0)) mails := captureSeam(d) scope := "pbsdr-box" if et == "offsite_box_recovered" { scope = "pool-box" } d.ProcessEvent(scope, et, "info", "reachable again after 45m0s", `{"scope":"`+scope+`"}`, "hub") op := mailsFor(*mails, "op@felhom.eu") if len(op) != 1 { t.Fatalf("%s: operator mails = %d, want 1 — the all-clear must reach the operator; "+ "0 means the recoveredPairedDownTypes entry is missing and \"info\" was dropped by the severity gate", et, len(op)) } // Customer leg is a no-op BY CONSTRUCTION: the scope is not a customer id, so no prefs row // exists and no paired customer "sent" row can be found. if len(*mails) != 1 { t.Fatalf("%s: total mails = %d, want 1 — a customer-less scope must never produce a customer mail", et, len(*mails)) } } } // The DOWN edge needs no pairing entry — "warning" already notifies — but if that ever changed the // operator would hear the all-clear for an outage they were never told about. Pin both edges. func TestBoxUnreachable_ReachesTheOperatorOnItsOwnSeverity(t *testing.T) { for _, c := range []struct{ scope, et string }{ {"pbsdr-box", "pbsdr_box_unreachable"}, {"pool-box", "offsite_box_unreachable"}, } { st := newDispStore(t) d := NewDispatcher(st, "test-key", "hub@felhom.eu", "op@felhom.eu", true, log.New(io.Discard, "", 0)) mails := captureSeam(d) d.ProcessEvent(c.scope, c.et, "warning", "unreachable — 3 consecutive checks failed", `{"scope":"`+c.scope+`"}`, "hub") op := mailsFor(*mails, "op@felhom.eu") if len(op) != 1 { t.Fatalf("%s: operator mails = %d, want 1", c.et, len(op)) } if len(*mails) != 1 { t.Fatalf("%s: total mails = %d, want 1 — operator-only", c.et, len(*mails)) } } } // Both recovery types must be registered against the RIGHT down type. A recovery paired with the // wrong down event would still mail the operator (processOperator runs unconditionally) while // silently breaking the customer pairing rule for any future customer-scoped reuse. func TestBoxRecovery_PairedWithTheCorrectDownType(t *testing.T) { want := map[string]string{ "pbsdr_box_recovered": "pbsdr_box_unreachable", "offsite_box_recovered": "offsite_box_unreachable", } for rec, down := range want { paired, ok := recoveredPairedDownTypes[rec] if !ok { t.Fatalf("%s is not on the recovery branch — its \"info\" severity makes it silent", rec) } found := false for _, p := range paired { if p == down { found = true } } if !found { t.Fatalf("%s must pair with %s; got %v", rec, down, paired) } } }