//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 }