package test // Prozessgrenzen-Test für den Ruhezeit-Toast: quiet_mode = toast in aktiver // Ruhezeit löst eine Desktop-Benachrichtigung aus — hier ein fake // notify-send im PATH des Daemons, das seine Argumente protokolliert. import ( "os" "path/filepath" "runtime" "strings" "testing" "time" ) func TestRuhezeitToastZeigtNotification(t *testing.T) { if runtime.GOOS != "linux" { t.Skip("fake notify-send gibt es nur auf Linux") } root := t.TempDir() bin := filepath.Join(root, "bin") if err := os.MkdirAll(bin, 0o755); err != nil { t.Fatal(err) } seen := filepath.Join(root, "seen.txt") script := "#!/bin/sh\nprintf '%s\\n' \"$@\" > \"" + seen + "\"\n" if err := os.WriteFile(filepath.Join(bin, "notify-send"), []byte(script), 0o755); err != nil { t.Fatal(err) } fake := newFakeProvider(t, 0) d := startDaemon(t, root, fake.srv.URL, map[string]string{ "TALK_QUIET_HOURS": fensterUm(), "TALK_QUIET_MODE": "toast", "PATH": bin + string(os.PathListSeparator) + os.Getenv("PATH"), }) code, m := speak(t, d, `{"text":"Build fertig, bitte Review"}`) if code != 202 || m["discarded"] != "quiet_hours" || m["toast"] != true { t.Fatalf("speak in Ruhezeit (toast): %d %v", code, m) } deadline := time.Now().Add(3 * time.Second) for { if b, err := os.ReadFile(seen); err == nil { if !strings.Contains(string(b), "Build fertig, bitte Review") || !strings.Contains(string(b), "talk") { t.Errorf("notify-send-Argumente = %q", b) } break } if time.Now().After(deadline) { t.Fatalf("notify-send wurde nicht gerufen — Daemon-Log:\n%s", d.stderr.String()) } time.Sleep(25 * time.Millisecond) } fake.assertNoHits(t, 200*time.Millisecond) }