perf(e2e): 并行化 E2E 测试,从 ~2h 降至 ~102s

- testutil: 用 sync.Once 缓存 LollyImageAvailable 结果
- testutil: 原子计数器替代时间戳避免容器名竞态
- testutil: SetupProxyTest 接受 suffix 参数生成独立 Docker 网络
- testutil: CleanupProxyTest 显式调用 network.Remove() 清理
- testutil: 移除死代码 SetupProxyTestEnv/ProxyTestEnv
- testutil: HealthCheckWaitTimeout 30s→15s, DefaultTestTimeout 180s→120s
- e2e: 所有 107 个测试函数添加 t.Parallel()
- e2e: 替换 65 处硬编码 30*time.Second 为常量
- make: test-all 三类测试并行运行,显式 PID wait 收集退出码
- make: test-e2e 添加 -parallel 4 flag

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xfy 2026-04-28 13:19:46 +08:00
parent 179090fa34
commit 2cb10eb749
17 changed files with 350 additions and 270 deletions

View File

@ -155,8 +155,8 @@ test-integration:
# 运行 L3 E2E 测试(需要 Docker
test-e2e:
@echo "Running L3 E2E tests (requires Docker)..."
go test -v -tags=e2e ./internal/e2e/...
@echo "Running L3 E2E tests (parallel: $(or $(E2E_PARALLEL),4))..."
go test -tags=e2e -parallel $(or $(E2E_PARALLEL),4) -count 1 ./internal/e2e/...
# 运行 L3 E2E 测试(带覆盖率)
test-e2e-cover:
@ -170,9 +170,18 @@ test-e2e-short:
@echo "Running L3 E2E tests (short mode - testutil only)..."
go test -tags=e2e -short -v ./internal/e2e/testutil/... -timeout 60s
# 运行所有测试(单元 + 集成 + E2E
test-all: test test-integration test-e2e
@echo "All tests passed."
# 运行所有测试(单元 + 集成 + E2E— 并行执行
test-all:
@echo "Running all tests in parallel..."
@FAIL=0; \
$(MAKE) test & PID1=$$!; \
$(MAKE) test-integration & PID2=$$!; \
$(MAKE) test-e2e & PID3=$$!; \
wait $$PID1 || FAIL=1; \
wait $$PID2 || FAIL=1; \
wait $$PID3 || FAIL=1; \
if [ $$FAIL -eq 0 ]; then echo "All tests passed."; fi; \
exit $$FAIL
# 运行测试(带覆盖率)
test-cover:

View File

