sub2api/LOCAL_TEST_GUIDE.md
win 12ae97b755 fix: Increase maxOutputTokens in Antigravity test request from 1 to 10
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>
2026-04-11 18:49:53 +08:00

8.0 KiB
Raw Permalink Blame History

本地单元测试指南Antigravity 账号验证

概述

本指南帮助你在本地环境中,不通过 HTTP直接调用服务器代码来测试 Antigravity 账号 ID 68 的连接性。

当前测试状态

基础验证已通过

  • 账号 ID: 68
  • 平台: antigravity
  • 类型: oauth
  • 凭证完整性: ✓
  • Token 有效期: ✓ (有效期至 2026-04-11 18:25:54)
  • Project ID: kinetic-sum-r3tp7

运行基础测试

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 中的 TestConnectionantigravityRetryLoop
  3. 编码错误

    • 错误消息在 SSE 流中被破坏
    • 问题位置:account_test_service.go 中的 SSE 事件处理

创建增强的诊断测试

创建文件:backend/internal/service/antigravity_test_diagnostic_test.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.gosendErrorAndEnd 函数:

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.gorouteAntigravityTest 函数:

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.goTestConnection 函数:

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 命令,但启用详细日志:

# 启用应用的详细日志记录
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

// 这个文件需要:
// 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 流中的损坏数据

日志文件位置

在完整服务运行中,查看日志:

# 应用日志
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
状态: 就绪 ✓