lolly/internal/lua/api_location_test.go
xfy 7d53cc3dea feat(lua): 改进子请求父请求数据继承
ngx.location.capture 改进:
- 子请求继承父请求的 headers 和 query args
- 支持通过 opts.args 覆盖查询参数
- 通过 LState Context 传递 RequestCtx
- 添加测试验证父请求数据继承

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:24:43 +08:00

149 lines
3.9 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 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]interface{}{
"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.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")
}