The test request was using maxOutputTokens: 1, which caused Google API to generate only 1 token. When decoded, this single token produced "It" as the response, making it look like an error. Changed: - Content: "." → "Test connection" (more meaningful prompt) - MaxTokens: 1 → 10 (enough tokens to verify connection is working) This fixes the issue where account test always showed "It" in the response, which was actually just the truncated output from the single-token generation. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
285 lines
8.0 KiB
Markdown
285 lines
8.0 KiB
Markdown
# 本地单元测试指南:Antigravity 账号验证
|
||
|
||
## 概述
|
||
|
||
本指南帮助你在本地环境中,不通过 HTTP,直接调用服务器代码来测试 Antigravity 账号 ID 68 的连接性。
|
||
|
||
## 当前测试状态
|
||
|
||
✅ **基础验证已通过**:
|
||
- 账号 ID: 68
|
||
- 平台: antigravity
|
||
- 类型: oauth
|
||
- 凭证完整性: ✓
|
||
- Token 有效期: ✓ (有效期至 2026-04-11 18:25:54)
|
||
- Project ID: kinetic-sum-r3tp7
|
||
|
||
## 运行基础测试
|
||
|
||
```bash
|
||
cd backend
|
||
go test -v -run TestAntigravityCredentialsValidation ./internal/service
|
||
```
|
||
|
||
**预期输出**:
|
||
```
|
||
=== RUN TestAntigravityCredentialsValidation
|
||
...
|
||
--- PASS: TestAntigravityCredentialsValidation (0.00s)
|
||
PASS
|
||
ok github.com/Wei-Shaw/sub2api/internal/service 0.607s
|
||
```
|
||
|
||
## 问题诊断:找出 "IT" 错误的来源
|
||
|
||
当前问题:HTTP 请求返回了 "IT" 错误,这不是一个有意义的错误消息。
|
||
|
||
### 可能的原因
|
||
|
||
1. **错误消息被截断**
|
||
- 原始错误可能是 "INTERNAL_ERROR" 或其他,但在某个地方被截断成 "IT"
|
||
- 问题位置:`account_test_service.go` 中的 `sendErrorAndEnd` 或错误处理逻辑
|
||
|
||
2. **HTTP 响应体包含不完整的字符**
|
||
- 上游 API 返回的错误响应可能被不完整地处理
|
||
- 问题位置:`antigravity_gateway_service.go` 中的 `TestConnection` 或 `antigravityRetryLoop`
|
||
|
||
3. **编码错误**
|
||
- 错误消息在 SSE 流中被破坏
|
||
- 问题位置:`account_test_service.go` 中的 SSE 事件处理
|
||
|
||
## 创建增强的诊断测试
|
||
|
||
创建文件:`backend/internal/service/antigravity_test_diagnostic_test.go`
|
||
|
||
```go
|
||
package service
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
// TestAntigravityDiagnoseConnectionError 诊断性测试
|
||
// 直接调用 AntigravityGatewayService.TestConnection,捕获完整的错误信息
|
||
func TestAntigravityDiagnoseConnectionError(t *testing.T) {
|
||
// 这个测试需要依赖注入:
|
||
// - AccountRepository
|
||
// - TokenProvider
|
||
// - HTTPUpstream
|
||
// - AntigravityGatewayService
|
||
//
|
||
// 由于本地测试无法访问真实数据库和配置,
|
||
// 需要在集成测试环境中运行
|
||
|
||
t.Skip("Requires integration test environment with database access")
|
||
|
||
// 伪代码:实际实现步骤
|
||
|
||
// 1. 从数据库获取账号
|
||
// account, err := accountRepo.GetByID(ctx, 68)
|
||
// if err != nil {
|
||
// t.Fatalf("Failed to load account: %v", err)
|
||
// }
|
||
|
||
// 2. 调用 TestConnection
|
||
// result, err := gatewayService.TestConnection(ctx, account, "claude-opus-4-6")
|
||
//
|
||
// if err != nil {
|
||
// // 完整的错误信息应该会显示在这里,而不是 "IT"
|
||
// t.Logf("Error type: %T", err)
|
||
// t.Logf("Error message: %s", err.Error())
|
||
// t.Logf("Error details: %#v", err)
|
||
//
|
||
// // 进行根因分析
|
||
// analyzeAntigravityError(t, err, account)
|
||
// return
|
||
// }
|
||
//
|
||
// t.Logf("✅ Test passed")
|
||
// t.Logf("Response: %+v", result)
|
||
}
|
||
|
||
// analyzeAntigravityError 分析 Antigravity 错误的根本原因
|
||
func analyzeAntigravityError(t *testing.T, err error, account *Account) {
|
||
t.Logf("📊 Error Analysis for Account %d:", account.ID)
|
||
t.Logf(" Error type: %T", err)
|
||
t.Logf(" Error message: %s", err.Error())
|
||
|
||
// 检查是否是 AccountSwitchError
|
||
// if switchErr, ok := IsAntigravityAccountSwitchError(err); ok {
|
||
// t.Logf(" ⚠️ Account Switch Error:")
|
||
// t.Logf(" Original Account ID: %d", switchErr.OriginalAccountID)
|
||
// t.Logf(" Rate Limited Model: %s", switchErr.RateLimitedModel)
|
||
// return
|
||
// }
|
||
|
||
// 其他错误分析...
|
||
}
|
||
```
|
||
|
||
## 实际诊断步骤
|
||
|
||
### 步骤 1:增加日志记录
|
||
|
||
编辑 `account_test_service.go` 的 `sendErrorAndEnd` 函数:
|
||
|
||
```go
|
||
func (s *AccountTestService) sendErrorAndEnd(c *gin.Context, msg string) error {
|
||
// ADD: 完整的错误日志
|
||
log.Printf("[DIAGNOSTIC] sendErrorAndEnd called with message: %q (len=%d)", msg, len(msg))
|
||
|
||
s.sendEvent(c, TestEvent{
|
||
Type: "test_error",
|
||
Error: msg,
|
||
Success: false,
|
||
})
|
||
s.sendEvent(c, TestEvent{Type: "test_complete", Success: false})
|
||
return nil
|
||
}
|
||
```
|
||
|
||
### 步骤 2:追踪 routeAntigravityTest 的路径
|
||
|
||
编辑 `account_test_service.go` 的 `routeAntigravityTest` 函数:
|
||
|
||
```go
|
||
func (s *AccountTestService) routeAntigravityTest(c *gin.Context, account *Account, modelID string, prompt string) error {
|
||
log.Printf("[DIAGNOSTIC] routeAntigravityTest: account=%d, platform=%s, type=%s, modelID=%s",
|
||
account.ID, account.Platform, account.Type, modelID)
|
||
|
||
if account.Type == AccountTypeAPIKey {
|
||
log.Printf("[DIAGNOSTIC] Using APIKey path")
|
||
if strings.HasPrefix(modelID, "gemini-") {
|
||
return s.testGeminiAccountConnection(c, account, modelID, prompt)
|
||
}
|
||
return s.testClaudeAccountConnection(c, account, modelID)
|
||
}
|
||
|
||
log.Printf("[DIAGNOSTIC] Using testAntigravityAccountConnection path")
|
||
return s.testAntigravityAccountConnection(c, account, modelID)
|
||
}
|
||
```
|
||
|
||
### 步骤 3:在 TestConnection 中增加诊断日志
|
||
|
||
编辑 `antigravity_gateway_service.go` 的 `TestConnection` 函数:
|
||
|
||
```go
|
||
func (s *AntigravityGatewayService) TestConnection(ctx context.Context, account *Account, modelID string) (*TestConnectionResult, error) {
|
||
log.Printf("[DIAGNOSTIC] TestConnection start: account=%d, modelID=%s", account.ID, modelID)
|
||
|
||
// ... 现有代码 ...
|
||
|
||
accessToken, err := s.tokenProvider.GetAccessToken(ctx, account)
|
||
if err != nil {
|
||
errMsg := fmt.Sprintf("获取 access_token 失败: %w", err)
|
||
log.Printf("[DIAGNOSTIC] GetAccessToken failed: %v", err)
|
||
return nil, errors.New(errMsg)
|
||
}
|
||
log.Printf("[DIAGNOSTIC] Access token obtained successfully")
|
||
|
||
// ... 继续现有代码 ...
|
||
|
||
result, err := s.antigravityRetryLoop(p)
|
||
if err != nil {
|
||
log.Printf("[DIAGNOSTIC] antigravityRetryLoop failed with error type %T: %v", err, err)
|
||
return nil, err
|
||
}
|
||
|
||
log.Printf("[DIAGNOSTIC] TestConnection completed successfully")
|
||
return &TestConnectionResult{Text: text, MappedModel: mappedModel}, nil
|
||
}
|
||
```
|
||
|
||
## 在完整环境中运行诊断
|
||
|
||
### 方法 A:使用现有的测试端点
|
||
|
||
使用你的 curl 命令,但启用详细日志:
|
||
|
||
```bash
|
||
# 启用应用的详细日志记录
|
||
export LOGLEVEL=debug
|
||
|
||
# 运行测试端点
|
||
curl -X POST 'https://temp365.top/api/v1/admin/accounts/68/test' \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'authorization: Bearer YOUR_JWT_TOKEN' \
|
||
-d '{"model_id":"claude-opus-4-6","prompt":""}' \
|
||
-v
|
||
```
|
||
|
||
### 方法 B:编写集成测试
|
||
|
||
创建 `backend/internal/service/antigravity_integration_test.go`:
|
||
|
||
```go
|
||
// 这个文件需要:
|
||
// 1. 数据库连接
|
||
// 2. 真实的 HTTP 客户端配置
|
||
// 3. 配置文件
|
||
//
|
||
// 在完整的开发环境中运行
|
||
```
|
||
|
||
## 预期的完整错误消息示例
|
||
|
||
正确的错误消息应该类似于:
|
||
|
||
```
|
||
"Invalid access token"
|
||
"Account not found"
|
||
"Project ID not available"
|
||
"Google API returned 401: Invalid credentials"
|
||
"Network timeout connecting to upstream"
|
||
"Request rate limit exceeded for model claude-opus-4-6"
|
||
```
|
||
|
||
如果返回的是 "IT",说明:
|
||
|
||
1. ❌ 错误被截断(原文可能是 20+ 个字符,被截断成 2 个)
|
||
2. ❌ 字符编码问题(UTF-8/ASCII 混淆)
|
||
3. ❌ SSE 流中的损坏数据
|
||
|
||
## 日志文件位置
|
||
|
||
在完整服务运行中,查看日志:
|
||
|
||
```bash
|
||
# 应用日志
|
||
tail -f /var/log/sub2api/server.log | grep "DIAGNOSTIC"
|
||
|
||
# Docker 日志
|
||
docker logs -f <container-id> | grep "DIAGNOSTIC"
|
||
```
|
||
|
||
## 下一步
|
||
|
||
1. ✅ **已完成**:本地基础验证
|
||
2. ⏭️ **待做**:增加诊断日志并重新测试
|
||
3. ⏭️ **待做**:分析完整的错误消息
|
||
4. ⏭️ **待做**:修复根本原因
|
||
|
||
## 参考代码位置
|
||
|
||
- 账号测试服务:`backend/internal/service/account_test_service.go`
|
||
- `TestAccountConnection()` - 第 162 行
|
||
- `testAntigravityAccountConnection()` - 第 629 行
|
||
- `routeAntigravityTest()` - 第 617 行
|
||
- `sendErrorAndEnd()` - 查找函数定义
|
||
|
||
- Antigravity 网关服务:`backend/internal/service/antigravity_gateway_service.go`
|
||
- `TestConnection()` - 第 1114 行
|
||
- `antigravityRetryLoop()` - 查找函数定义
|
||
|
||
- HTTP 处理器:`backend/internal/handler/admin/account_handler.go`
|
||
- `Test()` - 第 671 行(路由处理)
|
||
|
||
---
|
||
|
||
**创建时间**: 2026-04-11
|
||
**测试版本**: v1
|
||
**状态**: 就绪 ✓
|