368 lines
7.8 KiB
Go
368 lines
7.8 KiB
Go
// Package lua 提供 ngx.ctx API 测试
|
|
package lua
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
// TestNgxCtxAPI 测试 ngx.ctx API 基础功能
|
|
func TestNgxCtxAPI(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试 ngx.ctx 存在且是一个 table
|
|
err = coro.Execute(`
|
|
if type(ngx) ~= "table" then
|
|
error("ngx is not a table")
|
|
end
|
|
if type(ngx.ctx) ~= "table" then
|
|
error("ngx.ctx is not a table")
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxStringValue 测试存储字符串值
|
|
func TestNgxCtxStringValue(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试字符串存储
|
|
err = coro.Execute(`
|
|
ngx.ctx.message = "hello world"
|
|
local msg = ngx.ctx.message
|
|
if msg ~= "hello world" then
|
|
error("string value mismatch: " .. tostring(msg))
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxNumberValue 测试存储数字值
|
|
func TestNgxCtxNumberValue(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试数字存储
|
|
err = coro.Execute(`
|
|
ngx.ctx.count = 42
|
|
ngx.ctx.pi = 3.14159
|
|
|
|
local count = ngx.ctx.count
|
|
local pi = ngx.ctx.pi
|
|
|
|
if count ~= 42 then
|
|
error("count should be 42, got: " .. tostring(count))
|
|
end
|
|
|
|
if math.abs(pi - 3.14159) > 0.00001 then
|
|
error("pi should be 3.14159, got: " .. tostring(pi))
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxTableValue 测试存储 table 值
|
|
func TestNgxCtxTableValue(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试 table 存储
|
|
err = coro.Execute(`
|
|
ngx.ctx.data = {
|
|
name = "test",
|
|
items = {1, 2, 3, 4, 5}
|
|
}
|
|
|
|
local data = ngx.ctx.data
|
|
if type(data) ~= "table" then
|
|
error("data should be a table")
|
|
end
|
|
|
|
if data.name ~= "test" then
|
|
error("data.name should be 'test'")
|
|
end
|
|
|
|
if type(data.items) ~= "table" then
|
|
error("data.items should be a table")
|
|
end
|
|
|
|
if data.items[1] ~= 1 then
|
|
error("data.items[1] should be 1")
|
|
end
|
|
|
|
if data.items[5] ~= 5 then
|
|
error("data.items[5] should be 5")
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxFunctionValue 测试存储函数值
|
|
func TestNgxCtxFunctionValue(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试函数存储
|
|
err = coro.Execute(`
|
|
ngx.ctx.handler = function(x)
|
|
return x * 2
|
|
end
|
|
|
|
local handler = ngx.ctx.handler
|
|
if type(handler) ~= "function" then
|
|
error("handler should be a function")
|
|
end
|
|
|
|
local result = handler(21)
|
|
if result ~= 42 then
|
|
error("handler(21) should return 42, got: " .. tostring(result))
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxBooleanValue 测试存储布尔值
|
|
func TestNgxCtxBooleanValue(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试布尔值存储
|
|
err = coro.Execute(`
|
|
ngx.ctx.enabled = true
|
|
ngx.ctx.disabled = false
|
|
|
|
if ngx.ctx.enabled ~= true then
|
|
error("enabled should be true")
|
|
end
|
|
|
|
if ngx.ctx.disabled ~= false then
|
|
error("disabled should be false")
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxNilValue 测试存储和读取 nil 值
|
|
func TestNgxCtxNilValue(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试 nil 值
|
|
err = coro.Execute(`
|
|
ngx.ctx.nothing = nil
|
|
local val = ngx.ctx.nothing
|
|
if val ~= nil then
|
|
error("nothing should be nil")
|
|
end
|
|
|
|
-- 读取不存在的键
|
|
local missing = ngx.ctx.missing_key
|
|
if missing ~= nil then
|
|
error("missing_key should be nil")
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxMultipleScripts 测试在同一个脚本中读写 ngx.ctx
|
|
// 注意:协程在执行后变成 dead 状态,不能多次执行
|
|
func TestNgxCtxMultipleScripts(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 在同一个脚本中设置和读取值(协程只能执行一次)
|
|
err = coro.Execute(`
|
|
-- 设置值
|
|
ngx.ctx.shared_value = "shared"
|
|
ngx.ctx.counter = 1
|
|
|
|
-- 读取并验证值
|
|
local val = ngx.ctx.shared_value
|
|
if val ~= "shared" then
|
|
error("shared_value should be 'shared'")
|
|
end
|
|
|
|
-- 修改值
|
|
ngx.ctx.counter = ngx.ctx.counter + 1
|
|
if ngx.ctx.counter ~= 2 then
|
|
error("counter should be 2")
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// TestNgxCtxNestedTable 测试嵌套 table
|
|
func TestNgxCtxNestedTable(t *testing.T) {
|
|
var req fasthttp.Request
|
|
req.Header.SetMethod("GET")
|
|
req.Header.SetRequestURI("/test")
|
|
|
|
ctx := &fasthttp.RequestCtx{}
|
|
ctx.Init(&req, nil, nil)
|
|
|
|
engine, err := NewEngine(DefaultConfig())
|
|
require.NoError(t, err)
|
|
defer engine.Close()
|
|
|
|
coro, err := engine.NewCoroutine(ctx)
|
|
require.NoError(t, err)
|
|
defer coro.Close()
|
|
|
|
err = coro.SetupSandbox()
|
|
require.NoError(t, err)
|
|
|
|
// 测试嵌套 table
|
|
err = coro.Execute(`
|
|
ngx.ctx.config = {
|
|
database = {
|
|
host = "localhost",
|
|
port = 5432
|
|
},
|
|
cache = {
|
|
ttl = 3600
|
|
}
|
|
}
|
|
|
|
local host = ngx.ctx.config.database.host
|
|
if host ~= "localhost" then
|
|
error("config.database.host should be 'localhost'")
|
|
end
|
|
|
|
local port = ngx.ctx.config.database.port
|
|
if port ~= 5432 then
|
|
error("config.database.port should be 5432")
|
|
end
|
|
|
|
ngx.ctx.config.database.port = 3306
|
|
if ngx.ctx.config.database.port ~= 3306 then
|
|
error("config.database.port should be updated to 3306")
|
|
end
|
|
`)
|
|
assert.NoError(t, err)
|
|
}
|