package test // Prozessgrenzen-Tests für die Längen- und Alters-Gesetze: queue.max_text // kürzt überlange Texte beim Eintritt (Antwort truncated, CLI-Hinweis, der // Provider sieht die gekürzte Fassung); queue.max_age verwirft Ansagen, die // zu lange geparkt haben (expired, nie gesprochen). import ( "strings" "testing" "time" ) // TestMaxTextKuerzt: Ein 60-Wörter-Text gegen max_text=40 — /speak meldet // truncated, die CLI warnt auf stderr, der Fake-Provider bekommt höchstens // 40 Zeichen, und /status zeigt das Limit. func TestMaxTextKuerzt(t *testing.T) { root := t.TempDir() fake := newFakeProvider(t, 0) d := startDaemon(t, root, fake.srv.URL, map[string]string{"TALK_MAX_TEXT": "40"}) lang := strings.Repeat("viel zu lange Antwort ", 12) code, m := speak(t, d, `{"text":"`+lang+`"}`) if code != 202 || m["id"] == "" || m["truncated"] != true { t.Fatalf("speak: %d %v, want 202 mit id und truncated=true", code, m) } hits := fake.waitCompleted(t, 1) if n := len([]rune(hits[0].Text)); n > 40 || !strings.HasPrefix(hits[0].Text, "viel zu lange Antwort") { t.Errorf("Provider bekam %q (%d Zeichen), want ≤ 40 Zeichen vom Anfang", hits[0].Text, n) } env := daemonEnv(root, d.port, fake.srv.URL, nil) res := runTalk(t, env, "say", lang) if res.code != 0 || !strings.Contains(res.stderr, "gekürzt") { t.Errorf("talk say (lang): Exit %d, stderr %q — will Kürzungs-Hinweis", res.code, res.stderr) } fake.waitCompleted(t, 2) res = runTalk(t, env, "say", "kurz genug") if strings.Contains(res.stderr, "gekürzt") { t.Errorf("kurzer Text mit Kürzungs-Hinweis: %q", res.stderr) } fake.waitCompleted(t, 3) res = runTalk(t, env, "status") if !strings.Contains(res.stdout, "limits: max. 40 Zeichen") { t.Errorf("talk status ohne Limits-Zeile: %q", res.stdout) } } // TestMaxAgeVerwirftGeparkte: Rate-Limit 1 s, max_age 1,5 s, drei normal- // Ansagen direkt hintereinander: die erste spielt sofort, die zweite parkt // 1 s (frisch genug), die dritte wäre erst nach 2 s fällig — veraltet, // verworfen, nie beim Provider. func TestMaxAgeVerwirftGeparkte(t *testing.T) { root := t.TempDir() fake := newFakeProvider(t, 0) d := startDaemon(t, root, fake.srv.URL, map[string]string{ "TALK_RATE_LIMIT": "1s", "TALK_MAX_AGE": "1500ms", }) for _, text := range []string{"eins", "zwei", "drei"} { code, m := speak(t, d, `{"text":"`+text+`"}`) if code != 202 || m["id"] == "" { t.Fatalf("speak %s: %d %v — beim Eintritt darf nichts verfallen", text, code, m) } } hits := fake.waitCompleted(t, 2) if hits[0].Text != "eins" || hits[1].Text != "zwei" { t.Errorf("gesprochen = %q, %q; want eins, zwei", hits[0].Text, hits[1].Text) } fake.assertNoFurtherArrivals(t, 1500*time.Millisecond) waitStatusIdle(t, d, 3*time.Second) if !strings.Contains(d.stderr.String(), "max_age") { t.Errorf("Daemon-Protokoll nennt den Verfall nicht:\n%s", d.stderr.String()) } }