164 lines
4.7 KiB
Lua
164 lines
4.7 KiB
Lua
local setmetatable = setmetatable
|
|
local ipairs = ipairs
|
|
local pairs = pairs
|
|
local pcall = pcall
|
|
local error = error
|
|
|
|
local http_mock = {}
|
|
|
|
local build_in_checks = {}
|
|
|
|
local eventually_MT = {}
|
|
eventually_MT.__index = eventually_MT
|
|
|
|
local step_time = 0.01
|
|
|
|
-- example for a check function
|
|
-- local function(session, status)
|
|
-- -- must throw error if the assertion is not true
|
|
-- -- instead of return false
|
|
-- assert.same(session.resp.status, status)
|
|
-- -- return a string to tell what condition is satisfied
|
|
-- -- so we can construct an error message for reverse assertion
|
|
-- -- in this case it would be "we don't expect that: has a response with status 200"
|
|
-- return "has a response with status " .. status
|
|
-- end
|
|
|
|
local function eventually_has(check, mock, ...)
|
|
local time = 0
|
|
local ok, err
|
|
while time < mock.eventually_timeout do
|
|
local logs = mock:retrieve_mocking_logs()
|
|
for _, log in ipairs(logs) do
|
|
-- use pcall so the user may use lua assert like assert.same
|
|
ok, err = pcall(check, log, ...)
|
|
if ok then
|
|
return true
|
|
end
|
|
end
|
|
|
|
ngx.sleep(step_time)
|
|
time = time + step_time
|
|
end
|
|
|
|
error(err or "assertion fail. No request is sent and recorded.", 2)
|
|
end
|
|
|
|
-- wait until timeout to check if the assertion is true for all logs
|
|
local function eventually_all(check, mock, ...)
|
|
local time = 0
|
|
local ok, err
|
|
while time < mock.eventually_timeout do
|
|
local logs = mock:retrieve_mocking_logs()
|
|
for _, log in ipairs(logs) do
|
|
ok, err = pcall(check, log, ...)
|
|
if not ok then
|
|
error(err or "assertion fail", 2)
|
|
end
|
|
end
|
|
|
|
ngx.sleep(step_time)
|
|
time = time + step_time
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-- a session is a request/response pair
|
|
function build_in_checks.session_satisfy(session, f)
|
|
return f(session) or "session satisfy"
|
|
end
|
|
|
|
function build_in_checks.request_satisfy(session, f)
|
|
return f(session.req) or "request satisfy"
|
|
end
|
|
|
|
function build_in_checks.request()
|
|
return "request exist"
|
|
end
|
|
|
|
function build_in_checks.response_satisfy(session, f)
|
|
return f(session.resp) or "response satisfy"
|
|
end
|
|
|
|
function build_in_checks.error_satisfy(session, f)
|
|
return f(session.err) or "error satisfy"
|
|
end
|
|
|
|
function build_in_checks.error(session)
|
|
assert(session.err, "has no error")
|
|
return "has error"
|
|
end
|
|
|
|
local function register_assert(name, impl)
|
|
eventually_MT["has_" .. name] = function(self, ...)
|
|
return eventually_has(impl, self.__mock, ...)
|
|
end
|
|
|
|
eventually_MT["all_" .. name] = function(self, ...)
|
|
return eventually_all(impl, self.__mock, ...)
|
|
end
|
|
|
|
local function reverse_impl(session, ...)
|
|
local ok, err = pcall(impl, session, ...)
|
|
if ok then
|
|
error("we don't expect that: " .. (name or err), 2)
|
|
end
|
|
return true
|
|
end
|
|
|
|
eventually_MT["has_no_" .. name] = function(self, ...)
|
|
return eventually_all(reverse_impl, self.__mock, ...)
|
|
end
|
|
|
|
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
|
|
register_assert(name, impl)
|
|
end
|
|
|
|
|
|
function http_mock:_set_eventually_table()
|
|
local eventually = setmetatable({}, eventually_MT)
|
|
eventually.__mock = self
|
|
self.eventually = eventually
|
|
return eventually
|
|
end
|
|
|
|
-- usually this function is not called by a user. I will add more assertions in the future with it. @StarlightIbuki
|
|
|
|
-- @function http_mock.register_assert()
|
|
-- @param name: the name of the assertion
|
|
-- @param impl: the implementation of the assertion
|
|
-- implement a new eventually assertion
|
|
-- @usage:
|
|
-- impl is a function
|
|
-- -- @param session: the session object, with req, resp, err, start_time, end_time as fields
|
|
-- -- @param ...: the arguments passed to the assertion
|
|
-- -- @return: human readable message if the assertion is true, or throw error if not
|
|
--
|
|
-- a session means a request/response pair.
|
|
-- The impl callback throws error if the assertion is not true
|
|
-- and returns a string to tell what condition is satisfied
|
|
-- This design is to allow the user to use lua asserts in the callback
|
|
-- (or even callback the registered assertion accept as argument), like the example;
|
|
-- and for has_no/not_all assertions, we can construct an error message for it like:
|
|
-- "we don't expect that: has header foo"
|
|
-- @example:
|
|
-- http_mock.register_assert("req_has_header", function(mock, name)
|
|
-- assert.same(name, session.req.headers[name])
|
|
-- return "has header " .. name
|
|
-- end)
|
|
-- mock.eventually:has_req_has_header("foo")
|
|
-- mock.eventually:has_no_req_has_header("bar")
|
|
-- mock.eventually:all_req_has_header("baz")
|
|
-- mock.eventually:not_all_req_has_header("bar")
|
|
http_mock.register_assert = register_assert
|
|
|
|
return http_mock
|