Files
CLIProxyAPI/sdk/api/handlers/claude/code_handlers_error_test.go
T
2026-05-19 16:05:40 +08:00

95 lines
3.4 KiB
Go

package claude
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/router-for-me/CLIProxyAPI/v7/internal/interfaces"
"github.com/tidwall/gjson"
)
func TestClaudeErrorExtractsOpenAIStyleUpstreamJSON(t *testing.T) {
handler := &ClaudeCodeAPIHandler{}
msg := &interfaces.ErrorMessage{
StatusCode: http.StatusBadRequest,
Error: errors.New(`{"error":{"message":"Your input exceeds the context window of this model. Please adjust your input and try again.","type":"invalid_request_error","code":"context_too_large"}}`),
}
got := handler.toClaudeError(msg)
if got.Type != "error" {
t.Fatalf("type = %q, want error", got.Type)
}
if got.Error.Type != "invalid_request_error" {
t.Fatalf("error.type = %q, want invalid_request_error", got.Error.Type)
}
if got.Error.Message != "Your input exceeds the context window of this model. Please adjust your input and try again." {
t.Fatalf("error.message = %q", got.Error.Message)
}
}
func TestClaudeErrorExtractsClaudeStyleUpstreamJSON(t *testing.T) {
handler := &ClaudeCodeAPIHandler{}
msg := &interfaces.ErrorMessage{
StatusCode: http.StatusTooManyRequests,
Error: errors.New(`{"type":"error","error":{"type":"rate_limit_error","message":"This request would exceed your account's rate limit. Please try again later."},"request_id":"req_123"}`),
}
got := handler.toClaudeError(msg)
if got.Error.Type != "rate_limit_error" {
t.Fatalf("error.type = %q, want rate_limit_error", got.Error.Type)
}
if got.Error.Message != "This request would exceed your account's rate limit. Please try again later." {
t.Fatalf("error.message = %q", got.Error.Message)
}
}
func TestWriteClaudeErrorResponseUsesClaudeEnvelope(t *testing.T) {
gin.SetMode(gin.TestMode)
recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder)
handler := &ClaudeCodeAPIHandler{}
msg := &interfaces.ErrorMessage{
StatusCode: http.StatusBadRequest,
Error: errors.New(`{"error":{"message":"Your input exceeds the context window of this model. Please adjust your input and try again.","type":"invalid_request_error","code":"context_too_large"}}`),
}
handler.WriteErrorResponse(c, msg)
if recorder.Code != http.StatusBadRequest {
t.Fatalf("status = %d, want %d", recorder.Code, http.StatusBadRequest)
}
body := recorder.Body.Bytes()
if got := gjson.GetBytes(body, "type").String(); got != "error" {
t.Fatalf("type = %q, want error; body=%s", got, body)
}
if got := gjson.GetBytes(body, "error.type").String(); got != "invalid_request_error" {
t.Fatalf("error.type = %q, want invalid_request_error; body=%s", got, body)
}
if got := gjson.GetBytes(body, "error.message").String(); got != "Your input exceeds the context window of this model. Please adjust your input and try again." {
t.Fatalf("error.message = %q; body=%s", got, body)
}
}
func TestPendingClaudeStreamErrorUsesBufferedError(t *testing.T) {
wantErr := &interfaces.ErrorMessage{
StatusCode: http.StatusBadRequest,
Error: errors.New(`{"error":{"message":"Your input exceeds the context window of this model. Please adjust your input and try again.","type":"invalid_request_error","code":"context_too_large"}}`),
}
errs := make(chan *interfaces.ErrorMessage, 1)
errs <- wantErr
close(errs)
gotErr, ok := pendingClaudeStreamError(errs)
if !ok {
t.Fatal("expected pending stream error")
}
if gotErr != wantErr {
t.Fatalf("pending error = %p, want %p", gotErr, wantErr)
}
}