Files
2026-07-13 12:32:21 +08:00

340 lines
9.4 KiB
Lua

local helpers = require "spec.helpers"
local cjson = require "cjson"
local TCP_PORT = 16945
local pack = function(...) return { n = select("#", ...), ... } end
local unpack = function(t) return unpack(t, 1, t.n) end
-- @param port the port to listen on
-- @param duration the duration for which to listen and accept connections (seconds)
local function bad_tcp_server(port, duration, ...)
local threads = require "llthreads2.ex"
local thread = threads.new({
function(port, duration)
local socket = require "socket"
local expire = socket.gettime() + duration
local server = assert(socket.tcp())
local tries = 0
server:settimeout(0.1)
assert(server:setoption('reuseaddr', true))
assert(server:bind("127.0.0.1", port))
assert(server:listen())
while socket.gettime() < expire do
local client, err = server:accept()
socket.sleep(0.1)
if client then
client:close() -- we're behaving bad, do nothing, just close
tries = tries + 1
elseif err ~= "timeout" then
return nil, "error accepting tcp connection; " .. tostring(err)
end
end
server:close()
return tries
end
}, port, duration)
local result = pack(thread:start(...))
ngx.sleep(0.2) -- wait for server to start
return unpack(result)
end
for _, strategy in helpers.each_strategy() do
describe("DNS [#" .. strategy .. "]", function()
describe("retries", function()
local retries = 3
local proxy_client
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services",
})
local service = bp.services:insert {
name = "tests-retries",
port = TCP_PORT,
retries = retries,
}
bp.routes:insert {
hosts = { "retries.test" },
service = service
}
assert(helpers.start_kong{
database = strategy,
})
proxy_client = helpers.proxy_client()
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong()
end)
it("validates the number of retries", function()
-- setup a bad server
local thread = bad_tcp_server(TCP_PORT, 1)
-- make a request to it
local r = proxy_client:send {
method = "GET",
path = "/",
headers = {
host = "retries.test"
}
}
assert.response(r).has.status(502)
-- Getting back the TCP server count of the tries
local ok, tries = thread:join()
assert.True(ok)
assert.equals(retries, tries-1 ) -- the -1 is because the initial one is not a retry.
end)
end)
describe("upstream resolve failure", function()
local proxy_client
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services",
})
local service = bp.services:insert {
name = "tests-retries",
host = "nowthisdoesnotexistatall.test",
path = "/exist",
port = 80,
protocol = "http"
}
bp.routes:insert {
hosts = { "retries.test" },
protocols = { "http" },
service = service
}
assert(helpers.start_kong({
database = strategy,
}))
proxy_client = helpers.proxy_client()
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong()
end)
it("fails with 503", function()
local r = proxy_client:send {
method = "GET",
path = "/",
headers = {
host = "retries.test"
}
}
assert.response(r).has.status(503)
end)
end)
-- lua-resty-dns is used for DNS query. It will create some UDP sockets
-- during initialization. These sockets should be released after Query finish.
-- The release is done by explicitly calling a destroy method that we patch.
-- This test case is to check the UDP sockets are released after the DNS query
-- is done.
describe("udp sockets", function()
local domain_name = "www.example.test"
local address = "127.0.0.10"
local proxy_client
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services",
})
local fixtures = {
dns_mock = helpers.dns_mock.new()
}
fixtures.dns_mock:A({
name = domain_name,
address = address,
})
local service = bp.services:insert {
name = "foo",
host = domain_name,
}
bp.routes:insert {
name = "foo",
paths = { "/foo" },
service = service,
}
assert(helpers.start_kong({ database = strategy }, nil, nil, fixtures))
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
assert(helpers.stop_kong())
end)
it("release", function()
proxy_client = helpers.proxy_client()
proxy_client:send {
method = "GET",
path = "/foo",
headers = {
host = domain_name
}
}
assert.logfile().has.line("serving '".. domain_name .. "' from mocks", true, 30)
local ok, stderr, stdout = helpers.execute("netstat -n | grep 53 | grep udp | wc -l")
assert.truthy(ok, stderr)
assert.equals(0, assert(tonumber(stdout)))
end)
end)
describe("run in stream subsystem", function()
local domain_name = "www.example.test"
local address = "127.0.0.1"
local fixtures = {
dns_mock = helpers.dns_mock.new()
}
fixtures.dns_mock:A({
name = domain_name,
address = address,
})
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services",
})
local tcp_srv = bp.services:insert({
name = "tcp",
host = domain_name,
port = helpers.mock_upstream_stream_port,
protocol = "tcp",
})
bp.routes:insert {
destinations = {
{ ip = "0.0.0.0/0", port = 19000 },
},
protocols = {
"tcp",
},
service = tcp_srv,
}
assert(helpers.start_kong({
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
stream_listen = helpers.get_proxy_ip(false) .. ":19000",
log_level = "info",
}, nil, nil, fixtures))
end)
lazy_teardown(function()
helpers.stop_kong()
end)
it("resolve domain name", function()
local tcp = ngx.socket.tcp()
assert(tcp:connect(helpers.get_proxy_ip(false), 19000))
local MESSAGE = "echo, ping, pong. echo, ping, pong. echo, ping, pong.\n"
assert(tcp:send(MESSAGE))
local body = assert(tcp:receive("*a"))
assert.equal(MESSAGE, body)
tcp:close()
end)
end)
describe("dns query queue", function()
local upstream, target
local admin_client, error_log_path
if strategy ~= "off" then
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services",
"upstreams"
})
upstream = bp.upstreams:insert {name = "upstream",}
target = bp.targets:insert {
target = "127.0.0.1:8000",
upstream = { id = upstream.id },
}
assert(helpers.start_kong {
log_level = "info",
prefix = "servroot1",
database = strategy,
proxy_listen = "0.0.0.0:8000, 0.0.0.0:8443 ssl",
admin_listen = "0.0.0.0:8001",
nginx_conf = "spec/fixtures/custom_nginx.template",
})
assert(helpers.start_kong {
log_level = "info",
prefix = "servroot2",
database = strategy,
proxy_listen = "0.0.0.0:9000, 0.0.0.0:9443 ssl",
admin_listen = "0.0.0.0:9001",
})
admin_client = helpers.admin_client(nil, 8001)
error_log_path = "servroot2/logs/error.log"
end)
lazy_teardown(function ()
assert(helpers.stop_kong("servroot1"))
assert(helpers.stop_kong("servroot2"))
if admin_client then
admin_client:close()
end
end)
it("delete target", function()
local res = assert(admin_client: send {
method = "GET",
path = "/upstreams/"..upstream.name.."/targets/"..target.id
})
res = assert.status(200,res)
res = assert(cjson.decode(res))
assert.same(target.id, res.id)
res = assert(admin_client: send {
method = "DELETE",
path = "/upstreams/"..upstream.name.."/targets/"..target.id
})
assert.status(204,res)
assert.logfile(error_log_path).has.no.line
("could not stop DNS renewal for target", true, 10)
end)
end
end)
end)
end