Files
felhom.eu/hub/internal/notify/backup_target_message_test.go
T
admin 1257014c2b hub v0.81.0 — E-2: backup_target_absent gets its own signal (ships first)
An event type the hub does not allowlist makes POST /event return 400 and the
event vanishes (R-97a). The controller cannot emit backup_target_absent until
this is live, so the hub half ships first.

E-2 Phase 0 established that an absent backup target has NO prompt signal today.
The controller's drive-gate path stops apps and logs a WARN but emits nothing:
NotifyStorageDisconnected is defined and never called anywhere (verified against
the gitignored-cmd/ trap with a positive control). A drive that is ONLY a backup
target has no apps to stop, so it is entirely silent. The sole signal is the
tier's own failure at its next due cycle -- up to ~24h on the daily local tier,
which is the R-100 shape: a real fault visible only after a deadline elapses.

Added to BOTH registers, because each half fails differently:
  allowedEventTypes  -- without it the event is lost at the door;
  customerMessages   -- without it the event IS delivered but in the controller's
                        raw operator English, and nothing looks broken.

backup_target_absent is deliberately NOT folded into storage_disconnected: that
says "a drive went away and some apps may have stopped"; this says "the thing
that makes your backup survive a disk failure is gone".

Hungarian copy names the consequence, not just the fact. backup_target_restored
is the paired recovery at info severity -- severityNotifies NOT widened.

Three tests pin the pair and the copy's substance. All red-proofed with the
mutation VERIFIED to have landed first: the initial attempt silently no-op'd
(gofmt had realigned the map) and the test "passed" -- a false proof that would
have been reported as evidence.

Green gate: build + vet + test rc=0, run separately from this commit.
2026-07-29 07:55:18 +02:00

39 lines
1.9 KiB
Go

package notify
import (
"strings"
"testing"
)
// E-2 — the Hungarian half of the backup_target_absent pair.
//
// Companion to api.TestBackupTargetEventTypesAreAllowlisted, which pins the allowlist half. They are
// deliberately two tests in two packages because the registers live in two packages, and the failure
// modes differ: an allowlist miss makes POST /event 400 (loud, the event is lost); a customerMessages
// miss delivers the event but falls back to the controller's raw operator English
// (templates.go FormatCustomerEmail: hunMessage == "" → message). The customer would receive
// "Backup target drive absent: ..." in English and nothing would look broken.
func TestBackupTargetCustomerMessagesArePresent(t *testing.T) {
for _, et := range []string{"backup_target_absent", "backup_target_restored"} {
msg, ok := customerMessages[et]
if !ok || strings.TrimSpace(msg) == "" {
t.Fatalf("customerMessages[%q] is missing — the event would be delivered to the customer "+
"in the controller's operator English instead of Hungarian", et)
}
}
}
// The absent message must name the CONSEQUENCE, not just the fact. "A drive is missing" is a fact the
// customer can do nothing with; "the whole-system backup will not be made until you reconnect it" is
// the thing that makes them act. This pins the distinction the copy was written for — a future
// shortening to a bare "Meghajtó hiányzik." would pass the presence test above and lose the point.
func TestBackupTargetAbsentMessageNamesTheConsequence(t *testing.T) {
msg := customerMessages["backup_target_absent"]
if !strings.Contains(msg, "rendszermentés") {
t.Errorf("backup_target_absent must name WHAT is at risk (the rendszermentés), got: %q", msg)
}
if !strings.Contains(strings.ToLower(msg), "nem készül") {
t.Errorf("backup_target_absent must state the consequence (the backup will not be made), got: %q", msg)
}
}