bug: cannot set apisix.extra_lua_path in tests via yaml_config or extra_yaml_config
- Dominant language
- Lua
- Stars
- 17.1k
- Forks
- 2.9k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 63
Description
### Current Behavior
#### The Issue
When creating a test file for a custom plugin, it's currently not possible to set a custom path for plugins, via `--- yaml_config` or `--- extra_yaml_config`.
#### The Cause
The issue is caused by the snippet below:
https://github.com/apache/apisix/blob/77dacda31277a31d6014b4970e36bae2a5c30907/t/APISIX.pm#L272-L275
This is different from the following, where we put the content of field `apisix.extra_lua_path` config at the beginning of `lua_package_path`:
https://github.com/apache/apisix/blob/77dacda31277a31d6014b4970e36bae2a5c30907/apisix/cli/ngx_tpl.lua#L270-L276
### Expected Behavior
I'd like to be able to set a custom path for APISIX plugins, as we have for APISIX runtime via `apisix.extra_lua_path`. Example:
```yaml
apisix:
extra_lua_path: "/usr/local/apisix/apisix/plugins/custom/?.lua"
```
With this configuration, we can place custom plugins in `/usr/local/apisix/apisix/plugins/custom/apisix/plugins/` and APISIX will load them.
### Error Logs
_No response_
### Steps to Reproduce
#### Minimal Reproducible Example
File `${apisix_home}/apisix/custom/apisix/plugins/myplugin.lua` (simple custom plugin):
```lua
local plugin_name = "myplugin"
local core = require("apisix.core")
local schema = {
type = "object",
properties = {
message = {
type = "string",
default = "Hello World!\n",
}
}
}
local _M = {
version = 0.1,
priority = 0,
name = plugin_name,
schema = schema,
}
function _M.check_schema(conf, _)
return core.schema.check(schema, conf)
end
function _M.access(conf, _)
return 200, conf.message
end
return _M
```
Test file `t/custom/plugin/extra_path.t`:
```perl
use t::APISIX 'no_plan';
repeat_each(1);
no_root_location();
run_tests;
__DATA__
=== TEST 1: Check apisix.extra_lua_path
Verify that the extra Lua path is included in lua_package_path
--- extra_yaml_config
apisix:
extra_lua_path: "/usr/local/apisix/apisix/plugins/custom/?.lua"
--- config
location /t {
content_by_lua_block {
ngx.say("Content of lua_package_path: ", package.path)
}
}
--- request
GET /t
--- response_body_like
.+/usr/local/apisix/apisix/plugins/custom/.+
=== TEST 2: Try loading the custom plugin "myplugin"
Verify that the custom plugin can be loaded.
--- extra_lua_path: /usr/local/apisix/apisix/custom/?.lua
--- extra_yaml_config
plugins:
- myplugin
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.myplugin")
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
```
If we run the test we obtain the following:
```bash
t/custom/plugin/extra_path.t .. 1/?
# Failed test 't/custom/plugin/extra_path.t TEST 1: Check apisix.extra_lua_path - response_body_like - response is expected (Content of lua_package_path: /usr/local/apisix/?.lua;/usr/local/apisix/?/init.lua;/usr/local/apisix/deps/share/lua/5.1/?/init.lua;/usr/local/apisix/deps/share/lua/5.1/?.lua;/usr/local/apisix/apisix/?.lua;/usr/local/apisix/t/?.lua;/usr/local/apisix/t/xrpc/?.lua;/usr/local/apisix/t/xrpc/?/init.lua;/usr/local/openresty/site/lualib/?.ljbc;/usr/local/openresty/site/lualib/?/init.ljbc;/usr/local/openresty/lualib/?.ljbc;/usr/local/openresty/lualib/?/init.ljbc;/usr/local/openresty/site/lualib/?.lua;/usr/local/openresty/site/lualib/?/init.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/?/init.lua;./?.lua;/usr/local/openresty/luajit/share/luajit-2.1/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/openresty/luajit/share/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/?/init.lua;)'
# at /usr/local/apisix/../test-nginx/lib/Test/Nginx/Socket.pm line 1731.
# 'Content of lua_package_path: /usr/local/apisix/?.lua;/usr/local/apisix/?/init.lua;/usr/local/apisix/deps/share/lua/5.1/?/init.lua;/usr/local/apisix/deps/share/lua/5.1/?.lua;/usr/local/apisix/apisix/?.lua;/usr/local/apisix/t/?.lua;/usr/local/apisix/t/xrpc/?.lua;/usr/local/apisix/t/xrpc/?/init.lua;/usr/local/openresty/site/lualib/?.ljbc;/usr/local/openresty/site/lualib/?/init.ljbc;/usr/local/openresty/lualib/?.ljbc;/usr/local/openresty/lualib/?/init.ljbc;/usr/local/openresty/site/lualib/?.lua;/usr/local/openresty/site/lualib/?/init.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/?/init.lua;./?.lua;/usr/local/openresty/luajit/share/luajit-2.1/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/openresty/luajit/share/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/?/init.lua;
# '
# doesn't match '(?^s:.+/usr/local/apisix/apisix/plugins/custom/.+
# )'
# Failed test 't/custom/plugin/extra_path.t TEST 2: Try loading the custom plugin "myplugin" - response_body - response is expected (repeated req 0, req 0)'
# at /usr/local/apisix/../test-nginx/lib/Test/Nginx/Socket.pm line 1685.
# got: ''
# expected: 'done
# '
# Failed test 't/custom/plugin/extra_path.t TEST 2: Try loading the custom plugin "myplugin" - pattern "[error]" should not match any line in error.log but matches line "2025/06/30 08:57:23 [error] 638#638: *2 [lua] plugin.lua:144: load_plugin(): failed to load plugin [myplugin] err: module 'apisix.plugins.myplugin' not found:" (req 0)
# no field package.preload['apisix.plugins.myplugin']
# no file '/usr/local/apisix/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/apisix/plugins/myplugin/init.lua'
# no file '/usr/local/apisix/deps/share/lua/5.1/apisix/plugins/myplugin/init.lua'
# no file '/usr/local/apisix/deps/share/lua/5.1/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/apisix/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/t/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/t/xrpc/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/t/xrpc/apisix/plugins/myplugin/init.lua'
# '
# at /usr/local/apisix/../test-nginx/lib/Test/Nginx/Socket.pm line 1356.
# Failed test 't/custom/plugin/extra_path.t TEST 2: Try loading the custom plugin "myplugin" - pattern "[error]" should not match any line in error.log but matches line "2025/06/30 08:57:23 [error] 637#637: *1 [lua] plugin.lua:144: load_plugin(): failed to load plugin [myplugin] err: module 'apisix.plugins.myplugin' not found:" (req 0)
# no field package.preload['apisix.plugins.myplugin']
# no file '/usr/local/apisix/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/apisix/plugins/myplugin/init.lua'
# no file '/usr/local/apisix/deps/share/lua/5.1/apisix/plugins/myplugin/init.lua'
# no file '/usr/local/apisix/deps/share/lua/5.1/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/apisix/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/t/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/t/xrpc/apisix/plugins/myplugin.lua'
# no file '/usr/local/apisix/t/xrpc/apisix/plugins/myplugin/init.lua'
# '
# at /usr/local/apisix/../test-nginx/lib/Test/Nginx/Socket.pm line 1356.
t/custom/plugin/extra_path.t .. Failed 4/7 subtests
Test Summary Report
-------------------
t/custom/plugin/extra_path.t (Wstat: 0 Tests: 7 Failed: 4)
Failed tests: 2, 5-7
Parse errors: No plan found in TAP output
Files=1, Tests=7, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.18 cusr 0.07 csys = 0.26 CPU)
Result: FAIL
```
As we can see, both tests fail:
- `lua_package_path` doesn't include `/usr/local/apisix/apisix/plugins/custom/?.lua`
- APISIX cannot load custom plugin `myplugin`: `load_plugin(): failed to load plugin [myplugin]`
### Environment
- APISIX version (run `apisix version`): 3.13.0
Contributor guide
Research direction
Start with the test harness logic in t/APISIX.pm at the linked lines and compare it with apisix/cli/ngx_tpl.lua at the linked lines. Run t/custom/plugin/extra_path.t to reproduce both failures. Done means yaml_config or extra_yaml_config makes the configured path appear in lua_package_path and allows myplugin to load.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- lua, perl
- Domain
- backend, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100