lolly/internal/e2e/ssl_e2e_test.go
xfy e5b494c058 refactor(e2e): 简化 SSL E2E 测试代码
使用 testutil 工具包重构,减少重复代码

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 09:35:25 +08:00

178 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//go:build e2e
// ssl_e2e_test.go - SSL/TLS E2E 测试L3 层,需要 Docker
//
// 使用 testcontainers-go 进行真实的 HTTPS 测试。
// 需要在有 Docker 的环境中运行。
//
// 作者xfy
package e2e
import (
"context"
"crypto/tls"
"net/http"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"rua.plus/lolly/internal/e2e/testutil"
)
// TestE2ESSLHandshake 测试 SSL 握手环境。
func TestE2ESSLHandshake(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if !testutil.DockerAvailable(ctx) {
t.Skip("Docker not available")
}
t.Log("Docker is available for E2E SSL tests")
}
// TestE2ESSLWithLolly 测试 lolly SSL/TLS 功能。
// 需要 lolly:latest 镜像和测试证书。
func TestE2ESSLWithLolly(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
if !testutil.DockerAvailable(ctx) {
t.Skip("Docker not available")
}
if !testutil.LollyImageAvailable(ctx) {
t.Skip("lolly:latest image not available, run 'make docker-build' first")
}
// 生成自签名证书
certPath, keyPath, cleanup, err := testutil.GenerateSelfSignedCert(t.TempDir())
require.NoError(t, err, "Failed to generate self-signed certificate")
defer cleanup()
t.Logf("Generated certificate: %s", certPath)
t.Logf("Generated key: %s", keyPath)
// 启动 lolly SSL 服务器
lolly, err := testutil.StartLollyContainer(ctx, "")
require.NoError(t, err, "Failed to start lolly container")
defer lolly.Terminate(ctx)
t.Logf("Lolly HTTPS server: %s", lolly.HTTPSBaseURL())
// 使用跳过证书验证的客户端(测试证书是自签名的)
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
client := &http.Client{
Transport: tr,
Timeout: 10 * time.Second,
}
// 测试 HTTPS 连接
resp, err := client.Get(lolly.HTTPSBaseURL())
require.NoError(t, err, "Failed to reach lolly HTTPS")
defer resp.Body.Close()
// lolly 默认配置没有静态文件,返回 404
assert.Equal(t, 404, resp.StatusCode, "Lolly HTTPS should return 404 without static files")
}
// TestE2ESSLDockerAvailable 测试 Docker 是否可用。
func TestE2ESSLDockerAvailable(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if !testutil.DockerAvailable(ctx) {
t.Skip("Docker not available, skipping E2E SSL tests")
}
t.Log("Docker is available for E2E SSL tests")
}
// TestE2ESSLEnvironmentCheck 检查测试环境。
func TestE2ESSLEnvironmentCheck(t *testing.T) {
dockerHost := os.Getenv("DOCKER_HOST")
if dockerHost != "" {
t.Logf("DOCKER_HOST: %s", dockerHost)
}
if os.Getenv("CI") != "" {
t.Log("Running in CI environment")
}
if _, err := os.Stat("/.dockerenv"); err == nil {
t.Log("Running inside a Docker container")
}
}
// TestE2ESSLHTTP3Placeholder HTTP/3 测试占位符。
func TestE2ESSLHTTP3Placeholder(t *testing.T) {
if testing.Short() {
t.Skip("Skipping E2E test in short mode")
}
t.Log("HTTP/3 E2E test placeholder - requires UDP port configuration")
}
// TestE2ESSLContainer 测试带 SSL 的容器。
func TestE2ESSLContainer(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
container, addr, err := testutil.StartNginxContainer(ctx)
require.NoError(t, err, "Failed to start nginx container")
defer container.Terminate(ctx)
t.Logf("HTTP address: %s", addr)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(addr)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, 200, resp.StatusCode)
}
// TestE2ESSLCertificateGeneration 测试证书生成。
func TestE2ESSLCertificateGeneration(t *testing.T) {
tmpDir := t.TempDir()
certPath, keyPath, cleanup, err := testutil.GenerateSelfSignedCert(tmpDir)
require.NoError(t, err, "Failed to generate certificate")
defer cleanup()
assert.FileExists(t, certPath, "Certificate file should exist")
assert.FileExists(t, keyPath, "Key file should exist")
// 验证证书可以被加载
certPool, err := testutil.GenerateCertPool(certPath)
require.NoError(t, err, "Failed to create cert pool")
assert.NotNil(t, certPool)
}
// TestE2ESSLConcurrent 测试并发 SSL 连接。
func TestE2ESSLConcurrent(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
container, addr, err := testutil.StartNginxContainer(ctx)
require.NoError(t, err, "Failed to start nginx container")
defer container.Terminate(ctx)
// 使用真正的并发测试
failures := testutil.RunAndVerifyConcurrentRequests(t, testutil.ConcurrentRequestConfig{
URL: addr,
Count: 10,
Timeout: 10 * time.Second,
ExpectCode: 200,
})
assert.Empty(t, failures, "All concurrent requests should succeed")
}