From 0f93c3a04763130fe02fabf7967e9171538502b9 Mon Sep 17 00:00:00 2001 From: xumin Date: Thu, 6 Jul 2023 14:57:13 +0800 Subject: [PATCH 1/4] chore(http_mock): trivial improvements bug fix: assert turthy alias for not_all more checks better comment&document some fixes wrt docs rendering Co-authored-by: Thijs Schreijer --- spec/helpers/http_mock.lua | 109 +++++++++++++++++----- spec/helpers/http_mock/asserts.lua | 4 + spec/helpers/http_mock/clients.lua | 1 + spec/helpers/http_mock/debug_port.lua | 3 +- spec/helpers/http_mock/nginx_instance.lua | 1 + spec/helpers/http_mock/template.lua | 2 +- 6 files changed, 96 insertions(+), 24 deletions(-) diff --git a/spec/helpers/http_mock.lua b/spec/helpers/http_mock.lua index 2f2fd96a7a7..9c5709ad764 100644 --- a/spec/helpers/http_mock.lua +++ b/spec/helpers/http_mock.lua @@ -1,3 +1,6 @@ +--- Module implementing http_mock, a HTTP mocking server for testing. +-- @module spec.helpers.http_mock + local helpers = require "spec.helpers" local pairs = pairs @@ -42,11 +45,22 @@ local function default_field(tbl, key, default) end end --- create a mock instance which represents a HTTP mocking server --- @param listens: the listen directive of the mock server, defaults to "0.0.0.0:8000" --- @param code: the code of the mock server, defaults to a simple response. --- @param opts: options for the mock server, left it empty to use the defaults --- @return: a mock instance +--- create a mock instance which represents a HTTP mocking server +-- @tparam[opt] table|string|number listens the listen directive of the mock server, defaults to a random available port +-- @tparam[opt] table|string routes the code of the mock server, defaults to a simple response. +-- @tparam[opt={}] table opts options for the mock server, supporting fields: +-- @tparam[opt="servroot_tapping"] string opts.prefix the prefix of the mock server +-- @tparam[opt="_"] string opts.hostname the hostname of the mock server +-- @tparam[opt=false] bool opts.tls whether to use tls +-- @tparam[opt={}] table opts.directives the extra directives of the mock server +-- @tparam[opt={}] table opts.log_opts the options for logging with fields listed below: +-- @tparam[opt=true] bool opts.log_opts.collect_req whether to log requests() +-- @tparam[opt=true] bool opts.log_opts.collect_req_body_large whether to log large request bodies +-- @tparam[opt=false] bool opts.log_opts.collect_resp whether to log responses +-- @tparam[opt=false] bool opts.log_opts.collect_resp_body whether to log response bodies +-- @tparam[opt=true] bool opts.log_opts.collect_err: whether to log errors +-- @treturn http_mock a mock instance +-- @treturn string the port the mock server listens to -- @usage -- local mock = http_mock.new(8000, [[ -- ngx.req.set_header("X-Test", "test") @@ -75,7 +89,7 @@ end -- client:send({}) -- local logs = mock:retrieve_mocking_logs() -- get all the logs of HTTP sessions -- mock:stop() --- +-- -- listens can be a number, which will be used as the port of the mock server; -- or a string, which will be used as the param of listen directive of the mock server; -- or a table represents multiple listen ports. @@ -99,18 +113,6 @@ end -- }, -- } -- or a string, which will be used as the access phase handler. --- --- opts: --- prefix: the prefix of the mock server, defaults to "mockserver" --- hostname: the hostname of the mock server, defaults to "_" --- directives: the extra directives of the mock server, defaults to {} --- log_opts: the options for logging with fields listed below: --- collect_req: whether to log requests(), defaults to true --- collect_req_body_large: whether to log large request bodies, defaults to true --- collect_resp: whether to log responses, defaults to false --- collect_resp_body: whether to log response bodies, defaults to false --- collect_err: whether to log errors, defaults to true --- tls: whether to use tls, defaults to false function http_mock.new(listens, routes, opts) opts = opts or {} @@ -135,7 +137,7 @@ function http_mock.new(listens, routes, opts) } } end - + opts.log_opts = opts.log_opts or {} local log_opts = opts.log_opts default_field(log_opts, "req", true) @@ -145,7 +147,7 @@ function http_mock.new(listens, routes, opts) default_field(log_opts, "resp_body", false) default_field(log_opts, "err", true) - local prefix = opts.prefix or "mockserver" + local prefix = opts.prefix or "servroot_mock" local hostname = opts.hostname or "_" local directives = opts.directives or {} @@ -172,11 +174,74 @@ function http_mock.new(listens, routes, opts) _self:_set_eventually_table() _self:_setup_debug() - return _self + return _self, port end +---@type http_mock +---@field eventually http_mock.eventually contains eventually assertions + +--- start a dedicate nginx instance for this mock +---@function http_mock:start +--- @tparam[opt=true,default=false] bool error_on_exist whether to throw error if the directory already exists + +--- stop a dedicate nginx instance for this mock +---@function http_mock:stop +--- @tparam[opt=true,default=false] bool no_clean whether to preserve the logs +--- @tparam[opt=true,default="TERM"] string signal the signal to send to the nginx process +--- @tparam[opt=true,default=10] number timeout the timeout to wait for the nginx process to exit + +--- get a http_client to access the mock server +---@function http_mock:get_client +--- @treturn http_client a http_client instance + +--- returns the default port of the mock server. +---@function http_mock:get_default_port +--- @treturn string the port of the mock server (from the first listen directive) function http_mock:get_default_port() return self.listens[1]:match(":(%d+)") end -return http_mock \ No newline at end of file +--- retrieve the logs of HTTP sessions +---@function http_mock:retrieve_mocking_logs +--- @treturn table the logs of HTTP sessions + +--- purge the logs of HTTP sessions +---@function http_mock:purge_mocking_logs + +--- clean the logs of HTTP sessions +---@function http_mock:clean + +--- wait until all the requests are finished +---@function http_mock:wait_until_no_request +--- @tparam[opt=true,default=5] number timeout the timeout to wait for the nginx process to exit + +--- make assertions on HTTP requests +--- with a timeout to wait for the requests to arrive +---@class http_mock.eventually + +--- assert if the condition is true for one of the logs. Replace "session" in the name of the function to assert on fields of the log. +--- The field can be one of "session", "request", "response", "error". +---@function http_mock.eventually:has_session_satisfy +--- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- assert if the condition is true for all the logs. Replace "session" in the name of the function to assert on fields of the log. +--- The field can be one of "session", "request", "response", "error". +---@function http_mock.eventually:all_session_satisfy +--- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- assert if none of the logs satisfy the condition. Replace "session" in the name of the function to assert on fields of the log. +--- The field can be one of "session", "request", "response", "error". +---@function http_mock.eventually:has_no_session_satisfy +--- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- assert if not all the logs satisfy the condition. Replace "session" in the name of the function to assert on fields of the log. +--- The field can be one of "session", "request", "response", "error". +---@function http_mock.eventually:not_all_session_satisfy +--- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- alias for eventually:not_all_{session,request,response,error}_satisfy. Replace "session" in the name of the function to assert on fields of the log. +--- The field can be one of "session", "request", "response", "error". +---@function http_mock.eventually:has_one_without_session_satisfy +--- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +return http_mock diff --git a/spec/helpers/http_mock/asserts.lua b/spec/helpers/http_mock/asserts.lua index 87836692ebd..8d3705c90b5 100644 --- a/spec/helpers/http_mock/asserts.lua +++ b/spec/helpers/http_mock/asserts.lua @@ -4,10 +4,12 @@ local pairs = pairs local pcall = pcall local error = error +---@class http_mock local http_mock = {} local build_in_checks = {} +---@class http_mock_asserts local eventually_MT = {} eventually_MT.__index = eventually_MT @@ -114,6 +116,8 @@ local function register_assert(name, impl) eventually_MT["not_all_" .. name] = function(self, ...) return eventually_has(reverse_impl, self.__mock, ...) end + + eventually_MT["has_one_without_" .. name] = eventually_MT["not_all_" .. name] end for name, impl in pairs(build_in_checks) do diff --git a/spec/helpers/http_mock/clients.lua b/spec/helpers/http_mock/clients.lua index caee1f0d36a..3cf3b2a9df1 100644 --- a/spec/helpers/http_mock/clients.lua +++ b/spec/helpers/http_mock/clients.lua @@ -1,6 +1,7 @@ local helpers = require "spec.helpers" local http_client = helpers.http_client +---@class http_mock local http_mock = {} -- we need to get rid of dependence to the "helpers" diff --git a/spec/helpers/http_mock/debug_port.lua b/spec/helpers/http_mock/debug_port.lua index 9ac5a9451e0..e5db9e5327f 100644 --- a/spec/helpers/http_mock/debug_port.lua +++ b/spec/helpers/http_mock/debug_port.lua @@ -6,6 +6,7 @@ local ipairs = ipairs local insert = table.insert local assert = assert +---@class http_mock local http_mock = {} -- POST as it's not idempotent @@ -36,7 +37,7 @@ local get_status_param = { -- internal API function http_mock:_setup_debug(debug_param) local debug_port = helpers.get_available_port() - local debug_client = http.new() + local debug_client = assert(http.new()) local debug_connect = { scheme = "http", host = "localhost", diff --git a/spec/helpers/http_mock/nginx_instance.lua b/spec/helpers/http_mock/nginx_instance.lua index 36d26bc8a9f..264b48807f9 100644 --- a/spec/helpers/http_mock/nginx_instance.lua +++ b/spec/helpers/http_mock/nginx_instance.lua @@ -16,6 +16,7 @@ local shallow_copy = require "kong.tools.utils".shallow_copy local template = assert(pl_template.compile(template_str)) local render_env = {ipairs = ipairs, pairs = pairs, error = error, } +---@class http_mock local http_mock = {} -- start a dedicate nginx instance for this mock diff --git a/spec/helpers/http_mock/template.lua b/spec/helpers/http_mock/template.lua index 2fa152f40bc..093bc0d334d 100644 --- a/spec/helpers/http_mock/template.lua +++ b/spec/helpers/http_mock/template.lua @@ -43,7 +43,7 @@ http { function assert(truthy, err) -- luacheck: ignore if truthy then - return + return truthy end if ngx.ctx then From d5432de091d094458158b9ce7e0252061c8e446b Mon Sep 17 00:00:00 2001 From: xumin Date: Thu, 6 Jul 2023 14:58:46 +0800 Subject: [PATCH 2/4] feat(test): tapping --- .../01-helpers/03-http_mock_spec.lua | 58 +++++++++++++++++++ spec/helpers/http_mock/tapping.lua | 46 +++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 spec/helpers/http_mock/tapping.lua diff --git a/spec/02-integration/01-helpers/03-http_mock_spec.lua b/spec/02-integration/01-helpers/03-http_mock_spec.lua index acbdd8cbe04..b1250c1febc 100644 --- a/spec/02-integration/01-helpers/03-http_mock_spec.lua +++ b/spec/02-integration/01-helpers/03-http_mock_spec.lua @@ -1,4 +1,5 @@ local http_mock = require "spec.helpers.http_mock" +local tapping = require "spec.helpers.http_mock.tapping" local pl_file = require "pl.file" for _, tls in ipairs {true, false} do @@ -220,3 +221,60 @@ describe("http_mock config", function() assert(pl_file.access_time(pid_filename) ~= nil, "mocking not in the correct place") end) end) + +local function remove_volatile_headers(req_t) + req_t.headers["Connection"] = nil + req_t.headers["Host"] = nil + req_t.headers["User-Agent"] = nil + req_t.headers["Content-Length"] = nil +end + +describe("http_mock.tapping", function() + local tapped, tapped_port + lazy_setup(function() + tapped, tapped_port = http_mock.new(nil, nil, { + log_opts = { + req = true, + req_body = true, + req_body_large = true, + } + }) + tapped:start() + end) + lazy_teardown(function() + tapped:stop(true) + end) + + it("works", function() + local tapping_mock = tapping.new(tapped_port) + tapping_mock:start() + finally(function() + tapping_mock:stop(true) + end) + local client = tapping_mock:get_client() + local request = { + headers = { + ["test"] = "mock_debug" + }, + method = "POST", + path = "/test!", + body = "hello world", + } + local res = assert(client:send(request)) + assert.response(res).has.status(200) + assert.same(res:read_body(), "ok") + + request.uri = request.path + request.path = nil + + local record = tapping_mock:retrieve_mocking_logs() + local req_t = assert(record[1].req) + remove_volatile_headers(req_t) + assert.same(request, req_t) + + local upstream_record = tapped:retrieve_mocking_logs() + local upstream_req_t = assert(upstream_record[1].req) + remove_volatile_headers(upstream_req_t) + assert.same(request, upstream_req_t) + end) +end) diff --git a/spec/helpers/http_mock/tapping.lua b/spec/helpers/http_mock/tapping.lua new file mode 100644 index 00000000000..e49c16e61c6 --- /dev/null +++ b/spec/helpers/http_mock/tapping.lua @@ -0,0 +1,46 @@ +local http_mock = require "spec.helpers.http_mock" + +--- tapping implemented with http_mock +---@class http_mock.tapping: http_mock +local tapping = {} + +-- create a new tapping route +-- @param target string|number: the target host/port of the tapping route +-- @return table: the tapping route +function tapping.new_tapping_route(target) + if tonumber(target) then + -- TODO: handle the resovler! + target = "http://127.0.0.1:" .. target + end + + if not target:find("://") then + target = "http://" .. target + end + + return { + ["/"] = { + directives = [[proxy_pass ]] .. target .. [[;]], + } + } +end + +-- create a new http_mock.tapping instance with a tapping route +-- @param target string|number: the target host/port of the tapping route +-- @param listens table|string|number|nil: the listen directive of the mock server, defaults to a random available port +-- @param prefix string|nil: the prefix of the mock server, defaults to "servroot_tapping" +-- @param log_opts table|nil: log_opts, left it empty to use the defaults, with req_large_body enabled +-- @return http_mock.tapping: a tapping instance +-- @return number: the port the mock server listens to +function tapping.new(target, listens, prefix, log_opts) + ---@diagnostic disable-next-line: return-type-mismatch + return http_mock.new(listens, tapping.new_tapping_route(target), { + prefix = prefix or "servroot_tapping", + log_opts = log_opts or { + req = true, + req_body = true, + req_large_body = true, + }, + }) +end + +return tapping From 44ade8feaecb48995e757dcf9ebc63d843f5b8a9 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 10 Jul 2023 09:00:19 +0200 Subject: [PATCH 3/4] fix example --- spec/helpers/http_mock.lua | 27 +++++++++++++------------ spec/renderdocs.sh | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 12 deletions(-) create mode 100755 spec/renderdocs.sh diff --git a/spec/helpers/http_mock.lua b/spec/helpers/http_mock.lua index 9c5709ad764..8efdcb0e2dd 100644 --- a/spec/helpers/http_mock.lua +++ b/spec/helpers/http_mock.lua @@ -46,8 +46,10 @@ local function default_field(tbl, key, default) end --- create a mock instance which represents a HTTP mocking server --- @tparam[opt] table|string|number listens the listen directive of the mock server, defaults to a random available port --- @tparam[opt] table|string routes the code of the mock server, defaults to a simple response. +-- @tparam[opt] table|string|number listens the listen directive of the mock server. This can be +-- a single directive (string), or a list of directives (table), or a number which will be used as the port. +-- Defaults to a random available port +-- @tparam[opt] table|string routes the code of the mock server, defaults to a simple response. See Examples. -- @tparam[opt={}] table opts options for the mock server, supporting fields: -- @tparam[opt="servroot_tapping"] string opts.prefix the prefix of the mock server -- @tparam[opt="_"] string opts.hostname the hostname of the mock server @@ -89,15 +91,8 @@ end -- client:send({}) -- local logs = mock:retrieve_mocking_logs() -- get all the logs of HTTP sessions -- mock:stop() --- --- listens can be a number, which will be used as the port of the mock server; --- or a string, which will be used as the param of listen directive of the mock server; --- or a table represents multiple listen ports. --- if the port is not specified, a random port will be used. --- call mock:get_default_port() to get the first port the mock server listens to. --- if the port is a number and opts.tls is set to ture, ssl will be appended. --- --- routes can be a table like this: +-- @usage +-- -- routes can be a table like this: -- routes = { -- ["/"] = { -- access = [[ @@ -112,7 +107,15 @@ end -- }, -- }, -- } --- or a string, which will be used as the access phase handler. +-- +-- -- or single a string, which will be used as the access phase handler. +-- routes = [[ ngx.print("hello world") ]] +-- -- which is equivalent to: +-- routes = { +-- ["/"] = { +-- access = [[ ngx.print("hello world") ]], +-- }, +-- } function http_mock.new(listens, routes, opts) opts = opts or {} diff --git a/spec/renderdocs.sh b/spec/renderdocs.sh new file mode 100755 index 00000000000..86cfe1f2540 --- /dev/null +++ b/spec/renderdocs.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# auto-doc renderer +# +# will watch the spec directory and upon changes automatically +# render the helper documentation using `ldoc .` +# resulting docs are in ./spec/docs/index.html + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +pushd $SCRIPT_DIR + +watched_files=$(find . -name '*.lua') + +if [ -z "$watched_files" ]; then + echo "Nothing to watch, abort" + exit 1 +else + echo "watching: $watched_files" +fi + +previous_checksum="dummy" +while true ; do + checksum=$(md5 $watched_files | md5) + if [ "$checksum" != "$previous_checksum" ]; then + ldoc . + result=$? + if [ $result -ne 0 ]; then + echo -e "\033[0;31mldoc failed, exitcode: $result\033[0m" + echo + else + echo + echo "docs updated at: $(pwd)/docs/index.html" + echo -e "\033[1;33mwatching for changes...\033[0m" + echo + fi + fi + previous_checksum="$checksum" + sleep 1 +done + From 076390bd93ea9877cc2378dfcec2411a582b85a1 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 10 Jul 2023 12:05:16 +0200 Subject: [PATCH 4/4] more doc fixes --- spec/helpers/http_mock.lua | 96 ++++++++++------------- spec/helpers/http_mock/clients.lua | 14 +++- spec/helpers/http_mock/nginx_instance.lua | 20 +++-- spec/helpers/http_mock/tapping.lua | 23 +++--- 4 files changed, 81 insertions(+), 72 deletions(-) diff --git a/spec/helpers/http_mock.lua b/spec/helpers/http_mock.lua index 8efdcb0e2dd..5319a06d577 100644 --- a/spec/helpers/http_mock.lua +++ b/spec/helpers/http_mock.lua @@ -180,71 +180,61 @@ function http_mock.new(listens, routes, opts) return _self, port end ----@type http_mock ----@field eventually http_mock.eventually contains eventually assertions - ---- start a dedicate nginx instance for this mock ----@function http_mock:start ---- @tparam[opt=true,default=false] bool error_on_exist whether to throw error if the directory already exists - ---- stop a dedicate nginx instance for this mock ----@function http_mock:stop ---- @tparam[opt=true,default=false] bool no_clean whether to preserve the logs ---- @tparam[opt=true,default="TERM"] string signal the signal to send to the nginx process ---- @tparam[opt=true,default=10] number timeout the timeout to wait for the nginx process to exit - ---- get a http_client to access the mock server ----@function http_mock:get_client ---- @treturn http_client a http_client instance +--- @type http_mock --- returns the default port of the mock server. ----@function http_mock:get_default_port ---- @treturn string the port of the mock server (from the first listen directive) +-- @function http_mock:get_default_port +-- @treturn string the port of the mock server (from the first listen directive) function http_mock:get_default_port() return self.listens[1]:match(":(%d+)") end --- retrieve the logs of HTTP sessions ----@function http_mock:retrieve_mocking_logs ---- @treturn table the logs of HTTP sessions +-- @function http_mock:retrieve_mocking_logs +-- @treturn table the logs of HTTP sessions --- purge the logs of HTTP sessions ----@function http_mock:purge_mocking_logs +-- @function http_mock:purge_mocking_logs --- clean the logs of HTTP sessions ----@function http_mock:clean +-- @function http_mock:clean --- wait until all the requests are finished ----@function http_mock:wait_until_no_request ---- @tparam[opt=true,default=5] number timeout the timeout to wait for the nginx process to exit - ---- make assertions on HTTP requests ---- with a timeout to wait for the requests to arrive ----@class http_mock.eventually - ---- assert if the condition is true for one of the logs. Replace "session" in the name of the function to assert on fields of the log. ---- The field can be one of "session", "request", "response", "error". ----@function http_mock.eventually:has_session_satisfy ---- @tparam function check the check function, accept a log and throw error if the condition is not satisfied - ---- assert if the condition is true for all the logs. Replace "session" in the name of the function to assert on fields of the log. ---- The field can be one of "session", "request", "response", "error". ----@function http_mock.eventually:all_session_satisfy ---- @tparam function check the check function, accept a log and throw error if the condition is not satisfied - ---- assert if none of the logs satisfy the condition. Replace "session" in the name of the function to assert on fields of the log. ---- The field can be one of "session", "request", "response", "error". ----@function http_mock.eventually:has_no_session_satisfy ---- @tparam function check the check function, accept a log and throw error if the condition is not satisfied - ---- assert if not all the logs satisfy the condition. Replace "session" in the name of the function to assert on fields of the log. ---- The field can be one of "session", "request", "response", "error". ----@function http_mock.eventually:not_all_session_satisfy ---- @tparam function check the check function, accept a log and throw error if the condition is not satisfied - ---- alias for eventually:not_all_{session,request,response,error}_satisfy. Replace "session" in the name of the function to assert on fields of the log. ---- The field can be one of "session", "request", "response", "error". ----@function http_mock.eventually:has_one_without_session_satisfy ---- @tparam function check the check function, accept a log and throw error if the condition is not satisfied +-- @function http_mock:wait_until_no_request +-- @tparam[opt=true,default=5] number timeout the timeout to wait for the nginx process to exit + +--- make assertions on HTTP requests. +-- with a timeout to wait for the requests to arrive +-- @class http_mock.eventually + +--- assert if the condition is true for one of the logs. +-- Replace "session" in the name of the function to assert on fields of the log. +-- The field can be one of "session", "request", "response", "error". +-- @function http_mock.eventually:has_session_satisfy +-- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- assert if the condition is true for all the logs. +-- Replace "session" in the name of the function to assert on fields of the log. +-- The field can be one of "session", "request", "response", "error". +-- @function http_mock.eventually:all_session_satisfy +-- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- assert if none of the logs satisfy the condition. +-- Replace "session" in the name of the function to assert on fields of the log. +-- The field can be one of "session", "request", "response", "error". +-- @function http_mock.eventually:has_no_session_satisfy +-- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- assert if not all the logs satisfy the condition. +-- Replace "session" in the name of the function to assert on fields of the log. +-- The field can be one of "session", "request", "response", "error". +-- @function http_mock.eventually:not_all_session_satisfy +-- @tparam function check the check function, accept a log and throw error if the condition is not satisfied + +--- alias for eventually:not_all_{session,request,response,error}_satisfy. +-- Replace "session" in the name of the function to assert on fields of the log. +-- The field can be one of "session", "request", "response", "error". +-- @function http_mock.eventually:has_one_without_session_satisfy +-- @tparam function check the check function, accept a log and throw error if the condition is not satisfied return http_mock diff --git a/spec/helpers/http_mock/clients.lua b/spec/helpers/http_mock/clients.lua index 3cf3b2a9df1..98f560e93d1 100644 --- a/spec/helpers/http_mock/clients.lua +++ b/spec/helpers/http_mock/clients.lua @@ -1,16 +1,24 @@ +--- part of http_mock +-- @submodule spec.helpers.http_mock + local helpers = require "spec.helpers" local http_client = helpers.http_client ----@class http_mock local http_mock = {} --- we need to get rid of dependence to the "helpers" +--- get a `helpers.http_client` to access the mock server +-- @function http_mock:get_client +-- @treturn http_client a `helpers.http_client` instance +-- @within http_mock +-- @usage +-- httpc = http_mock:get_client() +-- result = httpc:get("/services/foo", opts) function http_mock:get_client() local client = self.client if not client then client = http_client({ scheme = self.client_opts.tls and "https" or "http", - host = "localhost", + host = "localhost", port = self.client_opts.port, }) diff --git a/spec/helpers/http_mock/nginx_instance.lua b/spec/helpers/http_mock/nginx_instance.lua index 264b48807f9..860a12439f6 100644 --- a/spec/helpers/http_mock/nginx_instance.lua +++ b/spec/helpers/http_mock/nginx_instance.lua @@ -1,3 +1,6 @@ +--- part of http_mock +-- @submodule spec.helpers.http_mock + local template_str = require "spec.helpers.http_mock.template" local pl_template = require "pl.template" local pl_path = require "pl.path" @@ -15,17 +18,18 @@ local shallow_copy = require "kong.tools.utils".shallow_copy local template = assert(pl_template.compile(template_str)) local render_env = {ipairs = ipairs, pairs = pairs, error = error, } - ----@class http_mock local http_mock = {} --- start a dedicate nginx instance for this mock +--- start a dedicate nginx instance for this mock +-- @tparam[opt=false] bool error_on_exist whether to throw error if the directory already exists +-- @within http_mock +-- @usage http_mock:start(true) function http_mock:start(error_on_exist) local ok = (pl_path.mkdir(self.prefix)) and (pl_path.mkdir(self.prefix .. "/logs")) and (pl_path.mkdir(self.prefix .. "/conf")) if error_on_exist then assert(ok, "failed to create directory " .. self.prefix) end - + local render = assert(template:render(shallow_copy(self), render_env)) local conf_path = self.prefix .. "/conf/nginx.conf" local conf_file = assert(io.open(conf_path, "w")) @@ -40,7 +44,13 @@ end local sleep_step = 0.01 --- stop a dedicate nginx instance for this mock +--- stop a dedicate nginx instance for this mock +-- @function http_mock:stop +-- @tparam[opt=false] bool no_clean whether to preserve the logs +-- @tparam[opt="TERM"] string signal the signal name to send to the nginx process +-- @tparam[opt=10] number timeout the timeout to wait for the nginx process to exit +-- @within http_mock +-- @usage http_mock:stop(false, "TERM", 10) function http_mock:stop(no_clean, signal, timeout) signal = signal or "TERM" timeout = timeout or 10 diff --git a/spec/helpers/http_mock/tapping.lua b/spec/helpers/http_mock/tapping.lua index e49c16e61c6..65e84435d20 100644 --- a/spec/helpers/http_mock/tapping.lua +++ b/spec/helpers/http_mock/tapping.lua @@ -1,12 +1,13 @@ +--- A http_mock subclass for tapping. +-- @module spec.helpers.http_mock.tapping + local http_mock = require "spec.helpers.http_mock" ---- tapping implemented with http_mock ----@class http_mock.tapping: http_mock local tapping = {} -- create a new tapping route --- @param target string|number: the target host/port of the tapping route --- @return table: the tapping route +-- @tparam string|number target the target host/port of the tapping route +-- @return the tapping route instance function tapping.new_tapping_route(target) if tonumber(target) then -- TODO: handle the resovler! @@ -24,13 +25,13 @@ function tapping.new_tapping_route(target) } end --- create a new http_mock.tapping instance with a tapping route --- @param target string|number: the target host/port of the tapping route --- @param listens table|string|number|nil: the listen directive of the mock server, defaults to a random available port --- @param prefix string|nil: the prefix of the mock server, defaults to "servroot_tapping" --- @param log_opts table|nil: log_opts, left it empty to use the defaults, with req_large_body enabled --- @return http_mock.tapping: a tapping instance --- @return number: the port the mock server listens to +--- create a new `http_mock.tapping` instance with a tapping route +-- @tparam string|number target the target host/port of the tapping route +-- @tparam[opt] table|string|number listens see `http_mock.new` +-- @tparam[opt="servroot_tapping"] string prefix the prefix of the mock server +-- @tparam[opt={}] table log_opts see `http_mock.new`, uses the defaults, with `req_large_body` enabled +-- @treturn http_mock.tapping a tapping instance +-- @treturn string the port the mock server listens to function tapping.new(target, listens, prefix, log_opts) ---@diagnostic disable-next-line: return-type-mismatch return http_mock.new(listens, tapping.new_tapping_route(target), {