Files
felhom-controller/controller/internal/nightchain/banner_test.go
T

124 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package nightchain
import (
"testing"
"time"
)
// R-871 / decision 110 — the banner's rules. Red-proofs: catchup-2026-10-05/partB/red-proofs.txt.
func laptop() *HourDays { // on 18:00–23:59 every day of the week (Tester 2's shape)
var h HourDays
for k := 18; k <= 23; k++ {
h[k] = 7
}
return &h
}
func offAt(on bool) func(time.Time) (bool, bool) {
return func(time.Time) (bool, bool) { return on, true }
}
func base(now time.Time) BannerInput {
return BannerInput{Now: now, Window: "02:30", Loc: bud, SeededAt: at(1, 12, 0), DBDumpOK: at(3, 2, 31),
OnAtW: offAt(false), Hours: laptop()}
}
// Shown: the last dump is 2+ days old, the box was off at 02:30, and the record suggests 21:00.
// RED-PROOF: return Banner{} when stale (the pre-v0.295.0 silence) → "not shown".
func TestBanner_ShownWithReasonAndSuggestion(t *testing.T) {
b := ComputeBanner(base(at(5, 19, 0)))
if !b.Show {
t.Fatal("not shown although the last backup is 2 days old")
}
if b.OffAt != "02:30" || b.Suggest != "21:00" || b.DaysAgo != 2 {
t.Fatalf("banner = %+v, want off at 02:30, suggest 21:00, 2 days ago", b)
}
}
// Not shown: a backup within the last 26 h.
func TestBanner_NotShownWhenFresh(t *testing.T) {
in := base(at(5, 19, 0))
in.DBDumpOK = at(5, 2, 31)
if b := ComputeBanner(in); b.Show {
t.Fatalf("shown although the last dump is 16 h old: %+v", b)
}
}
// Not shown right after an upgrade (the ledger was seeded less than 26 h ago and knows no dump).
func TestBanner_NotShownBeforeTheRecordKnows(t *testing.T) {
in := base(at(5, 19, 0))
in.SeededAt, in.DBDumpOK = at(5, 9, 0), time.Time{}
if b := ComputeBanner(in); b.Show {
t.Fatalf("shown on the day of the upgrade: %+v", b)
}
}
// Dismissed: closed until the NEXT missed backup time, then back.
// RED-PROOF: drop the Dismissed check → "a closed banner came back without a new miss".
func TestBanner_DismissedThenBackAfterANewMiss(t *testing.T) {
in := base(at(5, 19, 0))
b := ComputeBanner(in)
in.Dismissed = b.MissedAt // the household closed it (02:30 on the 5th)
if ComputeBanner(in).Show {
t.Fatal("a closed banner came back without a new miss")
}
in.Now = at(5, 23, 0) // same evening — still the same miss
if ComputeBanner(in).Show {
t.Fatal("a closed banner came back the same evening")
}
in.Now = at(6, 19, 0) // off again at 02:30 on the 6th
if !ComputeBanner(in).Show {
t.Fatal("the banner did not come back after the next missed backup time")
}
}
// Gone by itself after a successful night (e.g. the catch-up ran).
func TestBanner_GoneAfterASuccess(t *testing.T) {
in := base(at(5, 19, 0))
in.DBDumpOK = at(5, 18, 20) // the catch-up's dump
if ComputeBanner(in).Show {
t.Fatal("still shown after a successful backup")
}
}
// The off-site tier counts when configured: a fresh dump with a 3-day-old off-site copy still shows.
func TestBanner_OffsiteTierCounts(t *testing.T) {
in := base(at(5, 19, 0))
in.DBDumpOK = at(5, 18, 20)
in.OffsiteConfigured, in.OffsiteOK = true, at(2, 4, 20)
b := ComputeBanner(in)
if !b.Show || b.DaysAgo != 3 {
t.Fatalf("banner = %+v, want shown with the off-site copy's 3 days", b)
}
}
// No clear pattern → no suggestion ("choose a time when the box is usually on"); box ON at W → no "off at".
// RED-PROOF: let Suggest return the first start without checking the days → a time is suggested from noise.
func TestBanner_NoPatternNoSuggestion(t *testing.T) {
in := base(at(5, 19, 0))
var noisy HourDays
for k := 18; k <= 23; k++ {
noisy[k] = 2 // on some evenings — 2 of 7 days is not "usually"
}
in.Hours, in.OnAtW = &noisy, offAt(true)
b := ComputeBanner(in)
if !b.Show || b.Suggest != "" || b.OffAt != "" {
t.Fatalf("banner = %+v, want shown, no suggestion, no 'off at'", b)
}
}
// A box usually ON at its window gets no new time (the miss has another cause).
func TestBanner_UsuallyOnAtWNoSuggestion(t *testing.T) {
var always HourDays
for k := range always {
always[k] = 7
}
if s := Suggest(always, 2); s != "" {
t.Fatalf("suggested %q for a box that is on at its window", s)
}
if s := Suggest(*laptop(), 2); s != "21:00" {
t.Fatalf("laptop suggestion %q, want 21:00", s)
}
}