package main import ( "go/ast" "go/parser" "go/token" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/i18n" ) // R-359 — the scheduled job must be PROVEN WIRED. // // `func main()` cannot be called from a test, so this walks its AST. A `strings.Contains` would not // do: a commented-out call still contains the string, and this project has a recorded case of a // text-based wiring test passing the very red-proof it existed to fail (2026-07-21). // // This is the check for the class that has now bitten seven times here — a complete mechanism with no // caller. R-397 is one instance (the notifiers), R-400 another (the debug button that posted to // nothing). A job that exists and is never registered would be the third in this one release. func TestR359_JobIsRegisteredInMain(t *testing.T) { body := mainBody(t) var found, named bool ast.Inspect(body, func(n ast.Node) bool { call, ok := n.(*ast.CallExpr) if !ok { return true } sel, ok := call.Fun.(*ast.SelectorExpr) if !ok || sel.Sel.Name != "Daily" { return true } if len(call.Args) == 0 { return true } lit, ok := call.Args[0].(*ast.BasicLit) if !ok || lit.Kind != token.STRING { return true } if lit.Value == `"offsite-integrity"` { found = true // The schedule argument must be a literal time, not a variable that could resolve to "". if len(call.Args) > 1 { if s, ok := call.Args[1].(*ast.BasicLit); ok && s.Kind == token.STRING && len(s.Value) > 2 { named = true } } } return true }) if !found { t.Fatal("func main() never registers the `offsite-integrity` daily job — the check exists and " + "nothing would ever run it, which is the built-but-never-wired class this release closes " + "two instances of") } if !named { t.Error("the job is registered without a literal HH:MM schedule") } } // TestR359_DebugCallbackIsWired pins the other caller. The debug button posted to a route that did not // exist for its entire life (R-400); a route that exists but whose callback is nil is the same defect // one layer down, and it would answer „Nem bekötött" forever. func TestR359_DebugCallbackIsWired(t *testing.T) { body := mainBody(t) var wired bool ast.Inspect(body, func(n ast.Node) bool { as, ok := n.(*ast.AssignStmt) if !ok { return true } for _, lhs := range as.Lhs { sel, ok := lhs.(*ast.SelectorExpr) if ok && sel.Sel.Name == "RunIntegrityCheck" { wired = true } } return true }) if !wired { t.Fatal("DebugCallbacks.RunIntegrityCheck is never assigned in func main() — the debug route " + "would answer „Nem bekötött" + " forever, which is exactly the shape of the button this " + "release is fixing") } } func TestR359_OutcomeMessagesCarryNoMachineDetail(t *testing.T) { // The customer gets a sentence; restic's words go to the log. R-379: 615 bytes of raw database // text reached a customer once. R-585: the sentence is a bundle key now, so BOTH languages are // held to it — an English household must be told what not to do just as plainly. b, err := i18n.Shared() if err != nil { t.Fatal(err) } for _, tc := range []struct { lang string wants []string }{ {"hu", []string{"Ne törölj semmit", "vedd fel velünk a kapcsolatot"}}, {"en", []string{"Do not delete anything", "contact us"}}, } { msg, fellBack, ok := b.Text(tc.lang, "event.backup_integrity_failed") if !ok || fellBack { t.Fatalf("%s: event.backup_integrity_failed is missing (ok=%v fellBack=%v)", tc.lang, ok, fellBack) } for _, bad := range []string{"sftp:", "restic", "exit status", "@", "/srv/"} { if contains(msg, bad) { t.Errorf("%s: the failure sentence carries machine detail %q: %q", tc.lang, bad, msg) } } // It must still tell them what to do — and what NOT to do. for _, want := range tc.wants { if !contains(msg, want) { t.Errorf("%s: the failure sentence is a dead end; missing %q", tc.lang, want) } } } } func contains(s, sub string) bool { return len(sub) > 0 && len(s) >= len(sub) && (func() bool { for i := 0; i+len(sub) <= len(s); i++ { if s[i:i+len(sub)] == sub { return true } } return false })() } var _ = parser.ParseFile var _ = token.NewFileSet