0cfcc42464
PlaceOffsiteRestore: live target via raw GetStackHDDPath not AppNamespaceRoot (F-3a-1a: no SSD merge; undeployed refused), placement headroom gate (F-3a-1b), stat pre-pass over all placements before any copy (F-3a-4: no partial writes), scratch removed on success/kept on failure (F-3a-2). mapOffsiteRestorePaths refuses the namespace root itself (F-3a-3). Delivery chain: DefaultEnabledEvents + GetNotificationPrefs append-if-absent migration + settings checkbox + handler slice; paired with hub v0.55.0 allowlist (no customerMessages entry — raw dynamic message survives). +8 tests; all 6 controller §10 red-proofs verified.
80 lines
2.3 KiB
Go
80 lines
2.3 KiB
Go
package settings
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func contains(list []string, want string) bool {
|
|
for _, e := range list {
|
|
if e == want {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
func count(list []string, want string) int {
|
|
n := 0
|
|
for _, e := range list {
|
|
if e == want {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// F2a: the new warning type is on by default for new customers.
|
|
func TestDefaultEnabledEvents_ContainsEnlargeBlocked(t *testing.T) {
|
|
if !contains(DefaultEnabledEvents, "offbox_enlarge_blocked") {
|
|
t.Error("DefaultEnabledEvents must contain offbox_enlarge_blocked (new customers get it)")
|
|
}
|
|
}
|
|
|
|
// F2b: an EXISTING customer's stored prefs (predating the type) gain it via append-if-absent —
|
|
// idempotent (two reads → one entry) and their OTHER choices are preserved.
|
|
func TestGetNotificationPrefs_MigratesExisting(t *testing.T) {
|
|
s, err := Load(filepath.Join(t.TempDir(), "settings.json"), discardLog())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// A customer who kept only two events and never had the new one.
|
|
if err := s.SetNotificationPrefs(&NotificationPrefs{
|
|
Email: "c@example.com",
|
|
EnabledEvents: []string{"backup_failed", "disk_warning"},
|
|
CooldownHours: 6,
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
p1 := s.GetNotificationPrefs()
|
|
if !contains(p1.EnabledEvents, "offbox_enlarge_blocked") {
|
|
t.Error("existing prefs must gain offbox_enlarge_blocked (append-if-absent migration)")
|
|
}
|
|
if !contains(p1.EnabledEvents, "backup_failed") || !contains(p1.EnabledEvents, "disk_warning") {
|
|
t.Error("the customer's existing choices must be preserved")
|
|
}
|
|
|
|
// idempotent: a second read still has exactly ONE entry.
|
|
p2 := s.GetNotificationPrefs()
|
|
if c := count(p2.EnabledEvents, "offbox_enlarge_blocked"); c != 1 {
|
|
t.Errorf("migration must be idempotent, got %d entries", c)
|
|
}
|
|
}
|
|
|
|
// A customer who already has the type keeps exactly one (no duplication).
|
|
func TestGetNotificationPrefs_AlreadyPresentNoDuplicate(t *testing.T) {
|
|
s, err := Load(filepath.Join(t.TempDir(), "settings.json"), discardLog())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.SetNotificationPrefs(&NotificationPrefs{
|
|
EnabledEvents: []string{"offbox_enlarge_blocked", "backup_failed"},
|
|
CooldownHours: 6,
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c := count(s.GetNotificationPrefs().EnabledEvents, "offbox_enlarge_blocked"); c != 1 {
|
|
t.Errorf("already-present type must not duplicate, got %d", c)
|
|
}
|
|
}
|