4110da50e9
gates / gates (push) Successful in 27s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
83 lines
3.6 KiB
Go
83 lines
3.6 KiB
Go
package web
|
|
|
|
import (
|
|
"bytes"
|
|
"html"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/i18n"
|
|
)
|
|
|
|
// R-685 page half (v0.272.0) — when the agent (v0.134.0+) SKIPPED a whole-box backup because it cannot fit,
|
|
// the backup page says so in plain words, in the reader's language, with the numbers the agent measured.
|
|
// Per state: a space skip (the agent's exact sentence, taken from the live proof 2026-09-24), a space skip
|
|
// whose numbers cannot be read, an ordinary failure (no line), and a success (no line); rendered through the
|
|
// REAL backups template.
|
|
//
|
|
// COMPANION RED-PROOF (REPORT.md): drop `tv.NoSpaceLine = noSpaceLine(...)` — this test fails at "a space skip
|
|
// must be said on the page".
|
|
func TestR685_BackupPageSaysTheBackupDoesNotFit(t *testing.T) {
|
|
b, err := i18n.Shared()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
now := time.Date(2026, 9, 25, 9, 0, 0, 0, time.UTC)
|
|
live := "skipped: not enough space: local has 14.9 GiB free; the last archive of guest 9201 was 7.6 GiB, so a new one needs about 11.3 GiB (old archives are removed only after a successful backup)"
|
|
tiers := func(errText string, ok bool) []agentapi.TierBackupState {
|
|
return []agentapi.TierBackupState{{Target: "local", Primary: true, Storage: "present",
|
|
LastSuccess: &agentapi.BackupRecord{StartedAt: now.Add(-50 * time.Hour).Format(time.RFC3339), SizeBytes: 8 << 30},
|
|
LastAttempt: &agentapi.TierAttempt{StartedAt: now.Add(-2 * time.Hour).Format(time.RFC3339), Success: ok, Error: errText}}}
|
|
}
|
|
cases := []struct {
|
|
name, err string
|
|
ok bool
|
|
want map[string]string // lang → substring; "" = no line
|
|
}{
|
|
{"space skip", live, false, map[string]string{
|
|
"hu": "A teljes rendszermentés nem fér el: 11.3 GiB kell, 14.9 GiB szabad.",
|
|
"en": "The full system backup does not fit: it needs 11.3 GiB and 14.9 GiB is free."}},
|
|
{"space skip, unreadable numbers", "skipped: not enough space: something new", false, map[string]string{
|
|
"hu": "A teljes rendszermentés nem fér el a lemezen.", "en": "The full system backup does not fit on the disk."}},
|
|
{"ordinary failure", "vzdump failed: job errors", false, map[string]string{"hu": "", "en": ""}},
|
|
{"success", "", true, map[string]string{"hu": "", "en": ""}},
|
|
}
|
|
s := securityHarness(t)
|
|
s.loadTemplates()
|
|
for _, c := range cases {
|
|
for _, lang := range []string{"hu", "en"} {
|
|
msg := func(key string, a ...interface{}) string {
|
|
if len(a) == 0 {
|
|
return b.Msg(lang, key)
|
|
}
|
|
return b.Msgf(lang, key, a...)
|
|
}
|
|
v := &guestBackupView{Available: true}
|
|
buildTierViews(v, tiers(c.err, c.ok), map[string]int64{"local": 86400}, now, msg)
|
|
got := v.Tiers[0].NoSpaceLine
|
|
if c.want[lang] == "" {
|
|
if got != "" {
|
|
t.Errorf("%s [%s]: no sentence expected, got %q", c.name, lang, got)
|
|
}
|
|
continue
|
|
}
|
|
if !strings.Contains(got, c.want[lang]) {
|
|
t.Fatalf("%s [%s]: a space skip must be said on the page — got %q, want %q", c.name, lang, got, c.want[lang])
|
|
}
|
|
if lang == "hu" {
|
|
var buf bytes.Buffer
|
|
if err := s.tmpl.ExecuteTemplate(&buf, "backups", map[string]interface{}{"Page": "backups", "Title": "t", "GuestBackup": v, "Backup": map[string]interface{}{"Enabled": true, "DumpFiles": []interface{}{}}}); err != nil {
|
|
t.Fatalf("the backups page did not render: %v", err)
|
|
}
|
|
out := html.UnescapeString(buf.String())
|
|
if !strings.Contains(out, c.want[lang]) || !strings.Contains(out, `data-no-space="true"`) {
|
|
i := strings.Index(out, "backup-tier-table")
|
|
t.Fatalf("%s: the rendered page does not carry the sentence; near table: %q", c.name, out[max(0, i):min(len(out), i+1500)])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|