Phase 6: schedules, blocklists, allowlists (editors + effective state)
- Weekly schedule editor per device: a Monday-Sunday grid of blocking windows, including windows that cross midnight. - Blocklist/allowlist editor per device: app (Android package / Windows process) and site (hostname) entries, tagged by the device platform. - Effective desired state: a manual lock, an active schedule window, or neither. While blocked the allowlist is honoured (Spotify stays while other apps are blocked). Published retained with reason schedule/manual. - Boundary-aware republish loop so a window turns on and off on time, and manual lock expiry is cleared promptly. - CONTROL_TIMEZONE (default Australia/Sydney) with embedded tzdata, so wall-clock windows are evaluated in the family zone, not the container. - Every change is written to the append-only audit log (FR-15). Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -37,6 +37,29 @@ func TestLoadDefaultsAndValidation(t *testing.T) {
|
||||
if !cfg.CookieSecure {
|
||||
t.Error("CookieSecure = false, want true by default")
|
||||
}
|
||||
if cfg.ScheduleLocation == nil || cfg.ScheduleLocation.String() != DefaultTimezone {
|
||||
t.Errorf("ScheduleLocation = %v, want %s", cfg.ScheduleLocation, DefaultTimezone)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScheduleTimezone(t *testing.T) {
|
||||
t.Setenv("CONTROL_SESSION_SECRET", "0123456789abcdef")
|
||||
t.Setenv("CONTROL_ADMIN_PASSWORD", "hunter2")
|
||||
t.Setenv("CONTROL_MQTT_INSECURE", "true")
|
||||
|
||||
t.Setenv("CONTROL_TIMEZONE", "UTC")
|
||||
cfg, err := Load()
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if cfg.ScheduleLocation == nil || cfg.ScheduleLocation.String() != "UTC" {
|
||||
t.Errorf("ScheduleLocation = %v, want UTC", cfg.ScheduleLocation)
|
||||
}
|
||||
|
||||
t.Setenv("CONTROL_TIMEZONE", "Not/AZone")
|
||||
if _, err := Load(); err == nil {
|
||||
t.Error("expected an error for an unknown CONTROL_TIMEZONE")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRequiresSecretAndPassword(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user