c732fe1283
gates / gates (push) Successful in 18s
Both are one shape: something the box already knows, drawn as its opposite. R-259 — A DISK WE FAILED TO READ WAS DRAWN AS A HEALTHY EMPTY DISK. readDiskUsage (internal/system/info_linux.go) logged a statfs failure at DEBUG and returned, leaving the caller's TotalGB/UsedGB/AvailGB/Percent at zero — and usageColor(0) is "nominal". The dashboard's most-looked-at meter therefore rendered "0.0 GB / 0.0 GB (0%)" with a 0%-wide bar in the healthy colour. "We could not look" and "there is plenty of room" were the same picture. readDiskUsage now returns whether the measurement succeeded; SystemInfo gains DiskKnown and HDDKnown (HDDConfigured is not a substitute: it says a path was configured, not that reading it worked); and the template draws NO figure, NO percentage and NO meter fill when unknown, saying "A tarhely merete most nem olvashato ki." instead. A healthy box is byte-identical, colour band included. This session rules the convention (felhom.eu CONTEXT.md S-39): an explicit `...Known bool` companion beside the figures, checked in the template — the shape Offbox.StatsKnown already uses, whose own comment says "a 0%-wide bar over an unread store is a picture of emptiness, and a picture is a claim". Pointers and separate error fields are both legitimate Go, but a codebase with three dialects cannot be gated (ROADMAP G-3 was blocked on exactly this). Existing call sites NOT converted. R-258 — THE PER-APP BACKUP TICK WAS GREEN ON PRESENCE, AND RED ONLY ON A GLOBAL CONDITION. buildAppBackupRows set Tier1LastStatus from status.LastDBDump.Success, which is the box's single most recent dump RUN, whichever app it belonged to. An app whose own dump failed showed a tick as long as some other app dumped successfully afterwards; an app with no database took the nil branch and went green on the mere existence of a restore point. appDumpVerdict now reads THIS app's own entries in DBDumpStatus.Results (matched on DumpResult.DB.StackName, failure = non-nil Error). Three states: any failing database -> error; all clean -> ok; no result recorded -> NO verdict and no icon, titled "Errol a mentesrol nincs eredmenyunk." The recovery unit carries no per-run outcome of its own, so green cannot honestly be derived from presence. The global tier1DBStatus label is untouched — it is correct as a global. RECENCY IS DELIBERATELY NOT ADDED. A tick over a three-week-old restore point is a real weakness, but an age threshold means inventing a number and the time is already printed beside the icon. Recorded as an observation, not changed. AN EXISTING TEST WAS ASSERTING THE DEFECT AND WAS CORRECTED, NOT DELETED: TestBuildAppBackupRows_Tier1FromRestorePoints expected "ok" for a status with no LastDBDump at all — green from nothing but a file's existence. It now expects no verdict; its real subject, the Tier1LastRun time, is unchanged. The dashboard test EXTRACTS the meter block from the shipped template rather than copying it: a copied block drifts, and a drifted copy passes while the page it claims to cover has changed — the fixture-is-not-the-wire mistake this project has now hit twice. Six red-proofs across both parts, each with the mutation asserted applied. No new tag on any declared wire — report/builder.go maps into its own types and is untouched; wire_contract_gate.py confirmed green. go build / go vet / go test ./... green (28 packages), controller_gates --fast all OK, both run separately from this commit.
113 lines
4.3 KiB
Go
113 lines
4.3 KiB
Go
package web
|
|
|
|
import (
|
|
"bytes"
|
|
"html/template"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
|
|
)
|
|
|
|
// R-259 — a disk we could not measure must not be drawn as a healthy empty one.
|
|
//
|
|
// These render the REAL dashboard template block against a real SystemInfo, because the defect was
|
|
// entirely in what the markup does with a zero. A test on the Go struct alone cannot see it.
|
|
|
|
// diskMeterBlock EXTRACTS the system-disk block from the SHIPPED dashboard.html, rather than
|
|
// duplicating it here. A copied block drifts, and a drifted copy is a test that passes while the
|
|
// page it claims to cover has changed — the fixture-is-not-the-wire mistake, which this project has
|
|
// now hit twice (R-262, and the OOB fixture in hub v0.99.0).
|
|
func diskMeterBlock(t *testing.T) string {
|
|
t.Helper()
|
|
raw, err := templateFS.ReadFile("templates/dashboard.html")
|
|
if err != nil {
|
|
t.Fatalf("read dashboard.html: %v", err)
|
|
}
|
|
src := string(raw)
|
|
const startMark = `{{if not .SystemInfo.DiskKnown}}`
|
|
i := strings.Index(src, startMark)
|
|
if i < 0 {
|
|
t.Fatalf("the DiskKnown guard is not in dashboard.html — R-259's fix is not in the shipped markup")
|
|
}
|
|
// the guard's matching {{end}} is the one closing the if/else chain: take through the
|
|
// "Kritikusan kevés hely" branch and its two closers
|
|
const endMark = `Kritikusan kevés hely</div>{{end}}`
|
|
j := strings.Index(src[i:], endMark)
|
|
if j < 0 {
|
|
t.Fatal("could not find the end of the disk meter block")
|
|
}
|
|
block := src[i : i+j+len(endMark)]
|
|
// close the outer if/else opened by startMark
|
|
return block + "\n </div>\n {{end}}"
|
|
}
|
|
|
|
// renderDiskMeter renders just the system-disk block of dashboard.html with the production funcmap.
|
|
func renderDiskMeter(t *testing.T, info system.SystemInfo) string {
|
|
t.Helper()
|
|
// the block under test, copied verbatim from dashboard.html by the guard below
|
|
src := diskMeterBlock(t)
|
|
tpl, err := template.New("m").Funcs((&Server{}).templateFuncMap()).Parse(src)
|
|
if err != nil {
|
|
t.Fatalf("parse: %v", err)
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := tpl.Execute(&buf, map[string]any{"SystemInfo": info}); err != nil {
|
|
t.Fatalf("execute: %v", err)
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
func healthyDisk() system.SystemInfo {
|
|
return system.SystemInfo{
|
|
DiskTotalGB: 100, DiskUsedGB: 42, DiskAvailGB: 58, DiskPercent: 42, DiskKnown: true,
|
|
}
|
|
}
|
|
|
|
// SCENARIO D — a disk we could not read says so, and draws nothing.
|
|
func TestDiskMeter_UnknownDrawsNoPictureAndSaysSo(t *testing.T) {
|
|
// exactly what a failed statfs leaves behind: every figure zero, and now DiskKnown=false
|
|
out := renderDiskMeter(t, system.SystemInfo{DiskKnown: false})
|
|
|
|
if strings.Contains(out, "0.0 GB") || strings.Contains(out, "(0%)") {
|
|
t.Errorf("a failed measurement printed a figure — „0.0 GB / 0.0 GB (0%%)\" is R-259, "+
|
|
"and it is the healthy-looking picture of an unread disk.\n%s", out)
|
|
}
|
|
if strings.Contains(out, "meter-fill") {
|
|
t.Errorf("a meter fill was drawn for a disk that was never measured — a 0%%-wide bar over an "+
|
|
"unread store is a picture of emptiness, and a picture is a claim.\n%s", out)
|
|
}
|
|
if strings.Contains(out, "nominal") {
|
|
t.Errorf("an unmeasured disk was coloured as healthy.\n%s", out)
|
|
}
|
|
if !strings.Contains(out, "nem olvashat") { // ASCII-safe fragment of „nem olvasható ki"
|
|
t.Errorf("the customer is not told the measurement could not be taken.\n%s", out)
|
|
}
|
|
}
|
|
|
|
// SCENARIO E — a disk we CAN read is unchanged, including its colour band.
|
|
func TestDiskMeter_KnownIsUnchanged(t *testing.T) {
|
|
out := renderDiskMeter(t, healthyDisk())
|
|
|
|
// fmtGB: >=100 renders whole, >=10 renders one decimal (funcmap.go:208-215)
|
|
for _, want := range []string{"42.0 GB", "100 GB", "(42%)", "meter-fill", "nominal"} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("a healthy box lost %q from its meter — this change must be invisible on a "+
|
|
"machine that is fine.\n%s", want, out)
|
|
}
|
|
}
|
|
if strings.Contains(out, "nem olvashat") {
|
|
t.Errorf("a healthy box gained the could-not-measure caveat.\n%s", out)
|
|
}
|
|
}
|
|
|
|
// The colour bands still work on a known disk — the guard must not have swallowed them.
|
|
func TestDiskMeter_KnownStillBands(t *testing.T) {
|
|
crit := healthyDisk()
|
|
crit.DiskPercent = 92
|
|
out := renderDiskMeter(t, crit)
|
|
if !strings.Contains(out, "crit") || !strings.Contains(out, "Kritikusan") {
|
|
t.Errorf("a critically full KNOWN disk lost its warning.\n%s", out)
|
|
}
|
|
}
|