You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by we...@apache.org on 2020/11/30 02:32:43 UTC

[apisix] branch master updated: ci: make it work under OpenResty 1.19 (#2768)

This is an automated email from the ASF dual-hosted git repository.

wenming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 44855ec  ci: make it work under OpenResty 1.19 (#2768)
44855ec is described below

commit 44855ec1a79efae931151a2f578531cb3f123133
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Mon Nov 30 10:32:35 2020 +0800

    ci: make it work under OpenResty 1.19 (#2768)
---
 .github/workflows/build.yml                        |  14 +-
 .gitignore                                         |   2 +
 .gitmodules                                        |   3 +
 .travis/ASF-Release.cfg                            |   3 +
 .../linux_openresty_1_17_runner.sh                 |   8 +-
 t/admin/health-check.t                             |   2 +-
 t/admin/plugins-reload.t                           |   2 +-
 t/admin/plugins.t                                  |  95 +++++-
 t/admin/schema.t                                   |   4 +-
 t/admin/services.t                                 |   2 +-
 t/config-center-yaml/plugin.t                      |  12 +-
 t/core/config-default.t                            |   6 +-
 t/core/config.t                                    |   4 +-
 t/core/json.t                                      |   2 +-
 t/core/lrucache.t                                  |  36 +--
 t/core/string.t                                    |   6 +-
 t/core/table.t                                     |   4 +-
 t/core/utils.t                                     |   6 +-
 t/lib/json_sort.lua                                | 104 -------
 t/lib/server.lua                                   |   4 +-
 t/lib/test_admin.lua                               |   2 +-
 t/node/chash-balance.t                             |  10 +-
 t/node/chash-hashon.t                              |  14 +-
 t/node/consumer-plugin.t                           |   2 +-
 t/node/ewma.t                                      |   4 +-
 t/node/healthcheck-ipv6.t                          |   9 +-
 t/node/healthcheck-multiple-worker.t               |   2 +-
 t/node/healthcheck-passive.t                       |   2 +-
 t/node/healthcheck.t                               |  15 +-
 t/node/invalid-route.t                             |   2 +-
 t/node/invalid-service.t                           |   4 +-
 t/node/invalid-upstream.t                          |   4 +-
 t/node/rr-balance.t                                |   8 +-
 t/node/upstream-node-dns.t                         | 104 ++++---
 t/plugin/api-breaker.t                             |  10 +-
 t/plugin/authz-keycloak.t                          |   4 +-
 t/plugin/basic-auth.t                              |   9 +-
 t/plugin/consumer-restriction.t                    |   4 +-
 t/plugin/echo.t                                    |   2 +-
 t/plugin/example.t                                 |   4 +-
 t/plugin/grpc-transcode.t                          |  24 +-
 t/plugin/hmac-auth.t                               |  20 +-
 t/plugin/http-logger-log-format.t                  |  12 +-
 t/plugin/http-logger-new-line.t                    |   4 +-
 t/plugin/ip-restriction.t                          |   8 +-
 t/plugin/jwt-auth.t                                | 321 ++++++++++++++-------
 t/plugin/limit-req.t                               |   5 +-
 t/plugin/openid-connect.t                          |   2 +-
 t/plugin/plugin.t                                  |  30 +-
 t/plugin/proxy-rewrite.t                           |  16 +-
 t/plugin/response-rewrite.t                        |   2 +-
 t/plugin/wolf-rbac.t                               |  53 +++-
 t/toolkit                                          |   1 +
 t/utils/batch-processor.t                          |   4 +-
 utils/linux-install-openresty.sh                   |   9 +-
 55 files changed, 624 insertions(+), 421 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8fa8ddb..e0cf416 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,6 +15,7 @@ jobs:
           - ubuntu-18.04
         os_name:
           - linux_openresty
+          - linux_openresty_1_17
           - linux_tengine
           - linux_apisix_master_luarocks
           - linux_apisix_current_luarocks
@@ -23,6 +24,7 @@ jobs:
     runs-on: ${{ matrix.platform }}
     env:
       SERVER_NAME: ${{ matrix.os_name }}
+      OPENRESTY_VERSION: default
 
 
     services:
@@ -47,6 +49,8 @@ jobs:
     steps:
       - name: Check out code
         uses: actions/checkout@v2
+        with:
+          submodules: recursive
 
       - name: Linux Get dependencies
         run: sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl
@@ -55,7 +59,7 @@ jobs:
         run: sudo ./.travis/${{ matrix.os_name }}_runner.sh before_install
 
       - name: Install Redis Cluster
-        if: matrix.os_name == 'linux_openresty'
+        if: matrix.os_name == 'linux_openresty' || matrix.os_name == 'linux_openresty_1_17'
         uses: vishnudxb/redis-cluster@1.0.5
         with:
           master1-port: 5000
@@ -66,7 +70,7 @@ jobs:
           slave3-port: 5005
 
       - name: Running Redis Cluster Test
-        if: matrix.os_name == 'linux_openresty'
+        if: matrix.os_name == 'linux_openresty' || matrix.os_name == 'linux_openresty_1_17'
         run: |
           sudo apt-get install -y redis-tools
           docker ps -a
@@ -74,7 +78,7 @@ jobs:
           redis-cli -h 127.0.0.1 -p 5000 cluster nodes
 
       - name: Running etcd server with TLS
-        if: matrix.os_name == 'linux_openresty'
+        if: matrix.os_name == 'linux_openresty' || matrix.os_name == 'linux_openresty_1_17'
         run: |
             sudo docker run -d -p 12379:12379 -p 12380:12380 \
             -e ALLOW_NONE_AUTHENTICATION=yes \
@@ -88,7 +92,9 @@ jobs:
             bitnami/etcd:3.4.0
 
       - name: Linux Install
-        run: sudo ./.travis/${{ matrix.os_name }}_runner.sh do_install
+        run: |
+            sudo --preserve-env=OPENRESTY_VERSION \
+            ./.travis/${{ matrix.os_name }}_runner.sh do_install
 
       - name: Linux Script
         run: sudo ./.travis/${{ matrix.os_name }}_runner.sh script
diff --git a/.gitignore b/.gitignore
index 2654e45..6bf3a23 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,7 +57,9 @@ default.etcd/
 .idea/
 *.iml
 \.*
+!.github/
 !.travis/
+!.gitmodules
 /conf/apisix.yaml
 /conf/apisix-*.yaml
 /conf/config-*.yaml
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..beb354b
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "t/toolkit"]
+	path = t/toolkit
+	url = https://github.com/api7/test-toolkit.git
diff --git a/.travis/ASF-Release.cfg b/.travis/ASF-Release.cfg
index 37283b4..b086045 100644
--- a/.travis/ASF-Release.cfg
+++ b/.travis/ASF-Release.cfg
@@ -91,6 +91,9 @@ t/servroot
 conf
 .travis/openwhisk-utilities
 
+# Exclude test toolkit files
+t/toolkit
+
 # Exclude dashboard files
 dashboard
 
diff --git a/utils/linux-install-openresty.sh b/.travis/linux_openresty_1_17_runner.sh
similarity index 70%
copy from utils/linux-install-openresty.sh
copy to .travis/linux_openresty_1_17_runner.sh
index 098a59f..e36dd83 100755
--- a/utils/linux-install-openresty.sh
+++ b/.travis/linux_openresty_1_17_runner.sh
@@ -16,10 +16,6 @@
 # limitations under the License.
 #
 
-wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
-sudo apt-get -y update --fix-missing
-sudo apt-get -y install software-properties-common
-sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
 
-sudo apt-get update
-sudo apt-get install openresty-debug=1.17.8.2\* lua5.1 liblua5.1-0-dev
+export OPENRESTY_VERSION=1.17.8.2
+. ./.travis/linux_openresty_runner.sh
diff --git a/t/admin/health-check.t b/t/admin/health-check.t
index 54905bc..7e8498a 100644
--- a/t/admin/health-check.t
+++ b/t/admin/health-check.t
@@ -30,7 +30,7 @@ add_block_preprocessor(sub {
     apisix = require("apisix")
     apisix.http_init()
 
-    json = require("cjson.safe")
+    json = require("toolkit.json")
     req_data = json.decode([[{
         "methods": ["GET"],
         "upstream": {
diff --git a/t/admin/plugins-reload.t b/t/admin/plugins-reload.t
index 349e9ad..667c9ad 100644
--- a/t/admin/plugins-reload.t
+++ b/t/admin/plugins-reload.t
@@ -84,7 +84,7 @@ location /t {
                 for _, conf_value in config_util.iterate_values(plugins_conf.values) do
                     core.table.insert_tail(plugins, unpack(conf_value.value))
                 end
-                ngx.log(ngx.WARN, core.json.encode(plugins))
+                ngx.log(ngx.WARN, require("toolkit.json").encode(plugins))
             end,
         })
         if not plugins_conf then
diff --git a/t/admin/plugins.t b/t/admin/plugins.t
index 634d9eb..40a46d7 100644
--- a/t/admin/plugins.t
+++ b/t/admin/plugins.t
@@ -22,6 +22,16 @@ no_root_location();
 no_shuffle();
 log_level("info");
 
+add_block_preprocessor(sub {
+    my ($block) = @_;
+
+    if (!defined $block->request) {
+        $block->set_value("request", "GET /t");
+    }
+
+    $block;
+});
+
 run_tests;
 
 __DATA__
@@ -48,49 +58,104 @@ GET /apisix/admin/plugins
 
 
 === TEST 3: get plugin schema
---- request
-GET /apisix/admin/plugins/limit-req
---- response_body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/plugins/limit-req',
+                ngx.HTTP_GET,
+                nil,
+                [[
 {"properties":{"rate":{"minimum":0,"type":"number"},"burst":{"minimum":0,"type":"number"},"key":{"enum":["remote_addr","server_addr","http_x_real_ip","http_x_forwarded_for","consumer_name"],"type":"string"},"rejected_code":{"type":"integer","default":503,"minimum":200}},"required":["rate","burst","key"],"type":"object"}
+                ]]
+                )
+
+            ngx.status = code
+        }
+    }
 --- no_error_log
 [error]
 
 
 
 === TEST 4: get plugin node-status schema
---- request
-GET /apisix/admin/plugins/node-status
---- response_body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/plugins/node-status',
+                ngx.HTTP_GET,
+                nil,
+                [[
 {"properties":{"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"}
+                ]]
+                )
+
+            ngx.status = code
+        }
+    }
 --- no_error_log
 [error]
 
 
 
 === TEST 5: get plugin prometheus schema
---- request
-GET /apisix/admin/plugins/prometheus
---- response_body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/plugins/prometheus',
+                ngx.HTTP_GET,
+                nil,
+                [[
 {"properties":{"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"}
+                ]]
+                )
+
+            ngx.status = code
+        }
+    }
 --- no_error_log
 [error]
 
 
 
 === TEST 6: get plugin basic-auth schema
---- request
-GET /apisix/admin/plugins/basic-auth
---- response_body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/plugins/basic-auth',
+                ngx.HTTP_GET,
+                nil,
+                [[
 {"properties":{"disable":{"type":"boolean"}},"title":"work with route or service object","additionalProperties":false,"type":"object"}
+                ]]
+                )
+
+            ngx.status = code
+        }
+    }
 --- no_error_log
 [error]
 
 
 
 === TEST 7: get plugin basic-auth schema by schema_type
