package web import ( "fmt" "strings" "testing" "time" "gitea.dooplex.hu/admin/felhom-hub/internal/store" "gitea.dooplex.hu/admin/felhom-hub/internal/sysfacts" ) // R-444 (`09` §3 decision 139): the System page's "Last disk trim" cell — one case per branch. Staleness is judged on // last_ok_at, never on the attempt time ("presence is not success"). func TestTrimCell(t *testing.T) { now := time.Date(2026, 10, 6, 12, 0, 0, 0, time.UTC) at := func(d time.Duration) string { return now.Add(-d).Format(time.RFC3339) } day := 24 * time.Hour dt := func(gs ...sysfacts.GuestTrim) *sysfacts.DiskTrim { return &sysfacts.DiskTrim{Schedule: "weekly", Guests: gs} } cases := []struct { name string dt *sysfacts.DiskTrim text string class string titleHas string }{ {"agent sends nothing", nil, "—", "", "reports no disk trim"}, {"stanza, no guest yet", dt(), "none yet", "", "has not trimmed a guest yet"}, {"recent ok", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(2 * day), LastOKAt: at(2 * day), OK: true, BytesTrimmed: 32427003904}), "2 days ago · 30.2 GiB", "", "schedule: weekly"}, {"ok but older than 14 days", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(15 * day), LastOKAt: at(15 * day), OK: true, BytesTrimmed: 1 << 30}), "15 days ago · 1.0 GiB", "warn", "older than 14 days"}, {"exactly 14 days is not stale", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(14 * day), LastOKAt: at(14 * day), OK: true}), "14 days ago · 0.0 GiB", "", ""}, {"newest failed, recent success before it", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(1 * day), LastOKAt: at(8 * day), OK: false, Error: "pct fstrim: exit 255"}), "FAILED 24 h ago: pct fstrim: exit 255 (last ok 8 days ago)", "warn", "the newest trim failed"}, {"failed and never ok", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(1 * day), OK: false}), "FAILED 24 h ago: no error text (never ok)", "warn", "the newest trim failed"}, {"a recent ATTEMPT does not hide a 20-day-old success", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(1 * day), LastOKAt: at(20 * day), OK: false, Error: "busy"}), "FAILED 24 h ago: busy (last ok 20 days ago)", "warn", "older than 14 days"}, {"two guests, one amber", dt( sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: at(2 * day), LastOKAt: at(2 * day), OK: true, BytesTrimmed: 2 << 30}, sysfacts.GuestTrim{VMID: 9202, LastAttemptAt: at(1 * day), OK: false, Error: "x"}), "9201: 2 days ago · 2.0 GiB / 9202: FAILED 24 h ago: x (never ok)", "warn", "guest 9202"}, {"unreadable time", dt(sysfacts.GuestTrim{VMID: 9201, LastAttemptAt: "yesterday", OK: true}), "unknown", "warn", "unreadable last_attempt_at"}, } for _, c := range cases { got := trimCell(c.dt, now) if got.Text != c.text || got.Class != c.class || !strings.Contains(got.Title, c.titleHas) { t.Errorf("%s: got %+v, want text %q class %q title containing %q", c.name, got, c.text, c.class, c.titleHas) } } } // The cell reaches the rendered page, read from the stored host report (the endpoint the operator's browser calls). func TestSystemPage_LastDiskTrim(t *testing.T) { s, st, _ := systemServer(t) when := time.Now().Add(-20 * 24 * time.Hour).UTC().Format(time.RFC3339) body := fmt.Sprintf(`{"host":{"cpu_percent":1},"guest_disk_trim":{"schedule":"weekly","guests":[{"vmid":9201,"last_attempt_at":%q,"ok":true,"bytes_trimmed":32427003904,"mounts":2,"duration_seconds":24.4,"last_ok_at":%q}]}}`, when, when) if err := st.UpsertHost(&store.Host{HostID: "trim-1", CustomerID: "c-trim", APIKey: "k-trim"}); err != nil { t.Fatal(err) } if err := st.SaveHostReport("trim-1", "c-trim", []byte(body), store.HostReportDenorm{AgentVersion: "0.150.0", CloudflaredStatus: "running"}); err != nil { t.Fatal(err) } b := getSystem(t, s) if !strings.Contains(b, ">Last disk trim") { t.Error("the System page lacks the Last disk trim column") } if !strings.Contains(b, "20 days ago · 30.2 GiB") { t.Errorf("the trim-1 box's trim is not on the page") } if !strings.Contains(b, `class="c-warn" title="guest 9201: the last successful trim is older than 14 days`) { t.Error("a 20-day-old trim must be amber, with its reason") } if !strings.Contains(b, `title="the agent reports no disk trim`) { t.Error("a box whose agent sends no trim must read — with its reason") } }