From 2cb10eb749fe86612a423793e4a9b1e347415e03 Mon Sep 17 00:00:00 2001 From: xfy Date: Tue, 28 Apr 2026 13:19:46 +0800 Subject: [PATCH] =?UTF-8?q?perf(e2e):=20=E5=B9=B6=E8=A1=8C=E5=8C=96=20E2E?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=EF=BC=8C=E4=BB=8E=20~2h=20=E9=99=8D?= =?UTF-8?q?=E8=87=B3=20~102s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- Makefile | 19 +++- internal/e2e/access_e2e_test.go | 18 ++-- internal/e2e/cache_e2e_test.go | 112 +++++++++++++---------- internal/e2e/compression_e2e_test.go | 12 ++- internal/e2e/e2e_test.go | 1 + internal/e2e/healthcheck_e2e_test.go | 105 ++++++++++++--------- internal/e2e/http2_e2e_test.go | 5 + internal/e2e/loadbalance_e2e_test.go | 70 ++++++++------ internal/e2e/proxy_e2e_test.go | 12 ++- internal/e2e/ratelimit_e2e_test.go | 12 ++- internal/e2e/rewrite_e2e_test.go | 18 ++-- internal/e2e/ssl_e2e_test.go | 18 +++- internal/e2e/static_e2e_test.go | 8 +- internal/e2e/testutil/constants.go | 4 +- internal/e2e/testutil/container.go | 131 +++++++++------------------ internal/e2e/testutil/setup.go | 57 ++++++------ internal/e2e/websocket_e2e_test.go | 18 +++- 17 files changed, 350 insertions(+), 270 deletions(-) diff --git a/Makefile b/Makefile index 92cb9c9..662cbac 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/internal/e2e/access_e2e_test.go b/internal/e2e/access_e2e_test.go index af87ba7..87275f2 100644 --- a/internal/e2e/access_e2e_test.go +++ b/internal/e2e/access_e2e_test.go @@ -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} diff --git a/internal/e2e/cache_e2e_test.go b/internal/e2e/cache_e2e_test.go index 60307bc..3894710 100644 --- a/internal/e2e/cache_e2e_test.go +++ b/internal/e2e/cache_e2e_test.go @@ -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} diff --git a/internal/e2e/compression_e2e_test.go b/internal/e2e/compression_e2e_test.go index cddbe87..a8058e2 100644 --- a/internal/e2e/compression_e2e_test.go +++ b/internal/e2e/compression_e2e_test.go @@ -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} diff --git a/internal/e2e/e2e_test.go b/internal/e2e/e2e_test.go index 761d2dd..b470d4d 100644 --- a/internal/e2e/e2e_test.go +++ b/internal/e2e/e2e_test.go @@ -9,5 +9,6 @@ import ( ) func TestE2ESetup(t *testing.T) { + t.Parallel() t.Log("E2E test infrastructure initialized") } diff --git a/internal/e2e/healthcheck_e2e_test.go b/internal/e2e/healthcheck_e2e_test.go index de370a4..d90abf5 100644 --- a/internal/e2e/healthcheck_e2e_test.go +++ b/internal/e2e/healthcheck_e2e_test.go @@ -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} diff --git a/internal/e2e/http2_e2e_test.go b/internal/e2e/http2_e2e_test.go index 1479bc6..24b6e56 100644 --- a/internal/e2e/http2_e2e_test.go +++ b/internal/e2e/http2_e2e_test.go @@ -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() diff --git a/internal/e2e/loadbalance_e2e_test.go b/internal/e2e/loadbalance_e2e_test.go index 8fe5c76..26e5e5f 100644 --- a/internal/e2e/loadbalance_e2e_test.go +++ b/internal/e2e/loadbalance_e2e_test.go @@ -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") // 发送请求 diff --git a/internal/e2e/proxy_e2e_test.go b/internal/e2e/proxy_e2e_test.go index 832f605..a7ff4d9 100644 --- a/internal/e2e/proxy_e2e_test.go +++ b/internal/e2e/proxy_e2e_test.go @@ -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() diff --git a/internal/e2e/ratelimit_e2e_test.go b/internal/e2e/ratelimit_e2e_test.go index a7f57dc..b9bd85e 100644 --- a/internal/e2e/ratelimit_e2e_test.go +++ b/internal/e2e/ratelimit_e2e_test.go @@ -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} diff --git a/internal/e2e/rewrite_e2e_test.go b/internal/e2e/rewrite_e2e_test.go index dd3b367..b7362c2 100644 --- a/internal/e2e/rewrite_e2e_test.go +++ b/internal/e2e/rewrite_e2e_test.go @@ -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 { diff --git a/internal/e2e/ssl_e2e_test.go b/internal/e2e/ssl_e2e_test.go index 67596e1..e66a253 100644 --- a/internal/e2e/ssl_e2e_test.go +++ b/internal/e2e/ssl_e2e_test.go @@ -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() diff --git a/internal/e2e/static_e2e_test.go b/internal/e2e/static_e2e_test.go index 30d9c50..1f90f4e 100644 --- a/internal/e2e/static_e2e_test.go +++ b/internal/e2e/static_e2e_test.go @@ -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() diff --git a/internal/e2e/testutil/constants.go b/internal/e2e/testutil/constants.go index 4ce47fe..396ab8a 100644 --- a/internal/e2e/testutil/constants.go +++ b/internal/e2e/testutil/constants.go @@ -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 diff --git a/internal/e2e/testutil/container.go b/internal/e2e/testutil/container.go index 79903d8..ae10315 100644 --- a/internal/e2e/testutil/container.go +++ b/internal/e2e/testutil/container.go @@ -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) + } } diff --git a/internal/e2e/testutil/setup.go b/internal/e2e/testutil/setup.go index 2800641..9bcbf90 100644 --- a/internal/e2e/testutil/setup.go +++ b/internal/e2e/testutil/setup.go @@ -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() } diff --git a/internal/e2e/websocket_e2e_test.go b/internal/e2e/websocket_e2e_test.go index d5ffbde..b8e2fe5 100644 --- a/internal/e2e/websocket_e2e_test.go +++ b/internal/e2e/websocket_e2e_test.go @@ -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 后端)