Files
sarin/e2e/script_test.go
2026-02-18 00:03:59 +04:00

393 lines
11 KiB
Go

package e2e
import (
"net/http"
"testing"
)
func TestLuaScriptInline(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.headers["X-Lua"] = {"from-lua"} return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Headers["X-Lua"]; !ok || len(v) == 0 || v[0] != "from-lua" {
t.Errorf("expected X-Lua: from-lua, got headers: %v", req.Headers)
}
}
func TestJsScriptInline(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) { req.headers["X-Js"] = ["from-js"]; return req; }`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-js", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Headers["X-Js"]; !ok || len(v) == 0 || v[0] != "from-js" {
t.Errorf("expected X-Js: from-js, got headers: %v", req.Headers)
}
}
func TestLuaScriptFromFile(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
scriptContent := `function transform(req)
req.headers["X-From-File"] = {"yes"}
return req
end`
scriptPath := writeTemp(t, "test.lua", scriptContent)
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", "@"+scriptPath)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Headers["X-From-File"]; !ok || len(v) == 0 || v[0] != "yes" {
t.Errorf("expected X-From-File: yes, got headers: %v", req.Headers)
}
}
func TestJsScriptFromFile(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
scriptContent := `function transform(req) {
req.headers["X-From-File"] = ["yes"];
return req;
}`
scriptPath := writeTemp(t, "test.js", scriptContent)
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-js", "@"+scriptPath)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Headers["X-From-File"]; !ok || len(v) == 0 || v[0] != "yes" {
t.Errorf("expected X-From-File: yes, got headers: %v", req.Headers)
}
}
func TestLuaScriptModifiesMethod(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.method = "PUT" return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if req.Method != http.MethodPut {
t.Errorf("expected method PUT after Lua transform, got %s", req.Method)
}
}
func TestJsScriptModifiesMethod(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) { req.method = "DELETE"; return req; }`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-js", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if req.Method != http.MethodDelete {
t.Errorf("expected method DELETE after JS transform, got %s", req.Method)
}
}
func TestLuaScriptModifiesPath(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.path = "/modified" return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if req.Path != "/modified" {
t.Errorf("expected path /modified, got %s", req.Path)
}
}
func TestLuaScriptModifiesBody(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.body = "lua-body" return req end`
res := run("-U", cs.URL, "-r", "1", "-M", "POST", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if req.Body != "lua-body" {
t.Errorf("expected body 'lua-body', got %q", req.Body)
}
}
func TestJsScriptModifiesBody(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) { req.body = "js-body"; return req; }`
res := run("-U", cs.URL, "-r", "1", "-M", "POST", "-q", "-o", "json",
"-js", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if req.Body != "js-body" {
t.Errorf("expected body 'js-body', got %q", req.Body)
}
}
func TestLuaScriptModifiesParams(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.params["lua_param"] = {"lua_value"} return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Query["lua_param"]; !ok || len(v) == 0 || v[0] != "lua_value" {
t.Errorf("expected lua_param=lua_value, got query: %v", req.Query)
}
}
func TestJsScriptModifiesParams(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) { req.params["js_param"] = ["js_value"]; return req; }`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-js", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Query["js_param"]; !ok || len(v) == 0 || v[0] != "js_value" {
t.Errorf("expected js_param=js_value, got query: %v", req.Query)
}
}
func TestLuaScriptModifiesCookies(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.cookies["lua_cookie"] = {"lua_val"} return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Cookies["lua_cookie"]; !ok || v != "lua_val" {
t.Errorf("expected cookie lua_cookie=lua_val, got cookies: %v", req.Cookies)
}
}
func TestJsScriptModifiesCookies(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) { req.cookies["js_cookie"] = ["js_val"]; return req; }`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-js", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Cookies["js_cookie"]; !ok || v != "js_val" {
t.Errorf("expected cookie js_cookie=js_val, got cookies: %v", req.Cookies)
}
}
func TestScriptChainLuaThenJs(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
luaScript := `function transform(req) req.headers["X-Step"] = {"lua"} return req end`
jsScript := `function transform(req) { req.headers["X-Js-Step"] = ["js"]; return req; }`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", luaScript,
"-js", jsScript)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v, ok := req.Headers["X-Step"]; !ok || len(v) == 0 || v[0] != "lua" {
t.Errorf("expected X-Step: lua from Lua script, got %v", req.Headers["X-Step"])
}
if v, ok := req.Headers["X-Js-Step"]; !ok || len(v) == 0 || v[0] != "js" {
t.Errorf("expected X-Js-Step: js from JS script, got %v", req.Headers["X-Js-Step"])
}
}
func TestMultipleLuaScriptsChained(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
lua1 := `function transform(req) req.headers["X-First"] = {"1"} return req end`
lua2 := `function transform(req) req.headers["X-Second"] = {"2"} return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", lua1,
"-lua", lua2)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v := req.Headers["X-First"]; len(v) == 0 || v[0] != "1" {
t.Errorf("expected X-First: 1, got %v", v)
}
if v := req.Headers["X-Second"]; len(v) == 0 || v[0] != "2" {
t.Errorf("expected X-Second: 2, got %v", v)
}
}
func TestScriptWithEscapedAt(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
// @@ means the first @ is stripped, rest is treated as inline script
script := `@@function transform(req) req.headers["X-At"] = {"escaped"} return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
// The @@ prefix strips one @, leaving "@function transform..." which is valid Lua?
// Actually no — after stripping the first @, it becomes:
// "@function transform(req) ..." which would be interpreted as a file reference.
// Wait — the code says: strings starting with "@@" → content = source[1:] = "@function..."
// Then it's returned as inline content "@function transform..."
// Lua would fail because "@" is not valid Lua syntax.
// So this test just validates that the @@ mechanism doesn't crash.
// It should fail at the validation step since "@function..." is not valid Lua.
assertExitCode(t, res, 1)
}
func TestLuaScriptMultipleHeaderValues(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
script := `function transform(req) req.headers["X-Multi"] = {"val1", "val2"} return req end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
vals, ok := req.Headers["X-Multi"]
if !ok {
t.Fatalf("expected X-Multi header, got headers: %v", req.Headers)
}
if len(vals) != 2 || vals[0] != "val1" || vals[1] != "val2" {
t.Errorf("expected X-Multi: [val1, val2], got %v", vals)
}
}
func TestJsScriptCanReadExistingHeaders(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
// Set a header via CLI, then read it in JS and set a new one based on it
script := `function transform(req) {
var original = req.headers["X-Original"];
if (original && original.length > 0) {
req.headers["X-Copy"] = [original[0]];
}
return req;
}`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-H", "X-Original: hello",
"-js", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v := req.Headers["X-Copy"]; len(v) == 0 || v[0] != "hello" {
t.Errorf("expected X-Copy: hello (copied from X-Original), got %v", v)
}
}
func TestLuaScriptCanReadExistingParams(t *testing.T) {
t.Parallel()
cs := newCaptureServer()
defer cs.Close()
// Set a param via CLI, then read it in Lua
script := `function transform(req)
local original = req.params["key1"]
if original and #original > 0 then
req.params["key1_copy"] = {original[1]}
end
return req
end`
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-P", "key1=val1",
"-lua", script)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v := req.Query["key1_copy"]; len(v) == 0 || v[0] != "val1" {
t.Errorf("expected key1_copy=val1 (copied from key1), got %v", v)
}
}
func TestScriptFromHTTPURL(t *testing.T) {
t.Parallel()
// Serve a Lua script via HTTP
scriptContent := `function transform(req) req.headers["X-Remote"] = {"yes"} return req end`
scriptServer := statusServerWithBody(scriptContent)
defer scriptServer.Close()
cs := newCaptureServer()
defer cs.Close()
res := run("-U", cs.URL, "-r", "1", "-q", "-o", "json",
"-lua", "@"+scriptServer.URL)
assertExitCode(t, res, 0)
req := cs.lastRequest()
if v := req.Headers["X-Remote"]; len(v) == 0 || v[0] != "yes" {
t.Errorf("expected X-Remote: yes from remote script, got %v", req.Headers)
}
}