gateway: the loop guard's long-reply test streams 1000 lines, not all of gateway.go, and waits a minute (69c21cdd's macOS -race CI red)

TestLongReplyThatDoesNotLoopGoesThrough/gemini failed on macOS -race in
run 37946485821: "the stream never ended". It streamed all of gateway.go
(199KB, ~20k events of 11 bytes) through the gateway on each protocol, and
askStream waited 20s. Locally under -race each protocol took ~5s with the
guard and ~5s without it (5.0s off, 6.0s on for gemini), so the time is
the gateway translating 20k events, and CI's runner is ~4x slower: a
bound with no room, not a slow guard.

- The test streams gateway.go's first 40KB, cut at a line end (1001
  lines, several times the guard's 256-unit window).
- askStream waits a minute.
- TestLoopGuardLeavesOrdinaryRepliesAlone feeds the first 256KB of each
  file (app.js and i18n.js run to megabytes): 72s -> 37s under -race.

Ran: gofmt -l, go vet (darwin, GOOS=linux, GOOS=windows), go test -race
-run 'TestLong|TestLoop' ./internal/gateway (long reply 3.9-4.7s per run
for all 4 protocols).
This commit is contained in:
yetone committed 2026-10-09 23:14:39 +08:00
1 parent ab72c8eb85
commit 319b72c7a5
1 file changed
+11 -1
+11 -1
View File
@@ -2,6 +2,7 @@ package gateway
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
@@ -214,6 +215,11 @@ func TestLoopGuardLeavesOrdinaryRepliesAlone(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// app.js and i18n.js run to megabytes; 256K of each is still thousands
// of lines, many times the window, and keeps -race on CI quick
if len(b) > 256<<10 {
b = b[:bytes.LastIndexByte(b[:256<<10], '\n')+1]
}
texts[f] = string(b)
}
var log, list, csv, hex, rules strings.Builder
@@ -345,7 +351,7 @@ func askStream(t *testing.T, url, body string) string {
}()
select {
case <-done:
case <-time.After(20 * time.Second):
case <-time.After(time.Minute):
t.Fatal("the stream never ended")
}
return out.String()
@@ -458,6 +464,10 @@ func TestLongReplyThatDoesNotLoopGoesThrough(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// ~1000 lines of real Go, several times the guard's window, and small
// enough that -race on a loaded CI runner streams it well inside
// askStream's bound (all of gateway.go took over 20s on macOS CI)
src = src[:bytes.LastIndexByte(src[:40<<10], '\n')+1]
for _, x := range loopAsks {
t.Run(x.name, func(t *testing.T) {
v := &loopingVendor{reasoning: string(src), letGo: make(chan bool, 1)}