- Delete unused files: tempfile subsystem, matcher variants, server/internal - Remove 200+ unused functions across proxy, ssl, lua, http2/3, stream, variable - Fix proxy test type errors (backgroundRefresh ctx→Request) - Move bench/tools mock backend into internal/testutil - Remove corresponding test functions for all deleted code
404 lines
11 KiB
Go
404 lines
11 KiB
Go
// Package lua 提供 Lua 中间件测试
|
||
package lua
|
||
|
||
import (
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/stretchr/testify/assert"
|
||
"github.com/stretchr/testify/require"
|
||
"github.com/valyala/fasthttp"
|
||
)
|
||
|
||
// TestLuaMiddlewareCreation 测试 LuaMiddleware 创建
|
||
func TestLuaMiddlewareCreation(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
// 创建临时脚本文件
|
||
tmpDir := t.TempDir()
|
||
scriptPath := filepath.Join(tmpDir, "test.lua")
|
||
err = os.WriteFile(scriptPath, []byte("ngx.say('hello')"), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
config := LuaMiddlewareConfig{
|
||
ScriptPath: scriptPath,
|
||
Phase: PhaseContent,
|
||
Timeout: 10 * time.Second,
|
||
Name: "test-middleware",
|
||
Enabled: true,
|
||
}
|
||
|
||
middleware, err := NewLuaMiddleware(engine, config)
|
||
require.NoError(t, err)
|
||
require.NotNil(t, middleware)
|
||
|
||
assert.Equal(t, "test-middleware", middleware.Name())
|
||
assert.Equal(t, scriptPath, middleware.GetScriptPath())
|
||
assert.Equal(t, PhaseContent, middleware.GetPhase())
|
||
assert.Equal(t, 10*time.Second, middleware.timeout)
|
||
assert.True(t, middleware.IsEnabled())
|
||
}
|
||
|
||
// TestLuaMiddlewareValidation 测试配置验证
|
||
func TestLuaMiddlewareValidation(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
// 缺少 engine
|
||
config := LuaMiddlewareConfig{ScriptPath: "test.lua"}
|
||
middleware, err := NewLuaMiddleware(nil, config)
|
||
assert.Error(t, err)
|
||
assert.Nil(t, middleware)
|
||
assert.Contains(t, err.Error(), "engine is required")
|
||
|
||
// 缺少 script path
|
||
middleware, err = NewLuaMiddleware(engine, LuaMiddlewareConfig{})
|
||
assert.Error(t, err)
|
||
assert.Nil(t, middleware)
|
||
assert.Contains(t, err.Error(), "script path is required")
|
||
}
|
||
|
||
// TestLuaMiddlewareProcess 测试中间件处理
|
||
func TestLuaMiddlewareProcess(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
// 创建脚本文件
|
||
tmpDir := t.TempDir()
|
||
scriptPath := filepath.Join(tmpDir, "test.lua")
|
||
err = os.WriteFile(scriptPath, []byte(`ngx.say("hello from lua")`), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
config := LuaMiddlewareConfig{
|
||
ScriptPath: scriptPath,
|
||
Phase: PhaseContent,
|
||
Enabled: true,
|
||
EnabledSet: true, // 显式启用
|
||
}
|
||
|
||
middleware, err := NewLuaMiddleware(engine, config)
|
||
require.NoError(t, err)
|
||
|
||
// 创建 RequestCtx
|
||
ctx := &fasthttp.RequestCtx{}
|
||
|
||
// 创建最终处理器
|
||
finalHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("final handler")
|
||
}
|
||
|
||
// 包装处理器
|
||
handler := middleware.Process(finalHandler)
|
||
|
||
// 执行
|
||
handler(ctx)
|
||
|
||
// 验证输出包含 Lua 输出
|
||
body := string(ctx.Response.Body())
|
||
assert.Contains(t, body, "hello from lua")
|
||
}
|
||
|
||
// TestLuaMiddlewareDisabled 测试禁用的中间件
|
||
func TestLuaMiddlewareDisabled(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
// 创建脚本文件
|
||
tmpDir := t.TempDir()
|
||
scriptPath := filepath.Join(tmpDir, "test.lua")
|
||
err = os.WriteFile(scriptPath, []byte(`ngx.say("lua output")`), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
config := LuaMiddlewareConfig{
|
||
ScriptPath: scriptPath,
|
||
Phase: PhaseContent,
|
||
Enabled: false, // 禁用
|
||
EnabledSet: true, // 显式设置
|
||
}
|
||
|
||
middleware, err := NewLuaMiddleware(engine, config)
|
||
require.NoError(t, err)
|
||
|
||
// 创建 RequestCtx
|
||
ctx := &fasthttp.RequestCtx{}
|
||
|
||
// 创建最终处理器
|
||
finalHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("final only")
|
||
}
|
||
|
||
// 包装处理器
|
||
handler := middleware.Process(finalHandler)
|
||
|
||
// 执行
|
||
handler(ctx)
|
||
|
||
// 禁用时只执行最终处理器
|
||
body := string(ctx.Response.Body())
|
||
assert.Equal(t, "final only", body)
|
||
assert.NotContains(t, body, "lua output")
|
||
}
|
||
|
||
// TestMultiPhaseLuaMiddlewareCreation 测试多阶段中间件创建
|
||
func TestMultiPhaseLuaMiddlewareCreation(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
multi := NewMultiPhaseLuaMiddleware(engine, "multi-test")
|
||
|
||
assert.Equal(t, "multi-test", multi.Name())
|
||
assert.Equal(t, 0, multi.PhaseCount())
|
||
}
|
||
|
||
// TestMultiPhaseLuaMiddlewareAddPhase 测试添加阶段
|
||
func TestMultiPhaseLuaMiddlewareAddPhase(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
tmpDir := t.TempDir()
|
||
|
||
multi := NewMultiPhaseLuaMiddleware(engine, "multi-test")
|
||
|
||
// 添加 rewrite 阶段
|
||
rewriteScript := filepath.Join(tmpDir, "rewrite.lua")
|
||
err = os.WriteFile(rewriteScript, []byte("ngx.var.uri = '/rewritten'"), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
err = multi.AddPhase(PhaseRewrite, rewriteScript, 10*time.Second)
|
||
require.NoError(t, err)
|
||
|
||
assert.Equal(t, 1, multi.PhaseCount())
|
||
assert.True(t, multi.HasPhase(PhaseRewrite))
|
||
|
||
// 添加 access 阶段
|
||
accessScript := filepath.Join(tmpDir, "access.lua")
|
||
err = os.WriteFile(accessScript, []byte("ngx.exit(403)"), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
err = multi.AddPhase(PhaseAccess, accessScript, 10*time.Second)
|
||
require.NoError(t, err)
|
||
|
||
assert.Equal(t, 2, multi.PhaseCount())
|
||
assert.True(t, multi.HasPhase(PhaseAccess))
|
||
}
|
||
|
||
// TestMultiPhaseLuaMiddlewareRemovePhase 测试移除阶段
|
||
func TestMultiPhaseLuaMiddlewareRemovePhase(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
tmpDir := t.TempDir()
|
||
|
||
multi := NewMultiPhaseLuaMiddleware(engine, "multi-test")
|
||
|
||
scriptPath := filepath.Join(tmpDir, "test.lua")
|
||
err = os.WriteFile(scriptPath, []byte("return 1"), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
err = multi.AddPhase(PhaseRewrite, scriptPath, 10*time.Second)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, 1, multi.PhaseCount())
|
||
|
||
// 移除阶段
|
||
multi.RemovePhase(PhaseRewrite)
|
||
assert.Equal(t, 0, multi.PhaseCount())
|
||
assert.False(t, multi.HasPhase(PhaseRewrite))
|
||
}
|
||
|
||
// TestMultiPhaseLuaMiddlewareProcess 测试多阶段执行
|
||
func TestMultiPhaseLuaMiddlewareProcess(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
tmpDir := t.TempDir()
|
||
|
||
multi := NewMultiPhaseLuaMiddleware(engine, "multi-test")
|
||
|
||
// rewrite 阎段脚本
|
||
rewriteScript := filepath.Join(tmpDir, "rewrite.lua")
|
||
err = os.WriteFile(rewriteScript, []byte(`ngx.say("rewrite")`), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
err = multi.AddPhase(PhaseRewrite, rewriteScript, 10*time.Second)
|
||
require.NoError(t, err)
|
||
|
||
// content 阎段脚本
|
||
contentScript := filepath.Join(tmpDir, "content.lua")
|
||
err = os.WriteFile(contentScript, []byte(`ngx.say("content")`), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
err = multi.AddPhase(PhaseContent, contentScript, 10*time.Second)
|
||
require.NoError(t, err)
|
||
|
||
// 创建 RequestCtx
|
||
ctx := &fasthttp.RequestCtx{}
|
||
|
||
// 创建最终处理器
|
||
finalHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("final")
|
||
}
|
||
|
||
// 包装处理器
|
||
handler := multi.Process(finalHandler)
|
||
|
||
// 执行
|
||
handler(ctx)
|
||
|
||
// 验证执行顺序:rewrite -> content -> final
|
||
body := string(ctx.Response.Body())
|
||
// 注意:由于 Lua 输出会追加到响应体,顺序可能不同
|
||
assert.Contains(t, body, "rewrite")
|
||
assert.Contains(t, body, "content")
|
||
}
|
||
|
||
// TestMultiPhaseLuaMiddlewareGetPhaseMiddleware 测试获取阶段中间件
|
||
func TestMultiPhaseLuaMiddlewareGetPhaseMiddleware(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
tmpDir := t.TempDir()
|
||
|
||
multi := NewMultiPhaseLuaMiddleware(engine, "multi-test")
|
||
|
||
scriptPath := filepath.Join(tmpDir, "test.lua")
|
||
err = os.WriteFile(scriptPath, []byte("return 1"), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
err = multi.AddPhase(PhaseRewrite, scriptPath, 10*time.Second)
|
||
require.NoError(t, err)
|
||
|
||
// 获取阶段中间件
|
||
middleware := multi.GetPhaseMiddleware(PhaseRewrite)
|
||
require.NotNil(t, middleware)
|
||
assert.Equal(t, PhaseRewrite, middleware.GetPhase())
|
||
|
||
// 获取不存在的阶段
|
||
middleware = multi.GetPhaseMiddleware(PhaseAccess)
|
||
assert.Nil(t, middleware)
|
||
}
|
||
|
||
// TestLuaMiddlewareIntegrationWithChain 测试与 middleware chain 集成
|
||
func TestLuaMiddlewareIntegrationWithChain(t *testing.T) {
|
||
// 这个测试验证 LuaMiddleware 可以与现有的 middleware 链集成
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
tmpDir := t.TempDir()
|
||
scriptPath := filepath.Join(tmpDir, "test.lua")
|
||
err = os.WriteFile(scriptPath, []byte(`ngx.say("lua middleware")`), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
config := LuaMiddlewareConfig{
|
||
ScriptPath: scriptPath,
|
||
Phase: PhaseContent,
|
||
Name: "lua-content",
|
||
}
|
||
|
||
middleware, err := NewLuaMiddleware(engine, config)
|
||
require.NoError(t, err)
|
||
|
||
// 验证实现了 Middleware 接口
|
||
// Name() 和 Process() 方法已实现
|
||
assert.Equal(t, "lua-content", middleware.Name())
|
||
|
||
// 创建 RequestCtx
|
||
ctx := &fasthttp.RequestCtx{}
|
||
|
||
// 创建处理器
|
||
handler := middleware.Process(func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("next")
|
||
})
|
||
|
||
// 执行
|
||
handler(ctx)
|
||
|
||
// 验证输出
|
||
body := string(ctx.Response.Body())
|
||
assert.Contains(t, body, "lua middleware")
|
||
}
|
||
|
||
// TestLuaMiddlewareExecutionError 测试执行错误处理
|
||
func TestLuaMiddlewareExecutionError(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
// 创建有语法错误的脚本
|
||
tmpDir := t.TempDir()
|
||
scriptPath := filepath.Join(tmpDir, "error.lua")
|
||
err = os.WriteFile(scriptPath, []byte("invalid lua syntax !!!"), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
config := LuaMiddlewareConfig{
|
||
ScriptPath: scriptPath,
|
||
Phase: PhaseContent,
|
||
}
|
||
|
||
middleware, err := NewLuaMiddleware(engine, config)
|
||
require.NoError(t, err)
|
||
|
||
ctx := &fasthttp.RequestCtx{}
|
||
|
||
handler := middleware.Process(func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("final")
|
||
})
|
||
|
||
handler(ctx)
|
||
|
||
// 执行错误时返回 500
|
||
assert.Equal(t, fasthttp.StatusInternalServerError, ctx.Response.StatusCode())
|
||
}
|
||
|
||
// TestLuaMiddlewareExit 测试 ngx.exit() 终止执行
|
||
func TestLuaMiddlewareExit(t *testing.T) {
|
||
engine, err := NewEngine(DefaultConfig())
|
||
require.NoError(t, err)
|
||
defer engine.Close()
|
||
|
||
tmpDir := t.TempDir()
|
||
scriptPath := filepath.Join(tmpDir, "exit.lua")
|
||
err = os.WriteFile(scriptPath, []byte(`ngx.say("before exit"); ngx.exit(200)`), 0o644)
|
||
require.NoError(t, err)
|
||
|
||
config := LuaMiddlewareConfig{
|
||
ScriptPath: scriptPath,
|
||
Phase: PhaseContent,
|
||
}
|
||
|
||
middleware, err := NewLuaMiddleware(engine, config)
|
||
require.NoError(t, err)
|
||
|
||
ctx := &fasthttp.RequestCtx{}
|
||
|
||
nextCalled := false
|
||
handler := middleware.Process(func(ctx *fasthttp.RequestCtx) {
|
||
nextCalled = true
|
||
ctx.WriteString("next handler")
|
||
})
|
||
|
||
handler(ctx)
|
||
|
||
// ngx.exit() 终止执行,next handler 不应被调用
|
||
assert.False(t, nextCalled)
|
||
|
||
// 状态码应为 200
|
||
assert.Equal(t, 200, ctx.Response.StatusCode())
|
||
|
||
// 输出包含 Lua 输出
|
||
body := string(ctx.Response.Body())
|
||
assert.Contains(t, body, "before exit")
|
||
}
|