Files
easyai-ai-gateway/apps/api/internal/runner/proxy_test.go
T
wangbo ea58d21d03 perf(queue): 限制大媒体任务内存并消除准入惊群
将同步与异步非文本任务的准入唤醒改为按任务和全局队首推进,批量续租等待者,避免大量请求同时争抢 advisory lock 和数据库连接。

对 Base64 请求解析、素材解码、上游媒体执行和结果物化增加分层并发限制,复用请求素材并释放重复 Gemini wire 数据;生产 API 默认入口解析并发 16,媒体物化并发 8。

新增 1000 个同步 Gemini 图像编辑请求的模拟上游压力验收,10 MiB 输入和输出下全部成功,Heap 峰值增长约 2.58 GiB,并验证共享上传哈希、单次 attempt 与本地零落盘。

验证:go test ./... -count=1;go vet ./...;gofmt -l 无输出;kubectl kustomize deploy/kubernetes/production;10 MiB Gemini Base64 千任务压力测试通过。
2026-07-30 13:13:32 +08:00

139 lines
4.4 KiB
Go

package runner
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/easyai/easyai-ai-gateway/apps/api/internal/config"
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
)
func TestProviderHTTPClientTimeoutAllowsLongRunningMediaRequests(t *testing.T) {
client := newHTTPClient(nil)
if client.Timeout != 10*time.Minute {
t.Fatalf("unexpected provider HTTP timeout: got %s want %s", client.Timeout, 10*time.Minute)
}
transport, ok := client.Transport.(*http.Transport)
if !ok {
t.Fatalf("provider transport type = %T, want *http.Transport", client.Transport)
}
if transport.MaxIdleConns != providerHTTPMaxIdleConnections ||
transport.MaxIdleConnsPerHost != providerHTTPMaxIdleConnectionsPerHost {
t.Fatalf(
"provider idle connection pool = %d/%d, want %d/%d",
transport.MaxIdleConns,
transport.MaxIdleConnsPerHost,
providerHTTPMaxIdleConnections,
providerHTTPMaxIdleConnectionsPerHost,
)
}
}
func TestPlatformProxyModeNoneIgnoresEnvironmentProxy(t *testing.T) {
var proxyHits int
proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
proxyHits++
w.WriteHeader(http.StatusTeapot)
}))
defer proxy.Close()
t.Setenv("HTTP_PROXY", proxy.URL)
t.Setenv("http_proxy", proxy.URL)
var targetHits int
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
targetHits++
_, _ = w.Write([]byte("ok"))
}))
defer target.Close()
client, err := testProxyService(config.Config{}).httpClientForCandidate(store.RuntimeModelCandidate{
PlatformConfig: map[string]any{"networkProxy": map[string]any{"mode": "none"}},
}, false)
if err != nil {
t.Fatalf("build http client: %v", err)
}
resp, err := client.Get(target.URL)
if err != nil {
t.Fatalf("get target: %v", err)
}
_, _ = io.Copy(io.Discard, resp.Body)
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK || targetHits != 1 || proxyHits != 0 {
t.Fatalf("unexpected status=%d targetHits=%d proxyHits=%d", resp.StatusCode, targetHits, proxyHits)
}
}
func TestPlatformProxyModeCustomUsesConfiguredHTTPProxy(t *testing.T) {
var targetHits int
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
targetHits++
_, _ = w.Write([]byte("target"))
}))
defer target.Close()
var proxyHits int
proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
proxyHits++
if r.URL.String() != target.URL && r.URL.String() != target.URL+"/" {
t.Fatalf("proxy received unexpected target URL %q", r.URL.String())
}
_, _ = w.Write([]byte("proxied"))
}))
defer proxy.Close()
client, err := testProxyService(config.Config{}).httpClientForCandidate(store.RuntimeModelCandidate{
PlatformConfig: map[string]any{"networkProxy": map[string]any{"mode": "custom", "httpProxy": proxy.URL}},
}, false)
if err != nil {
t.Fatalf("build http client: %v", err)
}
resp, err := client.Get(target.URL)
if err != nil {
t.Fatalf("get target through proxy: %v", err)
}
_, _ = io.Copy(io.Discard, resp.Body)
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK || proxyHits != 1 || targetHits != 0 {
t.Fatalf("unexpected status=%d proxyHits=%d targetHits=%d", resp.StatusCode, proxyHits, targetHits)
}
}
func TestPlatformProxyModeGlobalUsesConfiguredGlobalHTTPProxy(t *testing.T) {
var targetHits int
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
targetHits++
_, _ = w.Write([]byte("target"))
}))
defer target.Close()
var proxyHits int
proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
proxyHits++
_, _ = w.Write([]byte("proxied"))
}))
defer proxy.Close()
client, err := testProxyService(config.Config{GlobalHTTPProxy: proxy.URL}).httpClientForCandidate(store.RuntimeModelCandidate{
PlatformConfig: map[string]any{"networkProxy": map[string]any{"mode": "global"}},
}, false)
if err != nil {
t.Fatalf("build http client: %v", err)
}
resp, err := client.Get(target.URL)
if err != nil {
t.Fatalf("get target through global proxy: %v", err)
}
_, _ = io.Copy(io.Discard, resp.Body)
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK || proxyHits != 1 || targetHits != 0 {
t.Fatalf("unexpected status=%d proxyHits=%d targetHits=%d", resp.StatusCode, proxyHits, targetHits)
}
}
func testProxyService(cfg config.Config) *Service {
return &Service{cfg: cfg, httpClients: newHTTPClientCache()}
}