lolly/internal/lua/api_location_test.go
xfy 6c7cf73c87 refactor(lua): replace single LState with LState pool architecture
Replace the single LState + coroutine model with an LState pool to
eliminate concurrent map read/write issues in gopher-lua. Each request
now gets a completely independent LState with its own Global table.

Key changes:
- Add LStatePool for managing pooled LState instances
- Remove shared Engine.L and coroutine-based execution
- Simplify coroutine.go: remove yield handling, use direct PCall
- Remove ngxRegisterMu lock (no longer needed with isolated LStates)
- Update config.go: add LStatePoolInitialSize/MaxSize settings
- Update tests to work with the new architecture

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 10:38:10 +08:00

150 lines
4.0 KiB
Go
Raw Permalink 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 lua 提供 Lua 脚本嵌入能力
package lua
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
)
func TestLocationManagerRegister(t *testing.T) {
manager := NewLocationManager()
require.NotNil(t, manager)
// 注册 location
handler := func(ctx *fasthttp.RequestCtx) {
ctx.WriteString("test response")
}
manager.Register("/test", handler)
// 验证注册成功
manager.mu.Lock()
_, ok := manager.handlers["/test"]
manager.mu.Unlock()
assert.True(t, ok)
}
func TestLocationManagerCapture(t *testing.T) {
manager := NewLocationManager()
// 注册 location
handler := func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(200)
ctx.SetBodyString("hello from subrequest")
ctx.Response.Header.Set("X-Custom", "value")
}
manager.Register("/api/sub", handler)
// 创建父请求上下文
parentCtx := &fasthttp.RequestCtx{}
parentCtx.Request.SetRequestURI("/parent")
// 执行子请求
result, err := manager.Capture(parentCtx, "/api/sub", nil)
require.NoError(t, err)
require.NotNil(t, result)
assert.Equal(t, 200, result.Status)
assert.Equal(t, "hello from subrequest", string(result.Body))
assert.Equal(t, "value", result.Headers["X-Custom"])
}
func TestLocationManagerCaptureNotFound(t *testing.T) {
manager := NewLocationManager()
parentCtx := &fasthttp.RequestCtx{}
// 执行不存在的 location
result, err := manager.Capture(parentCtx, "/notexist", nil)
require.NoError(t, err)
require.NotNil(t, result)
assert.Equal(t, 404, result.Status)
}
func TestLocationManagerCaptureWithOptions(t *testing.T) {
manager := NewLocationManager()
// 注册 location
handler := func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(200)
ctx.WriteString("method: " + string(ctx.Method()) + ", body: " + string(ctx.PostBody()))
}
manager.Register("/echo", handler)
parentCtx := &fasthttp.RequestCtx{}
parentCtx.Request.SetRequestURI("/parent")
// 使用自定义选项
opts := map[string]any{
"method": "POST",
"body": "test body",
}
result, err := manager.Capture(parentCtx, "/echo", opts)
require.NoError(t, err)
require.NotNil(t, result)
assert.Equal(t, 200, result.Status)
assert.Contains(t, string(result.Body), "method: POST")
assert.Contains(t, string(result.Body), "body: test body")
}
func TestLocationLuaAPI(t *testing.T) {
engine, err := NewEngine(DefaultConfig())
require.NoError(t, err)
defer engine.Close()
L := engine.GetLStateForTest()
defer engine.PutLStateForTest(L)
// 注册 ngx.location API
ngx := L.NewTable()
L.SetGlobal("ngx", ngx)
RegisterLocationAPI(L, engine.LocationManager(), ngx)
// 测试 ngx.location.capture
err = L.DoString(`
-- 创建模拟的 location 结果
local result = ngx.location.capture("/test")
-- 验证结果结构
assert(result ~= nil)
assert(result.status ~= nil)
assert(result.body ~= nil)
`)
require.NoError(t, err)
}
// TestLocationCaptureWithParentRequest 测试子请求能够访问父请求数据
func TestLocationCaptureWithParentRequest(t *testing.T) {
engine, err := NewEngine(DefaultConfig())
require.NoError(t, err)
defer engine.Close()
// 注册 location handler它会检查父请求的头信息
engine.LocationManager().Register("/api/sub", func(ctx *fasthttp.RequestCtx) {
// 检查是否继承了父请求的头
parentHeader := ctx.Request.Header.Peek("X-Parent-Header")
ctx.SetStatusCode(200)
ctx.SetBodyString("parent_header: " + string(parentHeader))
})
// 创建父请求上下文
parentCtx := &fasthttp.RequestCtx{}
parentCtx.Request.SetRequestURI("/parent")
parentCtx.Request.Header.Set("X-Parent-Header", "header_value")
// 使用 Capture 进行子请求
result, err := engine.LocationManager().Capture(parentCtx, "/api/sub", nil)
require.NoError(t, err)
require.NotNil(t, result)
// 验证子请求能够访问父请求数据Headers 被继承)
assert.Equal(t, 200, result.Status)
assert.Contains(t, string(result.Body), "parent_header: header_value")
}