0fe04bb6d5
gates / gates (push) Successful in 28s
The 2026-09-20 English drill ended one screen short: the claim page was English and its answers were Hungarian, so a household who mistyped the code from their e-mail could not tell a typo from a dead code. Fourteen call sites carrying nine messages now go through s.msg; the backup page's two protection warnings — which are promises about whether the customer's files are safe — follow the same route. Hungarian is byte-identical, proved structurally by the go-parity gate against the frozen base capture and red-proofed on a single added full stop. data["Title"] was DEAD (claim.html is standalone; .Title is layout.html's) and is deleted rather than translated — a translated dead field is a permanent false signal about where the page's title comes from. Six existing copy-contract tests were kept, not weakened: each now resolves its key through the real bundle, so it still convicts on a reworded Hungarian sentence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
146 lines
6.8 KiB
Go
146 lines
6.8 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
|
|
)
|
|
|
|
// R-112 — SCENARIO E: THE SEAM. This is the test whose absence let E-2 ship.
|
|
//
|
|
// The endpoint was byte-correct the whole time. `resolveBackupTargetState` produced the right state,
|
|
// `degradedMessageFor` produced the right Hungarian, and v0.185.1 even added a test proving the route
|
|
// dispatched. None of that was ever reachable by a customer, because NOTHING fetched or rendered it:
|
|
// the controller's templates fetch 18 distinct /api/storage/* endpoints and backup-target was one of
|
|
// only two with zero references (felhom.eu audits/E2D-fresh-vm-2026-07-29.md §5.1).
|
|
//
|
|
// So these tests deliberately do NOT call the resolver and assert its string — that proves the
|
|
// resolver, which was never broken. They drive `backupsHandler` over httptest and assert the RENDERED
|
|
// HTML, travelling handler → backupTargetView → resolveBackupTargetState → degradedMessageFor →
|
|
// the production "backups" template. Delete the one line in backupsHandler that sets
|
|
// data["BackupTarget"] and every assertion below fails, which is precisely the class of regression
|
|
// that shipped five times in this project.
|
|
|
|
// renderBackupsPage drives the REAL page handler and returns the HTML a browser would receive.
|
|
func renderBackupsPage(t *testing.T, primary string, disks []agentapi.DiskInfo, registerPath string) string {
|
|
t.Helper()
|
|
s := absentHarness(t, primary, disks, registerPath)
|
|
s.loadTemplates()
|
|
rr := httptest.NewRecorder()
|
|
s.backupsHandler(rr, httptest.NewRequest("GET", "/backups", nil))
|
|
if rr.Code != 200 {
|
|
t.Fatalf("backups page returned %d, want 200", rr.Code)
|
|
}
|
|
return rr.Body.String()
|
|
}
|
|
|
|
// C — configured, drive absent: the truthful copy reaches the page, and no offer does.
|
|
func TestBackupsPageRendersTheAbsentDriveCopy(t *testing.T) {
|
|
html := renderBackupsPage(t, "felhom-backup", []agentapi.DiskInfo{theVanishedDrive}, "/mnt/felhom-drives/mentes2")
|
|
|
|
if !strings.Contains(html, huText(t, backupTargetAbsentKey)) {
|
|
t.Error("the absent-drive copy never reached the page — the customer is told nothing while " +
|
|
"their backup drive is missing (R-112: the state had no consumer at all)")
|
|
}
|
|
if strings.Contains(html, huText(t, backupTargetDegradedKey)) {
|
|
t.Error("the page shows the SYSTEM-DISK copy for an absent configured drive (R-114)")
|
|
}
|
|
// Assert the CONTROL's markup, not the bare id: the page script always contains
|
|
// getElementById('backup-target-assign'), so a substring match on the id alone matches the
|
|
// script and reports a control that is not there. (This test caught exactly that on itself.)
|
|
if strings.Contains(html, `id="backup-target-assign"`) {
|
|
t.Error("an offer control rendered while the configured target is absent — the remedy is to " +
|
|
"reconnect that drive, not to pick another")
|
|
}
|
|
if strings.Contains(html, `id="backup-target-offer"`) {
|
|
t.Error("the offer block rendered while the configured target is absent")
|
|
}
|
|
}
|
|
|
|
// A — never configured: the copy AND the offer control both render, and the control carries the
|
|
// drive's path so accepting it can only ever assign that one.
|
|
func TestBackupsPageRendersTheOfferWhenNeverConfigured(t *testing.T) {
|
|
html := renderBackupsPage(t, builtinLocalTarget, []agentapi.DiskInfo{{
|
|
Name: "hdd1", MountPath: "/mnt/hdd1", GuestPath: "/mnt/felhom-drives/hdd1", Role: "user-data",
|
|
}}, "/mnt/felhom-drives/hdd1")
|
|
|
|
if !strings.Contains(html, huText(t, backupTargetDegradedKey)) {
|
|
t.Error("the degraded copy never reached the page")
|
|
}
|
|
if !strings.Contains(html, huText(t, backupTargetOfferKey)) {
|
|
t.Error("the offer copy never reached the page")
|
|
}
|
|
if !strings.Contains(html, `id="backup-target-assign"`) {
|
|
t.Error("no offer control rendered — the customer is told to attach a drive but given no way " +
|
|
"to assign the one they already have")
|
|
}
|
|
if !strings.Contains(html, `data-path="/mnt/felhom-drives/hdd1"`) {
|
|
t.Error("the offer control does not carry the offered drive's path")
|
|
}
|
|
// It is an OFFER: it must not submit itself.
|
|
if strings.Contains(html, "backup-target-assign.click()") || strings.Contains(html, "autosubmit") {
|
|
t.Error("the offer control auto-submits — declining must be possible by doing nothing")
|
|
}
|
|
}
|
|
|
|
// B — healthy renders NOTHING. Assert the absence of all three strings, not the absence of an error.
|
|
func TestBackupsPageRendersNothingWhenHealthy(t *testing.T) {
|
|
html := renderBackupsPage(t, "felhom-backup", []agentapi.DiskInfo{{
|
|
Name: "mentes2", MountPath: "/mnt/mentes2", GuestPath: "/mnt/felhom-drives/mentes2",
|
|
Role: "user-data", BackupTarget: true,
|
|
}}, "/mnt/felhom-drives/mentes2")
|
|
|
|
assertNoBackupTargetCopy(t, html, "a HEALTHY box grew a banner — a working configuration must "+
|
|
"look normal, or every dashboard carries a permanent notice and warnings stop being read")
|
|
}
|
|
|
|
// D — unknown renders NOTHING. Not being able to ask the agent is not evidence of degradation.
|
|
func TestBackupsPageRendersNothingWhenAgentUnreachable(t *testing.T) {
|
|
s := testServer(t)
|
|
if err := s.settings.AddStoragePath(settings.StoragePath{Path: "/mnt/felhom-drives/hdd1"}); err != nil {
|
|
t.Fatalf("register: %v", err)
|
|
}
|
|
// No tiersFn/disksFn seams and no configured endpoint → agentClient() fails → Known:false.
|
|
s.loadTemplates()
|
|
rr := httptest.NewRecorder()
|
|
s.backupsHandler(rr, httptest.NewRequest("GET", "/backups", nil))
|
|
|
|
assertNoBackupTargetCopy(t, rr.Body.String(), "an UNREACHABLE agent produced a customer warning — "+
|
|
"absence of an answer is not evidence of degradation (R-88 Part 2's mistake)")
|
|
}
|
|
|
|
func assertNoBackupTargetCopy(t *testing.T, html, why string) {
|
|
t.Helper()
|
|
for _, s := range []struct{ frag, name string }{
|
|
{huText(t, backupTargetDegradedKey), "the system-disk copy"},
|
|
{huText(t, backupTargetAbsentKey), "the absent-drive copy"},
|
|
{huText(t, backupTargetOfferKey), "the offer copy"},
|
|
} {
|
|
if strings.Contains(html, s.frag) {
|
|
t.Errorf("%s rendered: %s", s.name, why)
|
|
}
|
|
}
|
|
if strings.Contains(html, `id="backup-target-alert"`) {
|
|
t.Errorf("the banner element rendered: %s", why)
|
|
}
|
|
}
|
|
|
|
// The view is nil — not an empty struct — in the two silent states, so a template typo cannot
|
|
// accidentally decorate a working box with an empty alert box.
|
|
func TestBackupTargetViewIsNilWhenNothingShouldRender(t *testing.T) {
|
|
healthy := absentHarness(t, "felhom-backup", []agentapi.DiskInfo{{
|
|
MountPath: "/mnt/mentes2", GuestPath: "/mnt/felhom-drives/mentes2", Role: "user-data", BackupTarget: true,
|
|
}}, "")
|
|
if v := healthy.backupTargetView(context.Background(), "hu"); v != nil {
|
|
t.Errorf("healthy returned a non-nil view %+v — nil is what makes the template render nothing", v)
|
|
}
|
|
unknown := testServer(t)
|
|
if v := unknown.backupTargetView(context.Background(), "hu"); v != nil {
|
|
t.Errorf("unknown returned a non-nil view %+v", v)
|
|
}
|
|
}
|