Some checks failed
Security Scan / backend-security (push) Failing after 3s
Security Scan / frontend-security (push) Failing after 5s
CI / test (push) Failing after 3s
CI / frontend (push) Failing after 3s
CI / golangci-lint (push) Failing after 3s
CI / windsurf-platform (macos-latest) (push) Has been cancelled
CI / windsurf-platform (windows-latest) (push) Has been cancelled
98 lines
3.1 KiB
Go
98 lines
3.1 KiB
Go
//go:build unit
|
||
|
||
package service
|
||
|
||
import (
|
||
"encoding/json"
|
||
"testing"
|
||
|
||
"github.com/stretchr/testify/require"
|
||
)
|
||
|
||
// 验证 parseAntigravitySmartRetryInfo 能识别 4 类 ErrorInfo.reason:
|
||
// - RATE_LIMIT_EXCEEDED (RESOURCE_EXHAUSTED)
|
||
// - QUOTA_EXHAUSTED (RESOURCE_EXHAUSTED)
|
||
// - INSUFFICIENT_G1_CREDITS_BALANCE (RESOURCE_EXHAUSTED)
|
||
// - MODEL_CAPACITY_EXHAUSTED (UNAVAILABLE)
|
||
func TestParseAntigravitySmartRetryInfo_4类_reason(t *testing.T) {
|
||
cases := []struct {
|
||
name string
|
||
status string
|
||
reason string
|
||
expectModelCapacity bool
|
||
expectQuotaExhausted bool
|
||
expectInsufficientCredit bool
|
||
}{
|
||
{
|
||
name: "RESOURCE_EXHAUSTED + RATE_LIMIT_EXCEEDED",
|
||
status: "RESOURCE_EXHAUSTED",
|
||
reason: "RATE_LIMIT_EXCEEDED",
|
||
},
|
||
{
|
||
name: "UNAVAILABLE + MODEL_CAPACITY_EXHAUSTED",
|
||
status: "UNAVAILABLE",
|
||
reason: "MODEL_CAPACITY_EXHAUSTED",
|
||
|
||
expectModelCapacity: true,
|
||
},
|
||
{
|
||
name: "RESOURCE_EXHAUSTED + QUOTA_EXHAUSTED",
|
||
status: "RESOURCE_EXHAUSTED",
|
||
reason: "QUOTA_EXHAUSTED",
|
||
expectQuotaExhausted: true,
|
||
},
|
||
{
|
||
name: "RESOURCE_EXHAUSTED + INSUFFICIENT_G1_CREDITS_BALANCE",
|
||
status: "RESOURCE_EXHAUSTED",
|
||
reason: "INSUFFICIENT_G1_CREDITS_BALANCE",
|
||
expectInsufficientCredit: true,
|
||
},
|
||
}
|
||
|
||
for _, tc := range cases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
body := buildAntigravityErrorBody(tc.status, tc.reason, "claude-sonnet-4-5", "0.5s")
|
||
info := parseAntigravitySmartRetryInfo(body)
|
||
require.NotNil(t, info, "应识别 reason=%s", tc.reason)
|
||
require.Equal(t, "claude-sonnet-4-5", info.ModelName)
|
||
require.Equal(t, tc.expectModelCapacity, info.IsModelCapacityExhausted)
|
||
require.Equal(t, tc.expectQuotaExhausted, info.IsQuotaExhausted)
|
||
require.Equal(t, tc.expectInsufficientCredit, info.IsInsufficientCredits)
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestParseAntigravitySmartRetryInfo_未知_reason_返回_nil(t *testing.T) {
|
||
body := buildAntigravityErrorBody("RESOURCE_EXHAUSTED", "SOME_UNKNOWN_REASON", "claude-x", "1s")
|
||
require.Nil(t, parseAntigravitySmartRetryInfo(body))
|
||
}
|
||
|
||
func TestParseAntigravitySmartRetryInfo_无_modelName_返回_nil(t *testing.T) {
|
||
// 有 reason 但 metadata.model 缺失,不应返回有效信息(避免无目标的限流)
|
||
body := buildAntigravityErrorBody("RESOURCE_EXHAUSTED", "QUOTA_EXHAUSTED", "", "1s")
|
||
require.Nil(t, parseAntigravitySmartRetryInfo(body))
|
||
}
|
||
|
||
// buildAntigravityErrorBody 构造一个 Google RPC 风格的 429/503 错误响应。
|
||
func buildAntigravityErrorBody(status, reason, model, retryDelay string) []byte {
|
||
errInfo := map[string]any{
|
||
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
|
||
"reason": reason,
|
||
}
|
||
if model != "" {
|
||
errInfo["metadata"] = map[string]any{"model": model}
|
||
}
|
||
retryInfo := map[string]any{
|
||
"@type": "type.googleapis.com/google.rpc.RetryInfo",
|
||
"retryDelay": retryDelay,
|
||
}
|
||
body := map[string]any{
|
||
"error": map[string]any{
|
||
"status": status,
|
||
"details": []any{errInfo, retryInfo},
|
||
},
|
||
}
|
||
out, _ := json.Marshal(body)
|
||
return out
|
||
}
|