test(queue): TestLawState ohne Zeitbombe — dynamisch inaktives Ruhefenster

Das feste Fenster 18:00-08:00 mit Toast-Modus toastete die Testansage
zwischen 18 und 8 Uhr statt sie zu sprechen; der Test und damit CI waren
14 Stunden am Tag rot. Jetzt beginnt das Fenster zwei Stunden nach jetzt
und dauert eine Stunde; ein Sweep über alle 24 Stunden sichert ab, dass es
zu keiner Tageszeit aktiv ist. Assertions bleiben gleich stark und prüfen
zusätzlich QuietActive/QuietUntil im LawState.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
m3ta-chironandClaude Fable 5.1 committed 2026-10-24 09:35:45 +02:00
1 parent 46bd507fd8
commit b86632006e
1 file changed
+40 -3
+40 -3
View File
@@ -497,15 +497,26 @@ func TestLawState(t *testing.T) {
}
q.Close()
fenster := mustQuiet(t, "18:00-08:00")
// Das Ruhezeit-Fenster muss JETZT inaktiv sein, sonst würde die Ansage
// unten getoastet statt gesprochen — ein festes Fenster wäre eine
// Zeitbombe (rot zu bestimmten Tageszeiten). Deshalb dynamisch: eine
// Stunde, die zwei Stunden in der Zukunft beginnt.
window := inactiveQuietWindow(time.Now())
fenster := mustQuiet(t, window)
if fenster.Active(time.Now()) {
t.Fatalf("Testfenster %s ist aktiv — darf nicht sein", window)
}
q2 := New(Laws{RateLimit: time.Hour, AllowHighBurst: true, Quiet: fenster, QuietMode: QuietModeToast}, g.speak, nil)
defer q2.Close()
st2 := q2.LawState()
if st2.RateLimit != time.Hour || !st2.AllowHighBurst {
t.Errorf("LawState = %+v, want 1h-Fenster mit Burst-Recht", st2)
}
if st2.Quiet.String() != "18:00-08:00" || st2.QuietMode != QuietModeToast {
t.Errorf("Ruhezeit in LawState = %q/%q", st2.Quiet, st2.QuietMode)
if st2.Quiet.String() != window || st2.QuietMode != QuietModeToast {
t.Errorf("Ruhezeit in LawState = %q/%q, want %q/toast", st2.Quiet, st2.QuietMode, window)
}
if st2.QuietActive || !st2.QuietUntil.IsZero() {
t.Errorf("Ruhezeit inaktiv erwartet, LawState meldet active=%v until=%v", st2.QuietActive, st2.QuietUntil)
}
q2.Enqueue(Item{Text: "erste"})
@@ -515,3 +526,29 @@ func TestLawState(t *testing.T) {
}
g.step <- struct{}{}
}
// inactiveQuietWindow liefert ein "HH:MM-HH:MM"-Fenster von einer Stunde,
// das zwei Stunden nach now beginnt — es enthält now garantiert nicht, egal
// zu welcher Tageszeit der Test läuft (auch über Mitternacht hinweg).
func inactiveQuietWindow(now time.Time) string {
start := now.Add(2 * time.Hour)
end := now.Add(3 * time.Hour)
return start.Format("15:04") + "-" + end.Format("15:04")
}
// TestInactiveQuietWindow: Das Test-Hilfsfenster darf zu KEINER Tageszeit
// aktiv sein — sonst wäre TestLawState wieder eine Zeitbombe.
func TestInactiveQuietWindow(t *testing.T) {
base := time.Date(2026, 10, 24, 0, 0, 0, 0, time.Local)
for m := 0; m < 24*60; m += 7 {
now := base.Add(time.Duration(m) * time.Minute)
w := inactiveQuietWindow(now)
q, err := ParseQuietHours(w)
if err != nil {
t.Fatalf("%s: %v", now.Format("15:04"), err)
}
if q.Active(now) {
t.Errorf("um %s ist Fenster %s aktiv", now.Format("15:04"), w)
}
}
}