@ -26,6 +26,7 @@ import (
// TestE2EAccessAllowWhitelist 测试 IP 白名单。
func TestE2EAccessAllowWhitelist(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -57,7 +58,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -73,6 +74,7 @@ servers:
// TestE2EAccessDenyBlacklist 测试 IP 黑名单。
func TestE2EAccessDenyBlacklist(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -100,7 +102,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -116,6 +118,7 @@ servers:
// TestE2EAccessDefaultDeny 测试默认拒绝策略。
func TestE2EAccessDefaultDeny(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -143,7 +146,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -159,6 +162,7 @@ servers:
// TestE2EAccessNoRestriction 测试无访问限制。
func TestE2EAccessNoRestriction(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -182,7 +186,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -198,6 +202,7 @@ servers:
// TestE2EAccessCIDRMatch 测试 CIDR 网段匹配。
func TestE2EAccessCIDRMatch(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -227,7 +232,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -244,6 +249,7 @@ servers:
// TestE2EAccessProxyWithAccessControl 测试代理模式下的访问控制。
func TestE2EAccessProxyWithAccessControl(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -277,7 +283,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}

View File

@ -26,6 +26,7 @@ import (
//
// 验证第二次请求返回缓存内容。
func TestE2EProxyCacheHit(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -34,9 +35,9 @@ func TestE2EProxyCacheHit(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用缓存
cfg := testutil.NewConfigBuilder().
@ -54,7 +55,7 @@ func TestE2EProxyCacheHit(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -96,6 +97,7 @@ func TestE2EProxyCacheHit(t *testing.T) {
//
// 验证缓存过期后重新获取。
func TestE2EProxyCacheExpire(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -104,9 +106,9 @@ func TestE2EProxyCacheExpire(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:短缓存时间
cfg := testutil.NewConfigBuilder().
@ -123,7 +125,7 @@ func TestE2EProxyCacheExpire(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -153,6 +155,7 @@ func TestE2EProxyCacheExpire(t *testing.T) {
//
// 验证缓存锁防止缓存击穿。
func TestE2EProxyCacheLock(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -161,9 +164,9 @@ func TestE2EProxyCacheLock(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用缓存锁
cfg := testutil.NewConfigBuilder().
@ -180,7 +183,7 @@ func TestE2EProxyCacheLock(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 并发发送相同请求
@ -198,6 +201,7 @@ func TestE2EProxyCacheLock(t *testing.T) {
//
// 验证特定请求绕过缓存。
func TestE2EProxyCacheBypass(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -206,9 +210,9 @@ func TestE2EProxyCacheBypass(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -225,7 +229,7 @@ func TestE2EProxyCacheBypass(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -251,6 +255,7 @@ func TestE2EProxyCacheBypass(t *testing.T) {
//
// 验证只有 GET 和 HEAD 被缓存。
func TestE2EProxyCacheMethods(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -259,9 +264,9 @@ func TestE2EProxyCacheMethods(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -278,7 +283,7 @@ func TestE2EProxyCacheMethods(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -305,6 +310,7 @@ func TestE2EProxyCacheMethods(t *testing.T) {
//
// 验证缓存头部正确设置。
func TestE2EProxyCacheHeaders(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -313,9 +319,9 @@ func TestE2EProxyCacheHeaders(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -332,7 +338,7 @@ func TestE2EProxyCacheHeaders(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -356,6 +362,7 @@ func TestE2EProxyCacheHeaders(t *testing.T) {
//
// 验证后端不可用时返回过期缓存。
func TestE2EProxyCacheStale(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -364,9 +371,9 @@ func TestE2EProxyCacheStale(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用 stale-while-revalidate
cfg := testutil.NewConfigBuilder().
@ -383,7 +390,7 @@ func TestE2EProxyCacheStale(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -410,6 +417,7 @@ func TestE2EProxyCacheStale(t *testing.T) {
//
// 验证 Vary 头部影响缓存键。
func TestE2EProxyCacheVary(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -418,9 +426,9 @@ func TestE2EProxyCacheVary(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -437,7 +445,7 @@ func TestE2EProxyCacheVary(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -462,6 +470,7 @@ func TestE2EProxyCacheVary(t *testing.T) {
//
// 验证条件请求正确处理。
func TestE2EProxyCacheRevalidate(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -470,9 +479,9 @@ func TestE2EProxyCacheRevalidate(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -489,7 +498,7 @@ func TestE2EProxyCacheRevalidate(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -522,6 +531,7 @@ func TestE2EProxyCacheRevalidate(t *testing.T) {
//
// 验证并发请求正确处理缓存。
func TestE2EProxyCacheConcurrent(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -530,9 +540,9 @@ func TestE2EProxyCacheConcurrent(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -549,7 +559,7 @@ func TestE2EProxyCacheConcurrent(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 并发请求
@ -569,6 +579,7 @@ func TestE2EProxyCacheConcurrent(t *testing.T) {
//
// 验证不同路径独立缓存。
func TestE2EProxyCacheMultiplePaths(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -577,9 +588,9 @@ func TestE2EProxyCacheMultiplePaths(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:多路径代理
cfg := testutil.NewConfigBuilder().
@ -599,7 +610,7 @@ func TestE2EProxyCacheMultiplePaths(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -626,6 +637,7 @@ func TestE2EProxyCacheMultiplePaths(t *testing.T) {
//
// 验证请求头正确传递并影响缓存。
func TestE2EProxyCacheWithHeaders(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -634,9 +646,9 @@ func TestE2EProxyCacheWithHeaders(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -662,7 +674,7 @@ func TestE2EProxyCacheWithHeaders(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -688,6 +700,7 @@ func TestE2EProxyCacheWithHeaders(t *testing.T) {
//
// 验证大响应不被缓存或正确处理。
func TestE2EProxyCacheSize(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -696,9 +709,9 @@ func TestE2EProxyCacheSize(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -715,7 +728,7 @@ func TestE2EProxyCacheSize(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 30 * time.Second}
@ -743,6 +756,7 @@ func TestE2EProxyCacheSize(t *testing.T) {
//
// 验证不同 HTTP 状态码的缓存行为。
func TestE2EProxyCacheStatusCodes(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -751,9 +765,9 @@ func TestE2EProxyCacheStatusCodes(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -770,7 +784,7 @@ func TestE2EProxyCacheStatusCodes(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -801,6 +815,7 @@ func TestE2EProxyCacheStatusCodes(t *testing.T) {
//
// 验证不同查询参数产生不同的缓存条目。
func TestE2EProxyCacheQueryParams(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -809,9 +824,9 @@ func TestE2EProxyCacheQueryParams(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -828,7 +843,7 @@ func TestE2EProxyCacheQueryParams(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -858,6 +873,7 @@ func TestE2EProxyCacheQueryParams(t *testing.T) {
//
// 验证缓存功能与其他功能的集成。
func TestE2EProxyCacheIntegration(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -866,9 +882,9 @@ func TestE2EProxyCacheIntegration(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:缓存 + 负载均衡
cfg := testutil.NewConfigBuilder().
@ -887,7 +903,7 @@ func TestE2EProxyCacheIntegration(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 30 * time.Second}

View File

@ -30,6 +30,7 @@ import (
// TestE2ECompressionGzip 测试 Gzip 压缩响应。
func TestE2ECompressionGzip(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -65,7 +66,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -99,6 +100,7 @@ servers:
// TestE2ECompressionNoAcceptEncoding 测试不发送 Accept-Encoding 时不压缩。
func TestE2ECompressionNoAcceptEncoding(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -129,7 +131,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -146,6 +148,7 @@ servers:
// TestE2ECompressionDisabled 测试禁用压缩。
func TestE2ECompressionDisabled(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -176,7 +179,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -197,6 +200,7 @@ servers:
// TestE2ECompressionPrecompressed 测试预压缩文件。
func TestE2ECompressionPrecompressed(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -229,7 +233,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}

View File

@ -9,5 +9,6 @@ import (
)
func TestE2ESetup(t *testing.T) {
t.Parallel()
t.Log("E2E test infrastructure initialized")
}

View File

@ -25,6 +25,7 @@ import (
//
// 验证定期探测后端状态,自动剔除不健康后端。
func TestE2EHealthCheckActive(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -33,9 +34,9 @@ func TestE2EHealthCheckActive(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用主动健康检查(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -57,7 +58,7 @@ func TestE2EHealthCheckActive(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -116,6 +117,7 @@ func TestE2EHealthCheckActive(t *testing.T) {
//
// 验证失败后自动剔除后端。
func TestE2EHealthCheckPassive(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -124,9 +126,9 @@ func TestE2EHealthCheckPassive(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置启用被动健康检查max_fails使用内部地址
targetOpts := [][]testutil.ProxyTargetOption{
@ -151,7 +153,7 @@ func TestE2EHealthCheckPassive(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -170,6 +172,7 @@ func TestE2EHealthCheckPassive(t *testing.T) {
//
// 验证后端恢复后重新加入负载均衡。
func TestE2EHealthCheckRecovery(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -178,9 +181,9 @@ func TestE2EHealthCheckRecovery(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -201,7 +204,7 @@ func TestE2EHealthCheckRecovery(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -268,6 +271,7 @@ func TestE2EHealthCheckRecovery(t *testing.T) {
//
// 验证健康检查按配置间隔执行。
func TestE2EHealthCheckInterval(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -276,9 +280,9 @@ func TestE2EHealthCheckInterval(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:短健康检查间隔(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -298,7 +302,7 @@ func TestE2EHealthCheckInterval(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -315,6 +319,7 @@ func TestE2EHealthCheckInterval(t *testing.T) {
//
// 验证健康检查超时正确处理。
func TestE2EHealthCheckTimeout(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -323,9 +328,9 @@ func TestE2EHealthCheckTimeout(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:短超时(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -345,7 +350,7 @@ func TestE2EHealthCheckTimeout(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -362,6 +367,7 @@ func TestE2EHealthCheckTimeout(t *testing.T) {
//
// 验证自定义健康检查路径。
func TestE2EHealthCheckPath(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -370,9 +376,9 @@ func TestE2EHealthCheckPath(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置使用根路径作为健康检查路径nginx 默认存在)
cfg := testutil.NewConfigBuilder().
@ -392,7 +398,7 @@ func TestE2EHealthCheckPath(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -409,6 +415,7 @@ func TestE2EHealthCheckPath(t *testing.T) {
//
// 验证多个后端的健康检查独立工作。
func TestE2EHealthCheckMultipleBackends(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -417,9 +424,9 @@ func TestE2EHealthCheckMultipleBackends(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 3)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 3, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -440,7 +447,7 @@ func TestE2EHealthCheckMultipleBackends(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -498,6 +505,7 @@ func TestE2EHealthCheckMultipleBackends(t *testing.T) {
//
// 验证后端故障时请求自动转移到健康后端。
func TestE2EHealthCheckFailover(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -506,9 +514,9 @@ func TestE2EHealthCheckFailover(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用故障转移(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -530,7 +538,7 @@ func TestE2EHealthCheckFailover(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -561,6 +569,7 @@ func TestE2EHealthCheckFailover(t *testing.T) {
//
// 验证所有后端不可用时的行为。
func TestE2EHealthCheckAllDown(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -569,9 +578,9 @@ func TestE2EHealthCheckAllDown(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -592,7 +601,7 @@ func TestE2EHealthCheckAllDown(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -630,6 +639,7 @@ func TestE2EHealthCheckAllDown(t *testing.T) {
//
// 验证备份服务器在主服务器不可用时启用。
func TestE2EHealthCheckBackupServer(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -638,9 +648,9 @@ func TestE2EHealthCheckBackupServer(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:第二个后端为备份(使用内部地址)
targetOpts := [][]testutil.ProxyTargetOption{
@ -666,7 +676,7 @@ func TestE2EHealthCheckBackupServer(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -685,6 +695,7 @@ func TestE2EHealthCheckBackupServer(t *testing.T) {
//
// 验证新后端逐渐接收流量。
func TestE2EHealthCheckSlowStart(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -693,9 +704,9 @@ func TestE2EHealthCheckSlowStart(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -715,7 +726,7 @@ func TestE2EHealthCheckSlowStart(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -732,6 +743,7 @@ func TestE2EHealthCheckSlowStart(t *testing.T) {
//
// 验证健康检查与各种负载均衡算法配合工作。
func TestE2EHealthCheckWithLoadBalance(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -740,9 +752,9 @@ func TestE2EHealthCheckWithLoadBalance(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 3)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 3, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
algorithms := []string{"round_robin", "least_conn"}
@ -765,7 +777,7 @@ func TestE2EHealthCheckWithLoadBalance(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -786,6 +798,7 @@ func TestE2EHealthCheckWithLoadBalance(t *testing.T) {
//
// 验证并发请求时健康检查正常工作。
func TestE2EHealthCheckConcurrent(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -794,9 +807,9 @@ func TestE2EHealthCheckConcurrent(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -817,7 +830,7 @@ func TestE2EHealthCheckConcurrent(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 并发请求
@ -837,6 +850,7 @@ func TestE2EHealthCheckConcurrent(t *testing.T) {
//
// 验证健康检查正确匹配状态码。
func TestE2EHealthCheckStatusCodes(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -845,9 +859,9 @@ func TestE2EHealthCheckStatusCodes(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -867,7 +881,7 @@ func TestE2EHealthCheckStatusCodes(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -885,6 +899,7 @@ func TestE2EHealthCheckStatusCodes(t *testing.T) {
//
// 验证健康检查与其他功能的集成。
func TestE2EHealthCheckIntegration(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -893,9 +908,9 @@ func TestE2EHealthCheckIntegration(t *testing.T) {
}
// 设置代理测试环境(使用网络模式)
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:健康检查 + 负载均衡 + 超时(使用内部地址)
cfg := testutil.NewConfigBuilder().
@ -918,7 +933,7 @@ func TestE2EHealthCheckIntegration(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 30 * time.Second}

View File

@ -28,6 +28,7 @@ import (
//
// 验证 HTTPS 连接可以成功建立。
func TestE2EHTTPSConnection(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -73,6 +74,7 @@ func TestE2EHTTPSConnection(t *testing.T) {
//
// 验证多个并发 HTTPS 请求正常工作。
func TestE2EHTTPSConcurrentRequests(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -144,6 +146,7 @@ func TestE2EHTTPSConcurrentRequests(t *testing.T) {
//
// 验证自定义头部正确传递。
func TestE2EHTTPSCustomHeaders(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -201,6 +204,7 @@ func TestE2EHTTPSCustomHeaders(t *testing.T) {
//
// 验证大请求体的处理。
func TestE2EHTTPSLargeRequest(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -253,6 +257,7 @@ func TestE2EHTTPSLargeRequest(t *testing.T) {
//
// 验证 TLS ALPN 扩展正常工作。
func TestE2EALPNNegotiation(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()

View File

@ -25,6 +25,7 @@ import (
//
// 验证请求均匀分布到多个后端。
func TestE2ELoadBalanceRoundRobin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -33,9 +34,9 @@ func TestE2ELoadBalanceRoundRobin(t *testing.T) {
}
// 启动 3 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 3)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 3, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
t.Logf("Backend pool: %v", pool.Addresses())
@ -53,7 +54,7 @@ func TestE2ELoadBalanceRoundRobin(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送 30 个请求,验证都成功
@ -81,6 +82,7 @@ func TestE2ELoadBalanceRoundRobin(t *testing.T) {
//
// 验证请求按权重比例分布。
func TestE2ELoadBalanceWeighted(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -89,9 +91,9 @@ func TestE2ELoadBalanceWeighted(t *testing.T) {
}
// 启动 2 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:权重 3:1
targetOpts := [][]testutil.ProxyTargetOption{
@ -112,7 +114,7 @@ func TestE2ELoadBalanceWeighted(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送 40 个请求
@ -137,6 +139,7 @@ func TestE2ELoadBalanceWeighted(t *testing.T) {
//
// 验证请求路由到连接数最少的后端。
func TestE2ELoadBalanceLeastConn(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -145,9 +148,9 @@ func TestE2ELoadBalanceLeastConn(t *testing.T) {
}
// 启动 2 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -162,7 +165,7 @@ func TestE2ELoadBalanceLeastConn(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 并发发送请求
@ -182,6 +185,7 @@ func TestE2ELoadBalanceLeastConn(t *testing.T) {
//
// 验证同一 IP 的请求总是路由到同一后端。
func TestE2ELoadBalanceIPHash(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -190,9 +194,9 @@ func TestE2ELoadBalanceIPHash(t *testing.T) {
}
// 启动 3 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 3)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 3, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -207,7 +211,7 @@ func TestE2ELoadBalanceIPHash(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 从同一客户端发送多个请求
@ -225,6 +229,7 @@ func TestE2ELoadBalanceIPHash(t *testing.T) {
//
// 验证基于请求 URI 的一致性哈希路由。
func TestE2ELoadBalanceConsistentHash(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -233,9 +238,9 @@ func TestE2ELoadBalanceConsistentHash(t *testing.T) {
}
// 启动 3 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 3)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 3, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置(使用 ip_hash 代替 consistent_hash因为可能不被支持
cfg := testutil.NewConfigBuilder().
@ -250,7 +255,7 @@ func TestE2ELoadBalanceConsistentHash(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送请求
@ -269,6 +274,7 @@ func TestE2ELoadBalanceConsistentHash(t *testing.T) {
//
// 验证后端故障时自动切换到其他后端。
func TestE2ELoadBalanceFailover(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -277,9 +283,9 @@ func TestE2ELoadBalanceFailover(t *testing.T) {
}
// 启动 2 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用故障转移
cfg := testutil.NewConfigBuilder().
@ -297,7 +303,7 @@ func TestE2ELoadBalanceFailover(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送请求验证正常工作
@ -337,6 +343,7 @@ func TestE2ELoadBalanceFailover(t *testing.T) {
//
// 验证不健康后端被自动剔除。
func TestE2ELoadBalanceHealthCheck(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -345,9 +352,9 @@ func TestE2ELoadBalanceHealthCheck(t *testing.T) {
}
// 启动 2 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:启用主动健康检查
cfg := testutil.NewConfigBuilder().
@ -365,7 +372,7 @@ func TestE2ELoadBalanceHealthCheck(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送请求验证正常工作
@ -385,6 +392,7 @@ func TestE2ELoadBalanceHealthCheck(t *testing.T) {
//
// 验证不同路径代理到不同后端。
func TestE2ELoadBalanceMultiplePaths(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -393,9 +401,9 @@ func TestE2ELoadBalanceMultiplePaths(t *testing.T) {
}
// 启动 2 个后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 2)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:多路径代理(都代理到根路径)
cfg := testutil.NewConfigBuilder().
@ -411,7 +419,7 @@ func TestE2ELoadBalanceMultiplePaths(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -436,6 +444,7 @@ func TestE2ELoadBalanceMultiplePaths(t *testing.T) {
//
// 验证超时配置生效。
func TestE2ELoadBalanceTimeout(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -444,9 +453,9 @@ func TestE2ELoadBalanceTimeout(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:设置超时
cfg := testutil.NewConfigBuilder().
@ -463,7 +472,7 @@ func TestE2ELoadBalanceTimeout(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送正常请求
@ -478,6 +487,7 @@ func TestE2ELoadBalanceTimeout(t *testing.T) {
//
// 验证请求头正确传递到后端。
func TestE2ELoadBalanceHeaders(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
defer cancel()
@ -486,9 +496,9 @@ func TestE2ELoadBalanceHeaders(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:设置代理头部
cfg := testutil.NewConfigBuilder().
@ -514,7 +524,7 @@ func TestE2ELoadBalanceHeaders(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 发送请求

View File

@ -24,6 +24,7 @@ import (
// TestE2EProxyBasic 测试 lolly 基本代理转发。
func TestE2EProxyBasic(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -46,7 +47,7 @@ func TestE2EProxyBasic(t *testing.T) {
t.Logf("Lolly proxy: %s", lolly.HTTPBaseURL())
// 等待 lolly 健康
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 测试 lolly 服务可达
@ -62,6 +63,7 @@ func TestE2EProxyBasic(t *testing.T) {
// TestE2EProxyWithLolly 测试 lolly 代理转发功能。
// 需要 lolly:latest 镜像。
func TestE2EProxyWithLolly(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -84,7 +86,7 @@ func TestE2EProxyWithLolly(t *testing.T) {
t.Logf("Lolly proxy: %s", lolly.HTTPBaseURL())
// 等待 lolly 健康
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 通过 lolly 访问
@ -99,6 +101,7 @@ func TestE2EProxyWithLolly(t *testing.T) {
// TestE2EProxyLoadBalance 测试 lolly 负载均衡。
func TestE2EProxyLoadBalance(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -144,6 +147,7 @@ func TestE2EProxyLoadBalance(t *testing.T) {
// TestE2EProxyHealthCheck 测试 lolly 健康检查。
func TestE2EProxyHealthCheck(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -168,6 +172,7 @@ func TestE2EProxyHealthCheck(t *testing.T) {
// TestE2EProxyTimeout 测试 lolly 代理超时处理。
func TestE2EProxyTimeout(t *testing.T) {
t.Parallel()
// 使用短超时客户端测试超时场景
shortTimeoutClient := &http.Client{Timeout: 1 * time.Second}
@ -180,6 +185,7 @@ func TestE2EProxyTimeout(t *testing.T) {
// TestE2EProxyErrorHandling 测试 lolly 代理错误处理。
func TestE2EProxyErrorHandling(t *testing.T) {
t.Parallel()
client := &http.Client{Timeout: 10 * time.Second}
// 测试连接被拒绝
@ -189,6 +195,7 @@ func TestE2EProxyErrorHandling(t *testing.T) {
// TestE2EProxyHeaders 测试 lolly 代理头部传递。
func TestE2EProxyHeaders(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -219,6 +226,7 @@ func TestE2EProxyHeaders(t *testing.T) {
// TestE2EProxyMultipleRequests 测试 lolly 并发代理请求。
func TestE2EProxyMultipleRequests(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()

View File

@ -27,6 +27,7 @@ import (
// TestE2ERateLimitBasic 测试基本请求限流。
func TestE2ERateLimitBasic(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -58,7 +59,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 5 * time.Second}
@ -96,6 +97,7 @@ servers:
// TestE2ERateLimitBurst 测试突发流量处理。
func TestE2ERateLimitBurst(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -129,7 +131,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 5 * time.Second}
@ -152,6 +154,7 @@ servers:
// TestE2ERateLimitRecovery 测试限流恢复。
func TestE2ERateLimitRecovery(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -185,7 +188,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 5 * time.Second}
@ -222,6 +225,7 @@ servers:
// TestE2ERateLimitDisabled 测试未配置限流时不限制。
func TestE2ERateLimitDisabled(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -251,7 +255,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 5 * time.Second}

View File

@ -26,6 +26,7 @@ import (
// TestE2ERewriteBasic 测试基本 URL 重写。
func TestE2ERewriteBasic(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -51,7 +52,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {
@ -71,6 +72,7 @@ servers:
// TestE2ERewriteRedirect 测试重写为重定向。
func TestE2ERewriteRedirect(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -96,7 +98,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {
@ -117,6 +119,7 @@ servers:
// TestE2ERewritePermanent 测试永久重定向。
func TestE2ERewritePermanent(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -142,7 +145,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {
@ -159,6 +162,7 @@ servers:
// TestE2ERewriteRegexCapture 测试正则表达式捕获组。
func TestE2ERewriteRegexCapture(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -184,7 +188,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {
@ -205,6 +209,7 @@ servers:
// TestE2ERewriteProxy 测试代理模式下的重写。
func TestE2ERewriteProxy(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -236,7 +241,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second}
@ -253,6 +258,7 @@ servers:
// TestE2ERewriteNoMatch 测试不匹配时不重写。
func TestE2ERewriteNoMatch(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -278,7 +284,7 @@ servers:
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
client := &http.Client{Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {

View File

@ -25,6 +25,7 @@ import (
//
// 验证 HTTPS 连接可以成功建立。
func TestE2ESSLHandshake(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -71,6 +72,7 @@ func TestE2ESSLHandshake(t *testing.T) {
//
// 验证 ALPN 协商成功HTTP/2 正常工作。
func TestE2ESSLHTTP2(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -116,6 +118,7 @@ func TestE2ESSLHTTP2(t *testing.T) {
//
// 验证 TLS 1.2 和 1.3 正常工作。
func TestE2ESSLProtocolVersions(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -162,6 +165,7 @@ func TestE2ESSLProtocolVersions(t *testing.T) {
//
// 验证证书链正确配置。
func TestE2ESSLCertificateChain(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -206,6 +210,7 @@ func TestE2ESSLCertificateChain(t *testing.T) {
//
// 验证可以跳过证书验证连接。
func TestE2ESSLInsecureSkipVerify(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -249,6 +254,7 @@ func TestE2ESSLInsecureSkipVerify(t *testing.T) {
//
// 验证代理可以连接 HTTPS 后端。
func TestE2ESSLProxyUpstream(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -257,9 +263,9 @@ func TestE2ESSLProxyUpstream(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to setup proxy test")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置:代理到 HTTP 后端
cfg := testutil.NewConfigBuilder().
@ -290,6 +296,7 @@ func TestE2ESSLProxyUpstream(t *testing.T) {
//
// 验证并发 SSL 连接正常工作。
func TestE2ESSLConcurrent(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -337,6 +344,7 @@ func TestE2ESSLConcurrent(t *testing.T) {
// TestE2ESSLWithLolly 测试 lolly SSL/TLS 功能(兼容旧测试)。
func TestE2ESSLWithLolly(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.MediumTestTimeout)
defer cancel()
@ -371,6 +379,7 @@ func TestE2ESSLWithLolly(t *testing.T) {
// TestE2ESSLCertificateGeneration 测试证书生成。
func TestE2ESSLCertificateGeneration(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
certPath, keyPath, cleanup, err := testutil.GenerateSelfSignedCert(tmpDir)
@ -388,6 +397,7 @@ func TestE2ESSLCertificateGeneration(t *testing.T) {
// TestE2ESSLHTTP3Placeholder HTTP/3 测试占位符。
func TestE2ESSLHTTP3Placeholder(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip("Skipping E2E test in short mode")
}
@ -397,6 +407,7 @@ func TestE2ESSLHTTP3Placeholder(t *testing.T) {
// TestE2ESSLDockerAvailable 测试 Docker 是否可用。
func TestE2ESSLDockerAvailable(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.ShortTestTimeout)
defer cancel()
@ -409,6 +420,7 @@ func TestE2ESSLDockerAvailable(t *testing.T) {
// TestE2ESSLEnvironmentCheck 检查测试环境。
func TestE2ESSLEnvironmentCheck(t *testing.T) {
t.Parallel()
dockerHost := os.Getenv("DOCKER_HOST")
if dockerHost != "" {
t.Logf("DOCKER_HOST: %s", dockerHost)
@ -425,6 +437,7 @@ func TestE2ESSLEnvironmentCheck(t *testing.T) {
// TestE2ESSLSessionTickets 测试 TLS Session Tickets。
func TestE2ESSLSessionTickets(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()
@ -473,6 +486,7 @@ func TestE2ESSLSessionTickets(t *testing.T) {
// TestE2ESSLHSTS 测试 HSTS 头部。
func TestE2ESSLHSTS(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.DefaultTestTimeout)
defer cancel()

View File

@ -26,6 +26,7 @@ import (
// TestE2EStaticWithLolly 测试 lolly 静态文件服务功能。
// 需要 lolly:latest 镜像。
func TestE2EStaticWithLolly(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -41,7 +42,7 @@ func TestE2EStaticWithLolly(t *testing.T) {
t.Logf("Lolly static server: %s", lolly.HTTPBaseURL())
// 等待 lolly 健康
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 测试静态文件服务
@ -56,6 +57,7 @@ func TestE2EStaticWithLolly(t *testing.T) {
// TestE2EStaticFileServe 测试 lolly 静态文件服务。
func TestE2EStaticFileServe(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -88,6 +90,7 @@ func TestE2EStaticFileServe(t *testing.T) {
// TestE2EStaticContentType 测试 lolly Content-Type 检测。
func TestE2EStaticContentType(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -112,6 +115,7 @@ func TestE2EStaticContentType(t *testing.T) {
// TestE2EStaticNotFound 测试 lolly 404 错误。
func TestE2EStaticNotFound(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -133,6 +137,7 @@ func TestE2EStaticNotFound(t *testing.T) {
// TestE2EStaticConcurrent 测试 lolly 并发静态文件请求。
func TestE2EStaticConcurrent(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
@ -157,6 +162,7 @@ func TestE2EStaticConcurrent(t *testing.T) {
// TestE2EStaticLargeFile 测试 lolly 大文件传输。
func TestE2EStaticLargeFile(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()

View File

@ -18,7 +18,7 @@ const (
ContainerStartupTimeout = 30 * time.Second
// HealthCheckWaitTimeout 健康检查等待超时。
HealthCheckWaitTimeout = 30 * time.Second
HealthCheckWaitTimeout = 15 * time.Second
// HealthCheckDetectionTime 健康检查检测时间。
HealthCheckDetectionTime = 10 * time.Second
@ -27,7 +27,7 @@ const (
CacheExpireBuffer = 1 * time.Second
// DefaultTestTimeout 测试上下文超时。
DefaultTestTimeout = 180 * time.Second
DefaultTestTimeout = 120 * time.Second
// DefaultClientTimeout HTTP 客户端超时。
DefaultClientTimeout = 10 * time.Second

View File

@ -13,6 +13,8 @@ import (
"io"
"net/http"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/testcontainers/testcontainers-go"
@ -375,7 +377,21 @@ func DockerAvailable(ctx context.Context) bool {
}
// LollyImageAvailable 检查 lolly:latest 镜像是否可用。
// 结果被 sync.Once 缓存,避免重复检查。
func LollyImageAvailable(ctx context.Context) bool {
lollyImageCheckOnce.Do(func() {
lollyImageAvailable = checkLollyImage(ctx)
})
return lollyImageAvailable
}
var (
lollyImageCheckOnce sync.Once
lollyImageAvailable bool
)
// checkLollyImage 实际执行镜像检查。
func checkLollyImage(ctx context.Context) bool {
req := testcontainers.ContainerRequest{
Image: "lolly:latest",
Cmd: []string{"/lolly", "-v"},
@ -488,8 +504,9 @@ func StartBackendPoolWithNetwork(ctx context.Context, count int, network string)
// startMockBackendWithNetwork 启动单个后端容器。
func startMockBackendWithNetwork(ctx context.Context, network string, index int) (testcontainers.Container, string, string, error) {
// 生成容器名称(用于网络通信)
containerName := fmt.Sprintf("backend-%d-%d", time.Now().UnixNano(), index)
// 生成容器名称(用于网络通信),使用原子计数器避免并行竞态
id := atomic.AddInt64(&backendCounter, 1)
containerName := fmt.Sprintf("backend-%d-%d", id, index)
req := testcontainers.ContainerRequest{
Image: "nginx:alpine",
@ -615,45 +632,51 @@ func CreateNetwork(ctx context.Context, name string) (testcontainers.Network, er
return network, nil
}
// sharedNetworkName 共享网络名称。
const sharedNetworkName = "lolly-e2e-test"
// 原子计数器,用于生成唯一的容器名和网络名。
var (
backendCounter int64
networkCounter int64
)
// SetupProxyTest 设置代理测试环境。
//
// 创建网络、启动后端池,返回网络名称和后端池。
// 创建独立网络、启动后端池,返回网络对象、网络名称和后端池。
// suffix 用于生成唯一网络名(通常传 t.Name()),配合原子计数器确保 -count N 安全。
// lolly 容器应使用 InternalAddresses() 作为代理目标。
// 使用共享网络名称,避免网络地址池耗尽。
//
// 使用示例:
//
// network, pool, err := testutil.SetupProxyTest(ctx, 2)
// netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 2, t.Name())
// if err != nil {
// t.Fatal(err)
// }
// defer testutil.CleanupProxyTest(ctx, network, pool)
// defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
//
// lolly, err := testutil.StartLolly(ctx,
// testutil.WithConfigYAML(configYAML),
// testutil.WithNetwork(network),
// testutil.WithNetwork(networkName),
// )
func SetupProxyTest(ctx context.Context, backendCount int) (string, *BackendPool, error) {
// 使用共享网络名称
networkName := sharedNetworkName
func SetupProxyTest(ctx context.Context, backendCount int, suffix string) (testcontainers.Network, string, *BackendPool, error) {
id := atomic.AddInt64(&networkCounter, 1)
// 防御性处理:子测试的 t.Name() 含 '/'Docker 网络名不支持
suffix = strings.ReplaceAll(suffix, "/", "-")
networkName := fmt.Sprintf("lolly-e2e-%s-%d", suffix, id)
// 尝试创建网络(如果不存在)
// 忽略"已存在"错误
_, err := CreateNetwork(ctx, networkName)
network, err := CreateNetwork(ctx, networkName)
if err != nil && !isNetworkExistsError(err) {
return "", nil, fmt.Errorf("failed to create network: %w", err)
return nil, "", nil, fmt.Errorf("failed to create network: %w", err)
}
// 启动后端池并加入网络
pool, err := StartBackendPoolWithNetwork(ctx, backendCount, networkName)
if err != nil {
return "", nil, fmt.Errorf("failed to start backend pool: %w", err)
if network != nil {
network.Remove(ctx)
}
return nil, "", nil, fmt.Errorf("failed to start backend pool: %w", err)
}
return networkName, pool, nil
return network, networkName, pool, nil
}
// isNetworkExistsError 检查是否是网络已存在错误。
@ -678,75 +701,11 @@ func containsSubstring(s, substr string) bool {
}
// CleanupProxyTest 清理代理测试环境。
func CleanupProxyTest(ctx context.Context, networkName string, pool *BackendPool) {
func CleanupProxyTest(ctx context.Context, network testcontainers.Network, networkName string, pool *BackendPool) {
if pool != nil {
pool.Terminate(ctx)
}
// 网络会随容器终止自动清理
}
// ProxyTestEnv 代理测试环境。
//
// 封装代理测试所需的资源。
type ProxyTestEnv struct {
Network string
Pool *BackendPool
Lolly *LollyContainer
Cleanup func()
HTTPClient *http.Client
}
// SetupProxyTestEnv 设置完整的代理测试环境。
//
// 创建网络、启动后端池、启动 lolly返回封装的环境。
// 这是一个便捷函数,简化测试设置。
//
// 使用示例:
//
// env, err := testutil.SetupProxyTestEnv(ctx, t, 2, func(pool *testutil.BackendPool) string {
// cfg := testutil.NewConfigBuilder().
// WithServer(":8080").
// WithProxy("/", pool.InternalAddresses())
// yaml, _ := cfg.Build()
// return yaml
// })
func SetupProxyTestEnv(ctx context.Context, backendCount int, configBuilder func(*BackendPool) string) (*ProxyTestEnv, error) {
// 设置代理测试环境
networkName, pool, err := SetupProxyTest(ctx, backendCount)
if err != nil {
return nil, err
}
// 构建配置
configYAML := configBuilder(pool)
// 启动 lolly
lolly, err := StartLolly(ctx,
WithConfigYAML(configYAML),
WithNetwork(networkName),
)
if err != nil {
CleanupProxyTest(ctx, networkName, pool)
return nil, fmt.Errorf("failed to start lolly: %w", err)
}
// 等待健康
if err := lolly.WaitForHealthy(ctx, 30*time.Second); err != nil {
CleanupProxyTest(ctx, networkName, pool)
lolly.Terminate(ctx)
return nil, fmt.Errorf("lolly not healthy: %w", err)
}
cleanup := func() {
lolly.Terminate(ctx)
CleanupProxyTest(ctx, networkName, pool)
}
return &ProxyTestEnv{
Network: networkName,
Pool: pool,
Lolly: lolly,
Cleanup: cleanup,
HTTPClient: &http.Client{Timeout: 10 * time.Second},
}, nil
if network != nil {
network.Remove(ctx)
}
}

View File

@ -12,18 +12,21 @@ import (
"net/http"
"testing"
"time"
"github.com/testcontainers/testcontainers-go"
)
// E2ETestEnv E2E 测试环境。
//
// 封装测试所需的资源和清理函数。
type E2ETestEnv struct {
Ctx context.Context
Network string
Pool *BackendPool
Lolly *LollyContainer
Client *http.Client
cleanup func()
Ctx context.Context
Network testcontainers.Network
NetworkName string
Pool *BackendPool
Lolly *LollyContainer
Client *http.Client
cleanup func()
}
// SetupE2ETest 设置 E2E 测试环境。
@ -55,7 +58,7 @@ func SetupE2ETest(t *testing.T, backendCount int, cfgBuilder func(*BackendPool)
t.Skip("lolly:latest image not available, run 'make docker-build' first")
}
network, pool, err := SetupProxyTest(ctx, backendCount)
netObj, networkName, pool, err := SetupProxyTest(ctx, backendCount, t.Name())
if err != nil {
cancel()
t.Fatalf("Failed to setup proxy test: %v", err)
@ -65,32 +68,33 @@ func SetupE2ETest(t *testing.T, backendCount int, cfgBuilder func(*BackendPool)
lolly, err := StartLolly(ctx,
WithConfigYAML(cfgYAML),
WithNetwork(network),
WithNetwork(networkName),
)
if err != nil {
CleanupProxyTest(ctx, network, pool)
CleanupProxyTest(ctx, netObj, networkName, pool)
cancel()
t.Fatalf("Failed to start lolly: %v", err)
}
if err := lolly.WaitForHealthy(ctx, HealthCheckWaitTimeout); err != nil {
lolly.Terminate(ctx)
CleanupProxyTest(ctx, network, pool)
CleanupProxyTest(ctx, netObj, networkName, pool)
cancel()
t.Fatalf("Lolly not healthy: %v", err)
}
env := &E2ETestEnv{
Ctx: ctx,
Network: network,
Pool: pool,
Lolly: lolly,
Client: CreateDefaultHTTPClient(),
Ctx: ctx,
Network: netObj,
NetworkName: networkName,
Pool: pool,
Lolly: lolly,
Client: CreateDefaultHTTPClient(),
}
env.cleanup = func() {
lolly.Terminate(ctx)
CleanupProxyTest(ctx, network, pool)
CleanupProxyTest(ctx, netObj, networkName, pool)
cancel()
}
@ -109,7 +113,7 @@ func SetupE2ETestWithTimeout(t *testing.T, backendCount int, timeout time.Durati
t.Skip("lolly:latest image not available, run 'make docker-build' first")
}
network, pool, err := SetupProxyTest(ctx, backendCount)
netObj, networkName, pool, err := SetupProxyTest(ctx, backendCount, t.Name())
if err != nil {
cancel()
t.Fatalf("Failed to setup proxy test: %v", err)
@ -119,32 +123,33 @@ func SetupE2ETestWithTimeout(t *testing.T, backendCount int, timeout time.Durati
lolly, err := StartLolly(ctx,
WithConfigYAML(cfgYAML),
WithNetwork(network),
WithNetwork(networkName),
)
if err != nil {
CleanupProxyTest(ctx, network, pool)
CleanupProxyTest(ctx, netObj, networkName, pool)
cancel()
t.Fatalf("Failed to start lolly: %v", err)
}
if err := lolly.WaitForHealthy(ctx, HealthCheckWaitTimeout); err != nil {
lolly.Terminate(ctx)
CleanupProxyTest(ctx, network, pool)
CleanupProxyTest(ctx, netObj, networkName, pool)
cancel()
t.Fatalf("Lolly not healthy: %v", err)
}
env := &E2ETestEnv{
Ctx: ctx,
Network: network,
Pool: pool,
Lolly: lolly,
Client: CreateDefaultHTTPClient(),
Ctx: ctx,
Network: netObj,
NetworkName: networkName,
Pool: pool,
Lolly: lolly,
Client: CreateDefaultHTTPClient(),
}
env.cleanup = func() {
lolly.Terminate(ctx)
CleanupProxyTest(ctx, network, pool)
CleanupProxyTest(ctx, netObj, networkName, pool)
cancel()
}

View File

@ -47,6 +47,7 @@ func wsEchoHandler(w http.ResponseWriter, r *http.Request) {
//
// 验证 WebSocket 连接可以成功建立和消息传递。
func TestE2EWebSocketBasic(t *testing.T) {
t.Parallel()
// 创建本地 WebSocket Echo 服务器
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -80,6 +81,7 @@ func TestE2EWebSocketBasic(t *testing.T) {
//
// 验证二进制消息正确传递。
func TestE2EWebSocketBinary(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -105,6 +107,7 @@ func TestE2EWebSocketBinary(t *testing.T) {
//
// 验证 JSON 消息正确传递。
func TestE2EWebSocketJSON(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -131,6 +134,7 @@ func TestE2EWebSocketJSON(t *testing.T) {
//
// 验证多个并发连接正常工作。
func TestE2EWebSocketConcurrent(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -166,6 +170,7 @@ func TestE2EWebSocketConcurrent(t *testing.T) {
//
// 验证连续发送多条消息正常工作。
func TestE2EWebSocketMultipleMessages(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -194,6 +199,7 @@ func TestE2EWebSocketMultipleMessages(t *testing.T) {
//
// 验证连接正确关闭。
func TestE2EWebSocketClose(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -226,6 +232,7 @@ func TestE2EWebSocketClose(t *testing.T) {
//
// 验证超时配置生效。
func TestE2EWebSocketTimeout(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -249,6 +256,7 @@ func TestE2EWebSocketTimeout(t *testing.T) {
//
// 验证自定义请求头正确传递。
func TestE2EWebSocketHeaders(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -278,6 +286,7 @@ func TestE2EWebSocketHeaders(t *testing.T) {
//
// 验证连接池的各种操作。
func TestE2EWebSocketPoolOperations(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -303,6 +312,7 @@ func TestE2EWebSocketPoolOperations(t *testing.T) {
//
// 验证客户端可以重新建立连接。
func TestE2EWebSocketReconnect(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -341,6 +351,7 @@ func TestE2EWebSocketReconnect(t *testing.T) {
//
// 验证大消息正确传递。
func TestE2EWebSocketLargeMessage(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(wsEchoHandler))
defer server.Close()
@ -370,6 +381,7 @@ func TestE2EWebSocketLargeMessage(t *testing.T) {
//
// 注意:此测试需要 Docker 环境,验证 lolly WebSocket 代理功能。
func TestE2EWebSocketProxyIntegration(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip("Skipping E2E WebSocket proxy test in short mode")
}
@ -382,9 +394,9 @@ func TestE2EWebSocketProxyIntegration(t *testing.T) {
}
// 启动后端
networkName, pool, err := testutil.SetupProxyTest(ctx, 1)
netObj, networkName, pool, err := testutil.SetupProxyTest(ctx, 1, t.Name())
require.NoError(t, err, "Failed to start backend pool")
defer testutil.CleanupProxyTest(ctx, networkName, pool)
defer testutil.CleanupProxyTest(ctx, netObj, networkName, pool)
// 构建配置
cfg := testutil.NewConfigBuilder().
@ -399,7 +411,7 @@ func TestE2EWebSocketProxyIntegration(t *testing.T) {
require.NoError(t, err, "Failed to start lolly")
defer lolly.Terminate(ctx)
err = lolly.WaitForHealthy(ctx, 30*time.Second)
err = lolly.WaitForHealthy(ctx, testutil.HealthCheckWaitTimeout)
require.NoError(t, err, "Lolly not healthy")
// 测试 HTTP 代理WebSocket 需要 WebSocket 后端)