lolly/internal/http3/server_test.go
xfy 9f3524f641 test(http2,http3): 添加 HTTP/2 和 HTTP/3 服务器测试
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 08:12:33 +08:00

698 lines
16 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.

// Package http3 提供 HTTP/3 服务器功能的测试。
//
// 该文件测试 HTTP/3 服务器模块的各项功能,包括:
// - 服务器创建和配置验证
// - Alt-Svc 头部生成
// - 服务器统计信息获取
// - 运行状态检查
// - 服务器停止和优雅停止
//
// 作者xfy
package http3
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"testing"
"time"
"github.com/valyala/fasthttp"
"rua.plus/lolly/internal/config"
)
// TestNewServer_NilConfig 测试空配置错误
func TestNewServer_NilConfig(t *testing.T) {
handler := func(_ *fasthttp.RequestCtx) {}
server, err := NewServer(nil, handler, &tls.Config{})
if err == nil {
t.Error("Expected error for nil config")
}
if server != nil {
t.Error("Expected nil server for nil config")
}
if err.Error() != "http3 config is nil" {
t.Errorf("Expected error message 'http3 config is nil', got: %v", err)
}
}
// TestNewServer_NilHandler 测试空 handler 错误
func TestNewServer_NilHandler(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
Enable0RTT: true,
}
server, err := NewServer(cfg, nil, &tls.Config{})
if err == nil {
t.Error("Expected error for nil handler")
}
if server != nil {
t.Error("Expected nil server for nil handler")
}
if err.Error() != "handler is nil" {
t.Errorf("Expected error message 'handler is nil', got: %v", err)
}
}
// TestNewServer_NilTLS 测试空 TLS 配置错误
func TestNewServer_NilTLS(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
Enable0RTT: true,
}
handler := func(_ *fasthttp.RequestCtx) {}
server, err := NewServer(cfg, handler, nil)
if err == nil {
t.Error("Expected error for nil TLS config")
}
if server != nil {
t.Error("Expected nil server for nil TLS config")
}
if err.Error() != "tls config is required for HTTP/3" {
t.Errorf("Expected error message 'tls config is required for HTTP/3', got: %v", err)
}
}
// TestNewServer_Success 测试成功创建服务器
func TestNewServer_Success(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
Enable0RTT: true,
MaxStreams: 100,
}
handler := func(_ *fasthttp.RequestCtx) {}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if server == nil {
t.Fatal("Expected non-nil server")
}
if server.config != cfg {
t.Error("Config not set correctly")
}
if server.handler == nil {
t.Error("Handler not set correctly")
}
if server.adapter == nil {
t.Error("Adapter not initialized")
}
if server.tlsConfig != tlsConfig {
t.Error("TLS config not set correctly")
}
if server.running {
t.Error("Server should not be running initially")
}
}
// TestGetAltSvcHeader_DefaultPort 测试默认端口 Alt-Svc 头
func TestGetAltSvcHeader_DefaultPort(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
header := server.GetAltSvcHeader()
expected := `h3=":443"; ma=86400`
if header != expected {
t.Errorf("Expected Alt-Svc header '%s', got '%s'", expected, header)
}
}
// TestGetAltSvcHeader_CustomPort 测试自定义端口 Alt-Svc 头
func TestGetAltSvcHeader_CustomPort(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":8443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
header := server.GetAltSvcHeader()
expected := `h3=":8443"; ma=86400`
if header != expected {
t.Errorf("Expected Alt-Svc header '%s', got '%s'", expected, header)
}
}
// TestGetAltSvcHeader_Disabled 测试禁用 HTTP/3 时返回空
func TestGetAltSvcHeader_Disabled(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: false,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
header := server.GetAltSvcHeader()
if header != "" {
t.Errorf("Expected empty Alt-Svc header when disabled, got '%s'", header)
}
}
// TestGetAltSvcHeader_EmptyListen 测试空监听地址时使用默认端口
func TestGetAltSvcHeader_EmptyListen(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: "", // 空,使用默认 :443
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
header := server.GetAltSvcHeader()
expected := `h3=":443"; ma=86400`
if header != expected {
t.Errorf("Expected Alt-Svc header '%s', got '%s'", expected, header)
}
}
// TestGetStats 测试获取统计信息
func TestGetStats(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":8443",
Enable0RTT: true,
MaxStreams: 200,
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
stats := server.GetStats()
if stats.Running {
t.Error("Expected Running to be false initially")
}
if stats.Listen != ":8443" {
t.Errorf("Expected Listen ':8443', got '%s'", stats.Listen)
}
if !stats.Enable0RTT {
t.Error("Expected Enable0RTT to be true")
}
if stats.MaxStreams != 200 {
t.Errorf("Expected MaxStreams 200, got %d", stats.MaxStreams)
}
}
// TestIsRunning 测试运行状态检查
func TestIsRunning(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 初始状态应该是 false
if server.IsRunning() {
t.Error("Expected IsRunning to be false initially")
}
// 手动设置运行状态(不启动真实服务器)
server.mu.Lock()
server.running = true
server.mu.Unlock()
if !server.IsRunning() {
t.Error("Expected IsRunning to be true after setting")
}
// 再次设置为 false
server.mu.Lock()
server.running = false
server.mu.Unlock()
if server.IsRunning() {
t.Error("Expected IsRunning to be false after unsetting")
}
}
// TestStop_NotRunning 测试停止未运行的服务器
func TestStop_NotRunning(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 服务器未启动Stop 应该返回 nil
err := server.Stop()
if err != nil {
t.Errorf("Expected nil error when stopping non-running server, got: %v", err)
}
}
// TestGracefulStop_NotRunning 测试优雅停止未运行的服务器
func TestGracefulStop_NotRunning(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 服务器未启动GracefulStop 应该返回 nil
err := server.GracefulStop(5 * time.Second)
if err != nil {
t.Errorf("Expected nil error when graceful stopping non-running server, got: %v", err)
}
}
// TestGracefulStop_WithTimeout 测试优雅停止超时
func TestGracefulStop_WithTimeout(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 测试不同超时值
tests := []struct {
name string
timeout time.Duration
}{
{"zero timeout", 0},
{"short timeout", 100 * time.Millisecond},
{"long timeout", 30 * time.Second},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := server.GracefulStop(tt.timeout)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
})
}
}
// TestServer_MultipleStop 测试多次调用 Stop
func TestServer_MultipleStop(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 多次调用 Stop 应该都是安全的
for i := 0; i < 3; i++ {
err := server.Stop()
if err != nil {
t.Errorf("Stop call %d returned error: %v", i+1, err)
}
}
}
// TestServer_MultipleGracefulStop 测试多次调用 GracefulStop
func TestServer_MultipleGracefulStop(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 多次调用 GracefulStop 应该都是安全的
for i := 0; i < 3; i++ {
err := server.GracefulStop(1 * time.Second)
if err != nil {
t.Errorf("GracefulStop call %d returned error: %v", i+1, err)
}
}
}
// TestGetAltSvcHeader_PortBoundaries 测试端口边界值
func TestGetAltSvcHeader_PortBoundaries(t *testing.T) {
tests := []struct {
name string
listen string
expected string
}{
{
name: "标准 HTTP 端口 80",
listen: ":80",
expected: `h3=":80"; ma=86400`,
},
{
name: "标准 HTTPS 端口 443",
listen: ":443",
expected: `h3=":443"; ma=86400`,
},
{
name: "高端口 65535",
listen: ":65535",
expected: `h3=":65535"; ma=86400`,
},
{
name: "低端口 1",
listen: ":1",
expected: `h3=":1"; ma=86400`,
},
{
name: "带 IP 地址的监听",
listen: "0.0.0.0:8443",
expected: `h3=":0.0.0.0:8443"; ma=86400`,
},
{
name: "带 IPv6 地址的监听",
listen: "[::]:8443",
expected: `h3=":[::]:8443"; ma=86400`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: tt.listen,
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
header := server.GetAltSvcHeader()
if header != tt.expected {
t.Errorf("GetAltSvcHeader() = %q, want %q", header, tt.expected)
}
})
}
}
// TestGetAltSvcHeader_DisabledServer 测试禁用状态下的服务器
func TestGetAltSvcHeader_DisabledServer(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: false,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
header := server.GetAltSvcHeader()
if header != "" {
t.Errorf("Expected empty Alt-Svc header when disabled, got %q", header)
}
}
// TestGetAltSvcHeader_NilConfig 测试 nil 配置情况
func TestGetAltSvcHeader_NilConfig(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":443",
}
handler := func(_ *fasthttp.RequestCtx) {}
server, _ := NewServer(cfg, handler, &tls.Config{})
// 正常情况下应该返回 header
header := server.GetAltSvcHeader()
if header == "" {
t.Error("Expected non-empty Alt-Svc header with valid config")
}
}
// TestStart_AlreadyRunning 测试启动已运行的服务器
func TestStart_AlreadyRunning(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":0", // 使用随机端口避免冲突
MaxStreams: 100,
}
handler := func(_ *fasthttp.RequestCtx) {}
cert := generateTestCertificate(t)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Fatalf("Failed to create server: %v", err)
}
// 启动服务器
err = server.Start()
if err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer server.Stop()
// 再次启动应该失败
err = server.Start()
if err == nil {
t.Error("Expected error when starting already running server")
}
if err.Error() != "server already running" {
t.Errorf("Expected 'server already running' error, got: %v", err)
}
}
// TestStart_InvalidListenAddress 测试无效监听地址
func TestStart_InvalidListenAddress(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: "invalid:address:format", // 无效地址
MaxStreams: 100,
}
handler := func(_ *fasthttp.RequestCtx) {}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Fatalf("Failed to create server: %v", err)
}
err = server.Start()
if err == nil {
t.Error("Expected error for invalid listen address")
server.Stop()
}
}
// TestStop_RunningServer 测试停止运行中的服务器
func TestStop_RunningServer(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":0",
MaxStreams: 100,
}
handler := func(_ *fasthttp.RequestCtx) {}
cert := generateTestCertificate(t)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Fatalf("Failed to create server: %v", err)
}
// 启动服务器
err = server.Start()
if err != nil {
t.Fatalf("Failed to start server: %v", err)
}
if !server.IsRunning() {
t.Error("Server should be running after Start()")
}
// 停止服务器
err = server.Stop()
if err != nil {
t.Errorf("Unexpected error stopping server: %v", err)
}
if server.IsRunning() {
t.Error("Server should not be running after Stop()")
}
}
// TestGracefulStop_RunningServer 测试优雅停止运行中的服务器
func TestGracefulStop_RunningServer(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":0",
MaxStreams: 100,
}
handler := func(_ *fasthttp.RequestCtx) {}
cert := generateTestCertificate(t)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Fatalf("Failed to create server: %v", err)
}
// 启动服务器
err = server.Start()
if err != nil {
t.Fatalf("Failed to start server: %v", err)
}
if !server.IsRunning() {
t.Error("Server should be running after Start()")
}
// 优雅停止服务器
err = server.GracefulStop(5 * time.Second)
if err != nil {
t.Errorf("Unexpected error graceful stopping server: %v", err)
}
if server.IsRunning() {
t.Error("Server should not be running after GracefulStop()")
}
}
// TestStart_Enable0RTT 测试启用 0-RTT 时的警告日志
func TestStart_Enable0RTT(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":0",
Enable0RTT: true,
MaxStreams: 100,
}
handler := func(_ *fasthttp.RequestCtx) {}
cert := generateTestCertificate(t)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Fatalf("Failed to create server: %v", err)
}
err = server.Start()
if err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer server.Stop()
// 验证服务器已启动
if !server.IsRunning() {
t.Error("Server should be running")
}
}
// TestStart_DefaultValues 测试默认值设置
func TestStart_DefaultValues(t *testing.T) {
cfg := &config.HTTP3Config{
Enabled: true,
Listen: ":0",
MaxStreams: 0, // 使用默认值
}
handler := func(_ *fasthttp.RequestCtx) {}
cert := generateTestCertificate(t)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
server, err := NewServer(cfg, handler, tlsConfig)
if err != nil {
t.Fatalf("Failed to create server: %v", err)
}
err = server.Start()
if err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer server.Stop()
if !server.IsRunning() {
t.Error("Server should be running")
}
}
// generateTestCertificate 生成用于测试的自签名证书
func generateTestCertificate(t *testing.T) tls.Certificate {
t.Helper()
// 使用 RSA 密钥生成自签名证书
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "localhost"},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
}
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("Failed to generate RSA key: %v", err)
}
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &priv.PublicKey, priv)
if err != nil {
t.Fatalf("Failed to create certificate: %v", err)
}
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
cert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
t.Fatalf("Failed to load certificate: %v", err)
}
return cert
}