diff --git a/.busted b/.busted index 57e2f9eabc2f..706d058cbb34 100644 --- a/.busted +++ b/.busted @@ -3,5 +3,6 @@ return { lpath = "./?.lua;./?/init.lua;", -- make setup() and teardown() behave like their lazy_ variants lazy = true, + helper = "./spec/busted-ci-helper.lua", } } diff --git a/kong-3.10.0-0.rockspec b/kong-3.10.0-0.rockspec index e8eac2999739..2ba7c9e54f2c 100644 --- a/kong-3.10.0-0.rockspec +++ b/kong-3.10.0-0.rockspec @@ -155,6 +155,7 @@ build = { ["kong.cmd.utils.prefix_handler"] = "kong/cmd/utils/prefix_handler.lua", ["kong.cmd.utils.process_secrets"] = "kong/cmd/utils/process_secrets.lua", ["kong.cmd.utils.inject_confs"] = "kong/cmd/utils/inject_confs.lua", + ["kong.cmd.utils.timer"] = "kong/cmd/utils/timer.lua", ["kong.api"] = "kong/api/init.lua", ["kong.api.api_helpers"] = "kong/api/api_helpers.lua", diff --git a/kong/cmd/init.lua b/kong/cmd/init.lua index 609d8c6f6cfc..28fe22416348 100644 --- a/kong/cmd/init.lua +++ b/kong/cmd/init.lua @@ -4,13 +4,7 @@ math.randomseed() -- Generate PRNG seed local pl_app = require "pl.lapp" local log = require "kong.cmd.utils.log" - -local function stop_timers() - -- shutdown lua-resty-timer-ng to allow the nginx worker to stop quickly - if _G.timerng then - _G.timerng:destroy() - end -end +local timer = require "kong.cmd.utils.timer" return function(cmd_name, args) local cmd = require("kong.cmd." .. cmd_name) @@ -42,5 +36,6 @@ return function(cmd_name, args) pl_app.quit(nil, true) end) - stop_timers() + -- shutdown lua-resty-timer-ng to allow the nginx worker to stop quickly + timer.shutdown() end diff --git a/kong/cmd/utils/timer.lua b/kong/cmd/utils/timer.lua new file mode 100644 index 000000000000..511bbaf4cc37 --- /dev/null +++ b/kong/cmd/utils/timer.lua @@ -0,0 +1,18 @@ +local _M = {} + +function _M.shutdown() + if _G.timerng then + pcall(_G.timerng.destroy, _G.timerng) + end + + -- kong.init_worker() stashes the timerng instance within the kong global and + -- removes the _G.timerng reference, so check there too + if _G.kong and _G.kong.timer and _G.kong.timer ~= _G.timerng then + pcall(_G.kong.timer.destroy, _G.kong.timer) + _G.kong.timer = nil + end + + _G.timerng = nil +end + +return _M diff --git a/spec/busted-ci-helper.lua b/spec/busted-ci-helper.lua index 1e9526a81179..2260138b890d 100644 --- a/spec/busted-ci-helper.lua +++ b/spec/busted-ci-helper.lua @@ -1,43 +1,55 @@ -- busted-ci-helper.lua +local busted = require 'busted' +do + local shutdown_timers = require("kong.cmd.utils.timer").shutdown + assert(type(shutdown_timers) == "function") --- needed before requiring 'socket.unix' -require 'socket' + -- shutdown lua-resty-timer-ng to allow the nginx worker to stop quickly + busted.subscribe({ 'exit' }, function() + shutdown_timers() -local busted = require 'busted' -local cjson = require 'cjson' -local socket_unix = require 'socket.unix' + -- second return value must be `true`, or else all other callbacks for this + -- event will be skipped + return nil, true + end) +end -local busted_event_path = os.getenv("BUSTED_EVENT_PATH") +local BUSTED_EVENT_PATH = os.getenv("BUSTED_EVENT_PATH") +if BUSTED_EVENT_PATH then + -- needed before requiring 'socket.unix' + require 'socket' --- Function to recursively copy a table, skipping keys associated with functions -local function copyTable(original, copied, cache, max_depth, current_depth) - copied = copied or {} - cache = cache or {} - max_depth = max_depth or 5 - current_depth = current_depth or 1 + local cjson = require 'cjson' + local socket_unix = require 'socket.unix' - if cache[original] then return cache[original] end - cache[original] = copied + -- Function to recursively copy a table, skipping keys associated with functions + local function copyTable(original, copied, cache, max_depth, current_depth) + copied = copied or {} + cache = cache or {} + max_depth = max_depth or 5 + current_depth = current_depth or 1 - for key, value in pairs(original) do - if type(value) == "table" then - if current_depth < max_depth then - copied[key] = copyTable(value, {}, cache, max_depth, current_depth + 1) + if cache[original] then return cache[original] end + cache[original] = copied + + for key, value in pairs(original) do + if type(value) == "table" then + if current_depth < max_depth then + copied[key] = copyTable(value, {}, cache, max_depth, current_depth + 1) + end + elseif type(value) == "userdata" then + copied[key] = tostring(value) + elseif type(value) ~= "function" then + copied[key] = value end - elseif type(value) == "userdata" then - copied[key] = tostring(value) - elseif type(value) ~= "function" then - copied[key] = value end - end - return copied -end + return copied + end -if busted_event_path then local sock = assert(socket_unix()) - assert(sock:connect(busted_event_path)) + assert(sock:connect(BUSTED_EVENT_PATH)) local events = {{ 'suite', 'reset' }, { 'suite', 'start' }, @@ -51,6 +63,7 @@ if busted_event_path then { 'error', 'it' }, { 'failure' }, { 'error' }} + for _, event in ipairs(events) do busted.subscribe(event, function (...) local args = {}