---- request
-GET /apisix/admin/plugins/basic-auth?schema_type=consumer
---- response_body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/plugins/basic-auth?schema_type=consumer',
+                ngx.HTTP_GET,
+                nil,
+                [[
 {"title":"work with consumer object","additionalProperties":false,"required":["username","password"],"properties":{"username":{"type":"string"},"password":{"type":"string"}},"type":"object"}
+                ]]
+                )
+
+            ngx.status = code
+        }
+    }
 --- no_error_log
 [error]
diff --git a/t/admin/schema.t b/t/admin/schema.t
index 5f78635..459f486 100644
--- a/t/admin/schema.t
+++ b/t/admin/schema.t
@@ -245,7 +245,7 @@ passed
 --- request
 GET /apisix/admin/schema/plugins/udp-logger
 --- response_body  eval
-qr/{"properties":/
+qr/"properties":/
 --- no_error_log
 [error]
 
@@ -255,7 +255,7 @@ qr/{"properties":/
 --- request
 GET /apisix/admin/schema/plugins/grpc-transcode
 --- response_body eval
-qr/"proto_id".*additionalProperties/
+qr/("proto_id".*additionalProperties|additionalProperties.*"proto_id")/
 --- no_error_log
 [error]
 
diff --git a/t/admin/services.t b/t/admin/services.t
index f897680..a852541 100644
--- a/t/admin/services.t
+++ b/t/admin/services.t
@@ -1427,7 +1427,7 @@ GET /t
             local t = require("lib.test_admin").test
             local code, body = t('/apisix/admin/services/1',
                  ngx.HTTP_PUT,
-                 require("cjson").encode({name = ("1"):rep(101)})
+                 require("toolkit.json").encode({name = ("1"):rep(101)})
                 )
 
             ngx.status = code
diff --git a/t/config-center-yaml/plugin.t b/t/config-center-yaml/plugin.t
index 165c5a9..bcd4575 100644
--- a/t/config-center-yaml/plugin.t
+++ b/t/config-center-yaml/plugin.t
@@ -29,6 +29,7 @@ apisix:
     node_listen: 1984
     config_center: yaml
     enable_admin: false
+    enable_debug: true
 _EOC_
 
     $block->set_value("yaml_config", $yaml_config);
@@ -68,8 +69,9 @@ GET /hello
 hello world
 --- error_log
 use config_center: yaml
-load(): new plugins: {"ip-restriction":true,"jwt-auth":true}
-load_stream(): new plugins: {"mqtt-proxy":true}
+load(): loaded plugin and sort by priority: 3000 name: ip-restriction
+load(): loaded plugin and sort by priority: 2510 name: jwt-auth
+load_stream(): loaded stream plugin and sort by priority: 1000 name: mqtt-proxy
 --- grep_error_log eval
 qr/load\(\): new plugins/
 --- grep_error_log_out
@@ -84,6 +86,7 @@ apisix:
     node_listen: 1984
     config_center: yaml
     enable_admin: false
+    enable_debug: true
 plugins:
     - ip-restriction
     - jwt-auth
@@ -100,8 +103,9 @@ GET /hello
 --- response_body
 hello world
 --- error_log
-load(): new plugins: {"ip-restriction":true,"jwt-auth":true}
-load_stream(): new plugins: {"mqtt-proxy":true}
+load(): loaded plugin and sort by priority: 3000 name: ip-restriction
+load(): loaded plugin and sort by priority: 2510 name: jwt-auth
+load_stream(): loaded stream plugin and sort by priority: 1000 name: mqtt-proxy
 load(): plugins not changed
 load_stream(): plugins not changed
 
diff --git a/t/core/config-default.t b/t/core/config-default.t
index 60a4859..a03a363 100644
--- a/t/core/config-default.t
+++ b/t/core/config-default.t
@@ -27,7 +27,7 @@ __DATA__
 --- config
     location /t {
         content_by_lua_block {
-            local encode_json = require "lib.json_sort" .encode
+            local encode_json = require("toolkit.json").encode
             local config = require("apisix.core").config.local_conf()
 
             ngx.say("node_listen: ", config.apisix.node_listen)
@@ -61,7 +61,7 @@ apisix:
 --- config
   location /t {
     content_by_lua_block {
-        local encode_json = require "lib.json_sort" .encode
+        local encode_json = require("toolkit.json").encode
         local config = require("apisix.core").config.local_conf()
 
         ngx.say("admin_key: ", encode_json(config.apisix.admin_key))
@@ -81,7 +81,7 @@ apisix:
 --- config
   location /t {
     content_by_lua_block {
-        local encode_json = require "lib.json_sort" .encode
+        local encode_json = require("toolkit.json").encode
         local config = require("apisix.core").config.local_conf()
 
         ngx.say("admin_key: ", encode_json(config.apisix.admin_key))
diff --git a/t/core/config.t b/t/core/config.t
index f86186f..115f4da 100644
--- a/t/core/config.t
+++ b/t/core/config.t
@@ -27,7 +27,7 @@ __DATA__
 --- config
     location /t {
         content_by_lua_block {
-            local encode_json = require "cjson.safe" .encode
+            local encode_json = require("toolkit.json").encode
             local config = require("apisix.core").config.local_conf()
 
             ngx.say("etcd host: ", config.etcd.host)
@@ -46,7 +46,7 @@ first plugin: "api-breaker"
 --- config
     location /t {
         content_by_lua_block {
-            local encode_json = require "lib.json_sort" .encode
+            local encode_json = require("toolkit.json").encode
             local config = require("apisix.core").config.local_conf()
 
             ngx.say("etcd host: ", config.etcd.host)
diff --git a/t/core/json.t b/t/core/json.t
index 34ed0b2..2e23731 100644
--- a/t/core/json.t
+++ b/t/core/json.t
@@ -85,7 +85,7 @@ data2 val: {"test":"test2"}
 --- request
 GET /t
 --- response_body_like eval
-qr/\{"test":"test","fun":"function: 0x[0-9a-f]+"}/
+qr/\{("test":"test","fun":"function: 0x[0-9a-f]+"|"fun":"function: 0x[0-9a-f]+","test":"test")}/
 --- no_error_log
 [error]
 
diff --git a/t/core/lrucache.t b/t/core/lrucache.t
index fbea92a..86511ac 100644
--- a/t/core/lrucache.t
+++ b/t/core/lrucache.t
@@ -38,13 +38,13 @@ __DATA__
             end
 
             local obj = core.lrucache.global("key", nil, create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = core.lrucache.global("key", nil, create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = core.lrucache.global("key", "1", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
         }
     }
 --- request
@@ -73,19 +73,19 @@ obj: {"idx":2}
             local lru_get = core.lrucache.new()
 
             local obj = lru_get("key", nil, create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = lru_get("key", nil, create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = lru_get("key", "1", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = lru_get("key", "1", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = lru_get("key-different", "1", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
         }
     }
 --- request
@@ -114,13 +114,13 @@ obj: {"idx":3}
             end
 
             local obj = core.lrucache.global("key", nil, create_num)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = core.lrucache.global("key", nil, create_num)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             obj = core.lrucache.global("key", "1", create_num)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
         }
     }
 --- request
@@ -141,7 +141,7 @@ obj: 2
             local core = require("apisix.core")
 
             local function server_release(self)
-                ngx.say("release: ", core.json.encode(self))
+                ngx.say("release: ", require("toolkit.json").encode(self))
             end
 
             local lrucache_server_picker = core.lrucache.new({
@@ -151,12 +151,12 @@ obj: 2
             local t1 = lrucache_server_picker("nnn", "t1",
                 function () return {name = "aaa"} end)
 
-            ngx.say("obj: ", core.json.encode(t1))
+            ngx.say("obj: ", require("toolkit.json").encode(t1))
 
             local t2 = lrucache_server_picker("nnn", "t2",
                 function () return {name = "bbb"} end)
 
-            ngx.say("obj: ", core.json.encode(t2))
+            ngx.say("obj: ", require("toolkit.json").encode(t2))
         }
     }
 --- request
@@ -187,13 +187,13 @@ obj: {"name":"bbb"}
             })
 
             local obj = lru_get("key", "ver", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
             local obj = lru_get("key", "ver", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
 
             ngx.sleep(0.15)
             local obj = lru_get("key", "ver", create_obj)
-            ngx.say("obj: ", core.json.encode(obj))
+            ngx.say("obj: ", require("toolkit.json").encode(obj))
         }
     }
 --- request
@@ -226,7 +226,7 @@ obj: {"idx":2}
 
             local function f()
                 local obj = lru_get("key", "ver", create_obj)
-                ngx.say("obj: ", core.json.encode(obj))
+                ngx.say("obj: ", require("toolkit.json").encode(obj))
             end
 
             ngx.thread.spawn(f)
diff --git a/t/core/string.t b/t/core/string.t
index 0e196e1..e9f4275 100644
--- a/t/core/string.t
+++ b/t/core/string.t
@@ -28,7 +28,7 @@ __DATA__
 --- config
     location /t {
         content_by_lua_block {
-            local encode = require "cjson".encode 
+            local encode = require "toolkit.json".encode 
             local str = require("apisix.core.string")
             local cases = {
                 {"xx", "", true},
@@ -70,7 +70,7 @@ GET /t
 --- config
     location /t {
         content_by_lua_block {
-            local encode = require "cjson".encode 
+            local encode = require "toolkit.json".encode 
             local str = require("apisix.core.string")
             local cases = {
                 {"xx", "", true},
@@ -110,7 +110,7 @@ GET /t
 --- config
     location /t {
         content_by_lua_block {
-            local encode = require "cjson".encode 
+            local encode = require "toolkit.json".encode 
             local str = require("apisix.core.string")
             local cases = {
                 {"xx", "", true},
diff --git a/t/core/table.t b/t/core/table.t
index fc5ea29..eae9194 100644
--- a/t/core/table.t
+++ b/t/core/table.t
@@ -32,10 +32,10 @@ __DATA__
             local t = {"first"}
             core.table.insert_tail(t, 'a', 1, true)
 
-            ngx.say("encode: ", core.json.encode(t))
+            ngx.say("encode: ", require("toolkit.json").encode(t))
 
             core.table.set(t, 'a', 1, true)
-            ngx.say("encode: ", core.json.encode(t))
+            ngx.say("encode: ", require("toolkit.json").encode(t))
         }
     }
 --- request
diff --git a/t/core/utils.t b/t/core/utils.t
index 402ae4e..f4904da 100644
--- a/t/core/utils.t
+++ b/t/core/utils.t
@@ -82,7 +82,7 @@ GET /t
             if not ip_info then
                 core.log.error("failed to parse domain: ", host, ", error: ",err)
             end
-            ngx.say(core.json.encode(ip_info))
+            ngx.say(require("toolkit.json").encode(ip_info))
         }
     }
 --- request
@@ -103,8 +103,8 @@ qr/"address":.+,"name":"github.com"/
             if not ip_info then
                 core.log.error("failed to parse domain: ", host, ", error: ",err)
             end
-            core.log.info("ip_info: ", core.json.encode(ip_info))
-            ngx.say("resolvers: ", core.json.encode(core.utils.resolvers))
+            core.log.info("ip_info: ", require("toolkit.json").encode(ip_info))
+            ngx.say("resolvers: ", require("toolkit.json").encode(core.utils.resolvers))
         }
     }
 --- request
diff --git a/t/lib/json_sort.lua b/t/lib/json_sort.lua
deleted file mode 100644
index bcda898..0000000
--- a/t/lib/json_sort.lua
+++ /dev/null
@@ -1,104 +0,0 @@
---
--- 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 type = type
-local concat = table.concat
-local tostring = tostring
-local ngx_null = ngx.null
-local gsub = string.gsub
-local sort = table.sort
-local pairs = pairs
-local ipairs = ipairs
-
-
-local _M = {}
-
-
-local meta_chars = {
-    ["\t"] = "\\t",
-    ["\\"] = "\\\\",
-    ['"'] = '\\"',
-    ["\r"] = "\\r",
-    ["\n"] = "\\n",
-}
-
-
-local function encode_str(s)
-    return gsub(s, '["\\\r\n\t]', meta_chars)
-end
-
-
-local function is_arr(t)
-    local exp = 1
-    for k, _ in pairs(t) do
-        if k ~= exp then
-            return nil
-        end
-        exp = exp + 1
-    end
-    return exp - 1
-end
-
-
-local encode
-function encode (v)
-    if v == nil or v == ngx_null then
-        return "null"
-    end
-
-    local typ = type(v)
-    if typ == 'string' then
-        return '"' .. encode_str(v) .. '"'
-    end
-
-    if typ == 'number' or typ == 'boolean' then
-        return tostring(v)
-    end
-
-    if typ == 'table' then
-        local n = is_arr(v)
-        if n then
-            local bits = {}
-            for i, elem in ipairs(v) do
-                bits[i] = encode(elem)
-            end
-            return "[" .. concat(bits, ",") .. "]"
-        end
-
-        local keys = {}
-        local i = 0
-        for key, _ in pairs(v) do
-            i = i + 1
-            keys[i] = key
-        end
-        sort(keys)
-
-        local bits = {}
-        i = 0
-        for _, key in ipairs(keys) do
-            i = i + 1
-            bits[i] = encode(key) .. ":" .. encode(v[key])
-        end
-        return "{" .. concat(bits, ",") .. "}"
-    end
-
-    return '"<' .. typ .. '>"'
-end
-_M.encode = encode
-
-
-return _M
diff --git a/t/lib/server.lua b/t/lib/server.lua
index f3ca00f..6dae39b 100644
--- a/t/lib/server.lua
+++ b/t/lib/server.lua
@@ -14,8 +14,8 @@
 -- See the License for the specific language governing permissions and
 -- limitations under the License.
 --
-local json_decode = require("cjson").decode
-local json_encode = require("cjson").encode
+local json_decode = require("toolkit.json").decode
+local json_encode = require("toolkit.json").encode
 
 local _M = {}
 
diff --git a/t/lib/test_admin.lua b/t/lib/test_admin.lua
index 5663b79..4c1c16f 100644
--- a/t/lib/test_admin.lua
+++ b/t/lib/test_admin.lua
@@ -15,7 +15,7 @@
 -- limitations under the License.
 --
 local http              = require("resty.http")
-local json              = require("cjson.safe")
+local json              = require("toolkit.json")
 local core              = require("apisix.core")
 local aes               = require "resty.aes"
 local ngx_encode_base64 = ngx.encode_base64
diff --git a/t/node/chash-balance.t b/t/node/chash-balance.t
index 52abaa4..8ee2d73 100644
--- a/t/node/chash-balance.t
+++ b/t/node/chash-balance.t
@@ -89,7 +89,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -167,7 +167,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -245,7 +245,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -323,7 +323,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -401,7 +401,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
diff --git a/t/node/chash-hashon.t b/t/node/chash-hashon.t
index 80ac311..e83fe4c 100644
--- a/t/node/chash-hashon.t
+++ b/t/node/chash-hashon.t
@@ -178,7 +178,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -236,7 +236,7 @@ chash_key: "jack"
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -326,7 +326,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -380,7 +380,7 @@ chash_key: "custom-one"
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -466,7 +466,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -520,7 +520,7 @@ chash_key: "cuscookie"
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -608,7 +608,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
diff --git a/t/node/consumer-plugin.t b/t/node/consumer-plugin.t
index 27ced03..2748b01 100644
--- a/t/node/consumer-plugin.t
+++ b/t/node/consumer-plugin.t
@@ -230,7 +230,7 @@ GET /t
     location /t {
         content_by_lua_block {
             local function test()
-                local json_encode = require("lib.json_sort").encode
+                local json_encode = require("toolkit.json").encode
                 local http = require "resty.http"
                 local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
 
diff --git a/t/node/ewma.t b/t/node/ewma.t
index bf1693c..955a6b7 100644
--- a/t/node/ewma.t
+++ b/t/node/ewma.t
@@ -108,7 +108,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -204,7 +204,7 @@ GET /t
                 ngx.say(err)
                 return
             end
-            ngx.say(require("cjson").encode({port = res.body, count = 1}))
+            ngx.say(require("toolkit.json").encode({port = res.body, count = 1}))
             ngx.exit(200)
         }
     }
diff --git a/t/node/healthcheck-ipv6.t b/t/node/healthcheck-ipv6.t
index 13c544e..75542b3 100644
--- a/t/node/healthcheck-ipv6.t
+++ b/t/node/healthcheck-ipv6.t
@@ -139,7 +139,7 @@ qr/^.*?\[error\](?!.*process exiting).*/
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -148,7 +148,8 @@ GET /t
 --- response_body
 [{"count":12,"port":"1980"}]
 --- grep_error_log eval
-qr/\[error\].*/
---- grep_error_log_out eval
-qr/Connection refused\) while connecting to upstream/
+qr/unhealthy .* for '.*'/
+--- grep_error_log_out
+unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
+unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
 --- timeout: 10
diff --git a/t/node/healthcheck-multiple-worker.t b/t/node/healthcheck-multiple-worker.t
index aa656ad..40a09e6 100644
--- a/t/node/healthcheck-multiple-worker.t
+++ b/t/node/healthcheck-multiple-worker.t
@@ -124,7 +124,7 @@ qr/^.*?\[error\](?!.*process exiting).*/
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
diff --git a/t/node/healthcheck-passive.t b/t/node/healthcheck-passive.t
index edc6017..b9299b9 100644
--- a/t/node/healthcheck-passive.t
+++ b/t/node/healthcheck-passive.t
@@ -92,7 +92,7 @@ passed
         content_by_lua_block {
             ngx.sleep(1) -- wait for sync
 
-            local json_sort = require("lib.json_sort")
+            local json_sort = require("toolkit.json")
             local http = require("resty.http")
             local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/server_port"
 
diff --git a/t/node/healthcheck.t b/t/node/healthcheck.t
index b6e754f..30e01ef 100644
--- a/t/node/healthcheck.t
+++ b/t/node/healthcheck.t
@@ -108,7 +108,7 @@ qr/^.*?\[error\](?!.*process exiting).*/
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -209,7 +209,7 @@ qr/^.*?\[error\](?!.*process exiting).*/
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -218,9 +218,10 @@ GET /t
 --- response_body
 [{"count":12,"port":"1980"}]
 --- grep_error_log eval
-qr/\[error\].*/
---- grep_error_log_out eval
-qr/Connection refused\) while connecting to upstream/
+qr/unhealthy .* for '.*'/
+--- grep_error_log_out
+unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
+unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
 --- timeout: 10
 
 
@@ -306,7 +307,7 @@ qr/^.*?\[error\](?!.*process exiting).*/
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -415,7 +416,7 @@ qr/^.*?\[error\](?!.*process exiting).*/
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
diff --git a/t/node/invalid-route.t b/t/node/invalid-route.t
index ca584a5..5788bf9 100644
--- a/t/node/invalid-route.t
+++ b/t/node/invalid-route.t
@@ -37,7 +37,7 @@ __DATA__
                 res.status = code
             end
 
-            ngx.print(core.json.encode(res.body))
+            ngx.print(require("toolkit.json").encode(res.body))
             ngx.sleep(1)
         }
     }
diff --git a/t/node/invalid-service.t b/t/node/invalid-service.t
index 8f4f0f9..883ead1 100644
--- a/t/node/invalid-service.t
+++ b/t/node/invalid-service.t
@@ -38,7 +38,7 @@ __DATA__
                 return ngx.say(res.body)
             end
 
-            ngx.print(core.json.encode(res.body))
+            ngx.print(require("toolkit.json").encode(res.body))
             ngx.sleep(1)
         }
     }
@@ -86,7 +86,7 @@ qr{invalid item data of \[/apisix/services/1\], val: mexxxxxxxxxxxxxxx, it shoud
                 ngx.status = code
             end
 
-            ngx.print(core.json.encode(res.body))
+            ngx.print(require("toolkit.json").encode(res.body))
         }
     }
 --- request
diff --git a/t/node/invalid-upstream.t b/t/node/invalid-upstream.t
index 9856c81..b42b1b1 100644
--- a/t/node/invalid-upstream.t
+++ b/t/node/invalid-upstream.t
@@ -37,7 +37,7 @@ __DATA__
                 res.status = code
             end
 
-            ngx.print(core.json.encode(res.body))
+            ngx.print(require("toolkit.json").encode(res.body))
             ngx.sleep(1)
         }
     }
@@ -132,7 +132,7 @@ GET /t
             if res.status >= 300 then
                 res.status = code
             end
-            ngx.print(core.json.encode(res.body))
+            ngx.print(require("toolkit.json").encode(res.body))
             ngx.sleep(1)
         }
     }
diff --git a/t/node/rr-balance.t b/t/node/rr-balance.t
index 58a8770..5245baa 100644
--- a/t/node/rr-balance.t
+++ b/t/node/rr-balance.t
@@ -89,7 +89,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -166,7 +166,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -243,7 +243,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
@@ -320,7 +320,7 @@ passed
             end
             table.sort(ports_arr, cmd)
 
-            ngx.say(require("cjson").encode(ports_arr))
+            ngx.say(require("toolkit.json").encode(ports_arr))
             ngx.exit(200)
         }
     }
diff --git a/t/node/upstream-node-dns.t b/t/node/upstream-node-dns.t
index b539873..1b6d701 100644
--- a/t/node/upstream-node-dns.t
+++ b/t/node/upstream-node-dns.t
@@ -253,20 +253,27 @@ location /t {
 GET /t
 --- grep_error_log eval
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
---- grep_error_log_out
-call /hello
+--- grep_error_log_out eval
+qr/call \/hello(
+dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test2.com to 127.0.0.2|
 dns resolver domain: test2.com to 127.0.0.1
-dns resolver domain: test.com to 127.0.0.2
-proxy request to 127.0.0.1:1980
-call /hello
+dns resolver domain: test.com to 127.0.0.2)
+proxy request to 127.0.0.[12]:1980
+call \/hello(
+dns resolver domain: test.com to 127.0.0.3
+dns resolver domain: test2.com to 127.0.0.4|
 dns resolver domain: test2.com to 127.0.0.3
-dns resolver domain: test.com to 127.0.0.4
-proxy request to 127.0.0.3:1980
-proxy request to 127.0.0.4:1980
-call /hello
+dns resolver domain: test.com to 127.0.0.4)
+proxy request to 127.0.0.[34]:1980
+proxy request to 127.0.0.[34]:1980
+call \/hello(
+dns resolver domain: test.com to 127.0.0.5
+dns resolver domain: test2.com to 127.0.0.6|
 dns resolver domain: test2.com to 127.0.0.5
-dns resolver domain: test.com to 127.0.0.6
-proxy request to 127.0.0.5:1980
+dns resolver domain: test.com to 127.0.0.6)
+proxy request to 127.0.0.[56]:1980
+/
 
 
 
@@ -459,22 +466,29 @@ location /t {
 GET /t
 --- grep_error_log eval
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
---- grep_error_log_out
-call /hello
+--- grep_error_log_out eval
+qr/call \/hello(
+dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test2.com to 127.0.0.2|
 dns resolver domain: test2.com to 127.0.0.1
-dns resolver domain: test.com to 127.0.0.2
-proxy request to 127.0.0.1:1980
-call /hello
+dns resolver domain: test.com to 127.0.0.2)
+proxy request to 127.0.0.[12]:1980
+call \/hello(
+dns resolver domain: test.com to 127.0.0.3
+dns resolver domain: test2.com to 127.0.0.4|
 dns resolver domain: test2.com to 127.0.0.3
-dns resolver domain: test.com to 127.0.0.4
-proxy request to 127.0.0.3:1980
-proxy request to 127.0.0.4:1980
-proxy request to 127.0.0.3:1980
-proxy request to 127.0.0.4:1980
-call /hello
+dns resolver domain: test.com to 127.0.0.4)
+proxy request to 127.0.0.[34]:1980
+proxy request to 127.0.0.[34]:1980
+proxy request to 127.0.0.[34]:1980
+proxy request to 127.0.0.[34]:1980
+call \/hello(
 dns resolver domain: test2.com to 127.0.0.5
-dns resolver domain: test.com to 127.0.0.6
-proxy request to 127.0.0.5:1980
+dns resolver domain: test.com to 127.0.0.6|
+dns resolver domain: test.com to 127.0.0.5
+dns resolver domain: test2.com to 127.0.0.6)
+proxy request to 127.0.0.[56]:1980
+/
 
 
 
@@ -519,22 +533,29 @@ location /t {
 GET /t
 --- grep_error_log eval
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
---- grep_error_log_out
-call /hello
-dns resolver domain: test2.com to 127.0.0.1
+--- grep_error_log_out eval
+qr/call \/hello(
 dns resolver domain: test.com to 127.0.0.1
-proxy request to 127.0.0.1:1980
-call /hello
+dns resolver domain: test2.com to 127.0.0.1|
 dns resolver domain: test2.com to 127.0.0.1
+dns resolver domain: test.com to 127.0.0.1)
+proxy request to 127.0.0.1:1980
+call \/hello(
 dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test2.com to 127.0.0.1|
+dns resolver domain: test2.com to 127.0.0.1
+dns resolver domain: test.com to 127.0.0.1)
 proxy request to 127.0.0.1:1980
 proxy request to 127.0.0.1:1980
 proxy request to 127.0.0.1:1980
 proxy request to 127.0.0.1:1980
-call /hello
-dns resolver domain: test2.com to 127.0.0.1
+call \/hello(
 dns resolver domain: test.com to 127.0.0.1
+dns resolver domain: test2.com to 127.0.0.1|
+dns resolver domain: test2.com to 127.0.0.1
+dns resolver domain: test.com to 127.0.0.1)
 proxy request to 127.0.0.1:1980
+/
 
 
 
@@ -612,16 +633,17 @@ location /t {
 GET /t
 --- grep_error_log eval
 qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:198\d/
---- grep_error_log_out
-call /hello
+--- grep_error_log_out eval
+qr/call \/hello
 dns resolver domain: test.com to 127.0.0.1
-proxy request to 127.0.0.1:1980
-call /hello
+proxy request to 127.0.0.(1:1980|5:1981)
+call \/hello
 dns resolver domain: test.com to 127.0.0.2
-proxy request to 127.0.0.2:1980
-proxy request to 127.0.0.5:1981
-proxy request to 127.0.0.2:1980
-proxy request to 127.0.0.5:1981
-call /hello
+proxy request to 127.0.0.(2:1980|5:1981)
+proxy request to 127.0.0.(2:1980|5:1981)
+proxy request to 127.0.0.(2:1980|5:1981)
+proxy request to 127.0.0.(2:1980|5:1981)
+call \/hello
 dns resolver domain: test.com to 127.0.0.3
-proxy request to 127.0.0.3:1980
+proxy request to 127.0.0.(3:1980|5:1981)
+/
diff --git a/t/plugin/api-breaker.t b/t/plugin/api-breaker.t
index c9142cf..ea38a84 100644
--- a/t/plugin/api-breaker.t
+++ b/t/plugin/api-breaker.t
@@ -71,7 +71,7 @@ done
                 ngx.say(err)
             end
 
-            ngx.say(require("lib.json_sort").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
@@ -98,7 +98,7 @@ GET /t
                 ngx.say(err)
             end
 
-            ngx.say(require("lib.json_sort").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
@@ -125,7 +125,7 @@ GET /t
                 ngx.say(err)
             end
 
-            ngx.say(require("lib.json_sort").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
@@ -401,7 +401,7 @@ passed
 location /t {
     content_by_lua_block {
         local t = require("lib.test_admin").test
-        local json = require("lib.json_sort")
+        local json = require("toolkit.json")
 
         -- trigger to unhealth
         for i = 1, 4 do
@@ -623,7 +623,7 @@ passed
     location /t {
         content_by_lua_block {
             local t = require("lib.test_admin").test
-            local json = require("lib.json_sort")
+            local json = require("toolkit.json")
 
             local status_count = {}
             for i = 1, 20 do
diff --git a/t/plugin/authz-keycloak.t b/t/plugin/authz-keycloak.t
index 3ac3c4b..309c1a3 100644
--- a/t/plugin/authz-keycloak.t
+++ b/t/plugin/authz-keycloak.t
@@ -169,7 +169,7 @@ passed
 --- config
     location /t {
         content_by_lua_block {
-            local json_decode = require("cjson").decode
+            local json_decode = require("toolkit.json").decode
             local http = require "resty.http"
             local httpc = http.new()
             local uri = "http://127.0.0.1:8090/auth/realms/University/protocol/openid-connect/token"
@@ -310,7 +310,7 @@ passed
 --- config
     location /t {
         content_by_lua_block {
-            local json_decode = require("cjson").decode
+            local json_decode = require("toolkit.json").decode
             local http = require "resty.http"
             local httpc = http.new()
             local uri = "http://127.0.0.1:8090/auth/realms/University/protocol/openid-connect/token"
diff --git a/t/plugin/basic-auth.t b/t/plugin/basic-auth.t
index 50ff775..4f04db6 100644
--- a/t/plugin/basic-auth.t
+++ b/t/plugin/basic-auth.t
@@ -62,9 +62,10 @@ done
     }
 --- request
 GET /t
---- response_body
-additional properties forbidden, found username
+--- response_body_like eval
+qr/additional properties forbidden, found (username|password)
 done
+/
 --- no_error_log
 [error]
 
@@ -254,8 +255,8 @@ GET /t
 --- request
 GET /t
 --- error_code: 400
---- response_body
-{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin basic-auth err: property \"username\" is required"}
+--- response_body_like eval
+qr/\{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin basic-auth err: property \\"(username|password)\\" is required"\}/
 --- no_error_log
 [error]
 
diff --git a/t/plugin/consumer-restriction.t b/t/plugin/consumer-restriction.t
index 4d1e041..45fb1dc 100644
--- a/t/plugin/consumer-restriction.t
+++ b/t/plugin/consumer-restriction.t
@@ -42,13 +42,13 @@ __DATA__
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
 GET /t
 --- response_body
-{"type":"consumer_name","title":"whitelist","rejected_code":403,"whitelist":["jack1","jack2"]}
+{"rejected_code":403,"title":"whitelist","type":"consumer_name","whitelist":["jack1","jack2"]}
 --- no_error_log
 [error]
 
diff --git a/t/plugin/echo.t b/t/plugin/echo.t
index 4e06552..81aa94c 100644
--- a/t/plugin/echo.t
+++ b/t/plugin/echo.t
@@ -477,7 +477,7 @@ Location: https://www.iresty.com
         content_by_lua_block {
             local core = require("apisix.core")
             local t = require("lib.test_admin").test
-            local encode_with_keys_sorted = require("lib.json_sort").encode
+            local encode_with_keys_sorted = require("toolkit.json").encode
 
             local code, _, body = t('/apisix/admin/routes/1',
                 ngx.HTTP_PUT,
diff --git a/t/plugin/example.t b/t/plugin/example.t
index 0fb069b..7149b1d 100644
--- a/t/plugin/example.t
+++ b/t/plugin/example.t
@@ -149,7 +149,7 @@ done
                 ngx.say("failed to load plugins: ", err)
             end
 
-            local encode_json = require "cjson.safe" .encode
+            local encode_json = require("toolkit.json").encode
             for _, plugin in ipairs(plugins) do
                 ngx.say("plugin name: ", plugin.name,
                         " priority: ", plugin.priority)
@@ -200,7 +200,7 @@ qr/module 'apisix.plugins.not-exist-plugin' not found/
                 modifiedIndex = 1,
             })
 
-            local encode_json = require "cjson.safe" .encode
+            local encode_json = require("toolkit.json").encode
             for i = 1, #filter_plugins, 2 do
                 local plugin = filter_plugins[i]
                 local plugin_conf = filter_plugins[i + 1]
diff --git a/t/plugin/grpc-transcode.t b/t/plugin/grpc-transcode.t
index 2b3aa56..6c82305 100644
--- a/t/plugin/grpc-transcode.t
+++ b/t/plugin/grpc-transcode.t
@@ -570,12 +570,24 @@ passed
 
 
 === TEST 20: hit route
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/grpctest',
+                ngx.HTTP_POST,
+                [[
+                {"name":"apisix", "items": ["a","b","c"]}
+                ]],
+                [[
+                {"message":"Hello apisix", "items": ["a","b","c"]}
+                ]],
+                {["Content-Type"] = "application/json"}
+                )
+            ngx.status = code
+        }
+    }
 --- request
-POST /grpctest
-{"name":"apisix", "items": ["a","b","c"]}
---- more_headers
-Content-Type: application/json
---- response_body eval
-qr/\{"items":\["a","b","c"\],"message":"Hello apisix"\}/
+GET /t
 --- no_error_log
 [error]
diff --git a/t/plugin/hmac-auth.t b/t/plugin/hmac-auth.t
index a8c77e3..f5eab11 100644
--- a/t/plugin/hmac-auth.t
+++ b/t/plugin/hmac-auth.t
@@ -870,7 +870,7 @@ passed
 GET /t
 --- error_code: 400
 --- response_body eval
-qr/\{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin hmac-auth err: property \\"secret_key\\" is required"\}/
+qr/\{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin hmac-auth err: property \\"(access|secret)_key\\" is required"\}/
 --- no_error_log
 [error]
 
@@ -1281,10 +1281,22 @@ GET /t
 
 
 === TEST 33: get the schema by schema_type
---- request
-GET /apisix/admin/schema/plugins/hmac-auth?schema_type=consumer
---- response_body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/schema/plugins/hmac-auth?schema_type=consumer',
+                ngx.HTTP_GET,
+                nil,
+                [[
 {"title":"work with consumer object","additionalProperties":false,"required":["access_key","secret_key"],"properties":{"clock_skew":{"default":0,"type":"integer"},"encode_uri_params":{"title":"Whether to escape the uri parameter","default":true,"type":"boolean"},"keep_headers":{"title":"whether to keep the http request header","default":false,"type":"boolean"},"secret_key":{"minLength":1,"maxLength":256,"type":"string"},"algorithm":{"type":"string","default":"hmac-sha256","enum":["hmac-s [...]
+                ]]
+                )
+            ngx.status = code
+        }
+    }
+--- request
+GET /t
 --- no_error_log
 [error]
 
diff --git a/t/plugin/http-logger-log-format.t b/t/plugin/http-logger-log-format.t
index 9526041..703418b 100644
--- a/t/plugin/http-logger-log-format.t
+++ b/t/plugin/http-logger-log-format.t
@@ -119,7 +119,7 @@ hello world
 --- no_error_log
 [error]
 --- error_log eval
-qr/request log: \{"host":"localhost","\@timestamp":.*,"client_ip":"127.0.0.1","route_id":"1"\}/
+qr/request log: \{.*route_id":"1".*\}/
 
 
 
@@ -187,10 +187,10 @@ GET /t
 --- no_error_log
 [error]
 --- grep_error_log eval
-qr/"host":"127.0.0.1","\@timestamp":/
+qr/"\@timestamp":"20/
 --- grep_error_log_out
-"host":"127.0.0.1","@timestamp":
-"host":"127.0.0.1","@timestamp":
+"@timestamp":"20
+"@timestamp":"20
 
 
 
@@ -247,7 +247,7 @@ hello world
 --- no_error_log
 [error]
 --- error_log eval
-qr/request log: \{"host":"localhost","\@timestamp":.*,"client_ip":"127.0.0.1","route_id":"1"\}/
+qr/request log: \{"\@timestamp":.*,"client_ip":"127.0.0.1","host":"localhost","route_id":"1"\}/
 
 
 
@@ -315,7 +315,7 @@ GET /t
 --- no_error_log
 [error]
 --- error_log eval
-qr/request log: \[\{"host":"127.0.0.1","\@timestamp":.*,"client_ip":"127.0.0.1","route_id":"1"\},\{"host":"127.0.0.1","\@timestamp":.*,"client_ip":"127.0.0.1","route_id":"1"\}\]/
+qr/request log: \[\{"\@timestamp":".*","client_ip":"127.0.0.1","host":"127.0.0.1","route_id":"1"\},\{"\@timestamp":".*","client_ip":"127.0.0.1","host":"127.0.0.1","route_id":"1"\}\]/
 
 
 
diff --git a/t/plugin/http-logger-new-line.t b/t/plugin/http-logger-new-line.t
index ce5517d..d82d3ed 100644
--- a/t/plugin/http-logger-new-line.t
+++ b/t/plugin/http-logger-new-line.t
@@ -76,8 +76,8 @@ hello world
 --- wait: 0.5
 --- no_error_log
 [error]
---- error_log
-request log: {"upstream":"127.0.0.1:1982"
+--- error_log eval
+qr/request log: .*"upstream":"127.0.0.1:1982"/
 
 
 
diff --git a/t/plugin/ip-restriction.t b/t/plugin/ip-restriction.t
index 0ed1c2b..5c83c9f 100644
--- a/t/plugin/ip-restriction.t
+++ b/t/plugin/ip-restriction.t
@@ -51,13 +51,13 @@ __DATA__
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
 GET /t
 --- response_body
-{"whitelist":["10.255.254.0\/24","192.168.0.0\/16"]}
+{"whitelist":["10.255.254.0/24","192.168.0.0/16"]}
 --- no_error_log
 [error]
 
@@ -79,7 +79,7 @@ GET /t
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
@@ -107,7 +107,7 @@ qr/invalid ip address: 10.255.256.0\/24/
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
diff --git a/t/plugin/jwt-auth.t b/t/plugin/jwt-auth.t
index be08df8..9440f63 100644
--- a/t/plugin/jwt-auth.t
+++ b/t/plugin/jwt-auth.t
@@ -37,13 +37,13 @@ __DATA__
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
 GET /t
 --- response_body_like eval
-qr/{"algorithm":"HS256","secret":"[a-zA-Z0-9+\\\/]+={0,2}","key":"123","exp":86400}/
+qr/{"algorithm":"HS256","exp":86400,"key":"123","secret":"[a-zA-Z0-9+\\\/]+={0,2}"}/
 --- no_error_log
 [error]
 
@@ -154,11 +154,33 @@ passed
 
 
 
-=== TEST 5: sign
+=== TEST 5: sign / verify in argument
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key',
+                ngx.HTTP_GET
+            )
+
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
+
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
+
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /apisix/plugin/jwt/sign?key=user-key
---- response_body_like eval
-qr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\w+.\w+/
+GET /t
+--- response_body
+hello world
 --- no_error_log
 [error]
 
@@ -204,17 +226,7 @@ GET /hello?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4
 
 
 
-=== TEST 10: verify (in argument)
---- request
-GET /hello?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs
---- response_body
-hello world
---- no_error_log
-[error]
-
-
-
-=== TEST 11: verify (in header)
+=== TEST 10: verify (in header)
 --- request
 GET /hello
 --- more_headers
@@ -226,7 +238,7 @@ hello world
 
 
 
-=== TEST 12: verify (in cookie)
+=== TEST 11: verify (in cookie)
 --- request
 GET /hello
 --- more_headers
@@ -238,7 +250,7 @@ hello world
 
 
 
-=== TEST 13: verify (in header without Bearer)
+=== TEST 12: verify (in header without Bearer)
 --- request
 GET /hello
 --- more_headers
@@ -250,7 +262,7 @@ hello world
 
 
 
-=== TEST 14: verify (header with bearer)
+=== TEST 13: verify (header with bearer)
 --- request
 GET /hello
 --- more_headers
@@ -262,7 +274,7 @@ hello world
 
 
 
-=== TEST 15: verify (invalid bearer token)
+=== TEST 14: verify (invalid bearer token)
 --- request
 GET /hello
 --- more_headers
@@ -275,7 +287,7 @@ Authorization: bearer invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c
 
 
 
-=== TEST 16: delete a exist consumer
+=== TEST 15: delete a exist consumer
 --- config
     location /t {
         content_by_lua_block {
@@ -332,7 +344,7 @@ code: true body: passed
 
 
 
-=== TEST 17: add consumer with username and plugins with base64 secret
+=== TEST 16: add consumer with username and plugins with base64 secret
 --- config
     location /t {
         content_by_lua_block {
@@ -378,7 +390,7 @@ passed
 
 
 
-=== TEST 18: enable jwt auth plugin with base64 secret
+=== TEST 17: enable jwt auth plugin with base64 secret
 --- config
     location /t {
         content_by_lua_block {
@@ -413,17 +425,39 @@ passed
 
 
 
-=== TEST 19: sign
+=== TEST 18: sign / verify
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key',
+                ngx.HTTP_GET
+            )
+
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
+
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
+
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /apisix/plugin/jwt/sign?key=user-key
---- response_body_like eval
-qr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\w+.\w+/
+GET /t
+--- response_body
+hello world
 --- no_error_log
 [error]
 
 
 
-=== TEST 20: verify: invalid JWT token
+=== TEST 19: verify: invalid JWT token
 --- request
 GET /hello?jwt=invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.pPNVvh-TQsdDzorRwa-uuiLYiEBODscp9wv0cwD6c68
 --- error_code: 401
@@ -434,7 +468,7 @@ GET /hello?jwt=invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtl
 
 
 
-=== TEST 21: verify: invalid signature
+=== TEST 20: verify: invalid signature
 --- request
 GET /hello
 --- more_headers
@@ -447,7 +481,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtle
 
 
 
-=== TEST 22: verify: happy path
+=== TEST 21: verify: happy path
 --- request
 GET /hello
 --- more_headers
@@ -459,7 +493,7 @@ hello world
 
 
 
-=== TEST 23: without key
+=== TEST 22: without key
 --- config
     location /t {
         content_by_lua_block {
@@ -483,7 +517,7 @@ property "key" is required
 
 
 
-=== TEST 24: enable jwt auth plugin with extra field
+=== TEST 23: enable jwt auth plugin with extra field
 --- config
     location /t {
         content_by_lua_block {
@@ -522,37 +556,74 @@ GET /t
 
 
 
-=== TEST 25: get the schema by schema_type
+=== TEST 24: get the schema by schema_type
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/schema/plugins/jwt-auth?schema_type=consumer',
+                ngx.HTTP_GET,
+                nil,
+                [[
+                {"required":["key"],"properties":{"exp":{"type":"integer","default":86400,"minimum":1},"private_key":{"type":"string"},"public_key":{"type":"string"},"algorithm":{"type":"string","default":"HS256","enum":["HS256","HS512","RS256"]},"base64_secret":{"default":false,"type":"boolean"},"secret":{"type":"string"},"key":{"type":"string"}},"additionalProperties":false,"type":"object"}
+                ]]
+                )
+
+            ngx.status = code
+        }
+    }
 --- request
-GET /apisix/admin/schema/plugins/jwt-auth?schema_type=consumer
---- response_body
-{"required":["key"],"properties":{"exp":{"type":"integer","default":86400,"minimum":1},"private_key":{"type":"string"},"public_key":{"type":"string"},"algorithm":{"type":"string","default":"HS256","enum":["HS256","HS512","RS256"]},"base64_secret":{"default":false,"type":"boolean"},"secret":{"type":"string"},"key":{"type":"string"}},"additionalProperties":false,"type":"object"}
+GET /t
 --- no_error_log
 [error]
 
 
 
-=== TEST 26: get the schema by error schema_type
+=== TEST 25: get the schema by error schema_type
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/schema/plugins/jwt-auth?schema_type=consumer123123',
+                ngx.HTTP_GET,
+                nil,
+                [[
+                {"properties":{"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"}
+                ]]
+                )
+            ngx.status = code
+        }
+    }
 --- request
-GET /apisix/admin/schema/plugins/jwt-auth?schema_type=consumer123123
---- response_body
-{"properties":{"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"}
+GET /t
 --- no_error_log
 [error]
 
 
 
-=== TEST 27: get the schema by default schema_type
+=== TEST 26: get the schema by default schema_type
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/schema/plugins/jwt-auth',
+                ngx.HTTP_GET,
+                nil,
+                [[
+                {"properties":{"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"}
+                ]]
+                )
+            ngx.status = code
+        }
+    }
 --- request
-GET /apisix/admin/schema/plugins/jwt-auth
---- response_body
-{"properties":{"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"}
+GET /t
 --- no_error_log
 [error]
 
 
 
-=== TEST 28: add consumer with username and plugins with public_key, private_key(private_key numbits = 512)
+=== TEST 27: add consumer with username and plugins with public_key, private_key(private_key numbits = 512)
 --- config
     location /t {
         content_by_lua_block {
@@ -600,7 +671,7 @@ passed
 
 
 
-=== TEST 29: JWT sign and verify use RS256 algorithm(private_key numbits = 512)
+=== TEST 28: JWT sign and verify use RS256 algorithm(private_key numbits = 512)
 --- config
     location /t {
         content_by_lua_block {
@@ -636,19 +707,31 @@ passed
 
 
 
-=== TEST 30: sign use RS256 algorithm(private_key numbits = 512)
---- request
-GET /apisix/plugin/jwt/sign?key=user-key-rs256
---- response_body_like eval
-qr/eyJ4NWMiOlsiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Gd3dEUVlKS29aSWh2Y05BUUVCQlFBRFN3QXdTQUpCQUtlYkR4bHZRTUd5RWVzQUwxcjFuSUpCa1NkcXUzSHJcbjdub3FcLzB1a2lacVZRTFNKUE1PdjBveFFTdXR2dkszaG9pYndHYWtET3phK3hSSVRCN2NzMmNFQ0F3RUFBUT09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0iXSwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.\w+.\w+/
---- no_error_log
-[error]
+=== TEST 29: sign/verify use RS256 algorithm(private_key numbits = 512)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256',
+                ngx.HTTP_GET
+            )
 
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
 
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
 
-=== TEST 31: verify (in argument) use RS256 algorithm(private_key numbits = 512)
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /hello?jwt=eyJ4NWMiOlsiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Gd3dEUVlKS29aSWh2Y05BUUVCQlFBRFN3QXdTQUpCQUtlYkR4bHZRTUd5RWVzQUwxcjFuSUpCa1NkcXUzSHJcbjdub3FcLzB1a2lacVZRTFNKUE1PdjBveFFTdXR2dkszaG9pYndHYWtET3phK3hSSVRCN2NzMmNFQ0F3RUFBUT09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS0iXSwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsImV4cCI6MTkxOTY5Mjg3OX0.S7XMbZjl3HAm_r9xlXaKGnvQgMA6-G9RZ-3esJM3B3gDuTeyPr_JvWzou-9aDVCArr0ogcSa2dx7EwiwKaOwIA
+GET /t
 --- response_body
 hello world
 --- no_error_log
@@ -656,7 +739,7 @@ hello world
 
 
 
-=== TEST 32: add consumer with username and plugins with public_key, private_key(private_key numbits = 1024)
+=== TEST 30: add consumer with username and plugins with public_key, private_key(private_key numbits = 1024)
 --- config
     location /t {
         content_by_lua_block {
@@ -707,7 +790,7 @@ passed
 
 
 
-=== TEST 33: JWT sign and verify use RS256 algorithm(private_key numbits = 1024)
+=== TEST 31: JWT sign and verify use RS256 algorithm(private_key numbits = 1024)
 --- config
     location /t {
         content_by_lua_block {
@@ -743,19 +826,31 @@ passed
 
 
 
-=== TEST 34: sign use RS256 algorithm(private_key numbits = 1024)
---- request
-GET /apisix/plugin/jwt/sign?key=user-key-rs256
---- response_body_like eval
-qr/eyJ4NWMiOlsiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRREd4T2ZWZVwvc2VQNVRcL1Y4cGtTNVlOQVBSQ1xuM0ZmeHhlZGk3djBweVpoXC80ZDRwOVF4MFA5d09tQUx3bE9xNEZ0Z2tzMzExcHhHMHpMMExjVEpZNGlrYmMzcjBcbmg4U00weWhqOVVWMVZHdHVpYTRZYWtvYnZwTTlVK2txM2x5SU1POVpQUmV6MGNQM0FKSVlDdDV5ZjhFN2JOWUpcbmpiSk5qbDhXeHZNMXRESHFWUUlEQVFBQlxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tIl0sImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.\w+.\w+/
---- no_error_log
-[error]
+=== TEST 32: sign/verify use RS256 algorithm(private_key numbits = 1024)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256',
+                ngx.HTTP_GET
+            )
 
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
 
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
 
-=== TEST 35: verify (in argument) use RS256 algorithm(private_key numbits = 1024)
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /hello?jwt=eyJ4NWMiOlsiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRREd4T2ZWZVwvc2VQNVRcL1Y4cGtTNVlOQVBSQ1xuM0ZmeHhlZGk3djBweVpoXC80ZDRwOVF4MFA5d09tQUx3bE9xNEZ0Z2tzMzExcHhHMHpMMExjVEpZNGlrYmMzcjBcbmg4U00weWhqOVVWMVZHdHVpYTRZYWtvYnZwTTlVK2txM2x5SU1POVpQUmV6MGNQM0FKSVlDdDV5ZjhFN2JOWUpcbmpiSk5qbDhXeHZNMXRESHFWUUlEQVFBQlxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tIl0sImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsImV4cCI6MTkxOTc4MjQ0M [...]
+GET /t
 --- response_body
 hello world
 --- no_error_log
@@ -763,7 +858,7 @@ hello world
 
 
 
-=== TEST 36: add consumer with username and plugins with public_key, private_key(private_key numbits = 2048)
+=== TEST 33: add consumer with username and plugins with public_key, private_key(private_key numbits = 2048)
 --- config
     location /t {
         content_by_lua_block {
@@ -814,7 +909,7 @@ passed
 
 
 
-=== TEST 37: JWT sign and verify use RS256 algorithm(private_key numbits = 2048)
+=== TEST 34: JWT sign and verify use RS256 algorithm(private_key numbits = 2048)
 --- config
     location /t {
         content_by_lua_block {
@@ -850,19 +945,31 @@ passed
 
 
 
-=== TEST 38: sign use RS256 algorithm(private_key numbits = 2048)
---- request
-GET /apisix/plugin/jwt/sign?key=user-key-rs256
---- response_body_like eval
-qr/eyJ4NWMiOlsiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdjVMSGpaNEZ4UTlqazZlUUdEUnRcbm9Sd0ZWa0xxK2RVQmViczk3aHJ6aXJva1ZyMkIrUm94cWRMZktBTStBc04yRGFkYXdaMkdxbENWOURMMFwvZ3o2XG5uV1NxVFFwV2JROGM3Q3JGMzFFa0lIVVlSelp2V3kxN0szV0M5T2RrXC9nTTFGVmQwSGJaMlJqdXFqOUFEZWVxeFxubmo5bnBEcUtyTU9ET0VOeTMxU3FaTmVyV1pzZGdHa01MNUpZYlg1aGJJMkw5TFJFdlJVMjFmRGdTZkdMNk13NFxuTmF4bm56Y3ZsbDR5cXdyQkVMU2VEWkVBdDArZVwvcDFkTzdtb3hGK2IxcEZraDl2UWw2ekd2bnZmOGZPcW41R [...]
---- no_error_log
-[error]
+=== TEST 35: sign/verify use RS256 algorithm(private_key numbits = 2048)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256',
+                ngx.HTTP_GET
+            )
 
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
 
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
 
-=== TEST 39: verify (in argument) use RS256 algorithm(private_key numbits = 2048)
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /hello?jwt=eyJ4NWMiOlsiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdjVMSGpaNEZ4UTlqazZlUUdEUnRcbm9Sd0ZWa0xxK2RVQmViczk3aHJ6aXJva1ZyMkIrUm94cWRMZktBTStBc04yRGFkYXdaMkdxbENWOURMMFwvZ3o2XG5uV1NxVFFwV2JROGM3Q3JGMzFFa0lIVVlSelp2V3kxN0szV0M5T2RrXC9nTTFGVmQwSGJaMlJqdXFqOUFEZWVxeFxubmo5bnBEcUtyTU9ET0VOeTMxU3FaTmVyV1pzZGdHa01MNUpZYlg1aGJJMkw5TFJFdlJVMjFmRGdTZkdMNk13NFxuTmF4bm56Y3ZsbDR5cXdyQkVMU2VEWkVBdDArZVwvcDFkTzdtb3hGK2IxcEZraDl2UWw2ekd2b [...]
+GET /t
 --- response_body
 hello world
 --- no_error_log
@@ -870,7 +977,7 @@ hello world
 
 
 
-=== TEST 40: JWT sign with the public key when using the RS256 algorithm
+=== TEST 36: JWT sign with the public key when using the RS256 algorithm
 --- config
     location /t {
         content_by_lua_block {
@@ -918,7 +1025,7 @@ passed
 
 
 
-=== TEST 41: JWT sign and verify RS256
+=== TEST 37: JWT sign and verify RS256
 --- config
     location /t {
         content_by_lua_block {
@@ -954,7 +1061,7 @@ passed
 
 
 
-=== TEST 42: sign failed
+=== TEST 38: sign failed
 --- request
 GET /apisix/plugin/jwt/sign?key=user-key-rs256
 --- error_code: 500
@@ -963,7 +1070,7 @@ qr/failed to sign jwt/
 
 
 
-=== TEST 43: sanity(algorithm = HS512)
+=== TEST 39: sanity(algorithm = HS512)
 --- config
     location /t {
         content_by_lua_block {
@@ -976,19 +1083,19 @@ qr/failed to sign jwt/
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
 GET /t
 --- response_body_like eval
-qr/{"algorithm":"HS512","secret":"[a-zA-Z0-9+\\\/]+={0,2}","key":"123","exp":86400}/
+qr/{"algorithm":"HS512","exp":86400,"key":"123","secret":"[a-zA-Z0-9+\\\/]+={0,2}"}/
 --- no_error_log
 [error]
 
 
 
-=== TEST 44: add consumer with username and plugins use HS512 algorithm
+=== TEST 40: add consumer with username and plugins use HS512 algorithm
 --- config
     location /t {
         content_by_lua_block {
@@ -1035,7 +1142,7 @@ passed
 
 
 
-=== TEST 45: JWT sign and verify use HS512 algorithm
+=== TEST 41: JWT sign and verify use HS512 algorithm
 --- config
     location /t {
         content_by_lua_block {
@@ -1071,19 +1178,31 @@ passed
 
 
 
-=== TEST 46: sign(algorithm = HS512)
---- request
-GET /apisix/plugin/jwt/sign?key=user-key-HS512
---- response_body_like eval
-qr/eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.\w+.\w+/
---- no_error_log
-[error]
+=== TEST 42: sign / verify (algorithm = HS512)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-HS512',
+                ngx.HTTP_GET
+            )
 
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
 
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
 
-=== TEST 47: verify (in argument) use HS512 algorithm
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /hello?jwt=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1IUzUxMiIsImV4cCI6MTkxOTc4NzU5OH0.zJAE-BDs6QtMvGbBmQL6hNbZ9seYSfZ9SDH3R3VSiOhY3UAjdrl3SUStTeCirlVzIV1eoEiW2jd_xHpKNw7nWA
+GET /t
 --- response_body
 hello world
 --- no_error_log
@@ -1091,7 +1210,7 @@ hello world
 
 
 
-=== TEST 48: test for unsupported algorithm
+=== TEST 43: test for unsupported algorithm
 --- request
 PATCH /apisix/plugin/jwt/sign?key=user-key
 --- config
@@ -1106,7 +1225,7 @@ PATCH /apisix/plugin/jwt/sign?key=user-key
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
@@ -1116,7 +1235,7 @@ qr/property "algorithm" validation failed/
 
 
 
-=== TEST 49: wrong format of secret
+=== TEST 44: wrong format of secret
 --- config
     location /t {
         content_by_lua_block {
@@ -1143,7 +1262,7 @@ GET /t
 
 
 
-=== TEST 50: when the exp value is not set, make sure the default value(86400) works
+=== TEST 45: when the exp value is not set, make sure the default value(86400) works
 --- config
     location /t {
         content_by_lua_block {
@@ -1176,7 +1295,7 @@ GET /t
                 )
 
             ngx.status = code
-            ngx.say(require("cjson").encode(res_data))
+            ngx.say(require("toolkit.json").encode(res_data))
         }
     }
 --- request
@@ -1188,7 +1307,7 @@ qr/"exp":86400/
 
 
 
-=== TEST 51: when the exp value is not set, sign jwt use the default value(86400)
+=== TEST 46: when the exp value is not set, sign jwt use the default value(86400)
 --- config
     location /t {
         content_by_lua_block {
diff --git a/t/plugin/limit-req.t b/t/plugin/limit-req.t
index 15a6016..a1ad0e1 100644
--- a/t/plugin/limit-req.t
+++ b/t/plugin/limit-req.t
@@ -72,9 +72,10 @@ done
     }
 --- request
 GET /t
---- response_body
-property "conn" is required
+--- response_body_like eval
+qr/property "(conn|default_conn_delay)" is required
 done
+/
 --- no_error_log
 [error]
 
diff --git a/t/plugin/openid-connect.t b/t/plugin/openid-connect.t
index d2d251b..ef8f8a9 100644
--- a/t/plugin/openid-connect.t
+++ b/t/plugin/openid-connect.t
@@ -501,7 +501,7 @@ passed
 --- config
     location /t {
         content_by_lua_block {
-            local json_decode = require("cjson").decode
+            local json_decode = require("toolkit.json").decode
             local http = require "resty.http"
             local httpc = http.new()
             local uri = "http://127.0.0.1:8090/auth/realms/University/protocol/openid-connect/token"
diff --git a/t/plugin/plugin.t b/t/plugin/plugin.t
index 367df8b..6c428c0 100644
--- a/t/plugin/plugin.t
+++ b/t/plugin/plugin.t
@@ -108,11 +108,33 @@ passed
 
 
 
-=== TEST 3: sign
+=== TEST 3: sign and verify
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key',
+                ngx.HTTP_GET
+            )
+
+            if code > 200 then
+                ngx.status = code
+                ngx.say(err)
+                return
+            end
+
+            local code, _, res = t('/hello?jwt=' .. sign,
+                ngx.HTTP_GET
+            )
+
+            ngx.status = code
+            ngx.print(res)
+        }
+    }
 --- request
-GET /apisix/plugin/jwt/sign?key=user-key
---- response_body_like eval
-qr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\w+.\w+/
+GET /t
+--- response_body
+hello world
 
 
 
diff --git a/t/plugin/proxy-rewrite.t b/t/plugin/proxy-rewrite.t
index 3af824d..719eb7b 100644
--- a/t/plugin/proxy-rewrite.t
+++ b/t/plugin/proxy-rewrite.t
@@ -515,10 +515,13 @@ passed
 === TEST 17: rewrite uri args
 --- request
 GET /hello?q=apisix&a=iresty HTTP/1.1
---- response_body
-uri: /plugin_proxy_rewrite_args
+--- response_body_like eval
+qr/uri: \/plugin_proxy_rewrite_args(
 q: apisix
+a: iresty|
 a: iresty
+q: apisix)
+/
 --- no_error_log
 [error]
 
@@ -1045,10 +1048,13 @@ passed
 === TEST 35: rewrite uri with args
 --- request
 GET /hello?a=iresty
---- response_body
-uri: /plugin_proxy_rewrite_args
+--- response_body_like eval
+qr/uri: \/plugin_proxy_rewrite_args(
 q: apisix
+a: iresty|
 a: iresty
+q: apisix)
+/
 --- no_error_log
 [error]
 
@@ -1060,7 +1066,7 @@ a: iresty
         content_by_lua_block {
             local core = require("apisix.core")
             local t = require("lib.test_admin").test
-            local encode_with_keys_sorted = require("lib.json_sort").encode
+            local encode_with_keys_sorted = require("toolkit.json").encode
 
             local code, _, body = t('/apisix/admin/routes/1',
                 ngx.HTTP_PUT,
diff --git a/t/plugin/response-rewrite.t b/t/plugin/response-rewrite.t
index 2a4bb54..5274b01 100644
--- a/t/plugin/response-rewrite.t
+++ b/t/plugin/response-rewrite.t
@@ -447,7 +447,7 @@ invalid base64 content
         content_by_lua_block {
             local core = require("apisix.core")
             local t = require("lib.test_admin").test
-            local encode_with_keys_sorted = require("lib.json_sort").encode
+            local encode_with_keys_sorted = require("toolkit.json").encode
 
             local code, _, body = t('/apisix/admin/routes/1',
                 ngx.HTTP_PUT,
diff --git a/t/plugin/wolf-rbac.t b/t/plugin/wolf-rbac.t
index 16fc565..530a9c4 100644
--- a/t/plugin/wolf-rbac.t
+++ b/t/plugin/wolf-rbac.t
@@ -39,13 +39,13 @@ __DATA__
                 ngx.say(err)
             end
 
-            ngx.say(require("cjson").encode(conf))
+            ngx.say(require("toolkit.json").encode(conf))
         }
     }
 --- request
 GET /t
 --- response_body_like eval
-qr/\{"appid":"unset","header_prefix":"X-","server":"http:\\\/\\\/127\.0\.0\.1:10080"\}/
+qr/\{"appid":"unset","header_prefix":"X-","server":"http:\/\/127\.0\.0\.1:10080"\}/
 --- no_error_log
 [error]
 
@@ -232,14 +232,25 @@ qr/ERR_PASSWORD_ERROR/
 
 
 === TEST 11: login successfully
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/plugin/wolf-rbac/login',
+                ngx.HTTP_POST,
+                [[
+                {"appid": "wolf-rbac-app", "username": "admin","password": "123456"}
+                ]],
+                [[
+                {"rbac_token":"V1#wolf-rbac-app#wolf-rbac-token","user_info":{"nickname":"administrator","username":"admin","id":"100"}}
+                ]],
+                {["Content-Type"] = "application/json"}
+                )
+            ngx.status = code
+        }
+    }
 --- request
-POST /apisix/plugin/wolf-rbac/login
-{"appid": "wolf-rbac-app", "username": "admin","password": "123456"}
---- more_headers
-Content-Type: application/json
---- error_code: 200
---- response_body_like eval
-qr/\{"rbac_token":"V1#wolf-rbac-app#wolf-rbac-token","user_info":\{"nickname":"administrator","username":"admin","id":"100"/
+GET /t
 --- no_error_log
 [error]
 
@@ -378,13 +389,25 @@ x-rbac-token: invalid-rbac-token
 
 
 === TEST 22: get userinfo
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/plugin/wolf-rbac/user_info',
+                ngx.HTTP_GET,
+                nil,
+                [[
+{"user_info":{"username":"admin","id":"100","nickname":"administrator"}}
+                ]],
+                {Cookie = "x-rbac-token=V1#wolf-rbac-app#wolf-rbac-token"}
+                )
+            ngx.status = code
+        }
+    }
 --- request
-GET /apisix/plugin/wolf-rbac/user_info
---- more_headers
-Cookie: x-rbac-token=V1#wolf-rbac-app#wolf-rbac-token
---- error_code: 200
---- response_body_like eval
-qr/\{"user_info":\{"nickname":"administrator","username":"admin","id":"100"/
+GET /t
+--- no_error_log
+[error]
 
 
 
diff --git a/t/toolkit b/t/toolkit
new file mode 160000
index 0000000..ab2471c
--- /dev/null
+++ b/t/toolkit
@@ -0,0 +1 @@
+Subproject commit ab2471cc9cbeec6fe605120160eeb9dd17ddda2c
diff --git a/t/utils/batch-processor.t b/t/utils/batch-processor.t
index 2e930d1..15cf5cc 100644
--- a/t/utils/batch-processor.t
+++ b/t/utils/batch-processor.t
@@ -370,7 +370,7 @@ Batch Processor[log buffer] successfully processed the entries
                 retry_delay  = 0,
             }
             local func_to_send = function(elements)
-                core.log.info(core.json.encode(elements))
+                core.log.info(require("toolkit.json").encode(elements))
                 return true
             end
             local log_buffer, err = Batch:new(func_to_send, config)
@@ -412,7 +412,7 @@ Batch Processor[log buffer] activating flush due to no activity
                 inactive_timeout = 1
             }
             local func_to_send = function(elements)
-                core.log.info(core.json.encode(elements))
+                core.log.info(require("toolkit.json").encode(elements))
                 return true
             end
             local log_buffer, err = Batch:new(func_to_send, config)
diff --git a/utils/linux-install-openresty.sh b/utils/linux-install-openresty.sh
index 098a59f..0558efd 100755
--- a/utils/linux-install-openresty.sh
+++ b/utils/linux-install-openresty.sh
@@ -22,4 +22,11 @@ sudo apt-get -y install software-properties-common
 sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
 
 sudo apt-get update
-sudo apt-get install openresty-debug=1.17.8.2\* lua5.1 liblua5.1-0-dev
+
+if [ "$OPENRESTY_VERSION" == "default" ]; then
+    openresty='openresty-debug'
+else
+    openresty="openresty-debug=$OPENRESTY_VERSION*"
+fi
+
+sudo apt-get install "$openresty" lua5.1 liblua5.1-0-dev