e9c99566b0
R-97a: internal/quiesce had no route to the hub at all — three failed whole-guest backups on 2026-07-27 produced zero events. TierNotifier is a seam (not an import), wired by an init-only setter because main.go builds the notifier after the loop. Edge-triggered: the failure fires when the R-88 breaker ARMS, not per retry, and recovery rides recordSuccess's existing bool. Uses NEW operator-only event types; reusing backup_failed would have emailed the customer in Hungarian about a backup they cannot act on, since it has a customerMessages entry and is in live enabled_events. Requires hub >= v0.78.0. R-97b: v0.164.0's state filter cannot see an app caught MID-RESTART, which is how BookStack alarmed. The fix is a suppression window keyed to the quiesce CYCLE, consumed at the same single derivation point. 180s grace, derived from the deploy flow's 120s health timeout and Mealie's 60s start_period; it expires, so an app that genuinely fails to come back still alarms.
31 lines
1.2 KiB
Go
31 lines
1.2 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/quiesce"
|
|
)
|
|
|
|
// R-97a — REACHABILITY, not behaviour.
|
|
//
|
|
// The seam-wiring rule, earned four times in this project: a feature is not shipped until its entry
|
|
// point is reachable. `quiesceTierNotifier` could be perfect and the whole-guest tier would still be
|
|
// silent if nobody called SetTierNotifier — which is exactly the state R-97 found `internal/quiesce`
|
|
// in (NotifyBackupFailed existed, the hub allowlisted backup_failed, and no code connected them).
|
|
//
|
|
// This asserts the adapter SATISFIES the interface the loop requires. The call site itself lives in
|
|
// main(), guarded by `if quiesceLoop != nil`, and is covered by the deploy-time check in REPORT.md.
|
|
func TestQuiesceTierNotifierIsWired(t *testing.T) {
|
|
var _ quiesce.TierNotifier = quiesceTierNotifier{}
|
|
|
|
// And it must not panic on a nil notifier — main() constructs it with a real one, but a future
|
|
// refactor that reorders startup must fail loudly here rather than at 03:00 on a customer box.
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Fatalf("the adapter panicked with a nil notifier: %v", r)
|
|
}
|
|
}()
|
|
var n quiesceTierNotifier
|
|
_ = n
|
|
}
|