5270bad76e
gates / gates (push) Successful in 23s
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
106 lines
4.3 KiB
Go
106 lines
4.3 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"log"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/monitor"
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/report"
|
|
)
|
|
|
|
// R-553 — the „your data is not on a separate drive" warning is shown quietly, inline under the
|
|
// storage bars on two pages. Which warning that is used to be decided by looking for „meghajtó" in
|
|
// the sentence; slice 2 translates it, and from that day the warning appears in the RED BANNER on
|
|
// every page of the dashboard instead — a household that changed nothing suddenly reads an alarm.
|
|
//
|
|
// RED-PROOF (REPORT): put the strings.Contains(w, "meghajtón"/"adattároló"/"meghajtó") test back in
|
|
// alerts.go and the TRANSLATED row below fails (Inline=false, no PageOnly).
|
|
func TestR553_DiskWarningPlacementSurvivesWordingChange(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
text, kind string
|
|
wantInline bool
|
|
}{
|
|
{"as shipped", "Az adattároló (/mnt/hdd) nem külön meghajtón van — az adatok a rendszermeghajtóra íródnak",
|
|
monitor.WarnKindStorageNotSeparate, true},
|
|
{"TRANSLATED", "The data storage (/mnt/hdd) is not on a separate drive — the data is written to the system drive",
|
|
monitor.WarnKindStorageNotSeparate, true},
|
|
{"a CPU warning stays in the banner", "CPU usage high: 91%", "", false},
|
|
{"a disconnected drive stays in the banner (its own alert covers it)",
|
|
"Meghajtó leválasztva: Külső (/mnt/usb)", monitor.WarnKindStorageDisconnected, false},
|
|
{"a warning that merely CONTAINS the old words is not moved",
|
|
"A meghajtó ellenőrzése nem futott le", "", false},
|
|
}
|
|
for _, c := range cases {
|
|
am := NewAlertManager(log.New(io.Discard, "", 0))
|
|
hr := &monitor.HealthReport{Status: "warn", Warnings: []string{c.text}, WarningKinds: []string{c.kind}}
|
|
cfg := &config.Config{}
|
|
cfg.Hub.Enabled = false
|
|
am.Refresh(hr, cfg, nil, false, "")
|
|
var found *Alert
|
|
for i, a := range am.GetAlerts("hu") {
|
|
if a.Message == c.text {
|
|
found = &am.GetAlerts("hu")[i]
|
|
}
|
|
}
|
|
if found == nil {
|
|
t.Fatalf("%s: the warning did not reach the alerts at all", c.name)
|
|
}
|
|
if found.Inline != c.wantInline {
|
|
t.Errorf("%s: Inline = %v, want %v (message %q)", c.name, found.Inline, c.wantInline, c.text)
|
|
}
|
|
wantPages := 0
|
|
if c.wantInline {
|
|
wantPages = 2
|
|
}
|
|
if len(found.PageOnly) != wantPages {
|
|
t.Errorf("%s: PageOnly = %v, want %d page(s)", c.name, found.PageOnly, wantPages)
|
|
}
|
|
if c.wantInline && (found.ID != "disk-not-separate" ||
|
|
strings.Join(found.PageOnly, ",") != "dashboard,monitoring") {
|
|
t.Errorf("%s: id/pages changed: %q %v", c.name, found.ID, found.PageOnly)
|
|
}
|
|
}
|
|
}
|
|
|
|
// THE WIRE IS SACRED — the kinds are an internal field and must not reach the hub. The report's
|
|
// health block is its own struct; this pins that it carries exactly three fields, their JSON names,
|
|
// and that a health report WITH kinds marshals to the same bytes as one without.
|
|
//
|
|
// RED-PROOF (REPORT): add `WarningKinds []string \`json:"warning_kinds"\`` to report.HealthReport and
|
|
// both halves fail.
|
|
func TestR553_HubReportWarningsAreUnchangedOnTheWire(t *testing.T) {
|
|
rt := reflect.TypeOf(report.HealthReport{})
|
|
var names []string
|
|
for i := 0; i < rt.NumField(); i++ {
|
|
names = append(names, rt.Field(i).Tag.Get("json"))
|
|
}
|
|
if got, want := strings.Join(names, ","), "status,issues,warnings"; got != want {
|
|
t.Errorf("the hub's health block changed shape: %q, want %q", got, want)
|
|
}
|
|
// The same warnings, one report built the way builder.go builds it (Status/Issues/Warnings only).
|
|
src := &monitor.HealthReport{
|
|
Status: "warn",
|
|
Issues: []string{},
|
|
Warnings: []string{"CPU usage high: 91%", "Az adattároló (/mnt/hdd) nem külön meghajtón van"},
|
|
WarningKinds: []string{"", monitor.WarnKindStorageNotSeparate},
|
|
}
|
|
wire := report.HealthReport{Status: src.Status, Issues: src.Issues, Warnings: src.Warnings}
|
|
b, err := json.Marshal(wire)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
const want = `{"status":"warn","issues":[],"warnings":["CPU usage high: 91%","Az adattároló (/mnt/hdd) nem külön meghajtón van"]}`
|
|
if string(b) != want {
|
|
t.Errorf("the hub report's health bytes CHANGED:\n got %s\nwant %s", b, want)
|
|
}
|
|
if strings.Contains(string(b), "kind") {
|
|
t.Error("a warning KIND reached the wire — the hub contract gained a field nobody agreed to")
|
|
}
|
|
}
|