Files
felhom-controller/controller/internal/notify/wire_golden_test.go
T
admin 5270bad76e
gates / gates (push) Successful in 23s
v0.252.0 — the sentences the program builds follow the language (R-557 slice 2 release A)
Slice 1 translated the dashboard's markup. The sentences the program BUILDS were still
Hungarian literals in Go, so an English household clicked an English button and was
answered in Hungarian. 226 of them move into the bundle here.

A flash was the hard part: it travels inside the redirect URL and is rendered by a
DIFFERENT request, so it now carries a bundle key plus its parameters. A link minted by
an older controller carries prose and is shown verbatim — never a raw key, never dropped.

Also converted: page data and view-model text, the internal/api JSON answers, the alert
banners (Alert.MessageKey, rendered on the way out of GetAlerts), 237 country names at
display, and the four page titles built around an app name (R-566 closed).

Hungarian is byte-identical, and that is measured rather than read:
scripts/i18n_go_parity.py freezes every Go literal at the base commit (7 467) and refuses
a key whose Hungarian is not that text, byte for byte. Three decoys, each seen to convict.
Its own first version filtered the capture through an ASCII-Hungarian word list and missed
seven real literals — the R-565 class. The filter is gone.

Nothing on the wire moved, and wire goldens now hold it there: the report's health
warnings and every notify event message stay Hungarian, because the hub MAILS the
controller's sentence when it has no entry of its own. Slice 3 (R-558) owns those.

MinAgent: 0.131.0 (unchanged). No hub release needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-18 10:15:56 +02:00

123 lines
4.8 KiB
Go

package notify
import (
"strings"
"testing"
)
// TestEventMessageWireTextIsFrozen — localisation slice 2 (R-557), scenario S6.
//
// An event's `message` is ON THE WIRE and, unlike most wire text, a CUSTOMER READS IT. The hub's
// FormatCustomerEmail (felhom.eu/hub/internal/notify/templates.go) uses the per-type Hungarian
// `customerMessages` entry when it has one and FALLS BACK TO THIS MESSAGE when it has none — and
// appends it as „- Üzenet: %s" whenever it differs from the entry. Several event types deliberately
// have no entry precisely so the controller's dynamic sentence is what the household is sent
// (hub/internal/api/handler.go, the notes around offbox_enlarge_blocked and its neighbours).
//
// So these sentences are NOT the dashboard's to translate. They follow the household's language in
// slice 3 (R-558), where the hub learns which language the box reports and composes the mail. Until
// then they stay Hungarian in every language, and this test is what makes "stay" measurable: the
// golden strings below were captured from the producers at 736f54b49610, the base commit of
// v0.252.0, before any conversion.
//
// Not every producer is here — the table covers one representative of each SHAPE (fixed sentence,
// one parameter, two parameters, a numeric parameter, a branch per case), which is what a conversion
// would break. A producer converted by accident would have to escape every shape to escape this.
func TestEventMessageWireTextIsFrozen(t *testing.T) {
cases := []struct {
name string
call func(n *Notifier)
want string
}{
{
name: "fixed sentence",
call: func(n *Notifier) { n.NotifyDBDumpCompleted(DBDumpDetails{}) },
want: "Adatbázis mentés elkészült",
},
{
name: "one parameter",
call: func(n *Notifier) { n.NotifyAppDeployed("privatebin", "PrivateBin") },
want: "Alkalmazás telepítve: PrivateBin",
},
{
name: "two parameters",
call: func(n *Notifier) { n.NotifyBackupTargetAbsent("Kulso HDD", "/mnt/hdd_1") },
want: "A rendszermentés meghajtója nem érhető el: Kulso HDD (/mnt/hdd_1)",
},
{
name: "numeric parameter",
call: func(n *Notifier) { n.NotifyDRStarted(3) },
want: "Katasztrófa helyreállítás elindítva (3 alkalmazás)",
},
{
name: "two numeric parameters",
call: func(n *Notifier) { n.NotifyDRCompleted(7, 2) },
want: "Katasztrófa helyreállítás befejezve (7 sikeres, 2 sikertelen)",
},
{
name: "branch: update succeeded",
call: func(n *Notifier) { n.NotifyControllerUpdated("0.251.0", "0.252.0", true) },
want: "Controller frissítve: 0.251.0 → 0.252.0",
},
{
name: "branch: update failed",
call: func(n *Notifier) { n.NotifyControllerUpdated("0.251.0", "0.252.0", false) },
want: "Controller frissítés sikertelen: 0.251.0 → 0.252.0",
},
{
name: "disk health, sector count",
call: func(n *Notifier) {
n.NotifyDiskHealthDegraded(DiskAlert{Label: "Kulso HDD", Kind: DiskAlertFailSectors, Sectors: 352})
},
want: "Lemez hiba: Kulso HDD — a meghajtón 352 olvashatatlan szektor van. " +
"Mentse az adatait, és keressen meg minket a meghajtó cseréjéhez.",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
var got string
var seen int
n := &Notifier{}
n.pushFn = func(_, _, message string, _ interface{}) {
got, seen = message, seen+1
}
tc.call(n)
// A producer that stopped pushing would otherwise leave `got` empty and compare unequal
// with a confusing message; say which it was.
if seen == 0 {
t.Fatalf("the producer pushed no event at all — the golden below was never compared")
}
if got != tc.want {
t.Errorf("event message moved (slice 2 may not translate what the hub mails)\n"+
" got %q\n want %q", got, tc.want)
}
})
}
}
// TestEventMessagesCarryNoBundleKey is the other half: a converted producer would push a KEY, or a
// sentence assembled from one. Neither can look Hungarian, so this catches the accident the golden
// table above would miss for a producer it does not list.
func TestEventMessagesCarryNoBundleKey(t *testing.T) {
var msgs []string
n := &Notifier{}
n.pushFn = func(_, _, message string, _ interface{}) { msgs = append(msgs, message) }
n.NotifyAppDeployed("privatebin", "PrivateBin")
n.NotifyAppRemoved("privatebin", "PrivateBin")
n.NotifyStorageReconnected("Kulso HDD")
n.NotifyDRStarted(1)
n.NotifyCrossDriveCompleted(CrossDriveDetails{StackName: "privatebin"})
if len(msgs) == 0 {
t.Fatal("no producer pushed — nothing was checked")
}
for _, m := range msgs {
// A bundle key is lower-case, dotted and has no space: "event.app_deployed".
if !strings.Contains(m, " ") && strings.Contains(m, ".") && m == strings.ToLower(m) {
t.Errorf("an event message looks like a bundle key, not a sentence: %q", m)
}
}
}