Skip to content

Commit b19827e

Browse files
author
inkyu.bae
committed
fix: support extra_lua_path in test framework
Add support for setting custom Lua paths in test files through two complementary methods: 1. Block definitions (preferred): --- extra_lua_path: /custom/path/?.lua --- extra_lua_cpath: /custom/path/?.so 2. YAML configuration parsing: --- extra_yaml_config apisix: extra_lua_path: "/custom/path/?.lua" The implementation prepends custom paths to lua_package_path and lua_package_cpath, aligning test behavior with APISIX runtime where extra_lua_path allows loading custom plugins from specified directories. Block definitions take precedence when both methods are used, ensuring explicit test configuration overrides YAML settings. Added comprehensive test suite (t/admin/extra-lua-path.t) covering: - Path addition via block definitions - YAML configuration parsing - Simultaneous lua_path and lua_cpath configuration - Correct path prepending behavior - Precedence rules between methods This enables testing custom plugins in custom directories without modifying core APISIX paths. Fixes #12389
1 parent f995b57 commit b19827e

File tree

3 files changed

+234
-2
lines changed

3 files changed

+234
-2
lines changed

docs/en/latest/internal/testing-framework.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,27 @@ GET /index.html
111111
no valid upstream node
112112
```
113113

114+
## Custom Lua Paths
115+
116+
To test custom plugins in custom directories, you can specify custom Lua paths:
117+
118+
**Using block definitions:**
119+
120+
```
121+
--- extra_lua_path: /custom/path/?.lua
122+
--- extra_lua_cpath: /custom/path/?.so
123+
```
124+
125+
**Using YAML config:**
126+
127+
```
128+
--- extra_yaml_config
129+
apisix:
130+
extra_lua_path: "/custom/path/?.lua"
131+
```
132+
133+
Block definitions take precedence over YAML config when both are provided.
134+
114135
## Preparing the upstream
115136

116137
To test the code, we need to provide a mock upstream.

t/APISIX.pm

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,34 @@ deployment:
271271
_EOC_
272272
}
273273

274+
my $extra_lua_path = "";
275+
my $extra_lua_cpath = "";
276+
277+
# Method 1: Block definition (preferred)
278+
if ($block->extra_lua_path) {
279+
$extra_lua_path = $block->extra_lua_path . ";";
280+
}
281+
if ($block->extra_lua_cpath) {
282+
$extra_lua_cpath = $block->extra_lua_cpath . ";";
283+
}
284+
285+
# Method 2: Extract from extra_yaml_config if block definition not provided
286+
if (!$extra_lua_path && $block->extra_yaml_config) {
287+
my $extra_yaml = $block->extra_yaml_config;
288+
if ($extra_yaml =~ m/^\s*extra_lua_path:\s*["\']?([^"\'\n]+)["\']?/m) {
289+
$extra_lua_path = $1 . ";";
290+
}
291+
}
292+
if (!$extra_lua_cpath && $block->extra_yaml_config) {
293+
my $extra_yaml = $block->extra_yaml_config;
294+
if ($extra_yaml =~ m/^\s*extra_lua_cpath:\s*["\']?([^"\'\n]+)["\']?/m) {
295+
$extra_lua_cpath = $1 . ";";
296+
}
297+
}
298+
274299
my $lua_deps_path = $block->lua_deps_path // <<_EOC_;
275-
lua_package_path "$apisix_home/?.lua;$apisix_home/?/init.lua;$apisix_home/deps/share/lua/5.1/?/init.lua;$apisix_home/deps/share/lua/5.1/?.lua;$apisix_home/apisix/?.lua;$apisix_home/t/?.lua;$apisix_home/t/xrpc/?.lua;$apisix_home/t/xrpc/?/init.lua;;";
276-
lua_package_cpath "$apisix_home/?.so;$apisix_home/deps/lib/lua/5.1/?.so;$apisix_home/deps/lib64/lua/5.1/?.so;;";
300+
lua_package_path "$extra_lua_path$apisix_home/?.lua;$apisix_home/?/init.lua;$apisix_home/deps/share/lua/5.1/?/init.lua;$apisix_home/deps/share/lua/5.1/?.lua;$apisix_home/apisix/?.lua;$apisix_home/t/?.lua;$apisix_home/t/xrpc/?.lua;$apisix_home/t/xrpc/?/init.lua;;";
301+
lua_package_cpath "$extra_lua_cpath$apisix_home/?.so;$apisix_home/deps/lib/lua/5.1/?.so;$apisix_home/deps/lib64/lua/5.1/?.so;;";
277302
_EOC_
278303

279304
my $main_config = $block->main_config // <<_EOC_;

t/admin/extra-lua-path.t

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
use t::APISIX 'no_plan';
2+
3+
repeat_each(1);
4+
no_long_string();
5+
no_root_location();
6+
7+
run_tests;
8+
9+
__DATA__
10+
11+
=== TEST 1: Check extra_lua_path via block definition
12+
Verify that extra_lua_path block definition adds path to lua_package_path
13+
--- extra_lua_path: /test/custom/path/?.lua
14+
--- config
15+
location /t {
16+
content_by_lua_block {
17+
local path = package.path
18+
if string.find(path, "/test/custom/path/?.lua", 1, true) then
19+
ngx.say("FOUND: extra_lua_path is in package.path")
20+
else
21+
ngx.say("NOT FOUND: extra_lua_path is missing")
22+
ngx.say("package.path: ", path)
23+
end
24+
}
25+
}
26+
--- request
27+
GET /t
28+
--- response_body
29+
FOUND: extra_lua_path is in package.path
30+
31+
32+
33+
=== TEST 2: Check extra_lua_cpath via block definition
34+
Verify that extra_lua_cpath block definition adds path to lua_package_cpath
35+
--- extra_lua_cpath: /test/custom/path/?.so
36+
--- config
37+
location /t {
38+
content_by_lua_block {
39+
local cpath = package.cpath
40+
if string.find(cpath, "/test/custom/path/?.so", 1, true) then
41+
ngx.say("FOUND: extra_lua_cpath is in package.cpath")
42+
else
43+
ngx.say("NOT FOUND: extra_lua_cpath is missing")
44+
ngx.say("package.cpath: ", cpath)
45+
end
46+
}
47+
}
48+
--- request
49+
GET /t
50+
--- response_body
51+
FOUND: extra_lua_cpath is in package.cpath
52+
53+
54+
55+
=== TEST 3: Check extra_lua_path from extra_yaml_config
56+
Verify that extra_lua_path is parsed from extra_yaml_config
57+
--- extra_yaml_config
58+
apisix:
59+
extra_lua_path: "/yaml/custom/path/?.lua"
60+
--- config
61+
location /t {
62+
content_by_lua_block {
63+
local path = package.path
64+
if string.find(path, "/yaml/custom/path/?.lua", 1, true) then
65+
ngx.say("FOUND: extra_lua_path from yaml config is in package.path")
66+
else
67+
ngx.say("NOT FOUND: extra_lua_path from yaml config is missing")
68+
ngx.say("package.path: ", path)
69+
end
70+
}
71+
}
72+
--- request
73+
GET /t
74+
--- response_body
75+
FOUND: extra_lua_path from yaml config is in package.path
76+
77+
78+
79+
=== TEST 4: Check extra_lua_cpath from extra_yaml_config
80+
Verify that extra_lua_cpath is parsed from extra_yaml_config
81+
--- extra_yaml_config
82+
apisix:
83+
extra_lua_cpath: "/yaml/custom/path/?.so"
84+
--- config
85+
location /t {
86+
content_by_lua_block {
87+
local cpath = package.cpath
88+
if string.find(cpath, "/yaml/custom/path/?.so", 1, true) then
89+
ngx.say("FOUND: extra_lua_cpath from yaml config is in package.cpath")
90+
else
91+
ngx.say("NOT FOUND: extra_lua_cpath from yaml config is missing")
92+
ngx.say("package.cpath: ", cpath)
93+
end
94+
}
95+
}
96+
--- request
97+
GET /t
98+
--- response_body
99+
FOUND: extra_lua_cpath from yaml config is in package.cpath
100+
101+
102+
103+
=== TEST 5: Check both extra_lua_path and extra_lua_cpath
104+
Verify that both paths can be set simultaneously
105+
--- extra_lua_path: /test/lua/?.lua
106+
--- extra_lua_cpath: /test/so/?.so
107+
--- config
108+
location /t {
109+
content_by_lua_block {
110+
local path = package.path
111+
local cpath = package.cpath
112+
local lua_found = string.find(path, "/test/lua/?.lua", 1, true)
113+
local so_found = string.find(cpath, "/test/so/?.so", 1, true)
114+
115+
if lua_found and so_found then
116+
ngx.say("FOUND: both extra_lua_path and extra_lua_cpath")
117+
else
118+
ngx.say("NOT FOUND")
119+
ngx.say("lua_path found: ", lua_found and "yes" or "no")
120+
ngx.say("so_path found: ", so_found and "yes" or "no")
121+
end
122+
}
123+
}
124+
--- request
125+
GET /t
126+
--- response_body
127+
FOUND: both extra_lua_path and extra_lua_cpath
128+
129+
130+
131+
=== TEST 6: Check path is prepended (comes first)
132+
Verify that extra_lua_path is at the beginning of package.path
133+
--- extra_lua_path: /first/path/?.lua
134+
--- config
135+
location /t {
136+
content_by_lua_block {
137+
local path = package.path
138+
-- Check if custom path appears before apisix_home
139+
local custom_pos = string.find(path, "/first/path/?.lua", 1, true)
140+
local apisix_pos = string.find(path, "/apisix/?.lua", 1, true)
141+
142+
if custom_pos and apisix_pos and custom_pos < apisix_pos then
143+
ngx.say("SUCCESS: extra_lua_path is prepended correctly")
144+
else
145+
ngx.say("FAIL: extra_lua_path is not at the beginning")
146+
ngx.say("custom_pos: ", custom_pos or "nil")
147+
ngx.say("apisix_pos: ", apisix_pos or "nil")
148+
end
149+
}
150+
}
151+
--- request
152+
GET /t
153+
--- response_body
154+
SUCCESS: extra_lua_path is prepended correctly
155+
156+
157+
158+
=== TEST 7: Block definition takes precedence over yaml_config
159+
Verify that block definition is used when both are provided
160+
--- extra_lua_path: /block/path/?.lua
161+
--- extra_yaml_config
162+
apisix:
163+
extra_lua_path: "/yaml/path/?.lua"
164+
--- config
165+
location /t {
166+
content_by_lua_block {
167+
local path = package.path
168+
local block_found = string.find(path, "/block/path/?.lua", 1, true)
169+
local yaml_found = string.find(path, "/yaml/path/?.lua", 1, true)
170+
171+
if block_found and not yaml_found then
172+
ngx.say("SUCCESS: block definition takes precedence")
173+
elseif yaml_found and not block_found then
174+
ngx.say("FAIL: yaml config was used instead of block")
175+
elseif block_found and yaml_found then
176+
ngx.say("UNEXPECTED: both paths found")
177+
else
178+
ngx.say("FAIL: neither path found")
179+
end
180+
}
181+
}
182+
--- request
183+
GET /t
184+
--- response_body
185+
SUCCESS: block definition takes precedence
186+

0 commit comments

Comments
 (0)