Files
felhom-controller/controller/internal/web/r403_surface_test.go
T
admin b48a7fa326
gates / gates (push) Successful in 11s
R-403: the restore OUTCOME names the package's date, not the run's
Live on demo-hp the confirm said 11:43 (the preserved package) and the outcome said 14:23 (the
copy's newest run) for the same restore. A customer reading both cannot tell which one they had, and
one of the two is the flattering sentence. Part 2.3's rule is 'not a plain green success ANYWHERE',
and the outcome is an anywhere.

tier2UnitSourceMsg now asks UnitRestoreDate, the same resolver the confirm uses, so the two cannot
disagree. TestR403_OutcomeNamesThePackageDateNotTheRunDate pins it, with a negative control for the
ordinary case.
2026-08-31 14:32:29 +02:00

138 lines
6.1 KiB
Go

package web
import (
"strings"
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/backup"
)
// R-403 Group D — the surfaces must not call a PRESERVED package a FRESH one.
//
// The guard keeps the customer's data. That gain is thrown away if the page then reports the run's
// own timestamp as the package's date: the customer would restore a week-old package believing it was
// last night's. Trading a data loss for a comforting lie is the failure family this project keeps
// finding, and it is not a fix.
//
// Every assertion compares against the NAMED CONSTANT rather than a Hungarian literal retyped here
// (R-364): a re-typed accented string can differ from the shipped one by a character nobody sees.
// D1 — TestR403_SkippedUnitLegIsNotRenderedAsFresh.
func TestR403_SkippedUnitLegIsNotRenderedAsFresh(t *testing.T) {
const runDate = "2026-08-31T03:30:00Z"
const pkgDate = "2026-08-25T03:30:00Z"
stale := r103Row(true, pkgDate, true)
stale.Tier2LastRun, stale.Tier2LastSuccess = runDate, runDate
stale.Tier2UnitStaleNotice = staleNoticeFor(pkgDate)
html := renderBackupPage(t, "backups_apps", baseBackupData([]AppBackupRow{stale}))
if !strings.Contains(html, stale.Tier2UnitStaleNotice) {
t.Error("the preserved-package notice is not on the page — a preserved copy renders as a fresh one")
}
// The PACKAGE's date is shown, not only the run's.
if !strings.Contains(html, fmtRFC3339Local(pkgDate)) {
t.Errorf("the package's own date %q is not on the page", fmtRFC3339Local(pkgDate))
}
// NEGATIVE CONTROL: an ordinary row must NOT carry the notice, or D1 would pass on a page that
// shows the warning to everybody.
fresh := r103Row(true, runDate, true)
freshHTML := renderBackupPage(t, "backups_apps", baseBackupData([]AppBackupRow{fresh}))
if strings.Contains(freshHTML, staleNoticeFor(pkgDate)) {
t.Error("an ordinary row carried the preserved-package notice")
}
if !strings.Contains(freshHTML, "/backup/tier2/unit-restore") {
t.Fatal("the ordinary row did not render at all — the negative control proves nothing")
}
}
func staleNoticeFor(pkgDate string) string {
return strings.Replace(tier2UnitStaleNoticeFmt, "%s", fmtRFC3339Local(pkgDate), 1)
}
// D2 — TestR403_UnitRestoreOfferNamesTheOlderPackageDate.
//
// The confirm is the last thing between the customer and an overwrite of their live data. After a
// preserved leg it must name the PACKAGE's date and say why it is older than the copy's newest run.
func TestR403_UnitRestoreOfferNamesTheOlderPackageDate(t *testing.T) {
const pkgDate = "2026-08-25T03:30:00Z"
staleConfirm := tier2UnitConfirmWithStaleness(pkgDate, true, true)
freshConfirm := tier2UnitConfirmWithStaleness(pkgDate, true, false)
if !strings.Contains(staleConfirm, tier2UnitStaleClause) {
t.Error("the confirm does not say the package is older than the newest run")
}
if !strings.Contains(staleConfirm, fmtRFC3339Local(pkgDate)) {
t.Error("the confirm does not name the package's date")
}
// Everything the ordinary confirm promised is still promised.
if !strings.Contains(staleConfirm, tier2UnitConfirmBase) || !strings.Contains(staleConfirm, tier2UnitConfirmContrast) {
t.Error("the stale confirm lost the overwrite warning or the additive contrast")
}
// NEGATIVE CONTROL: the ordinary confirm must NOT carry the clause.
if strings.Contains(freshConfirm, tier2UnitStaleClause) {
t.Error("an ordinary confirm carried the preserved-package clause")
}
if staleConfirm == freshConfirm {
t.Error("a preserved package and a fresh one produced the SAME confirm")
}
// And it reaches the rendered markup, not only the constant.
row := r103Row(true, pkgDate, true)
row.Tier2UnitConfirm = staleConfirm
html := renderBackupPage(t, "backups_apps", baseBackupData([]AppBackupRow{row}))
if !strings.Contains(html, "FIGYELEM") { // ASCII-only fragment, R-364
t.Error("the stale clause never reached the page")
}
// The ASCII control: the same page WITHOUT the clause must not match.
rowFresh := r103Row(true, pkgDate, true)
freshHTML := renderBackupPage(t, "backups_apps", baseBackupData([]AppBackupRow{rowFresh}))
if strings.Contains(freshHTML, "FIGYELEM") {
t.Error("the ASCII fragment matches a page that has no stale clause — the control fails")
}
}
// The two-argument wrapper still produces the ordinary confirm — yesterday's callers are unchanged.
func TestR403_TheOrdinaryConfirmIsUnchanged(t *testing.T) {
const d = "2026-08-25T03:30:00Z"
if tier2UnitConfirmMsg(d, true) != tier2UnitConfirmWithStaleness(d, true, false) {
t.Error("the two-argument confirm is no longer the not-stale case")
}
}
// D3 — the OUTCOME names the same date the CONFIRM did.
//
// Live on demo-hp 2026-08-31 they disagreed after a preserved leg: the confirm said 11:43 (the
// package) and the outcome said 14:23 (the copy's newest run). A customer reading both cannot tell
// which restore they just had, and one of the two sentences is flattering.
func TestR403_OutcomeNamesThePackageDateNotTheRunDate(t *testing.T) {
cov := backup.Tier2Coverage{
CopyLastSuccess: "2026-08-31T12:23:51Z", // the run
UnitPackageDate: "2026-08-31T09:43:41Z", // the preserved package
UnitLegPreserved: true,
}
msg := tier2UnitSourceMsg(cov)
pkg := fmtRFC3339Local("2026-08-31T09:43:41Z")
run := fmtRFC3339Local("2026-08-31T12:23:51Z")
if !strings.Contains(msg, pkg) {
t.Errorf("the outcome does not name the package's date %q: %q", pkg, msg)
}
if strings.Contains(msg, run) {
t.Errorf("the outcome names the RUN's date %q — the flattering one: %q", run, msg)
}
// The confirm and the outcome must agree.
date, stale := cov.UnitRestoreDate()
confirm := tier2UnitConfirmWithStaleness(date, true, stale)
if !strings.Contains(confirm, pkg) {
t.Errorf("the confirm does not name %q either: %q", pkg, confirm)
}
// NEGATIVE CONTROL: with no preserved leg, the package date IS the fresh one and both agree on it.
fresh := backup.Tier2Coverage{CopyLastSuccess: "2026-08-31T12:23:51Z", UnitPackageDate: "2026-08-31T12:23:00Z"}
if !strings.Contains(tier2UnitSourceMsg(fresh), fmtRFC3339Local("2026-08-31T12:23:00Z")) {
t.Error("the ordinary outcome stopped naming its own package date")
}
}