Skip to content

Commit

Permalink
Share the tcp server between test cases in a test file.
Browse files Browse the repository at this point in the history
Before this change, the 11-reports_spec.lua runtime is about 40
seconds. After this change, the runtime is 2.6 seconds. The current
mainline runtime is 0.5 seconds.
  • Loading branch information
zhongweiy committed Dec 15, 2023
1 parent 6fb21d5 commit 0c2378e
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 108 deletions.
31 changes: 15 additions & 16 deletions spec/01-unit/11-reports_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@ local cjson = require "cjson"

describe("reports", function()
local reports, bytes, err
local port = 8189
local expected_data = "version"
local port = 8189

setup(function()
helpers.start_echo_server(port)
end)

teardown(function()
helpers.stop_echo_server()
end)

before_each(function()
package.loaded["kong.reports"] = nil
reports = require "kong.reports"
Expand Down Expand Up @@ -43,8 +52,6 @@ describe("reports", function()
end)

it("sends report over TCP[TLS]", function()
local _, svr_dir = helpers.start_echo_server(port)

bytes, err = reports.send("stub", {
hello = "world",
foo = "bar",
Expand All @@ -57,8 +64,7 @@ describe("reports", function()
assert.truthy(bytes>0)
assert.is_nil(err)

local res = helpers.get_echo_server_received_data(svr_dir, expected_data)
helpers.stop_kong(svr_dir)
local res = helpers.get_echo_server_received_data(expected_data)

assert.matches("^<14>", res)
res = res:sub(5)
Expand All @@ -77,33 +83,29 @@ describe("reports", function()

it("doesn't send if not enabled", function()
reports.toggle(false)
local _, svr_dir = helpers.start_echo_server(port)

bytes, err = reports.send({
foo = "bar"
}, "127.0.0.1", port)
assert.is_nil(bytes)
assert.equal(err, "disabled")

local res = helpers.get_echo_server_received_data(svr_dir, expected_data, 0.1)
helpers.stop_kong(svr_dir)
local res = helpers.get_echo_server_received_data(expected_data, 0.1)
assert.equal("timeout", res)
end)

it("accepts custom immutable items", function()
reports.toggle(true)

local _, svr_dir = helpers.start_echo_server(port)

reports.add_immutable_value("imm1", "fooval")
reports.add_immutable_value("imm2", "barval")

bytes, err = reports.send("stub", {k1 = "bazval"}, "127.0.0.1", port)
assert.truthy(bytes > 0)
assert.is_nil(err)

local res = helpers.get_echo_server_received_data(svr_dir, expected_data)
helpers.stop_kong(svr_dir)
local res = helpers.get_echo_server_received_data(expected_data)

assert.matches("imm1=fooval", res)
assert.matches("imm2=barval", res)
assert.matches("k1=bazval", res)
Expand All @@ -114,11 +116,8 @@ describe("reports", function()
local conf_loader = require "kong.conf_loader"
local function send_reports_and_check_result(reports, conf, port, matches)
reports.configure_ping(conf)
local _, svr_dir = helpers.start_echo_server(port)

reports.send_ping("127.0.0.1", port)
local res = helpers.get_echo_server_received_data(svr_dir, expected_data)
helpers.stop_kong(svr_dir)
local res = helpers.get_echo_server_received_data(expected_data)

for _,m in ipairs(matches) do
assert.matches(m, res, nil, true)
Expand Down
203 changes: 111 additions & 92 deletions spec/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3793,108 +3793,126 @@ local function reload_kong(strategy, ...)
return ok, err
end

--- Run an echo TCP server.
--
-- @function start_echo_server
-- @param port the port to run the server.
-- @return the server running directory.
local function start_echo_server(port)
local test_port = 15383
local conf_template = [[
server {
listen localhost:%s ssl;
listen localhost:%s;
ssl_certificate ../spec/fixtures/kong_spec.crt;
ssl_certificate_key ../spec/fixtures/kong_spec.key;
error_log logs/error.log info;
content_by_lua_block {
local sock = assert(ngx.req.socket())
local data = sock:receive() -- read a line from downstream
if data then
sock:send(data.."\n") -- echo whatever was sent
ngx.log(ngx.INFO, "received data: " .. data)
else
ngx.log(ngx.WARN, "Nothing received")
end
}
}
]]
local conf = string.format(conf_template, port, test_port)
local fixtures = { stream_mock = { conf } }
local start_echo_server, get_echo_server_received_data, stop_echo_server
do
-- Message id is maintained within echo server context and not
-- needed for echo server user.
-- This id is extracted from the number in nginx error.log at each
-- line of log. i.e.:
-- 2023/12/15 14:10:12 [info] 718291#0: *303 stream [lua] content_by_lua ...
-- in above case, the id is 303.
local msg_id = -1
local server_dir = "servroot_tcp_echo"

assert(start_kong({
nginx_conf = "spec/fixtures/custom_nginx.template",
-- we don't actually use any stream proxy features in tcp_server,
-- but this is needed in order to load above stream_mock fixture.
stream_listen = get_proxy_ip(false) .. ":19000",
prefix = server_dir,
-- to fix "Database needs bootstrapping or is older than Kong 1.0" in CI.
database = "off",
log_level = "info",
}, nil, nil, fixtures))

-- ensure server is ready.
local sock = ngx.socket.tcp()
sock:settimeout(0.1)
local retry = 0
while true do
if sock:connect("localhost", test_port) then
sock:send("START\n")
local ok = sock:receive()
sock:close()
if ok == "START" then
return true, server_dir
end
else
retry = retry + 1
if retry > 10 then
assert(nil, "can not create server after "..retry.." retries")
--- Run an echo TCP server.
--
-- @function start_echo_server
-- @param port the port to run the server.
-- @return the server running directory.
function start_echo_server(port)
local test_port = 15383
local conf_template = [[
server {
listen localhost:%s ssl;
listen localhost:%s;
ssl_certificate ../spec/fixtures/kong_spec.crt;
ssl_certificate_key ../spec/fixtures/kong_spec.key;
error_log logs/error.log info;
content_by_lua_block {
local sock = assert(ngx.req.socket())
local data = sock:receive() -- read a line from downstream
if data then
sock:send(data.."\n") -- echo whatever was sent
ngx.log(ngx.INFO, "received data: " .. data)
else
ngx.log(ngx.WARN, "Nothing received")
end
}
}
]]
local conf = string.format(conf_template, port, test_port)
local fixtures = { stream_mock = { conf } }

assert(start_kong({
nginx_conf = "spec/fixtures/custom_nginx.template",
-- we don't actually use any stream proxy features in tcp_server,
-- but this is needed in order to load above stream_mock fixture.
stream_listen = get_proxy_ip(false) .. ":19000",
prefix = server_dir,
-- to fix "Database needs bootstrapping or is older than Kong 1.0" in CI.
database = "off",
log_level = "info",
}, nil, nil, fixtures))

-- ensure server is ready.
local sock = ngx.socket.tcp()
sock:settimeout(0.1)
local retry = 0
while true do
if sock:connect("localhost", test_port) then
sock:send("START\n")
local ok = sock:receive()
sock:close()
if ok == "START" then
return true
end
else
retry = retry + 1
if retry > 10 then
assert(nil, "can not create server after "..retry.." retries")
end
end
end
end
end

--- Get the echo server's received data.
-- This function check the part of expected data with a timeout.
--
-- @function get_echo_server_received_data
-- @param server_dir the running server directory.
-- @param expected part of the data expected.
-- @param timeout (optional) timeout in seconds, default is 0.5.
-- @return the data the echo server received. If timeouts, return "timeout".
local function get_echo_server_received_data(server_dir, expected, timeout)
if timeout == nil then
timeout = 0.5
end

local extract_cmd = "grep content_by_lua "..server_dir.."/logs/error.log | tail -1"
local ok, _, log = exec(extract_cmd)
assert(ok)
local pattern = "received data: " .. "(.*)"
local _, _, data = string.find(log, pattern)
-- unit is second.
local t = 0.1
local time_acc = 0

-- retry it when data is not available. because sometime,
-- the error.log has not been flushed yet.
while string.find(data, expected) == nil do
ngx.sleep(t)
time_acc = time_acc + t
if time_acc >= timeout then
return "timeout"
--- Get the echo server's received data.
-- This function check the part of expected data with a timeout.
--
-- @function get_echo_server_received_data
-- @param expected part of the data expected.
-- @param timeout (optional) timeout in seconds, default is 0.5.
-- @return the data the echo server received. If timeouts, return "timeout".
function get_echo_server_received_data(expected, timeout)
if timeout == nil then
timeout = 0.5
end

ok, _, log = exec(extract_cmd)
assert(ok)
_, _, data = string.find(log, pattern)
local extract_cmd = "grep content_by_lua "..server_dir.."/logs/error.log | tail -1"
local _, _, log = assert(exec(extract_cmd))
local pattern = "%*(%d+)%s.*received data: (.*)"
local cur_msg_id, data = string.match(log, pattern)

-- unit is second.
local t = 0.1
local time_acc = 0

-- retry it when data is not available. because sometime,
-- the error.log has not been flushed yet.
while string.find(data, expected) == nil or cur_msg_id == msg_id do
ngx.sleep(t)
time_acc = time_acc + t
if time_acc >= timeout then
return "timeout"
end

_, _, log = assert(exec(extract_cmd))
cur_msg_id, data = string.match(log, pattern)
end

-- update the msg_id, it persists during a cycle from echo server
-- start to stop.
msg_id = cur_msg_id

return data
end

return data
function stop_echo_server()
stop_kong(server_dir)
msg_id = -1
end
end

--- Simulate a Hybrid mode DP and connect to the CP specified in `opts`.
Expand Down Expand Up @@ -4134,6 +4152,7 @@ end
udp_server = udp_server,
kill_tcp_server = kill_tcp_server,
start_echo_server = start_echo_server,
stop_echo_server = stop_echo_server,
get_echo_server_received_data = get_echo_server_received_data,
http_mock = http_mock,
get_proxy_ip = get_proxy_ip,
Expand Down

0 comments on commit 0c2378e

Please sign in to comment.