Skip to content

Commit

Permalink
tests(request-aware-table): integration
Browse files Browse the repository at this point in the history
  • Loading branch information
samugi committed Aug 31, 2023
1 parent b2afb5d commit a977031
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 107 deletions.
110 changes: 3 additions & 107 deletions spec/01-unit/28-request-aware-table_spec.lua
Original file line number Diff line number Diff line change
@@ -1,39 +1,7 @@
local utils = require "kong.tools.utils"
local tablex = require "pl.tablex"

local rat

local function assert_rw_allowed(tab, orig_t)
for k, v in pairs(orig_t or {}) do
-- reads from orig_t succeed
local val = assert.has_no.errors(function() return tab[k] end)
assert.equal(v, val)
end

local k = utils.random_string()
local v = utils.random_string()
-- writing new values succeeds
assert.has_no.errors(function() tab[k] = v end)
-- reading new values succeeds
local val = assert.has_no.errors(function() return tab[k] end)
assert.equal(v, val)
end

local function assert_rw_denied(tab, orig_t)
local err_str = "race condition detected"
for k, v in pairs(orig_t or {}) do
-- reads from orig_t error out
assert.error_matches(function() return nil, tab[k] == v end, err_str)
end

local k = utils.random_string()
local v = utils.random_string()
-- writing new values errors out
assert.error_matches(function() tab[k] = v end, err_str)
-- reading new values errors out
assert.error_matches(function() return tab[k] == v end, err_str)
end

describe("Request aware table", function()
local old_ngx
local tab
Expand All @@ -52,51 +20,16 @@ describe("Request aware table", function()
end)

describe("with concurrency check enabled", function()
local orig_t
local orig_t = {}

before_each(function()
orig_t = {
k1 = utils.random_string(),
k2 = utils.random_string(),
}
tab = rat.new(orig_t, "on")
end)

it("allows access when there are no race conditions", function()
-- create a new RAT with request_id = 1 (clear after use)
_G.ngx.var.request_id = "1"
assert_rw_allowed(tab, orig_t)
tab.clear()

-- reuse RAT with different request_id (allowed)
_G.ngx.var.request_id = "2"
assert_rw_allowed(tab)
end)

it("denies access when there are race conditions", function()
-- create a new RAT with request_id = 1 (no clear)
_G.ngx.var.request_id = "1"
assert_rw_allowed(tab, orig_t)

-- reuse RAT with different request_id (not allowed)
_G.ngx.var.request_id = "2"
assert_rw_denied(tab)
end)

it("clears the table successfully", function()
-- create a new RAT with request_id = 1 (clear after use)
_G.ngx.var.request_id = "1"
assert_rw_allowed(tab, orig_t)
tab.clear()

assert.same(0, tablex.size(orig_t))
end)

it("allows defining a custom clear function", function()
-- create a new RAT with request_id = 1 (clear after use)
_G.ngx.var.request_id = "1"
orig_t.persist = "persistent_value"
assert_rw_allowed(tab, orig_t)
orig_t.foo = "bar"
orig_t.baz = "qux"

-- custom clear function that keeps persistent_value
tab.clear(function(t)
Expand All @@ -116,41 +49,4 @@ describe("Request aware table", function()
assert.same(0, tablex.size(orig_t))
end)
end)

describe("with concurrency check disabled", function()
local orig_t

before_each(function()
orig_t = {
k1 = utils.random_string(),
k2 = utils.random_string(),
}
tab = rat.new(orig_t, "off")
end)

before_each(function()
tab.clear()
end)

it("allows access when there are no race conditions", function()
-- create a new RAT with request_id = 1 (clear after use)
_G.ngx.var.request_id = "1"
assert_rw_allowed(tab, orig_t)
tab.clear()

-- reuse RAT with different request_id (allowed)
_G.ngx.var.request_id = "2"
assert_rw_allowed(tab, orig_t)
end)

it("allows access when there are race conditions", function()
-- create a new RAT with request_id = 1, (no clear)
_G.ngx.var.request_id = "1"
assert_rw_allowed(tab, orig_t)

-- reuse RAT with different request_id (allowed with check disabled)
_G.ngx.var.request_id = "2"
assert_rw_allowed(tab, orig_t)
end)
end)
end)
121 changes: 121 additions & 0 deletions spec/02-integration/05-proxy/31-request-aware-table_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
local helpers = require "spec.helpers"


local function clear_table(client, checks)
local res = client:get("/", {
query = {
checks = checks,
clear = true,
}
})
assert.response(res).has.status(200)
assert.logfile().has.no.line("[error]", true)
end

for _, checks in ipairs({ true, false }) do
for _, strategy in helpers.each_strategy() do
describe("request aware table tests [#" .. strategy .. "] .. checks=" .. tostring(checks), function()
local client
lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"plugins",
"routes",
"services",
}, {
"request-aware-table"
})

local service = assert(bp.services:insert({
url = helpers.mock_upstream_url
}))

local route = bp.routes:insert({
service = service,
paths = { "/" }
})

bp.plugins:insert({
name = "request-aware-table",
route = { id = route.id },
})

helpers.start_kong({
database = strategy,
plugins = "bundled, request-aware-table",
nginx_conf = "spec/fixtures/custom_nginx.template",
})
end)

