package monitor import ( "context" "errors" "io" "log" "testing" "time" ) // R-242 second half (S4, decision 199). The CONSEQUENCE: a published-but-unvouched golden raises one // operator warning after the grace; a vouch clears it; Gitea down says nothing. // RED-PROOF: make Check return before onEvent (the pre-v0.147.0 hub had no such checker) → "want 1 alarm". func TestGoldenVouchChecker(t *testing.T) { now := time.Date(2026, 10, 12, 12, 0, 0, 0, time.UTC) published := []string{"0.308.0", "0.301.0"} var listErr error vouched := "0.301.0" var events []string gc := NewGoldenVouchChecker( func(context.Context) ([]string, error) { return published, listErr }, func() string { return vouched }, func(cust, typ, sev, msg, det, src string) { events = append(events, typ+"/"+sev) }, log.New(io.Discard, "", 0)) gc.now = func() time.Time { return now } step := func(d time.Duration) { now = now.Add(d); gc.Check() } step(0) // first sight of the gap — no alarm yet step(time.Hour) if len(events) != 0 { t.Fatalf("alarm inside the grace: %v", events) } step(61 * time.Minute) // past 2 h if len(events) != 1 || events[0] != "golden_not_vouched/warning" { t.Fatalf("want 1 alarm golden_not_vouched/warning, got %v", events) } step(time.Hour) if len(events) != 1 { t.Fatalf("the same version alarmed twice: %v", events) } vouched = "0.308.0" // the operator vouches step(time.Hour) published = []string{"0.309.0", "0.308.0"} listErr = errors.New("gitea down") step(5 * time.Hour) if len(events) != 1 { t.Fatalf("an unreachable Gitea must not alarm: %v", events) } // Throttle: two calls within 15 min list once. calls := 0 gc2 := NewGoldenVouchChecker(func(context.Context) ([]string, error) { calls++; return published, nil }, func() string { return "0.309.0" }, func(_, _, _, _, _, _ string) {}, log.New(io.Discard, "", 0)) t0 := now gc2.now = func() time.Time { return t0 } gc2.Check() gc2.Check() if calls != 1 { t.Fatalf("throttle: %d listings in one window, want 1", calls) } }