You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2020/01/13 14:22:28 UTC
[incubator-apisix] branch master updated: feature: implemented new
`fault-injection` plugin. (#1042)
This is an automated email from the ASF dual-hosted git repository.
membphis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 9758a0e feature: implemented new `fault-injection` plugin. (#1042)
9758a0e is described below
commit 9758a0e3344c2242d8fc55e2621383ab707b55f9
Author: agile6v <ag...@agile6v.com>
AuthorDate: Mon Jan 13 22:22:21 2020 +0800
feature: implemented new `fault-injection` plugin. (#1042)
---
conf/config.yaml | 1 +
lua/apisix/plugins/fault-injection.lua | 74 +++++
t/admin/plugins.t | 2 +-
t/debug/debug-mode.t | 1 +
t/plugin/fault-injection.t | 526 +++++++++++++++++++++++++++++++++
5 files changed, 603 insertions(+), 1 deletion(-)
diff --git a/conf/config.yaml b/conf/config.yaml
index 844070e..495c709 100644
--- a/conf/config.yaml
+++ b/conf/config.yaml
@@ -93,6 +93,7 @@ plugins: # plugin list
- proxy-rewrite
- redirect
- response-rewrite
+ - fault-injection
stream_plugins:
- mqtt-proxy
diff --git a/lua/apisix/plugins/fault-injection.lua b/lua/apisix/plugins/fault-injection.lua
new file mode 100644
index 0000000..583ca0f
--- /dev/null
+++ b/lua/apisix/plugins/fault-injection.lua
@@ -0,0 +1,74 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core = require("apisix.core")
+local sleep = ngx.sleep
+
+local plugin_name = "fault-injection"
+
+local schema = {
+ type = "object",
+ properties = {
+ abort = {
+ type = "object",
+ properties = {
+ http_status = {type = "integer", minimum = 200},
+ body = {type = "string", minLength = 0},
+ },
+ required = {"http_status"}
+ },
+ delay = {
+ type = "object",
+ properties = {
+ duration = {type = "number", minimum = 0},
+ },
+ required = {"duration"}
+ }
+ },
+ minProperties = 1,
+}
+
+local _M = {
+ version = 0.1,
+ priority = 11000,
+ name = plugin_name,
+ schema = schema,
+}
+
+function _M.check_schema(conf)
+ local ok, err = core.schema.check(schema, conf)
+ if not ok then
+ return false, err
+ end
+
+ return true
+end
+
+
+function _M.rewrite(conf, ctx)
+ core.log.info("plugin rewrite phase, conf: ", core.json.delay_encode(conf))
+
+ if conf.delay and conf.delay.duration ~= nil then
+ sleep(conf.delay.duration)
+ end
+
+ if conf.abort and conf.abort.http_status ~= nil then
+ core.response.exit(conf.abort.http_status, conf.abort.body)
+ end
+end
+
+
+return _M
diff --git a/t/admin/plugins.t b/t/admin/plugins.t
index eae4a6d..e9fe92a 100644
--- a/t/admin/plugins.t
+++ b/t/admin/plugins.t
@@ -30,6 +30,6 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
-qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite"\]/
+qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection"\]/
--- no_error_log
[error]
diff --git a/t/debug/debug-mode.t b/t/debug/debug-mode.t
index 3e18a0f..bc2dd4d 100644
--- a/t/debug/debug-mode.t
+++ b/t/debug/debug-mode.t
@@ -55,6 +55,7 @@ done
--- grep_error_log eval
qr/loaded plugin and sort by priority: [-\d]+ name: [\w-]+/
--- grep_error_log_out
+loaded plugin and sort by priority: 11000 name: fault-injection
loaded plugin and sort by priority: 10000 name: serverless-pre-function
loaded plugin and sort by priority: 3000 name: ip-restriction
loaded plugin and sort by priority: 2599 name: openid-connect
diff --git a/t/plugin/fault-injection.t b/t/plugin/fault-injection.t
new file mode 100644
index 0000000..14e3770
--- /dev/null
+++ b/t/plugin/fault-injection.t
@@ -0,0 +1,526 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+BEGIN {
+ if ($ENV{TEST_NGINX_CHECK_LEAK}) {
+ $SkipReason = "unavailable for the hup tests";
+
+ } else {
+ $ENV{TEST_NGINX_USE_HUP} = 1;
+ undef $ENV{TEST_NGINX_USE_STAP};
+ }
+}
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_shuffle();
+no_root_location();
+log_level('info');
+run_tests;
+
+__DATA__
+
+=== TEST 1: set route(invalid http_status in the abort property)
+--- 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": 100,
+ "body": "Fault Injection!"
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body eval
+qr/validation failed/
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: set route(without http_status in the abort property)
+--- 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": {
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body eval
+qr/validation failed/
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: set route(without abort & delay properties)
+--- 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": {
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body eval
+qr/expect object to have at least 1 properties/
+--- no_error_log
+[error]
+
+
+
+=== TEST 4: set route(without duration in the delay property)
+--- 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": {
+ "delay": {
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body eval
+qr/validation failed/
+--- no_error_log
+[error]
+
+
+
+=== TEST 5: set route(invalid duration with string in the delay property)
+--- 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": {
+ "delay": {
+ "duration": "test"
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "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: 400
+--- response_body eval
+qr/wrong type: expected number, got string/
+--- no_error_log
+[error]
+
+
+
+=== TEST 6: set route(invalid duration with duoble dot in the delay property)
+--- 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": {
+ "delay": {
+ "duration": 0.1.1
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body eval
+qr/invalid request body/
+--- error_log eval
+qr/invalid request body/
+
+
+
+=== TEST 7: set route(invalid duration with whitespace in the delay property)
+--- 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": {
+ "delay": {
+ "duration": 0. 1
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "uri": "/hello"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body eval
+qr/invalid request body/
+--- error_log eval
+qr/invalid request body/
+
+
+
+=== TEST 8: set route(delay 1 seconds)
+--- 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": {
+ "delay": {
+ "duration": 1
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "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 9: hit route(delay 1 seconds and return hello world)
+--- request
+GET /hello HTTP/1.1
+--- response_body
+hello world
+--- no_error_log
+[error]
+
+
+
+=== TEST 10: set route(abort with http status 200 and return "Fault Injection!")
+--- 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": 200,
+ "body": "Fault Injection!"
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "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 11: hit route(abort with http code 200 and return "Fault Injection!")
+--- request
+GET /hello HTTP/1.1
+--- error_code: 200
+--- response_body
+Fault Injection!
+--- no_error_log
+[error]
+
+
+
+=== TEST 12: set route(abort with http status 405 and return "Fault Injection!")
+--- 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": 405,
+ "body": "Fault Injection!"
+ }
+ },
+ "proxy-rewrite": {
+ "uri": "/hello"
+ }
+ },
+ "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 13: hit route(abort with http status 405 and return "Fault Injection!")
+--- request
+GET /hello HTTP/1.1
+--- error_code: 405
+--- response_body
+Fault Injection!
+--- no_error_log
+[error]
+
+
+
+=== TEST 14: set route(play with redirect plugin)
+--- 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": 200,
+ "body": "Fault Injection!"
+ }
+ },
+ "redirect": {
+ "uri": "/hello/world",
+ "ret_code": 302
+ }
+ },
+ "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 15: hit route(abort with http status 200 and return "Fault Injection!")
+--- request
+GET /hello HTTP/1.1
+--- error_code: 200
+--- response_body
+Fault Injection!
+--- no_error_log
+[error]
+