package test // Process-boundary tests for the length and age laws: queue.max_text // truncates overlong texts on admission (response truncated, CLI note, the // provider sees the truncated version); queue.max_age discards // announcements that parked too long (expired, never spoken). import ( "strings" "testing" "time" ) // TestMaxTextTruncates: a 60-word text against max_text=40 — /speak reports // truncated, the CLI warns on stderr, the fake provider receives at most 40 // characters, and /status shows the limit. func TestMaxTextTruncates(t *testing.T) { root := t.TempDir() fake := newFakeProvider(t, 0) d := startDaemon(t, root, fake.srv.URL, map[string]string{"TALK_MAX_TEXT": "40"}) long := strings.Repeat("far too long an answer ", 12) code, m := speak(t, d, `{"text":"`+long+`"}`) if code != 202 || m["id"] == "" || m["truncated"] != true { t.Fatalf("speak: %d %v, want 202 with id and truncated=true", code, m) } hits := fake.waitCompleted(t, 1) if n := len([]rune(hits[0].Text)); n > 40 || !strings.HasPrefix(hits[0].Text, "far too long an answer") { t.Errorf("provider received %q (%d characters), want ≤ 40 characters from the start", hits[0].Text, n) } env := daemonEnv(root, d.port, fake.srv.URL, nil) res := runTalk(t, env, "say", long) if res.code != 0 || !strings.Contains(res.stderr, "truncated") { t.Errorf("talk say (long): exit %d, stderr %q — want the truncation note", res.code, res.stderr) } fake.waitCompleted(t, 2) res = runTalk(t, env, "say", "short enough") if strings.Contains(res.stderr, "truncated") { t.Errorf("short text with truncation note: %q", res.stderr) } fake.waitCompleted(t, 3) res = runTalk(t, env, "status") if !strings.Contains(res.stdout, "limits: max 40 characters") { t.Errorf("talk status without limits line: %q", res.stdout) } } // TestMaxAgeDiscardsParked: rate limit 1 s, max_age 1.5 s, three normal // announcements right after one another: the first plays immediately, the // second parks 1 s (fresh enough), the third would be due only after 2 s — // stale, discarded, never at the provider. func TestMaxAgeDiscardsParked(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{"one", "two", "three"} { code, m := speak(t, d, `{"text":"`+text+`"}`) if code != 202 || m["id"] == "" { t.Fatalf("speak %s: %d %v — nothing may expire on admission", text, code, m) } } hits := fake.waitCompleted(t, 2) if hits[0].Text != "one" || hits[1].Text != "two" { t.Errorf("spoken = %q, %q; want one, two", 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 log does not mention the expiry:\n%s", d.stderr.String()) } }