- windsurf_gateway_service: 添加上游延迟/TTFT/错误上下文记录 - endpoint: DeriveUpstreamEndpoint 添加 PlatformWindsurf 分支 - ops_error_logger: guessPlatformFromPath 添加 /windsurf/ 识别
195 lines
5.3 KiB
Go
195 lines
5.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/net/proxy"
|
|
)
|
|
|
|
// TestWithSOCKS5Proxy 使用指定的 SOCKS5 代理调用上游 API
|
|
func TestWithSOCKS5Proxy(t *testing.T) {
|
|
t.Log("🔥 使用 SOCKS5 代理调用 Google API...")
|
|
t.Log("")
|
|
|
|
// SOCKS5 代理配置
|
|
proxyAddr := "socks5://gostuser:fastapipwd@216.167.89.210:8760"
|
|
accessToken := "ya29.a0Aa7MYipSteGdNdr486LvE0xu_RrcbFjSSFZa5jGTf94nPv6NLKEnnRziPSVA_3ncadMlWnUQN8el05uvYac3rk9rOuaEC3jAUq02ejAcayg8tBn9CJT2IGuMsFDRPbfvHwXVHvY-hPGaklubxMIgfckRYsGC7YTpJPprH8kNGG-7ZWf3PvcVGcSrLWhi8FX6Yq1at5OdC1deNAaCgYKAVASARMSFQHGX2Mi2yEN9AChtlJFBwZ_spYEoQ0213"
|
|
|
|
t.Log("📌 代理信息:")
|
|
t.Logf(" 代理地址: %s", proxyAddr)
|
|
t.Logf(" 访问令牌: %s... (长度: %d)", accessToken[:30], len(accessToken))
|
|
t.Log("")
|
|
|
|
// 创建上下文和超时
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
// 步骤 1: 设置 SOCKS5 代理
|
|
t.Run("SetupSOCKS5Proxy", func(t *testing.T) {
|
|
t.Log("步骤 1: 配置 SOCKS5 代理...")
|
|
|
|
// 解析代理 URL
|
|
proxyURL, err := url.Parse(proxyAddr)
|
|
if err != nil {
|
|
t.Fatalf("❌ 解析代理 URL 失败: %v", err)
|
|
}
|
|
t.Logf(" ✓ 代理 URL 解析成功")
|
|
t.Logf(" Scheme: %s", proxyURL.Scheme)
|
|
t.Logf(" Host: %s", proxyURL.Host)
|
|
t.Logf(" User: %s", proxyURL.User.Username())
|
|
t.Log("")
|
|
|
|
// 创建代理拨号器
|
|
dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
|
|
if err != nil {
|
|
t.Fatalf("❌ 创建代理拨号器失败: %v", err)
|
|
}
|
|
t.Log(" ✓ 代理拨号器创建成功")
|
|
t.Log("")
|
|
|
|
// 创建自定义传输
|
|
transport := &http.Transport{
|
|
Dial: dialer.Dial,
|
|
}
|
|
|
|
// 创建自定义 HTTP 客户端
|
|
httpClient := &http.Client{
|
|
Transport: transport,
|
|
Timeout: 30 * time.Second,
|
|
}
|
|
|
|
t.Log(" ✓ HTTP 客户端创建成功")
|
|
t.Log("")
|
|
|
|
// 步骤 2: 测试代理连接
|
|
t.Log("步骤 2: 测试代理连接...")
|
|
|
|
// 尝试一个简单的 HTTP 请求来测试代理
|
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://www.google.com", nil)
|
|
if err != nil {
|
|
t.Logf("❌ 创建测试请求失败: %v", err)
|
|
return
|
|
}
|
|
|
|
resp, err := httpClient.Do(req)
|
|
if err != nil {
|
|
t.Logf("❌ 通过代理访问 Google 失败: %v", err)
|
|
t.Log(" (这可能表示代理配置或网络连接有问题)")
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
t.Logf(" ✓ 代理连接成功!")
|
|
t.Logf(" HTTP Status: %d", resp.StatusCode)
|
|
t.Log("")
|
|
})
|
|
|
|
// 步骤 3: 使用代理调用 Antigravity API
|
|
t.Run("CallAntigravityWithProxy", func(t *testing.T) {
|
|
t.Log("步骤 3: 通过代理调用 Antigravity API...")
|
|
t.Log("")
|
|
|
|
// 解析代理 URL
|
|
proxyURL, err := url.Parse(proxyAddr)
|
|
if err != nil {
|
|
t.Fatalf("❌ 解析代理 URL 失败: %v", err)
|
|
}
|
|
|
|
// 创建代理拨号器
|
|
dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
|
|
if err != nil {
|
|
t.Fatalf("❌ 创建代理拨号器失败: %v", err)
|
|
}
|
|
|
|
// 创建自定义传输
|
|
transport := &http.Transport{
|
|
Dial: dialer.Dial,
|
|
}
|
|
|
|
// 这里我们需要修改 antigravity.Client 来使用自定义的 HTTP 客户端
|
|
// 但由于 antigravity.NewClient 可能不支持自定义客户端,
|
|
// 我们直接创建一个 HTTP 客户端来调用 API
|
|
|
|
httpClient := &http.Client{
|
|
Transport: transport,
|
|
Timeout: 30 * time.Second,
|
|
}
|
|
|
|
t.Log(" 正在调用 Google Cloud Code API...")
|
|
t.Log("")
|
|
|
|
// 直接构造 API 请求
|
|
apiURL := "https://daily-cloudcode-pa.googleapis.com/v1internal:loadCodeAssist"
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "POST", apiURL, nil)
|
|
if err != nil {
|
|
t.Fatalf("❌ 创建请求失败: %v", err)
|
|
}
|
|
|
|
// 添加认证头
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("User-Agent", "Antigravity Client")
|
|
|
|
t.Logf(" 📤 请求信息:")
|
|
t.Logf(" URL: %s", apiURL)
|
|
t.Logf(" Method: POST")
|
|
t.Logf(" Auth: Bearer %s...", accessToken[:30])
|
|
t.Log("")
|
|
|
|
// 发送请求
|
|
t.Log(" ⏳ 正在等待响应...")
|
|
resp, err := httpClient.Do(req)
|
|
if err != nil {
|
|
t.Logf("❌ API 调用失败:")
|
|
t.Logf(" 错误类型: %T", err)
|
|
t.Logf(" 错误信息: %v", err)
|
|
t.Logf(" 错误字符串: %s", err.Error())
|
|
t.Log("")
|
|
|
|
// 分析错误
|
|
errStr := err.Error()
|
|
if len(errStr) >= 2 {
|
|
t.Logf("📊 错误的前 5 个字符: '%s'", errStr[:min(5, len(errStr))])
|
|
if errStr[:2] == "IT" {
|
|
t.Logf(" ✓ 找到了! 这就是 'IT' 错误的来源!")
|
|
}
|
|
}
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
t.Logf("✅ API 调用成功!")
|
|
t.Logf(" HTTP Status: %d", resp.StatusCode)
|
|
t.Logf(" Content-Type: %s", resp.Header.Get("Content-Type"))
|
|
t.Log("")
|
|
|
|
// 读取响应体
|
|
respBody, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Logf("❌ 读取响应失败: %v", err)
|
|
return
|
|
}
|
|
|
|
t.Log("📋 API 响应:")
|
|
if resp.StatusCode == 200 {
|
|
var result map[string]interface{}
|
|
if err := json.Unmarshal(respBody, &result); err == nil {
|
|
jsonBytes, _ := json.MarshalIndent(result, " ", " ")
|
|
t.Logf(" %s", string(jsonBytes))
|
|
} else {
|
|
t.Logf(" %s", string(respBody))
|
|
}
|
|
} else {
|
|
t.Logf(" 状态码: %d", resp.StatusCode)
|
|
t.Logf(" 错误响应: %s", string(respBody))
|
|
}
|
|
})
|
|
}
|