lazy_teardown(function()
helpers.stop_kong()
end)

before_each(function()
helpers.clean_logfile()
client = helpers.proxy_client()
clear_table(client, checks)
end)

after_each(function()
if client then
client:close()
end
end)

describe("with concurrency check enabled", function()
it("allows access when there are no race conditions", function()
local res = client:get("/", {
query = {
checks = checks,
}
})
assert.response(res).has.status(200)
assert.logfile().has.no.line("[error]", true)
end)
it("denies access when there are race conditions and checks are enabled", function()
-- access from request 1 (don't clear)
local ok, r = pcall(client.get, client, "/", {
query = {
checks = checks,
},
})
assert(ok)
assert.response(r).has.status(200)

-- access from request 2
ok, r = pcall(client.get, client, "/", {
query = {
checks = checks,
},
})
if checks then
assert(not ok)
assert.logfile().has.line("race condition detected", true)
else
assert(ok)
assert.response(r).has.status(200)
end
end)
it("allows access when table is cleared between requests", function()
-- access from request 1 (clear)
local r = client:get("/", {
query = {
checks = checks,
clear = true,
},
})
assert.response(r).has.status(200)

-- access from request 2
r = client:get("/", {
query = {
checks = checks,
},
})
assert.response(r).has.status(200)
assert.logfile().has.no.line("[error]", true)
end)
end)
end)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
local RAT = require "kong.tools.request_aware_table"

local get_phase = ngx.get_phase
local ngx = ngx
local kong = kong


local _M = {
PRIORITY = 1001,
VERSION = "1.0",
}

local checks_tab = RAT.new({}, "on")
local no_checks_tab = RAT.new({}, "off")

local function access_tables()
local query = kong.request.get_query()
local tab

if query.checks ~= "false" then
tab = checks_tab
else
tab = no_checks_tab
end

if query.clear == "true" and get_phase() == "access" then
tab.clear()
end

-- write access
tab.foo = "bar"
-- read access
ngx.log(ngx.DEBUG, "accessing to tab.foo" .. tab.foo)

if query.clear == "true" and get_phase() == "body_filter" then
tab.clear()
end
end

function _M:access(conf)
access_tables()
end

function _M:header_filter(conf)
access_tables()
end

function _M:body_filter(conf)
access_tables()
end

return _M
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
return {
name = "request-aware-table",
fields = {
{
config = {
type = "record",
fields = { }
}
}
}
}

0 comments on commit a977031

Please sign in to comment.