diff --git a/apisix/plugins/fault-injection.lua b/apisix/plugins/fault-injection.lua index 7a5afb155331..ac2846db7f80 100644 --- a/apisix/plugins/fault-injection.lua +++ b/apisix/plugins/fault-injection.lua @@ -15,9 +15,11 @@ -- limitations under the License. -- local core = require("apisix.core") +local expr = require("resty.expr.v1") local sleep = core.sleep local random = math.random +local ipairs = ipairs local plugin_name = "fault-injection" @@ -30,7 +32,11 @@ local schema = { properties = { http_status = {type = "integer", minimum = 200}, body = {type = "string", minLength = 0}, - percentage = {type = "integer", minimum = 0, maximum = 100} + percentage = {type = "integer", minimum = 0, maximum = 100}, + vars = { + type = "array", + maxItems = 20 + } }, required = {"http_status"}, }, @@ -38,7 +44,11 @@ local schema = { type = "object", properties = { duration = {type = "number", minimum = 0}, - percentage = {type = "integer", minimum = 0, maximum = 100} + percentage = {type = "integer", minimum = 0, maximum = 100}, + vars = { + type = "array", + maxItems = 20 + } }, required = {"duration"}, } @@ -64,12 +74,46 @@ local function sample_hit(percentage) end +local function vars_match(vars, ctx) + local match_result + for _, var in ipairs(vars) do + local expr, _ = expr.new(var) + match_result = expr:eval(ctx.var) + if match_result then + break + end + end + + return match_result +end + + function _M.check_schema(conf) local ok, err = core.schema.check(schema, conf) if not ok then return false, err end + if conf.abort and conf.abort.vars then + for _, var in ipairs(conf.abort.vars) do + local _, err = expr.new(var) + if err then + core.log.error("failed to create vars expression: ", err) + return false, err + end + end + end + + if conf.delay and conf.delay.vars then + for _, var in ipairs(conf.delay.vars) do + local _, err = expr.new(var) + if err then + core.log.error("failed to create vars expression: ", err) + return false, err + end + end + end + return true end @@ -77,11 +121,23 @@ end function _M.rewrite(conf, ctx) core.log.info("plugin rewrite phase, conf: ", core.json.delay_encode(conf)) - if conf.delay and sample_hit(conf.delay.percentage) then + local abort_vars = true + if conf.abort and conf.abort.vars then + abort_vars = vars_match(conf.abort.vars, ctx) + end + core.log.info("abort_vars: ", abort_vars) + + local delay_vars = true + if conf.delay and conf.delay.vars then + delay_vars = vars_match(conf.delay.vars, ctx) + end + core.log.info("delay_vars: ", delay_vars) + + if conf.delay and sample_hit(conf.delay.percentage) and delay_vars then sleep(conf.delay.duration) end - if conf.abort and sample_hit(conf.abort.percentage) then + if conf.abort and sample_hit(conf.abort.percentage) and abort_vars then return conf.abort.http_status, core.utils.resolve_var(conf.abort.body, ctx.var) end end diff --git a/doc/plugins/fault-injection.md b/doc/plugins/fault-injection.md index 3e96c27a738f..c0b255605a26 100644 --- a/doc/plugins/fault-injection.md +++ b/doc/plugins/fault-injection.md @@ -30,11 +30,29 @@ Fault injection plugin, this plugin can be used with other plugins and will be e | abort.http_status | integer | required | | [200, ...] | user-specified http code returned to the client. | | abort.body | string | optional | | | response data returned to the client. Nginx variable can be used inside, like `client addr: $remote_addr\n` | | abort.percentage | integer | optional | | [0, 100] | percentage of requests to be aborted. | +| abort.vars | array[] | optional | | | The rules for executing fault injection will only be executed when the rules are matched. `vars` is a list of expressions, which is from the [lua-resty-expr](https://github.com/api7/lua-resty-expr). | | delay.duration | number | required | | | delay time (can be decimal). | | delay.percentage | integer | optional | | [0, 100] | percentage of requests to be delayed. | +| delay.vars | array[] | optional | | | Execute the request delay rule, and the request will be delayed only after the rule matches. `vars` is a list of expressions, which is from the [lua-resty-expr](https://github.com/api7/lua-resty-expr). | Note: One of `abort` and `delay` must be specified. +The `vars` is a list of expression which is from the `lua-resty-expr`, which can flexibly implement the `and/or` relationship between rules. Example: + +```json +[ + [ + [ "arg_name","==","jack" ], + [ "arg_age","==",18 ] + ], + [ + [ "arg_name2","==","allen" ] + ] +] +``` + +This means that the relationship between the first two expressions is `and`, and the relationship between the first two expressions and the third expression is `or`. + ## How To Enable ### Enable the plugin @@ -119,6 +137,317 @@ user 0m0.007s sys 0m0.010s ``` +Example 3: Enable the `fault-injection` plugin for a specific route and specify the vars rule of the abort parameter. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + [ "arg_name","==","jack" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +Test plugin: + +1. The vars rule fails to match, and the request returns upstream response data: + +```shell +$ curl "http://127.0.0.1:9080/hello?name=allen" -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 07:21:57 GMT +Server: APISIX/2.2 + +hello +``` + +2. The vars rule is successfully matched and fault injection is performed: + +```shell +$ curl "http://127.0.0.1:9080/hello?name=jack" -i +HTTP/1.1 403 Forbidden +Date: Wed, 20 Jan 2021 07:23:37 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! +``` + +Example 4: Enable the `fault-injection` plugin for a specific route and specify the vars rule for the delay parameter. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "delay": { + "duration": 2, + "vars": [ + [ + [ "arg_name","==","jack" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +Test plugin: + +1. The vars rule fails to match and the request is not delayed: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=allen" -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 07:26:17 GMT +Server: APISIX/2.2 + +hello + +real 0m0.007s +user 0m0.003s +sys 0m0.003s +``` + +2. The vars rule is successfully matched, and the request is delayed for two seconds: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=jack" -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 07:57:50 GMT +Server: APISIX/2.2 + +hello + +real 0m2.009s +user 0m0.004s +sys 0m0.004s +``` + +Example 5: Enable the `fault-injection` plugin for a specific route, and specify the vars rules for the abort and delay parameters. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + [ "arg_name","==","jack" ] + ] + ] + }, + "delay": { + "duration": 2, + "vars": [ + [ + [ "http_age","==","18" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +Test plugin: + +1. The vars rules of abort and delay fail to match: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=allen" -H 'age: 20' -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 08:01:43 GMT +Server: APISIX/2.2 + +hello + +real 0m0.007s +user 0m0.003s +sys 0m0.003s +``` + +2. The abort vars rule fails to match, no fault injection is performed, but the request is delayed: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=allen" -H 'age: 18' -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 08:19:03 GMT +Server: APISIX/2.2 + +hello + +real 0m2.009s +user 0m0.001s +sys 0m0.006s +``` + +3. The vars rule of delay fails to match, the request is not delayed, but fault injection is performed: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=jack" -H 'age: 20' -i +HTTP/1.1 403 Forbidden +Date: Wed, 20 Jan 2021 08:20:18 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! + +real 0m0.007s +user 0m0.002s +sys 0m0.004s +``` + +4. The vars rules of abort and delay parameters match successfully, perform fault injection, and delay the request: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=jack" -H 'age: 18' -i +HTTP/1.1 403 Forbidden +Date: Wed, 20 Jan 2021 08:21:17 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! + +real 0m2.006s +user 0m0.001s +sys 0m0.005s +``` + +Example 6: Enable the `fault-injection` plugin for a specific route, and specify the vars rule of the abort parameter (the relationship of `or`). + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + ["arg_name","==","jack"], + ["arg_age","!","<",18] + ], + [ + ["http_apikey","==","apisix-key"] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +Indicates that when the request parameters name and age satisfy both `name == "jack"` and `age >= 18`, fault injection is performed. Or when the request header apikey satisfies `apikey == "apisix-key"`, fault injection is performed. + +Test plugin: + +1. The request parameter name and age match successfully, and the request header `apikey` is missing, and fault injection is performed: + +```shell +$ curl "http://127.0.0.1:9080/hello?name=jack&age=19" -i +HTTP/1.1 403 Forbidden +Date: Fri, 22 Jan 2021 11:05:46 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! +``` + +2. The request header `apikey` is successfully matched, and the request parameters are missing, and fault injection is performed: + +```shell +$ curl http://127.0.0.1:9080/hello -H "apikey: apisix-key" -i +HTTP/1.1 403 Forbidden +Date: Fri, 22 Jan 2021 11:08:34 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! +``` + +3. Both request parameters and request headers fail to match, and fault injection is not performed: + +```shell +$ curl http://127.0.0.1:9080/hello -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Fri, 22 Jan 2021 11:11:17 GMT +Server: APISIX/2.2 + +hello +``` + ## Disable Plugin Remove the corresponding JSON in the plugin configuration to disable the plugin immediately without restarting the service: diff --git a/doc/zh-cn/plugins/fault-injection.md b/doc/zh-cn/plugins/fault-injection.md index 45e5936279d3..2931bbdbb48a 100644 --- a/doc/zh-cn/plugins/fault-injection.md +++ b/doc/zh-cn/plugins/fault-injection.md @@ -30,11 +30,29 @@ | abort.http_status | integer | 必需 | | [200, ...] | 返回给客户端的 http 状态码 | | abort.body | string | 可选 | | | 返回给客户端的响应数据。支持使用 Nginx 变量,如 `client addr: $remote_addr\n`| | abort.percentage | integer | 可选 | | [0, 100] | 将被中断的请求占比 | +| abort.vars | array[] | 可选 | | | 执行故障注入的规则,当规则匹配通过后才会执行故障注。`vars` 是一个表达式的列表,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。 | | delay.duration | number | 必需 | | | 延迟时间,可以指定小数 | | delay.percentage | integer | 可选 | | [0, 100] | 将被延迟的请求占比 | +| delay.vars | array[] | 可选 | | | 执行请求延迟的规则,当规则匹配通过后才会延迟请求。`vars` 是一个表达式列表,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。 | 注:参数 abort 和 delay 至少要存在一个。 +`vars` 是由 `lua-resty-expr` 的表达式组成的列表,它可以灵活的实现规则之间的 `and/or` 关系,示例: + +```json +[ + [ + [ "arg_name","==","jack" ], + [ "arg_age","==",18 ] + ], + [ + [ "arg_name2","==","allen" ] + ] +] +``` + +这表示前两个表达式之间的关系是 `and` ,而前两个和第三个表达式之间的关系是 `or`。 + ## 示例 ### 启用插件 @@ -119,6 +137,317 @@ user 0m0.007s sys 0m0.010s ``` +示例3:为特定路由启用 `fault-injection` 插件,并指定 abort 参数的 vars 规则。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + [ "arg_name","==","jack" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +测试: + +1、vars 规则匹配失败,请求返回上游响应数据: + +```shell +$ curl "http://127.0.0.1:9080/hello?name=allen" -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 07:21:57 GMT +Server: APISIX/2.2 + +hello +``` + +2、vars 规则匹配成功,执行故障注入: + +```shell +$ curl "http://127.0.0.1:9080/hello?name=jack" -i +HTTP/1.1 403 Forbidden +Date: Wed, 20 Jan 2021 07:23:37 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! +``` + +示例4:为特定路由启用 `fault-injection` 插件,并指定 delay 参数的 vars 规则。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "delay": { + "duration": 2, + "vars": [ + [ + [ "arg_name","==","jack" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +测试: + +1、vars 规则匹配失败,不延迟请求: + +```shell +$ time "curl http://127.0.0.1:9080/hello?name=allen" -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 07:26:17 GMT +Server: APISIX/2.2 + +hello + +real 0m0.007s +user 0m0.003s +sys 0m0.003s +``` + +2、vars 规则匹配成功,延迟请求两秒: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=jack" -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 07:57:50 GMT +Server: APISIX/2.2 + +hello + +real 0m2.009s +user 0m0.004s +sys 0m0.004s +``` + +示例5:为特定路由启用 `fault-injection` 插件,并指定 abort 和 delay 参数的 vars 规则。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + [ "arg_name","==","jack" ] + ] + ] + }, + "delay": { + "duration": 2, + "vars": [ + [ + [ "http_age","==","18" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +测试: + +1、abort 和 delay 的 vars 规则匹配失败: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=allen" -H 'age: 20' -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 08:01:43 GMT +Server: APISIX/2.2 + +hello + +real 0m0.007s +user 0m0.003s +sys 0m0.003s +``` + +2、abort 的 vars 规则匹配失败,不执行故障注入,但延迟请求: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=allen" -H 'age: 18' -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Wed, 20 Jan 2021 08:19:03 GMT +Server: APISIX/2.2 + +hello + +real 0m2.009s +user 0m0.001s +sys 0m0.006s +``` + +3、delay 的 vars 规则匹配失败,不延迟请求,但执行故障注入: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=jack" -H 'age: 20' -i +HTTP/1.1 403 Forbidden +Date: Wed, 20 Jan 2021 08:20:18 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! + +real 0m0.007s +user 0m0.002s +sys 0m0.004s +``` + +4、abort 和 delay 参数的 vars 规则匹配成功,执行故障注入,并延迟请求: + +```shell +$ time curl "http://127.0.0.1:9080/hello?name=jack" -H 'age: 18' -i +HTTP/1.1 403 Forbidden +Date: Wed, 20 Jan 2021 08:21:17 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! + +real 0m2.006s +user 0m0.001s +sys 0m0.005s +``` + +示例6:为特定路由启用 `fault-injection` 插件,并指定 abort 参数的 vars 规则(`or` 的关系)。 + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + ["arg_name","==","jack"], + ["arg_age","!","<",18] + ], + [ + ["http_apikey","==","apisix-key"] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" +}' +``` + +表示当请求参数 name 和 age 同时满足 `name == "jack"`、`age >= 18` 时,执行故障注入。或请求头 apikey 满足 `apikey == "apisix-key"` 时,执行故障注入。 + +测试: + +1、请求参数 name 和 age 匹配成功,缺少请求头 `apikey`, 执行故障注入: + +```shell +$ curl "http://127.0.0.1:9080/hello?name=jack&age=19" -i +HTTP/1.1 403 Forbidden +Date: Fri, 22 Jan 2021 11:05:46 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! +``` + +2、请求头 `apikey` 匹配成功,缺少请求参数,执行故障注入: + +```shell +$ curl http://127.0.0.1:9080/hello -H "apikey: apisix-key" -i +HTTP/1.1 403 Forbidden +Date: Fri, 22 Jan 2021 11:08:34 GMT +Content-Type: text/plain; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Server: APISIX/2.2 + +Fault Injection! +``` + +3、请求参数与请求头都匹配失败,不执行故障注入: + +```shell +$ curl http://127.0.0.1:9080/hello -i +HTTP/1.1 200 OK +Content-Type: application/octet-stream +Transfer-Encoding: chunked +Connection: keep-alive +Date: Fri, 22 Jan 2021 11:11:17 GMT +Server: APISIX/2.2 + +hello +``` + ### 禁用插件 移除插件配置中相应的 JSON 配置可立即禁用该插件,无需重启服务: diff --git a/t/plugin/fault-injection.t b/t/plugin/fault-injection.t index 439381140b20..d0469f51ee37 100644 --- a/t/plugin/fault-injection.t +++ b/t/plugin/fault-injection.t @@ -741,3 +741,348 @@ GET /hello --- response_body --- no_error_log [error] + + + +=== TEST 24: vars schema validation passed +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.fault-injection") + local ok, err = plugin.check_schema({ + abort = { + http_status = 403, + body = "Fault Injection!\n", + vars = { + { + {"arg_name","==","jack"}, + {"arg_age","!","<",18} + }, + { + {"http_apikey","==","api-key"} + } + } + }, + delay = { + duration = 2, + vars = { + { + {"arg_name","==","jack"}, + {"arg_age","!","<",18} + }, + { + {"http_apikey","==","api-key"} + } + } + } + }) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- request +GET /t +--- response_body +done +--- no_error_log +[error] + + + +=== TEST 25: vars schema validation failed(abort failed) +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.fault-injection") + local ok, err = plugin.check_schema({ + abort = { + http_status = 403, + body = "Fault Injection!\n", + vars = { + {"arg_name","==","jack"} + } + }, + delay = { + duration = 2, + vars = { + { + {"arg_name","==","jack"}, + {"arg_age","!","<",18} + }, + { + {"http_apikey","==","api-key"} + } + } + } + }) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- request +GET /t +--- response_body +invalid expression +done +--- error_log eval +qr/failed to create vars expression:.*/ + + + +=== TEST 26: set route and configure the vars rule in abort +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [=[{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + ["arg_name","==","jack"], + [ "arg_age","!","<",18 ] + ], + [ + [ "http_apikey","==","api-key" ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]=] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- error_code: 200 +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 27: hit the route (all vars rules pass), execute abort +--- request +GET /hello?name=jack&age=18 +--- more_headers +apikey: api-key +--- error_code: 403 +--- response_body +Fault Injection! +--- no_error_log +[error] + + + +=== TEST 28: hit the route (missing apikey), execute abort +--- request +GET /hello?name=jack&age=20 +--- error_code: 403 +--- response_body +Fault Injection! +--- no_error_log +[error] + + + +=== TEST 29: hit the route (missing request parameters), execute abort +--- request +GET /hello +--- more_headers +apikey:api-key +--- error_code: 403 +--- response_body +Fault Injection! +--- no_error_log +[error] + + + +=== TEST 30: hit route(`vars` do not match, `age` is missing) +--- request +GET /hello?name=allen +--- response_body +hello world +--- no_error_log +[error] + + + +=== TEST 31: hit route(all `vars` do not match) +--- request +GET /hello +--- response_body +hello world +--- no_error_log +[error] + + + +=== TEST 32: set route and configure the vars rule in delay +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [=[{ + "uri": "/hello", + "plugins": { + "fault-injection": { + "delay": { + "duration": 2, + "vars": [ + [ + ["arg_name","==","jack"], + [ "arg_age","!","<",18 ] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + } + }]=] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- error_code: 200 +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 33: hit route(delay 2 seconds and return hello world) +--- request +GET /hello?name=jack&age=22 +--- response_body +hello world +--- no_error_log +[error] + + + +=== TEST 34: hit route (no wait and return hello1 world) +--- request +GET /hello HTTP/1.1 +--- error_code: 200 +--- response_body +hello world +--- no_error_log +[error] + + + +=== TEST 35: set route and configure the vars rule in abort and delay +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [=[{ + "plugins": { + "fault-injection": { + "abort": { + "http_status": 403, + "body": "Fault Injection!\n", + "vars": [ + [ + ["arg_name","==","jack"], + ["arg_age","!","<",18] + ] + ] + }, + "delay": { + "duration": 2, + "vars": [ + [ + ["http_apikey","==","api-key"] + ] + ] + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]=] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- error_code: 200 +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 36: hit the route (all vars rules are passed), execute abort and delay +--- request +GET /hello?name=jack&age=18 +--- more_headers +apikey: api-key +--- error_code: 403 +--- response_body +Fault Injection! +--- no_error_log +[error] + + + +=== TEST 37: hit the route (abort rule does not match), only execute delay +--- request +GET /hello?name=jack&age=16 +--- more_headers +apikey: api-key +--- response_body +hello world +--- no_error_log +[error]