80aeac71f6
gates / gates (push) Successful in 29s
Red-proofs RP40-RP42. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
59 lines
2.1 KiB
Go
59 lines
2.1 KiB
Go
package monitor
|
|
|
|
import (
|
|
"database/sql"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
|
)
|
|
|
|
func hostFor(t *testing.T, st *store.Store, path string, createdAgo time.Duration) {
|
|
t.Helper()
|
|
if err := st.UpsertHost(&store.Host{HostID: "c1-abc123", CustomerID: "c1", APIKey: "hk"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
db, err := sql.Open("sqlite", path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
if _, err := db.Exec(`UPDATE hosts SET created_at = ? WHERE host_id = 'c1-abc123'`,
|
|
time.Now().UTC().Add(-createdAgo).Format("2006-01-02 15:04:05")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// R-723 (v0.126.0) — the 2026-09-29 shape: the customer's previous box went silent 12 days ago (the hub
|
|
// seeds the customer as down), a NEW box enrolls and sends its first report. The CONSEQUENCE asserted: no
|
|
// `node_recovered` (it is the operator mail „recovered" for an outage the new box never had).
|
|
// COMPANION RED-PROOF: make isNewBox return false → the event list is [node_recovered].
|
|
func TestR723_ANewBoxIsNotARecovery(t *testing.T) {
|
|
st, path := seedStalenessCustomer(t, "ok", 12*24*time.Hour)
|
|
sc, events := newChecker(t, st) // seeds c1 as down (the old box's silence)
|
|
if sc.GetState("c1") != "down" {
|
|
t.Fatalf("setup: want down, got %q", sc.GetState("c1"))
|
|
}
|
|
hostFor(t, st, path, 2*time.Minute) // the new box enrolled 2 min ago
|
|
saveReportAged(t, st, path, "ok", 0) // …and reported
|
|
sc.Check()
|
|
if len(*events) != 0 {
|
|
t.Fatalf("a new box's first report emitted %v", *events)
|
|
}
|
|
if sc.GetState("c1") != "ok" {
|
|
t.Fatalf("state %q, want ok", sc.GetState("c1"))
|
|
}
|
|
}
|
|
|
|
// Control: the SAME box, enrolled long ago, coming back after an outage IS a recovery and still mails.
|
|
func TestR723_AnOldBoxComingBackIsStillARecovery(t *testing.T) {
|
|
st, path := seedStalenessCustomer(t, "ok", 12*24*time.Hour)
|
|
sc, events := newChecker(t, st)
|
|
hostFor(t, st, path, 40*24*time.Hour)
|
|
saveReportAged(t, st, path, "ok", 0)
|
|
sc.Check()
|
|
if len(*events) != 1 || (*events)[0] != "node_recovered" {
|
|
t.Fatalf("a real recovery must still emit node_recovered, got %v", *events)
|
|
}
|
|
}
|