test(runner): 补齐延迟 429 流式轮转回归

验证上游延迟返回 429 时,在首个 delta 前仍分类为可重试限流并冷却轮转到第二候选,响应不混入失败候选内容。

验证:完整 Go 单元测试通过;隔离 PostgreSQL 下新增 HTTP acceptance 场景通过;gofmt 与差异检查通过。
This commit is contained in:
2026-08-04 19:26:48 +08:00
parent 484b05d005
commit b2c9b4f6d9
2 changed files with 140 additions and 0 deletions
+78
View File
@@ -344,6 +344,84 @@ func TestOpenAIClientChatContract(t *testing.T) {
}
}
func TestOpenAIClientDelayedStream429ReturnsBeforeAnyDelta(t *testing.T) {
requestStarted := make(chan struct{})
releaseResponse := make(chan struct{})
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
close(requestStarted)
<-releaseResponse
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusTooManyRequests)
_ = json.NewEncoder(w).Encode(map[string]any{
"error": map[string]any{"message": "controlled delayed 429"},
})
}))
defer server.Close()
release := func() {
select {
case <-releaseResponse:
default:
close(releaseResponse)
}
}
defer release()
type runResult struct {
response Response
err error
}
deltaCount := 0
done := make(chan runResult, 1)
go func() {
response, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "chat.completions",
Model: "delayed-429-model",
Stream: true,
Body: map[string]any{
"model": "delayed-429-model",
"stream": true,
"messages": []any{map[string]any{"role": "user", "content": "ping"}},
},
Candidate: store.RuntimeModelCandidate{
BaseURL: server.URL,
ProviderModelName: "delayed-429-model",
Credentials: map[string]any{"apiKey": "test-key"},
},
StreamDelta: func(StreamDeltaEvent) error {
deltaCount++
return nil
},
})
done <- runResult{response: response, err: err}
}()
select {
case <-requestStarted:
case <-time.After(time.Second):
t.Fatal("upstream request did not start")
}
select {
case result := <-done:
t.Fatalf("stream returned before upstream status arrived: response=%+v err=%v", result.response, result.err)
case <-time.After(50 * time.Millisecond):
}
release()
var result runResult
select {
case result = <-done:
case <-time.After(time.Second):
t.Fatal("stream did not return after delayed 429")
}
clientErr, ok := result.err.(*ClientError)
if !ok || clientErr.Code != "rate_limit" || clientErr.StatusCode != http.StatusTooManyRequests || !clientErr.Retryable {
t.Fatalf("unexpected delayed 429 error: %T %+v", result.err, result.err)
}
if deltaCount != 0 {
t.Fatalf("delayed 429 emitted %d stream deltas, want 0", deltaCount)
}
}
func TestOpenAIClientAliyunChatSendsStandardInputAudioAndNormalizesLegacyAudioURL(t *testing.T) {
var captured map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {