MCPcopy Create free account
hub / github.com/codehamr/codehamr / TestChatIdleTimeoutAbortsStalledStream

Function TestChatIdleTimeoutAbortsStalledStream

internal/llm/llm_test.go:866–894  ·  view source on GitHub ↗

TestChatIdleTimeoutAbortsStalledStream reproduces the exact hang: the server returns 200 OK then sends nothing. Without the idle watchdog scanner.Scan() blocks forever; with it, the body is closed and the turn ends in an EventError naming the stall, a finite escape that doesn't need Ctrl+C.

(t *testing.T)

Source from the content-addressed store, hash-verified

864 defer srv.Close()
865
866 c := New(srv.URL, "some-model", "")
867 for _, e := range collect(c.Chat(context.Background(), nil, nil)) {
868 _ = e // the turn errors (the 400 is real), that's expected
869 }
870 if len(bodies) != 1 {
871 t.Fatalf("unrelated 400 must NOT trigger a fallback retry; got %d requests", len(bodies))
872 }
873 if c.noReasoningEffort.Load() {
874 t.Fatal("reasoning must not latch off on a 400 unrelated to reasoning")
875 }
876}
877
878// TestNewHasNoHTTPTimeout pins that the streaming Client must NOT set
879// http.Client.Timeout: that field is end-to-end (it covers body reads) and would
880// abort a legitimately slow SSE stream with "context deadline exceeded … while
881// reading body" on slow local backends. Per-turn context cancellation governs
882// request lifetime; this stops a refactor from reintroducing the wall-clock cap.
883func TestNewHasNoHTTPTimeout(t *testing.T) {
884 c := New("http://example.test", "model", "token")
885 if c.HTTP.Timeout != 0 {
886 t.Fatalf("http.Client.Timeout must be 0 so per-turn context governs SSE lifetime; got %v", c.HTTP.Timeout)
887 }
888}
889
890// TestIdleTimeoutFromEnv pins the CODEHAMR_IDLE_TIMEOUT contract: a Go duration
891// or bare-seconds string wins, anything else (unset, garbage, non-positive)
892// falls back to the default. The default is deliberately generous because this
893// is a dead-connection detector, not a loop guard.
894func TestIdleTimeoutFromEnv(t *testing.T) {
895 cases := []struct {
896 val string
897 set bool

Callers

nothing calls this directly

Calls 4

collectFunction · 0.85
ChatMethod · 0.80
ErrorMethod · 0.80
NewFunction · 0.70

Tested by

no test coverage detected