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") } }