kong/spec/02-integration/05-proxy/04-plugins_triggering_spec.lua (962 lines of code) (raw):
local helpers = require "spec.helpers"
local utils = require "kong.tools.utils"
local cjson = require "cjson"
local pl_path = require "pl.path"
local pl_file = require "pl.file"
local LOG_WAIT_TIMEOUT = 10
local TEST_CONF = helpers.test_conf
local function find_log_line(FILE_LOG_PATH, uuid, custom_check)
if pl_path.exists(FILE_LOG_PATH) and pl_path.getsize(FILE_LOG_PATH) > 0 then
local f = assert(io.open(FILE_LOG_PATH, "r"))
local line = f:read("*line")
while line do
local log_message = assert(cjson.decode(line))
if log_message.client_ip == "127.0.0.1" then
if uuid and log_message.request.headers["x-uuid"] ~= uuid then
goto continue
end
if custom_check and not custom_check(log_message) then
goto continue
end
-- found
f:close()
return log_message
end
::continue::
line = f:read("*line")
end
f:close()
end
return false
end
local function wait_for_log_line(FILE_LOG_PATH, uuid, custom_check)
helpers.wait_until(function()
return find_log_line(FILE_LOG_PATH, uuid, custom_check)
end, LOG_WAIT_TIMEOUT)
end
for _, strategy in helpers.each_strategy() do
describe("Plugins triggering [#" .. strategy .. "]", function()
local proxy_client
local db
local bp
lazy_setup(function()
bp, db = helpers.get_db_utils(strategy, {
"routes",
"services",
"plugins",
"consumers",
"keyauth_credentials",
}, {
"error-handler-log",
"short-circuit",
"error-generator",
})
db:truncate("ratelimiting_metrics")
local consumer1 = bp.consumers:insert {
username = "consumer1"
}
bp.keyauth_credentials:insert {
key = "secret1",
consumer = { id = consumer1.id },
}
local consumer2 = bp.consumers:insert {
username = "consumer2"
}
bp.keyauth_credentials:insert {
key = "secret2",
consumer = { id = consumer2.id },
}
local consumer3 = bp.consumers:insert {
username = "anonymous"
}
-- Global configuration
local service1 = bp.services:insert {
name = "global1",
}
bp.routes:insert {
hosts = { "global1.com" },
protocols = { "http" },
service = service1,
}
bp.plugins:insert {
name = "key-auth",
config = {},
}
bp.plugins:insert {
name = "rate-limiting",
config = {
policy = "local",
hour = 1,
},
}
-- API Specific Configuration
local service2 = bp.services:insert {
name = "api1",
}
local route1 = bp.routes:insert {
hosts = { "api1.com" },
protocols = { "http" },
service = service2,
}
bp.plugins:insert {
name = "rate-limiting",
route = { id = route1.id },
service = { id = service2.id },
config = {
policy = "local",
hour = 2,
},
}
-- Consumer Specific Configuration
bp.plugins:insert {
name = "rate-limiting",
consumer = { id = consumer2.id },
config = {
policy = "local",
hour = 3,
},
}
-- API and Consumer Configuration
local service3 = bp.services:insert {
name = "api2",
}
local route2 = bp.routes:insert {
hosts = { "api2.com" },
protocols = { "http" },
service = service3,
}
bp.plugins:insert {
name = "rate-limiting",
route = { id = route2.id },
consumer = { id = consumer2.id },
config = {
policy = "local",
hour = 4,
},
}
-- API with anonymous configuration
local service4 = bp.services:insert {
name = "api3",
}
local route3 = bp.routes:insert {
hosts = { "api3.com" },
protocols = { "http" },
service = service4,
}
bp.plugins:insert {
name = "key-auth",
config = {
anonymous = consumer3.id,
},
route = { id = route3.id },
service = { id = service4.id },
}
bp.plugins:insert {
name = "rate-limiting",
route = { id = route3.id },
service = { id = service4.id },
consumer = { id = consumer3.id },
config = {
policy = "local",
hour = 5,
}
}
local service_error = bp.services:insert {
name = "service-error",
}
bp.routes:insert {
hosts = { "service-error.test" },
protocols = { "http" },
service = service_error,
}
bp.plugins:insert {
name = "error-generator",
service = { id = service_error.id },
config = {
access = true,
}
}
bp.plugins:insert {
name = "error-handler-log",
service = { id = service_error.id },
config = {},
}
assert(helpers.start_kong({
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
}))
proxy_client = helpers.proxy_client()
end)
lazy_teardown(function()
if proxy_client then proxy_client:close() end
helpers.stop_kong(nil, true)
end)
it("checks global configuration without credentials", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = { Host = "global1.com" }
})
assert.res_status(401, res)
end)
it("checks global api configuration", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200?apikey=secret1",
headers = { Host = "global1.com" }
})
assert.res_status(200, res)
assert.equal("1", res.headers["x-ratelimit-limit-hour"])
end)
it("checks api specific configuration", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200?apikey=secret1",
headers = { Host = "api1.com" }
})
assert.res_status(200, res)
assert.equal("2", res.headers["x-ratelimit-limit-hour"])
end)
it("checks global consumer configuration", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200?apikey=secret2",
headers = { Host = "global1.com" }
})
assert.res_status(200, res)
assert.equal("3", res.headers["x-ratelimit-limit-hour"])
end)
it("checks consumer specific configuration", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200?apikey=secret2",
headers = { Host = "api2.com" }
})
assert.res_status(200, res)
assert.equal("4", res.headers["x-ratelimit-limit-hour"])
end)
it("checks anonymous consumer specific configuration", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = { Host = "api3.com" }
})
assert.res_status(200, res)
assert.equal("5", res.headers["x-ratelimit-limit-hour"])
end)
it("builds complete plugins iterator even when plugin errors", function()
local res = proxy_client:get("/status/200", {
headers = {
Host = "service-error.test",
}
})
assert.res_status(500, res)
assert.equal("header_filter", res.headers["Log-Plugin-Phases"])
end)
describe("short-circuited requests", function()
local FILE_LOG_PATH = os.tmpname()
lazy_setup(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong(nil, true)
db:truncate("routes")
db:truncate("services")
db:truncate("consumers")
db:truncate("plugins")
db:truncate("keyauth_credentials")
do
local service = bp.services:insert {
name = "example",
host = helpers.mock_upstream_host,
port = helpers.mock_upstream_port,
}
local route = assert(bp.routes:insert {
hosts = { "mock_upstream" },
protocols = { "http" },
service = service,
})
-- plugin able to short-circuit a request
assert(bp.plugins:insert {
name = "key-auth",
route = { id = route.id },
})
-- response/body filter plugin
assert(bp.plugins:insert {
name = "dummy",
route = { id = route.id },
config = {
append_body = "appended from body filtering",
}
})
-- log phase plugin
assert(bp.plugins:insert {
name = "file-log",
route = { id = route.id },
config = {
path = FILE_LOG_PATH,
},
})
end
do
local service = bp.services:insert {
name = "example_err",
host = helpers.mock_upstream_host,
port = helpers.mock_upstream_port,
}
-- route that will produce an error
local route = assert(bp.routes:insert {
hosts = { "mock_upstream_err" },
protocols = { "http" },
service = service,
})
-- plugin that produces an error
assert(bp.plugins:insert {
name = "dummy",
route = { id = route.id },
config = {
append_body = "obtained even with error",
}
})
-- log phase plugin
assert(bp.plugins:insert {
name = "file-log",
route = { id = route.id },
config = {
path = FILE_LOG_PATH,
},
})
end
assert(helpers.start_kong {
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
})
proxy_client = helpers.proxy_client()
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
os.remove(FILE_LOG_PATH)
helpers.stop_kong(nil, true)
end)
before_each(function()
os.execute("echo -n '' > " .. FILE_LOG_PATH)
os.execute("chmod 0777 " .. FILE_LOG_PATH)
end)
it("execute a log plugin", function()
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "mock_upstream",
["X-UUID"] = uuid,
-- /!\ no key credential
}
})
assert.res_status(401, res)
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, uuid)
end)
it("execute a header_filter plugin", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "mock_upstream",
}
})
assert.res_status(401, res)
-- TEST: ensure that the dummy plugin was executed by checking
-- that headers have been injected in the header_filter phase
-- Plugins such as CORS need to run on short-circuited requests
-- as well.
assert.not_nil(res.headers["dummy-plugin"])
end)
it("execute a body_filter plugin", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "mock_upstream",
}
})
local body = assert.res_status(401, res)
-- TEST: ensure that the dummy plugin was executed by checking
-- that the body filtering phase has run
assert.matches("appended from body filtering", body, nil, true)
end)
-- regression test for bug spotted in 0.12.0rc2
it("responses.send stops plugin but runloop continues", function()
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200?send_error=1",
headers = {
["Host"] = "mock_upstream_err",
["X-UUID"] = uuid,
}
})
local body = assert.res_status(404, res)
-- TEST: ensure that the dummy plugin stopped running after
-- running responses.send
assert.not_equal("dummy", res.headers["dummy-plugin-access-header"])
-- ...but ensure that further phases are still executed
-- header_filter phase of same plugin
assert.matches("obtained even with error", body, nil, true)
-- access phase got a chance to inject the logging plugin
wait_for_log_line(FILE_LOG_PATH, uuid)
end)
end)
describe("anonymous reports execution", function()
-- anonymous reports are implemented as a plugin which is being executed
-- by the plugins runloop, but which doesn't have a schema
--
-- This is a regression test after:
-- https://github.com/Kong/kong/issues/2756
-- to ensure that this plugin plays well when it is being executed by
-- the runloop (which accesses plugins schemas and is vulnerable to
-- Lua indexing errors)
--
-- At the time of this test, the issue only arises when a request is
-- authenticated via an auth plugin, and the runloop runs again, and
-- tries to evaluate is the `schema.no_consumer` flag is set.
-- Since the reports plugin has no `schema`, this indexing fails.
lazy_setup(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong(nil, true)
db:truncate("routes")
db:truncate("services")
db:truncate("consumers")
db:truncate("plugins")
db:truncate("keyauth_credentials")
local service = bp.services:insert {
name = "example",
}
local route = bp.routes:insert {
hosts = { "mock_upstream" },
protocols = { "http" },
service = service,
}
bp.plugins:insert {
name = "key-auth",
route = { id = route.id },
service = { id = service.id },
}
local consumer = bp.consumers:insert {
username = "bob",
}
bp.keyauth_credentials:insert {
key = "abcd",
consumer = { id = consumer.id },
}
assert(helpers.start_kong {
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
--anonymous_reports = true,
})
proxy_client = helpers.proxy_client()
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong(nil, true)
end)
it("runs without causing an internal error", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "mock_upstream",
},
})
assert.res_status(401, res)
res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "mock_upstream",
["apikey"] = "abcd",
},
})
assert.res_status(200, res)
end)
end)
describe("proxy-intercepted error", function()
local FILE_LOG_PATH = os.tmpname()
lazy_setup(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong()
db:truncate("routes")
db:truncate("services")
db:truncate("consumers")
db:truncate("plugins")
db:truncate("keyauth_credentials")
do
-- service to mock HTTP 502
local mock_service = bp.services:insert {
name = "conn_refused",
host = "127.0.0.2",
port = 26865,
}
bp.routes:insert {
hosts = { "refused" },
protocols = { "http" },
service = mock_service,
}
bp.plugins:insert {
name = "file-log",
service = { id = mock_service.id },
config = {
path = FILE_LOG_PATH,
reopen = true,
}
}
end
do
-- service to mock HTTP 503
local mock_service = bp.services:insert {
name = "unavailable",
}
bp.routes:insert {
hosts = { "unavailable" },
protocols = { "http" },
service = mock_service,
}
bp.plugins:insert {
name = "file-log",
service = { id = mock_service.id },
config = {
path = FILE_LOG_PATH,
reopen = true,
}
}
end
do
-- service to mock HTTP 504
local blackhole_service = bp.services:insert {
name = "timeout",
host = helpers.blackhole_host,
connect_timeout = 1, -- ms
}
bp.routes:insert {
hosts = { "connect_timeout" },
protocols = { "http" },
service = blackhole_service,
}
bp.plugins:insert {
name = "file-log",
service = { id = blackhole_service.id },
config = {
path = FILE_LOG_PATH,
reopen = true,
}
}
end
do
-- plugin to mock runtime exception
local mock_one_fn = [[
local nilValue = nil
kong.log.info('test' .. nilValue)
]]
local mock_two_fn = [[
ngx.header['X-Source'] = kong.response.get_source()
]]
local mock_service = bp.services:insert {
name = "runtime_exception",
}
bp.routes:insert {
hosts = { "runtime_exception" },
protocols = { "http" },
service = mock_service,
}
bp.plugins:insert {
name = "pre-function",
service = { id = mock_service.id },
config = {
["access"] = { mock_one_fn },
["header_filter"] = { mock_two_fn },
},
}
end
do
-- global plugin to catch Nginx-produced client errors
bp.plugins:insert {
name = "file-log",
config = {
path = FILE_LOG_PATH,
reopen = true,
}
}
bp.plugins:insert {
name = "error-handler-log",
config = {},
}
end
-- start Kong instance with our services and plugins
assert(helpers.start_kong {
database = strategy,
-- /!\ test with real nginx config
})
-- start mock httpbin instance
assert(helpers.start_kong {
database = strategy,
admin_listen = "127.0.0.1:9011",
proxy_listen = "127.0.0.1:9010",
proxy_listen_ssl = "127.0.0.1:9453",
admin_listen_ssl = "127.0.0.1:9454",
prefix = "servroot2",
nginx_conf = "spec/fixtures/custom_nginx.template",
})
end)
lazy_teardown(function()
helpers.stop_kong("servroot2")
helpers.stop_kong(nil, true)
end)
before_each(function()
proxy_client = helpers.proxy_client()
os.execute("echo -n '' > " .. FILE_LOG_PATH)
os.execute("chmod 0777 " .. FILE_LOG_PATH)
end)
after_each(function()
pl_file.delete(FILE_LOG_PATH)
if proxy_client then
proxy_client:close()
end
end)
it("executes a log plugin on Bad Gateway (HTTP 502)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "refused",
["X-UUID"] = uuid,
}
})
assert.res_status(502, res) -- Bad Gateway
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, uuid)
end)
it("log plugins sees same request in error_page handler (HTTP 502)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "POST",
path = "/status/200?foo=bar",
headers = {
["Host"] = "refused",
["X-UUID"] = uuid,
},
--[[ file-log plugin does not log request body
body = {
hello = "world",
}
--]]
})
assert.res_status(502, res) -- Bad Gateway
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, uuid, function(log_message)
return "refused" == log_message.request.headers.host
and "POST" == log_message.request.method
and "bar" == log_message.request.querystring.foo
and "/status/200?foo=bar" == log_message.upstream_uri
end)
end)
it("executes a log plugin on Service Unavailable (HTTP 503)", function()
-- Does not trigger error_page directive (no proxy_intercept_errors)
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/503",
headers = {
["Host"] = "unavailable",
["X-UUID"] = uuid,
}
})
assert.res_status(503, res) -- Service Unavailable
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, uuid)
end)
it("executes a log plugin on Gateway Timeout (HTTP 504)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "connect_timeout",
["X-UUID"] = uuid,
}
})
assert.res_status(504, res) -- Gateway Timeout
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, uuid)
end)
it("log plugins sees same request in error_page handler (HTTP 504)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "POST",
path = "/status/200?foo=bar",
headers = {
["Host"] = "connect_timeout",
["X-UUID"] = uuid,
},
--[[ file-log plugin does not log request body
body = {
hello = "world",
}
--]]
})
assert.res_status(504, res) -- Gateway Timeout
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, uuid, function(log_message)
return "connect_timeout" == log_message.request.headers.host
and "POST" == log_message.request.method
and "bar" == log_message.request.querystring.foo
and "/status/200?foo=bar" == log_message.upstream_uri
end)
end)
it("executes a global log plugin on Nginx-produced client errors (HTTP 400)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/",
headers = {
["Host"] = "unavailable",
["X-Large"] = string.rep("a", 2^10 * 10), -- default large_client_header_buffers is 8k
["X-UUID"] = uuid,
}
})
assert.res_status(400, res)
-- close and reopen to flush the request
proxy_client:close()
proxy_client = helpers.proxy_client()
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, nil, function(log_message)
return 400 == log_message.response.status
end)
end)
it("log plugins sees same request in error_page handler (HTTP 400)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "POST",
path = "/status/200?foo=bar",
headers = {
["Host"] = "unavailable",
["X-Large"] = string.rep("a", 2^10 * 10), -- default large_client_header_buffers is 8k
["X-UUID"] = uuid,
},
--[[ file-log plugin does not log request body
body = {
hello = "world",
}
--]]
})
assert.res_status(400, res)
-- close and reopen to flush the request
proxy_client:close()
proxy_client = helpers.proxy_client()
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, nil, function(log_message)
return "POST" == log_message.request.method
and "bar" == log_message.request.querystring.foo
and "" == log_message.upstream_uri -- no URI here since Nginx could not parse request
end)
end)
it("executes a global log plugin on Nginx-produced client errors (HTTP 414)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "GET",
path = "/?foo=" .. string.rep("a", 2^10 * 10),
headers = {
["Host"] = "unavailable",
["X-UUID"] = uuid,
}
})
assert.res_status(414, res)
-- close and reopen to flush the request
proxy_client:close()
proxy_client = helpers.proxy_client()
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, nil, function(log_message)
return #log_message.request.headers == 0
and 414 == log_message.response.status
end)
end)
it("log plugins sees same request in error_page handler (HTTP 414)", function()
-- triggers error_page directive
local uuid = utils.uuid()
local res = assert(proxy_client:send {
method = "POST",
path = "/?foo=" .. string.rep("a", 2^10 * 10),
headers = {
["Host"] = "unavailable",
["X-UUID"] = uuid,
},
--[[ file-log plugin does not log request body
body = {
hello = "world",
}
--]]
})
assert.res_status(414, res)
-- close and reopen to flush the request
proxy_client:close()
proxy_client = helpers.proxy_client()
-- TEST: ensure that our logging plugin was executed and wrote
-- something to disk.
wait_for_log_line(FILE_LOG_PATH, nil, function(log_message)
return "POST" == log_message.request.method
and "" == log_message.upstream_uri -- no URI here since Nginx could not parse request
and nil == log_message.request.headers["x-uuid"] -- none since Nginx could not parse request
and nil == log_message.request.headers.host -- none as well
end)
end)
it("executes plugins header_filter/body_filter on Nginx-produced client errors (HTTP 4xx)", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/?foo=" .. string.rep("a", 2^10 * 10),
headers = {
["Host"] = "unavailable",
}
})
local body = assert.res_status(414, res)
assert.equal("header_filter", res.headers["Log-Plugin-Phases"])
assert.equal("body_filter", body)
end)
it("executes plugins header_filter/body_filter on Nginx-produced server errors (HTTP 5xx)", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "connect_timeout",
}
})
local body = assert.res_status(504, res) -- Gateway Timeout
assert.equal("rewrite,access,header_filter", res.headers["Log-Plugin-Phases"]) -- rewrite + acecss from original request handling
assert.equal("body_filter", body)
end)
it("sees ctx introspection variables on Nginx-produced server errors (HTTP 5xx)", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "connect_timeout",
}
})
assert.res_status(504, res) -- Gateway Timeout
assert.equal("timeout", res.headers["Log-Plugin-Service-Matched"])
end)
it("kong.response.get_source() returns \"error\" if plugin runtime exception occurs, FTI-3200", function()
local res = assert(proxy_client:send {
method = "GET",
path = "/status/200",
headers = {
["Host"] = "runtime_exception"
}
})
local body = assert.res_status(500, res)
assert.same("body_filter", body)
assert.equal("error", res.headers["X-Source"])
end)
end)
describe("plugin's init_worker", function()
describe("[pre-configured]", function()
lazy_setup(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong()
db:truncate("routes")
db:truncate("services")
db:truncate("plugins")
-- never used as the plugins short-circuit
local service = assert(bp.services:insert {
name = "mock-service",
host = helpers.mock_upstream_host,
port = helpers.mock_upstream_port,
})
local route = assert(bp.routes:insert {
hosts = { "runs-init-worker.org" },
protocols = { "http" },
service = service,
})
bp.plugins:insert {
name = "short-circuit",
route = { id = route.id },
config = {
status = 200,
message = "plugin executed"
},
}
assert(helpers.start_kong {
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
plugins = "short-circuit,init-worker-lua-error",
})
proxy_client = helpers.proxy_client()
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong(nil, true)
end)
it("is executed", function()
local res = assert(proxy_client:get("/status/400", {
headers = {
["Host"] = "runs-init-worker.org",
}
}))
assert.equal("true", res.headers["Kong-Init-Worker-Called"])
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.same({
status = 200,
message = "plugin executed"
}, json)
end)
it("protects against failed init_worker handler, FTI-2473", function()
local logs = pl_file.read(TEST_CONF.prefix .. "/" .. TEST_CONF.proxy_error_log)
assert.matches([[worker initialization error: failed to execute the "init_worker" handler for plugin "init-worker-lua-error"]], logs, nil, true)
end)
end)
if strategy ~= "off" then
describe("[runtime-configured]", function()
local admin_client
local route
lazy_setup(function()
if proxy_client then
proxy_client:close()
end
helpers.stop_kong()
db:truncate("routes")
db:truncate("services")
db:truncate("plugins")
-- never used as the plugins short-circuit
local service = assert(bp.services:insert {
name = "mock-service",
host = helpers.mock_upstream_host,
port = helpers.mock_upstream_port,
})
route = assert(bp.routes:insert {
hosts = { "runs-init-worker.org" },
protocols = { "http" },
service = service,
})
assert(helpers.start_kong {
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
})
proxy_client = helpers.proxy_client()
admin_client = helpers.admin_client()
end)
lazy_teardown(function()
if proxy_client then
proxy_client:close()
end
if admin_client then
admin_client:close()
end
helpers.stop_kong(nil, true)
end)
it("is executed", function()
local res = assert(admin_client:post("/plugins", {
headers = {
["Content-Type"] = "application/json"
},
body = {
name = "short-circuit",
route = { id = route.id },
config = {
status = 200,
message = "plugin executed"
},
}
}))
assert.res_status(201, res)
local res, body
helpers.wait_until(function()
res = assert(proxy_client:get("/status/400", {
headers = {
["Host"] = "runs-init-worker.org",
}
}))
return pcall(function()
body = assert.res_status(200, res)
assert.equal("true", res.headers["Kong-Init-Worker-Called"])
end)
end, 10)
local json = cjson.decode(body)
assert.same({
status = 200,
message = "plugin executed"
}, json)
end)
end)
end
end)
end)
describe("Plugins triggering [#" .. strategy .. "] with TLS keepalive", function()
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services",
"plugins",
})
-- Global configuration
local service = bp.services:insert {
name = "mock",
}
local route = bp.routes:insert {
paths = { "/route-1" },
protocols = { "https" },
service = service,
}
bp.routes:insert {
paths = { "/route-2" },
protocols = { "https" },
service = service,
}
bp.plugins:insert {
name = "request-termination",
route = { id = route.id },
config = {
status_code = 201,
},
}
assert(helpers.start_kong({
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
}))
end)
lazy_teardown(function()
helpers.stop_kong(nil, true)
end)
it("certificate phase clears context, fix #7054", function()
local proxy_client = helpers.proxy_ssl_client()
local res = assert(proxy_client:get("/route-1/status/200"))
assert.res_status(201, res)
local res = assert(proxy_client:get("/route-2/status/200"))
assert.res_status(200, res)
end)
end)
end