fd28d70bff
Operator rulings 2026-10-12, 09 §3 decisions 196, 204-207, 223, 227. MinAgent 0.131.0 unchanged. R-255's sweep found one leak, fixed here: an optional-config secret_input was rendered into its settings page; it is now revealed on demand. Hungarian parity fixtures re-captured once for R-562. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
70 lines
2.5 KiB
Go
70 lines
2.5 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// R-521 controller half (operator ruling 2026-10-12, S32, `09` §3 decision 227): the household's own
|
|
// notification settings carry a lost-drive option (`storage_disconnected`), saved and sent to the hub in
|
|
// `enabled_events` exactly like the others — and ONLY when the household has it on. The hub mails a lost
|
|
// drive only when this setting carries it.
|
|
//
|
|
// RED-PROOF (REPORT.md): drop "storage_disconnected" from the single-event list in
|
|
// settingsNotificationsHandler → the "on" half fails (the option is silently not saved and not sent).
|
|
func TestR521_StorageDisconnectedOptionRoundTrips(t *testing.T) {
|
|
eventsOf := func(t *testing.T, body map[string]json.RawMessage) []string {
|
|
t.Helper()
|
|
var ev []string
|
|
if err := json.Unmarshal(body["enabled_events"], &ev); err != nil {
|
|
t.Fatalf("enabled_events is not a list: %s", body["enabled_events"])
|
|
}
|
|
return ev
|
|
}
|
|
has := func(list []string, e string) bool {
|
|
for _, x := range list {
|
|
if x == e {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ON: saved, sent, and the page shows it ticked.
|
|
s, sett, hub := r922Server(t)
|
|
s.loadTemplates()
|
|
rr := postNotifications(t, s, url.Values{
|
|
"notification_email": {"household@example.hu"},
|
|
"cooldown_hours": {"6"},
|
|
"event_backup_failed": {"on"},
|
|
"event_storage_disconnected": {"on"},
|
|
})
|
|
if p := sett.GetNotificationPrefs(); !has(p.EnabledEvents, "storage_disconnected") {
|
|
t.Fatalf("on: storage_disconnected not saved (stored %v)", p.EnabledEvents)
|
|
}
|
|
if ev := eventsOf(t, hub.last(t)); !has(ev, "storage_disconnected") {
|
|
t.Fatalf("on: storage_disconnected not sent to the hub (enabled_events %v)", ev)
|
|
}
|
|
if !strings.Contains(rr.Body.String(), `name="event_storage_disconnected" checked`) {
|
|
t.Error("on: the saved option does not render ticked")
|
|
}
|
|
|
|
// OFF: the same household switches it off — not saved, not sent, not ticked.
|
|
rr = postNotifications(t, s, url.Values{
|
|
"notification_email": {"household@example.hu"},
|
|
"cooldown_hours": {"6"},
|
|
"event_backup_failed": {"on"},
|
|
})
|
|
if p := sett.GetNotificationPrefs(); has(p.EnabledEvents, "storage_disconnected") {
|
|
t.Fatalf("off: storage_disconnected still saved (stored %v)", p.EnabledEvents)
|
|
}
|
|
if ev := eventsOf(t, hub.last(t)); has(ev, "storage_disconnected") {
|
|
t.Fatalf("off: storage_disconnected still sent to the hub (enabled_events %v)", ev)
|
|
}
|
|
if strings.Contains(rr.Body.String(), `name="event_storage_disconnected" checked`) {
|
|
t.Error("off: the option still renders ticked")
|
|
}
|
|
}
|