This is an automated email from the ASF dual-hosted git repository.
spacewander 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 fd8f875 docs: introducing APISIX's testing framework (#4692)
fd8f875 is described below
commit fd8f875429bd43462430bd662788940f6a579ff9
Author: 罗泽轩 <[email protected]>
AuthorDate: Fri Jul 30 14:37:24 2021 +0800
docs: introducing APISIX's testing framework (#4692)
Co-authored-by: Alex Zhang <[email protected]>
---
docs/en/latest/config.json | 7 +
docs/en/latest/internal/testing-framework.md | 288 +++++++++++++++++++++++++++
2 files changed, 295 insertions(+)
diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json
index 40ac11d..dfee6bc 100644
--- a/docs/en/latest/config.json
+++ b/docs/en/latest/config.json
@@ -232,6 +232,13 @@
"id": "debug-function"
},
{
+ "type": "category",
+ "label": "internal",
+ "items": [
+ "internal/testing-framework"
+ ]
+ },
+ {
"type": "doc",
"id": "profile"
}
diff --git a/docs/en/latest/internal/testing-framework.md
b/docs/en/latest/internal/testing-framework.md
new file mode 100644
index 0000000..e025405
--- /dev/null
+++ b/docs/en/latest/internal/testing-framework.md
@@ -0,0 +1,288 @@
+---
+title: Introducing APISIX's testing framework
+---
+
+<!--
+#
+# 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.
+#
+-->
+
+APISIX uses a testing framework based on our fork of test-nginx:
https://github.com/iresty/test-nginx.
+For details, you can check the documentation of this project.
+
+If you want to test the CLI behavior of APISIX (`./bin/apisix`),
+you need to write a shell script in the t/cli directory to test it. You can
refer to the existing test scripts for more details.
+
+If you want to test the others, you need to write test code based on the
framework.
+
+Here, we briefly describe how to do simple testing based on this framework.
+
+## Test file
+
+you need to write test cases in the t/ directory, in a corresponding `.t`
file. Note that a single test file should not exceed `800` lines, and if it is
too long, it needs to be divided by a suffix. For example:
+
+```
+t/
+├── admin
+│ ├── consumers.t
+│ ├── consumers2.t
+```
+
+Both `consumers.t` and `consumers2.t` contain tests for consumers in the Admin
API.
+
+Some of the test files start with this paragraph:
+
+```
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ if (! $block->request) {
+ $block->set_value("request", "GET /t");
+ }
+
+ if (! $block->no_error_log && ! $block->error_log) {
+ $block->set_value("no_error_log", "[error]\n[alert]");
+ }
+});
+```
+
+It means that all tests in this test file that do not define `request` are set
to `GET /t`. The same is true for error_log.
+
+## Preparing the configuration
+
+When testing a behavior, we need to prepare the configuration.
+
+If the configuration is from etcd:
+We can set up specific configurations through the Admin API.
+
+```
+=== TEST 7: refer to empty nodes upstream
+--- config
+ location /t {
+ content_by_lua_block {
+ local core = require("apisix.core")
+ local t = require("lib.test_admin").test
+ local code, message = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "upstream_id": "1",
+ "uri": "/index.html"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.print(message)
+ return
+ end
+
+ ngx.say(message)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+```
+
+Then trigger it in a later test:
+
+```
+=== TEST 8: hit empty nodes upstream
+--- request
+GET /index.html
+--- error_code: 503
+--- error_log
+no valid upstream node
+```
+
+## Send request
+
+We can initiate a request with `request` and set the request headers with
`more_headers`.
+
+For example.
+
+```
+--- request
+PUT /hello?xx=y&xx=z&&y=&&z
+body part of the request
+--- more_headers
+X-Req: foo
+X-Req: bar
+X-Resp: cat
+```
+
+Lua code can be used to send multiple requests.
+
+One request after another:
+
+```
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+ local uri = "http://127.0.0.1:" ... ngx.var.server_port
+ ... "/server_port"
+
+ local ports_count = {}
+ for i = 1, 12 do
+ local httpc = http.new()
+ local res, err = httpc:request_uri(uri, {method = "GET"})
+ if not res then
+ ngx.say(err)
+ return
+ end
+ ports_count[res.body] = (ports_count[res.body] or 0) + 1
+ end
+
+```
+
+Sending multiple requests concurrently:
+
+```
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+ local uri = "http://127.0.0.1:" ... ngx.var.server_port
+ ... "/server_port?var=2&var2="
+
+
+ local t = {}
+ local ports_count = {}
+ for i = 1, 180 do
+ local th = assert(ngx.thread.spawn(function(i))
+ local httpc = http.new()
+ local res, err = httpc:request_uri(uri..i, {method =
"GET"})
+ if not res then
+ ngx.log(ngx.ERR, err)
+ return
+ end
+ ports_count[res.body] = (ports_count[res.body] or 0) + 1
+ end, i))
+ table.insert(t, th)
+ end
+ for i, th in ipairs(t) do
+ ngx.thread.wait(th)
+ end
+```
+
+## Assertions
+
+The following assertions are commonly used.
+
+Check status (if not set, the framework will check if the request has 200
status code).
+
+```
+--- error_code: 405
+```
+
+Check response headers.
+
+```
+--- response_headers
+X-Resp: foo
+X-Req: foo, bar
+```
+
+Check response body.
+
+```
+--- response_body
+[{"count":12, "port": "1982"}]
+```
+
+Checking the error log (via grep error log with regular expression).
+
+```
+--- grep_error_log eval
+qr/hash_on: header|chash_key: "custom-one"/
+--- grep_error_log_out
+hash_on: header
+chash_key: "custom-one"
+hash_on: header
+chash_key: "custom-one"
+hash_on: header
+chash_key: "custom-one"
+hash_on: header
+chash_key: "custom-one"
+```
+
+The default log level is `info`, but you can get the debug level log with `--
log_level: debug`.
+
+## Upstream
+
+The test framework listens to multiple ports when it is started.
+
+* 1980/1981/1982/5044: HTTP upstream port
+* 1983: HTTPS upstream port
+* 1984: APISIX HTTP port. Can be used to verify HTTP related gateway logic,
such as concurrent access to an API.
+* 1994: APISIX HTTPS port. Can be used to verify HTTPS related gateway logic,
such as testing certificate matching logic.
+
+The methods in `t/lib/server.lua` are executed when accessing the upstream
port. `_M.go` is the entry point for this file.
+When the request accesses the upstream `/xxx`, the `_M.xxx` method is
executed. For example, a request for `/hello` will execute `_M.hello`.
+This allows us to write methods inside `t/lib/server.lua` to emulate specific
upstream logic, such as sending special responses.
+
+Note that before adding new methods to `t/lib/server.lua`, make sure that you
can reuse existing methods.
+
+## Run the test
+
+Assume your current work directory is the root of the apisix source code.
+
+1. Install our fork of [test-nginx](https://github.com/iresty/test-nginx) to
`../test-nginx`.
+2. Run the test: `prove -I. -I../test-nginx/inc -I../test-nginx/lib -r
t/path/to/file.t`.
+
+## Tips
+
+### Debugging test cases
+
+The Nginx configuration and logs generated by the test cases are located in
the t/servroot directory. The Nginx configuration template for testing is
located in t/APISIX.pm.
+
+### Running only some test cases
+
+Three notes can be used to control which parts of the tests are executed.
+
+FIRST & LAST:
+
+```
+=== TEST 1: vars rule with ! (set)
+--- FIRST
+--- config
+...
+--- response_body
+passed
+
+
+
+=== TEST 2: vars rule with ! (hit)
+--- request
+GET /hello?name=jack&age=17
+--- LAST
+--- error_code: 403
+--- response_body
+Fault Injection!
+```
+
+ONLY:
+
+```
+=== TEST 1: list empty resources
+--- ONLY
+--- config
+...
+--- response_body
+{"action":"get","count":0,"node":{"dir":true,"key":"/apisix/upstreams","nodes":{}}}
+```