- 拆分 server_extended_test.go 到独立测试文件 - 添加 pprof、purge、vhost、internal 测试 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1378 lines
30 KiB
Go
1378 lines
30 KiB
Go
// Package server 提供 HTTP 服务器功能的测试。
|
||
//
|
||
// 该文件测试服务器模块的各项功能,包括:
|
||
// - 服务器创建和初始化
|
||
// - 启动和停止控制
|
||
// - 优雅关闭
|
||
// - 中间件链构建
|
||
// - 请求统计追踪
|
||
// - 监听器管理
|
||
// - TLS 配置
|
||
// - 代理缓存统计
|
||
//
|
||
// 作者:xfy
|
||
package server
|
||
|
||
import (
|
||
"net"
|
||
"os"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/valyala/fasthttp"
|
||
"rua.plus/lolly/internal/config"
|
||
"rua.plus/lolly/internal/version"
|
||
)
|
||
|
||
// TestNew 测试服务器创建
|
||
func TestNew(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Static: []config.StaticConfig{{
|
||
Path: "/",
|
||
Root: "./static",
|
||
Index: []string{"index.html"},
|
||
}},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
if s == nil {
|
||
t.Fatal("New() returned nil, expected non-nil Server")
|
||
}
|
||
|
||
if s.config != cfg {
|
||
t.Error("Server.config not set correctly")
|
||
}
|
||
|
||
if s.running {
|
||
t.Error("Server.running should be false initially")
|
||
}
|
||
|
||
if s.fastServer != nil {
|
||
t.Error("Server.fastServer should be nil before Start()")
|
||
}
|
||
}
|
||
|
||
// TestStopWithoutServer 测试无服务器时调用 Stop
|
||
func TestStopWithoutServer(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 在未启动时调用 Stop,应返回 nil
|
||
err := s.StopWithTimeout(5 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("StopWithTimeout() on non-started server returned error: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestGracefulStop 测试 GracefulStop 调用
|
||
func TestGracefulStop(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 在未启动时调用 GracefulStop,应返回 nil
|
||
err := s.GracefulStop(5 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("GracefulStop() on non-started server returned error: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestStopAfterStop 测试多次调用 Stop
|
||
func TestStopAfterStop(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 多次调用 StopWithTimeout 应该都是安全的
|
||
for i := 0; i < 3; i++ {
|
||
err := s.StopWithTimeout(5 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("StopWithTimeout() call %d returned error: %v", i+1, err)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestGracefulStopWithZeroTimeout 测试零超时的 GracefulStop
|
||
func TestGracefulStopWithZeroTimeout(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
err := s.GracefulStop(0)
|
||
if err != nil {
|
||
t.Errorf("GracefulStop(0) returned error: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_AccessLog 测试访问日志中间件
|
||
func TestBuildMiddlewareChain_AccessLog(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_AccessControl 测试访问控制中间件
|
||
func TestBuildMiddlewareChain_AccessControl(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Security: config.SecurityConfig{
|
||
Access: config.AccessConfig{
|
||
Allow: []string{"127.0.0.1"},
|
||
},
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_RateLimiter 测试限流中间件
|
||
func TestBuildMiddlewareChain_RateLimiter(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Security: config.SecurityConfig{
|
||
RateLimit: config.RateLimitConfig{
|
||
RequestRate: 100,
|
||
Burst: 200,
|
||
},
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_Rewrite 测试重写中间件
|
||
func TestBuildMiddlewareChain_Rewrite(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Rewrite: []config.RewriteRule{
|
||
{Pattern: "/old/(.*)", Replacement: "/new/$1"},
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_Compression 测试压缩中间件
|
||
func TestBuildMiddlewareChain_Compression(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Compression: config.CompressionConfig{
|
||
Level: 6,
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_SecurityHeaders 测试安全头中间件
|
||
func TestBuildMiddlewareChain_SecurityHeaders(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Security: config.SecurityConfig{
|
||
Headers: config.SecurityHeaders{
|
||
XFrameOptions: "DENY",
|
||
XContentTypeOptions: "nosniff",
|
||
},
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_AllMiddlewares 测试所有中间件组合
|
||
func TestBuildMiddlewareChain_AllMiddlewares(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Security: config.SecurityConfig{
|
||
Access: config.AccessConfig{
|
||
Allow: []string{"127.0.0.1"},
|
||
},
|
||
RateLimit: config.RateLimitConfig{
|
||
RequestRate: 100,
|
||
Burst: 200,
|
||
},
|
||
Headers: config.SecurityHeaders{
|
||
XFrameOptions: "DENY",
|
||
},
|
||
},
|
||
Rewrite: []config.RewriteRule{
|
||
{Pattern: "/old/(.*)", Replacement: "/new/$1"},
|
||
},
|
||
Compression: config.CompressionConfig{
|
||
Level: 6,
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestTrackStats 测试请求统计追踪
|
||
func TestTrackStats(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 初始统计应该为 0
|
||
if s.requests.Load() != 0 {
|
||
t.Error("Initial requests should be 0")
|
||
}
|
||
if s.bytesSent.Load() != 0 {
|
||
t.Error("Initial bytesSent should be 0")
|
||
}
|
||
if s.bytesReceived.Load() != 0 {
|
||
t.Error("Initial bytesReceived should be 0")
|
||
}
|
||
|
||
// 创建测试 handler
|
||
handler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.SetBodyString("response body")
|
||
}
|
||
|
||
// 包装 handler
|
||
wrappedHandler := s.trackStats(handler)
|
||
|
||
// 创建测试请求上下文
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Init(&fasthttp.Request{}, nil, nil)
|
||
ctx.Request.SetBody([]byte("request body"))
|
||
|
||
// 执行
|
||
wrappedHandler(ctx)
|
||
|
||
// 验证统计
|
||
if s.requests.Load() != 1 {
|
||
t.Errorf("Expected 1 request, got %d", s.requests.Load())
|
||
}
|
||
|
||
if s.bytesReceived.Load() != int64(len("request body")) {
|
||
t.Errorf("Expected bytesReceived %d, got %d", len("request body"), s.bytesReceived.Load())
|
||
}
|
||
|
||
if s.bytesSent.Load() != int64(len("response body")) {
|
||
t.Errorf("Expected bytesSent %d, got %d", len("response body"), s.bytesSent.Load())
|
||
}
|
||
}
|
||
|
||
// TestTrackStats_MultipleRequests 测试多次请求统计
|
||
func TestTrackStats_MultipleRequests(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
handler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.SetBodyString("ok")
|
||
}
|
||
|
||
wrappedHandler := s.trackStats(handler)
|
||
|
||
// 执行多次请求
|
||
for i := 0; i < 10; i++ {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Init(&fasthttp.Request{}, nil, nil)
|
||
wrappedHandler(ctx)
|
||
}
|
||
|
||
if s.requests.Load() != 10 {
|
||
t.Errorf("Expected 10 requests, got %d", s.requests.Load())
|
||
}
|
||
}
|
||
|
||
// TestGetListeners_Empty 测试空监听器列表
|
||
func TestGetListeners_Empty(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
listeners := s.GetListeners()
|
||
if listeners != nil {
|
||
t.Errorf("Expected nil listeners, got %v", listeners)
|
||
}
|
||
}
|
||
|
||
// TestSetListeners 测试设置监听器
|
||
func TestSetListeners(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 创建模拟监听器
|
||
listener1, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
t.Fatalf("Failed to create listener: %v", err)
|
||
}
|
||
defer func() {
|
||
_ = listener1.Close()
|
||
}()
|
||
|
||
listener2, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
t.Fatalf("Failed to create listener: %v", err)
|
||
}
|
||
defer func() {
|
||
_ = listener2.Close()
|
||
}()
|
||
|
||
listeners := []net.Listener{listener1, listener2}
|
||
s.SetListeners(listeners)
|
||
|
||
// 验证设置成功
|
||
got := s.GetListeners()
|
||
if len(got) != 2 {
|
||
t.Errorf("Expected 2 listeners, got %d", len(got))
|
||
}
|
||
}
|
||
|
||
// TestGetTLSConfig_NotConfigured 测试未配置 TLS
|
||
func TestGetTLSConfig_NotConfigured(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
tlsConfig, err := s.GetTLSConfig()
|
||
if err == nil {
|
||
t.Error("Expected error for unconfigured TLS")
|
||
}
|
||
if tlsConfig != nil {
|
||
t.Error("Expected nil TLS config")
|
||
}
|
||
if err.Error() != "TLS not configured" {
|
||
t.Errorf("Expected error 'TLS not configured', got: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestGetHandler 测试获取 handler
|
||
func TestGetHandler(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 初始 handler 应该为 nil
|
||
handler := s.GetHandler()
|
||
if handler != nil {
|
||
t.Error("Expected nil handler initially")
|
||
}
|
||
|
||
// 设置一个 handler
|
||
testHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.SetBodyString("test")
|
||
}
|
||
s.handler = testHandler
|
||
|
||
// 验证获取成功
|
||
got := s.GetHandler()
|
||
if got == nil {
|
||
t.Error("Expected non-nil handler after setting")
|
||
}
|
||
}
|
||
|
||
// TestServer_Connections 测试连接统计
|
||
func TestServer_Connections(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 初始连接数应该为 0
|
||
if s.connections.Load() != 0 {
|
||
t.Error("Initial connections should be 0")
|
||
}
|
||
|
||
// 增加
|
||
s.connections.Add(1)
|
||
if s.connections.Load() != 1 {
|
||
t.Errorf("Expected 1 connection, got %d", s.connections.Load())
|
||
}
|
||
|
||
// 减少
|
||
s.connections.Add(-1)
|
||
if s.connections.Load() != 0 {
|
||
t.Errorf("Expected 0 connections, got %d", s.connections.Load())
|
||
}
|
||
}
|
||
|
||
// TestServer_Proxies 测试代理管理
|
||
func TestServer_Proxies(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 初始代理列表应为空
|
||
if len(s.proxies) != 0 {
|
||
t.Error("Initial proxies should be empty")
|
||
}
|
||
}
|
||
|
||
// TestServer_Running 测试运行状态
|
||
func TestServer_Running(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 初始状态应为未运行
|
||
if s.running {
|
||
t.Error("Initial running state should be false")
|
||
}
|
||
}
|
||
|
||
// TestServer_StopWithNilFastServer 测试无 fastServer 时停止
|
||
func TestServer_StopWithNilFastServer(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
s.fastServer = nil
|
||
|
||
err := s.StopWithTimeout(5 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("StopWithTimeout with nil fastServer should succeed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestServer_GracefulStopWithNilFastServer 测试无 fastServer 时优雅停止
|
||
func TestServer_GracefulStopWithNilFastServer(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
s.fastServer = nil
|
||
|
||
err := s.GracefulStop(5 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("GracefulStop with nil fastServer should succeed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestServer_GetProxyCacheStats 测试代理缓存统计
|
||
func TestServer_GetProxyCacheStats(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 无代理时应返回空统计
|
||
stats := s.getProxyCacheStats()
|
||
if stats.Entries != 0 {
|
||
t.Errorf("Expected 0 entries, got %d", stats.Entries)
|
||
}
|
||
if stats.Pending != 0 {
|
||
t.Errorf("Expected 0 pending, got %d", stats.Pending)
|
||
}
|
||
}
|
||
|
||
// TestServer_BuildMiddlewareChain_EmptyConfig 测试空配置的中间件链
|
||
func TestServer_BuildMiddlewareChain_EmptyConfig(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("Unexpected error: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestServer_TrackStats_EmptyBody 测试空响应体的统计
|
||
func TestServer_TrackStats_EmptyBody(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
handler := func(_ *fasthttp.RequestCtx) {
|
||
// 空响应
|
||
}
|
||
|
||
wrappedHandler := s.trackStats(handler)
|
||
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Init(&fasthttp.Request{}, nil, nil)
|
||
ctx.Request.SetBody(nil)
|
||
|
||
wrappedHandler(ctx)
|
||
|
||
if s.requests.Load() != 1 {
|
||
t.Errorf("Expected 1 request, got %d", s.requests.Load())
|
||
}
|
||
|
||
if s.bytesSent.Load() != 0 {
|
||
t.Errorf("Expected 0 bytes sent, got %d", s.bytesSent.Load())
|
||
}
|
||
}
|
||
|
||
// TestStart_Success 测试服务器配置初始化
|
||
func TestStart_Success(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 验证服务器正确初始化
|
||
if s == nil {
|
||
t.Fatal("New() returned nil, expected non-nil Server")
|
||
}
|
||
|
||
if s.config != cfg {
|
||
t.Error("Server.config not set correctly")
|
||
}
|
||
}
|
||
|
||
// TestStart_WithStaticFiles 测试静态文件配置
|
||
func TestStart_WithStaticFiles(t *testing.T) {
|
||
// 创建临时目录
|
||
tempDir := t.TempDir()
|
||
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Static: []config.StaticConfig{{
|
||
Path: "/static",
|
||
Root: tempDir,
|
||
Index: []string{"index.html"},
|
||
}},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
if s == nil {
|
||
t.Fatal("New() returned nil")
|
||
}
|
||
}
|
||
|
||
// TestStart_WithGoroutinePool 测试 GoroutinePool 配置
|
||
func TestStart_WithGoroutinePool(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
Performance: config.PerformanceConfig{
|
||
GoroutinePool: config.GoroutinePoolConfig{
|
||
Enabled: true,
|
||
MaxWorkers: 100,
|
||
MinWorkers: 10,
|
||
IdleTimeout: 30 * time.Second,
|
||
},
|
||
},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
if s == nil {
|
||
t.Fatal("New() returned nil")
|
||
}
|
||
}
|
||
|
||
// TestStart_WithFileCache 测试文件缓存配置
|
||
func TestStart_WithFileCache(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
Performance: config.PerformanceConfig{
|
||
FileCache: config.FileCacheConfig{
|
||
MaxEntries: 1000,
|
||
MaxSize: 100 * 1024 * 1024,
|
||
},
|
||
},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
if s == nil {
|
||
t.Fatal("New() returned nil")
|
||
}
|
||
}
|
||
|
||
// TestStop_Graceful 测试优雅停止(无 race 模式)
|
||
func TestStop_Graceful(t *testing.T) {
|
||
if testing.Short() {
|
||
t.Skip("skipping in short mode")
|
||
}
|
||
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 在未启动时调用 GracefulStop,应返回 nil
|
||
err := s.GracefulStop(1 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("GracefulStop() on non-started server returned error: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestGetTLSConfig_Nil 测试无 TLS 配置
|
||
func TestGetTLSConfig_Nil(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
tlsCfg, err := s.GetTLSConfig()
|
||
if err == nil {
|
||
t.Error("GetTLSConfig() should return error when TLS not configured")
|
||
}
|
||
if tlsCfg != nil {
|
||
t.Error("GetTLSConfig() should return nil when TLS not configured")
|
||
}
|
||
}
|
||
|
||
// TestGetTLSConfig_NilServer 测试 nil 服务器调用 GetTLSConfig
|
||
func TestGetTLSConfig_NilServer(t *testing.T) {
|
||
var s *Server
|
||
// 防御性:如果 s 为 nil,调用方法会 panic,这是预期的行为
|
||
// 这里我们只测试非 nil 但 tlsManager 为 nil 的情况
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
s = New(cfg)
|
||
|
||
// 确保 tlsManager 为 nil
|
||
if s.tlsManager != nil {
|
||
t.Skip("tlsManager should be nil initially")
|
||
}
|
||
|
||
tlsCfg, err := s.GetTLSConfig()
|
||
if err == nil {
|
||
t.Error("Expected error when tlsManager is nil")
|
||
}
|
||
if tlsCfg != nil {
|
||
t.Error("Expected nil TLS config when tlsManager is nil")
|
||
}
|
||
if err.Error() != "TLS not configured" {
|
||
t.Errorf("Expected error 'TLS not configured', got: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestGetServerName 测试服务器名称返回。
|
||
func TestGetServerName(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
cfg *config.ServerConfig
|
||
wantName string
|
||
}{
|
||
{
|
||
name: "nil config",
|
||
cfg: nil,
|
||
wantName: "lolly/" + version.Version,
|
||
},
|
||
{
|
||
name: "ServerTokens true (default)",
|
||
cfg: &config.ServerConfig{
|
||
ServerTokens: true,
|
||
},
|
||
wantName: "lolly/" + version.Version,
|
||
},
|
||
{
|
||
name: "ServerTokens false",
|
||
cfg: &config.ServerConfig{
|
||
ServerTokens: false,
|
||
},
|
||
wantName: "lolly",
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
s := &Server{}
|
||
got := s.getServerName(tt.cfg)
|
||
if got != tt.wantName {
|
||
t.Errorf("getServerName() = %q, want %q", got, tt.wantName)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestApplyTypesConfig 测试 MIME 类型配置应用。
|
||
func TestApplyTypesConfig(t *testing.T) {
|
||
t.Run("nil config", func(t *testing.T) {
|
||
s := &Server{}
|
||
// 不应该 panic
|
||
s.applyTypesConfig(nil)
|
||
})
|
||
|
||
t.Run("empty config", func(t *testing.T) {
|
||
s := &Server{}
|
||
cfg := &config.ServerConfig{}
|
||
// 不应该 panic
|
||
s.applyTypesConfig(cfg)
|
||
})
|
||
|
||
t.Run("with types map", func(t *testing.T) {
|
||
s := &Server{}
|
||
cfg := &config.ServerConfig{
|
||
Types: config.TypesConfig{
|
||
Map: map[string]string{
|
||
".custom": "application/x-custom",
|
||
},
|
||
},
|
||
}
|
||
// 不应该 panic
|
||
s.applyTypesConfig(cfg)
|
||
})
|
||
|
||
t.Run("with default type", func(t *testing.T) {
|
||
s := &Server{}
|
||
cfg := &config.ServerConfig{
|
||
Types: config.TypesConfig{
|
||
DefaultType: "application/octet-stream",
|
||
},
|
||
}
|
||
// 不应该 panic
|
||
s.applyTypesConfig(cfg)
|
||
})
|
||
}
|
||
|
||
// TestCreateListener_TCP 测试 TCP 监听器创建。
|
||
func TestCreateListener_TCP(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: "127.0.0.1:0", // 随机端口
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
ln, err := s.createListener(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Fatalf("createListener() error: %v", err)
|
||
}
|
||
if ln == nil {
|
||
t.Fatal("createListener() returned nil listener")
|
||
}
|
||
defer ln.Close()
|
||
|
||
if ln.Addr().Network() != "tcp" {
|
||
t.Errorf("expected tcp network, got %s", ln.Addr().Network())
|
||
}
|
||
}
|
||
|
||
// TestCreateListener_UnixSocket 测试 Unix Socket 监听器创建。
|
||
func TestCreateListener_UnixSocket(t *testing.T) {
|
||
tempDir := t.TempDir()
|
||
socketPath := tempDir + "/test.sock"
|
||
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: "unix:" + socketPath,
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
ln, err := s.createListener(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Fatalf("createListener() error: %v", err)
|
||
}
|
||
if ln == nil {
|
||
t.Fatal("createListener() returned nil listener")
|
||
}
|
||
defer ln.Close()
|
||
|
||
if ln.Addr().Network() != "unix" {
|
||
t.Errorf("expected unix network, got %s", ln.Addr().Network())
|
||
}
|
||
}
|
||
|
||
// TestCreateListener_UnixSocketWithPermissions 测试带权限的 Unix Socket 创建。
|
||
func TestCreateListener_UnixSocketWithPermissions(t *testing.T) {
|
||
tempDir := t.TempDir()
|
||
socketPath := tempDir + "/test_perm.sock"
|
||
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: "unix:" + socketPath,
|
||
UnixSocket: config.UnixSocketConfig{
|
||
Mode: 0o600,
|
||
User: "nobody",
|
||
Group: "nobody",
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
ln, err := s.createListener(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Fatalf("createListener() error: %v", err)
|
||
}
|
||
if ln == nil {
|
||
t.Fatal("createListener() returned nil listener")
|
||
}
|
||
defer ln.Close()
|
||
}
|
||
|
||
// TestCreateListener_UnixSocketCleanup 测试 Unix Socket 文件清理。
|
||
func TestCreateListener_UnixSocketCleanup(t *testing.T) {
|
||
tempDir := t.TempDir()
|
||
socketPath := tempDir + "/cleanup.sock"
|
||
|
||
// 先创建一个已存在的 socket 文件
|
||
if err := os.WriteFile(socketPath, []byte{}, 0o666); err != nil {
|
||
t.Fatalf("failed to create existing socket file: %v", err)
|
||
}
|
||
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: "unix:" + socketPath,
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
ln, err := s.createListener(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Fatalf("createListener() error: %v", err)
|
||
}
|
||
defer ln.Close()
|
||
}
|
||
|
||
// TestServer_StatsMethods 测试服务器统计方法。
|
||
func TestServer_StatsMethods(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 测试 startTime 初始值
|
||
if !s.startTime.IsZero() {
|
||
t.Error("startTime should be zero initially")
|
||
}
|
||
|
||
// 设置 startTime
|
||
s.startTime = time.Now()
|
||
if s.startTime.IsZero() {
|
||
t.Error("startTime should not be zero after setting")
|
||
}
|
||
|
||
// 测试统计值
|
||
if s.connections.Load() != 0 {
|
||
t.Error("initial connections should be 0")
|
||
}
|
||
if s.requests.Load() != 0 {
|
||
t.Error("initial requests should be 0")
|
||
}
|
||
if s.bytesSent.Load() != 0 {
|
||
t.Error("initial bytesSent should be 0")
|
||
}
|
||
if s.bytesReceived.Load() != 0 {
|
||
t.Error("initial bytesReceived should be 0")
|
||
}
|
||
}
|
||
|
||
// TestServer_SetResolver 测试设置解析器。
|
||
func TestServer_SetResolver(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 设置 nil resolver
|
||
s.SetResolver(nil)
|
||
if s.resolver != nil {
|
||
t.Error("resolver should be nil")
|
||
}
|
||
}
|
||
|
||
// TestServer_SetUpgradeManager 测试设置升级管理器。
|
||
func TestServer_SetUpgradeManager(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 设置 nil upgrade manager
|
||
s.SetUpgradeManager(nil)
|
||
if s.upgradeManager != nil {
|
||
t.Error("upgradeManager should be nil")
|
||
}
|
||
|
||
// 设置实际的 upgrade manager
|
||
um := NewUpgradeManager(s)
|
||
s.SetUpgradeManager(um)
|
||
if s.upgradeManager == nil {
|
||
t.Error("upgradeManager should not be nil after setting")
|
||
}
|
||
}
|
||
|
||
// TestServer_GetResolver 测试获取解析器。
|
||
func TestServer_GetResolver(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 初始 resolver 应为 nil
|
||
resolver := s.GetResolver()
|
||
if resolver != nil {
|
||
t.Error("expected nil resolver initially")
|
||
}
|
||
}
|
||
|
||
// TestServer_StopWithTimeout_WithListeners 测试带监听器的停止。
|
||
func TestServer_StopWithTimeout_WithListeners(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 创建监听器
|
||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
t.Fatalf("failed to create listener: %v", err)
|
||
}
|
||
s.listeners = []net.Listener{ln}
|
||
|
||
// 调用停止
|
||
err = s.StopWithTimeout(1 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("StopWithTimeout failed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestServer_GracefulStop_WithListeners 测试带监听器的优雅停止。
|
||
func TestServer_GracefulStop_WithListeners(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 创建监听器
|
||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
t.Fatalf("failed to create listener: %v", err)
|
||
}
|
||
s.listeners = []net.Listener{ln}
|
||
|
||
// 调用优雅停止
|
||
err = s.GracefulStop(1 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("GracefulStop failed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestServer_StopWithTimeout_WithFastServer 测试带 fastServer 的停止。
|
||
func TestServer_StopWithTimeout_WithFastServer(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
s.running = true
|
||
|
||
// 创建 mock fastServer
|
||
s.fastServer = &fasthttp.Server{}
|
||
|
||
// 调用停止
|
||
err := s.StopWithTimeout(1 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("StopWithTimeout failed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_BodyLimit 测试请求体限制中间件。
|
||
func TestBuildMiddlewareChain_BodyLimit(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
ClientMaxBodySize: "1MB",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_ErrorIntercept 测试错误拦截中间件。
|
||
func TestBuildMiddlewareChain_ErrorIntercept(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
Security: config.SecurityConfig{
|
||
ErrorPage: config.ErrorPageConfig{
|
||
Pages: map[int]string{
|
||
404: "/404.html",
|
||
},
|
||
},
|
||
},
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestBuildMiddlewareChain_NilServerConfig 测试 nil 服务器配置。
|
||
// 注意:buildMiddlewareChain 不接受 nil,所以这个测试验证空配置。
|
||
func TestBuildMiddlewareChain_NilServerConfig(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Logging: config.LoggingConfig{},
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
chain, err := s.buildMiddlewareChain(&cfg.Servers[0])
|
||
if err != nil {
|
||
t.Errorf("buildMiddlewareChain failed: %v", err)
|
||
}
|
||
if chain == nil {
|
||
t.Error("Expected non-nil chain")
|
||
}
|
||
}
|
||
|
||
// TestServer_StatusCode_MethodNotAllowed 测试不支持的 HTTP 方法。
|
||
func TestServer_StatusCode_MethodNotAllowed(t *testing.T) {
|
||
// 简单验证
|
||
if fasthttp.StatusMethodNotAllowed != 405 {
|
||
t.Errorf("StatusMethodNotAllowed should be 405")
|
||
}
|
||
}
|
||
|
||
// TestServer_ConnectionTracking 测试连接追踪。
|
||
func TestServer_ConnectionTracking(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 测试原子操作
|
||
initial := s.connections.Load()
|
||
s.connections.Add(1)
|
||
if s.connections.Load() != initial+1 {
|
||
t.Error("connections should have incremented")
|
||
}
|
||
s.connections.Add(-1)
|
||
if s.connections.Load() != initial {
|
||
t.Error("connections should be back to initial")
|
||
}
|
||
}
|
||
|
||
// TestServer_RequestTracking 测试请求追踪。
|
||
func TestServer_RequestTracking(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 测试原子操作
|
||
s.requests.Add(5)
|
||
if s.requests.Load() != 5 {
|
||
t.Errorf("expected 5 requests, got %d", s.requests.Load())
|
||
}
|
||
}
|
||
|
||
// TestServer_BytesTracking 测试字节追踪。
|
||
func TestServer_BytesTracking(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 测试原子操作
|
||
s.bytesSent.Add(1024)
|
||
s.bytesReceived.Add(512)
|
||
if s.bytesSent.Load() != 1024 {
|
||
t.Errorf("expected 1024 bytes sent, got %d", s.bytesSent.Load())
|
||
}
|
||
if s.bytesReceived.Load() != 512 {
|
||
t.Errorf("expected 512 bytes received, got %d", s.bytesReceived.Load())
|
||
}
|
||
}
|
||
|
||
// TestServer_GracefulStop_WithFastServers 测试带多个 fastServer 的优雅停止。
|
||
func TestServer_GracefulStop_WithFastServers(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
s.running = true
|
||
|
||
// 创建多个 fastServer
|
||
s.fastServers = []*fasthttp.Server{
|
||
{},
|
||
{},
|
||
}
|
||
|
||
// 调用优雅停止
|
||
err := s.GracefulStop(1 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("GracefulStop failed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestServer_StopWithTimeout_WithFastServers 测试带多个 fastServer 的停止。
|
||
func TestServer_StopWithTimeout_WithFastServers(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
s.running = true
|
||
|
||
// 创建多个 fastServer
|
||
s.fastServers = []*fasthttp.Server{
|
||
{},
|
||
{},
|
||
}
|
||
|
||
// 调用停止
|
||
err := s.StopWithTimeout(1 * time.Second)
|
||
if err != nil {
|
||
t.Errorf("StopWithTimeout failed: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestServer_GetProxyCacheStats_WithProxies 测试带代理的缓存统计。
|
||
func TestServer_GetProxyCacheStats_WithProxies(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":8080",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
s.proxies = nil // 确保 proxies 为 nil
|
||
|
||
// 无代理时应返回空统计
|
||
stats := s.getProxyCacheStats()
|
||
if stats.Entries != 0 {
|
||
t.Errorf("Expected 0 entries, got %d", stats.Entries)
|
||
}
|
||
}
|
||
|
||
// TestServer_MultipleListeners 测试多个监听器。
|
||
func TestServer_MultipleListeners(t *testing.T) {
|
||
cfg := &config.Config{
|
||
Servers: []config.ServerConfig{{
|
||
Listen: ":0",
|
||
}},
|
||
}
|
||
|
||
s := New(cfg)
|
||
|
||
// 创建多个监听器
|
||
ln1, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
t.Fatalf("failed to create listener: %v", err)
|
||
}
|
||
ln2, err := net.Listen("tcp", "127.0.0.1:0")
|
||
if err != nil {
|
||
t.Fatalf("failed to create listener: %v", err)
|
||
_ = ln1.Close()
|
||
}
|
||
|
||
s.listeners = []net.Listener{ln1, ln2}
|
||
|
||
// 验证可以获取监听器
|
||
got := s.GetListeners()
|
||
if len(got) != 2 {
|
||
t.Errorf("expected 2 listeners, got %d", len(got))
|
||
}
|
||
|
||
// 清理
|
||
_ = s.StopWithTimeout(1 * time.Second)
|
||
}
|