359 lines
9.7 KiB
Lua
359 lines
9.7 KiB
Lua
local cache_warmup = require("kong.cache.warmup")
|
|
local helpers = require("spec.helpers")
|
|
|
|
|
|
|
|
local function mock_entity(db_data, entity_name, cache_key)
|
|
return {
|
|
schema = {
|
|
name = entity_name,
|
|
},
|
|
each = function()
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
return db_data[entity_name][i]
|
|
end
|
|
end,
|
|
cache_key = function(self, value)
|
|
return tostring(value[cache_key])
|
|
end
|
|
}
|
|
end
|
|
|
|
|
|
local function mock_cache(cache_table, limit)
|
|
return {
|
|
safe_set = function(self, k, v)
|
|
if limit then
|
|
local n = 0
|
|
for _, _ in pairs(cache_table) do
|
|
n = n + 1
|
|
end
|
|
if n >= limit then
|
|
return nil, "no memory"
|
|
end
|
|
end
|
|
cache_table[k] = v
|
|
return true
|
|
end,
|
|
get = function(self, k, _, fn, arg)
|
|
if cache_table[k] == nil then
|
|
cache_table[k] = fn(arg)
|
|
end
|
|
return cache_table[k]
|
|
end,
|
|
}
|
|
end
|
|
|
|
|
|
local function mock_log(logged_warnings, logged_notices)
|
|
return {
|
|
warn = function(...)
|
|
table.insert(logged_warnings, table.concat({...}))
|
|
end,
|
|
notice = function(...)
|
|
table.insert(logged_notices, table.concat({...}))
|
|
end,
|
|
}
|
|
end
|
|
|
|
|
|
describe("cache_warmup", function()
|
|
|
|
it("uses right entity cache store", function()
|
|
local store = require "kong.constants".ENTITY_CACHE_STORE
|
|
assert.equal("cache", store.consumers)
|
|
assert.equal("core_cache", store.certificates)
|
|
assert.equal("core_cache", store.services)
|
|
assert.equal("core_cache", store.routes)
|
|
assert.equal("core_cache", store.snis)
|
|
assert.equal("core_cache", store.upstreams)
|
|
assert.equal("core_cache", store.targets)
|
|
assert.equal("core_cache", store.plugins)
|
|
assert.equal("cache", store.tags)
|
|
assert.equal("core_cache", store.ca_certificates)
|
|
assert.equal("cache", store.keyauth_credentials)
|
|
end)
|
|
|
|
it("caches entities", function()
|
|
local cache_table = {}
|
|
local db_data = {
|
|
["my_entity"] = {
|
|
{ aaa = 111, bbb = 222 },
|
|
{ aaa = 333, bbb = 444 },
|
|
},
|
|
["another_entity"] = {
|
|
{ xxx = 555, yyy = 666 },
|
|
{ xxx = 777, yyy = 888 },
|
|
}
|
|
}
|
|
|
|
local kong = {
|
|
db = {
|
|
my_entity = mock_entity(db_data, "my_entity", "aaa"),
|
|
another_entity = mock_entity(db_data, "another_entity", "xxx"),
|
|
},
|
|
core_cache = mock_cache(cache_table),
|
|
cache = mock_cache({}),
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
assert.truthy(cache_warmup.execute({"my_entity", "another_entity"}))
|
|
|
|
assert.same(kong.cache:get("111").bbb, 222)
|
|
assert.same(kong.cache:get("333").bbb, 444)
|
|
assert.same(kong.cache:get("555").yyy, 666)
|
|
assert.same(kong.cache:get("777").yyy, 888)
|
|
end)
|
|
|
|
it("does not cache routes", function()
|
|
local cache_table = {}
|
|
local logged_notices = {}
|
|
local db_data = {
|
|
["my_entity"] = {
|
|
{ aaa = 111, bbb = 222 },
|
|
{ aaa = 333, bbb = 444 },
|
|
},
|
|
["routes"] = {
|
|
{ xxx = 555, yyy = 666 },
|
|
{ xxx = 777, yyy = 888 },
|
|
}
|
|
}
|
|
|
|
local kong = {
|
|
db = {
|
|
my_entity = mock_entity(db_data, "my_entity", "aaa"),
|
|
routes = mock_entity(db_data, "routes", "xxx"),
|
|
},
|
|
core_cache = mock_cache(cache_table),
|
|
cache = mock_cache({}),
|
|
log = mock_log(nil, logged_notices),
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
assert.truthy(cache_warmup.execute({"my_entity", "routes"}))
|
|
|
|
assert.match("the 'routes' entity is ignored", logged_notices[1], 1, true)
|
|
|
|
assert.same(kong.cache:get("111").bbb, 222)
|
|
assert.same(kong.cache:get("333").bbb, 444)
|
|
assert.same(kong.cache:get("555", nil, function() return "nope" end), "nope")
|
|
assert.same(kong.cache:get("777", nil, function() return "nope" end), "nope")
|
|
end)
|
|
|
|
|
|
it("does not cache plugins", function()
|
|
local cache_table = {}
|
|
local logged_notices = {}
|
|
local db_data = {
|
|
["my_entity"] = {
|
|
{ aaa = 111, bbb = 222 },
|
|
{ aaa = 333, bbb = 444 },
|
|
},
|
|
["plugins"] = {
|
|
{ xxx = 555, yyy = 666 },
|
|
{ xxx = 777, yyy = 888 },
|
|
}
|
|
}
|
|
|
|
local kong = {
|
|
db = {
|
|
my_entity = mock_entity(db_data, "my_entity", "aaa"),
|
|
plugins = mock_entity(db_data, "plugins", "xxx"),
|
|
},
|
|
core_cache = mock_cache(cache_table),
|
|
cache = mock_cache({}),
|
|
log = mock_log(nil, logged_notices),
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
assert.truthy(cache_warmup.execute({"my_entity", "plugins"}))
|
|
|
|
assert.match("the 'plugins' entity is ignored", logged_notices[1], 1, true)
|
|
|
|
assert.same(kong.cache:get("111").bbb, 222)
|
|
assert.same(kong.cache:get("333").bbb, 444)
|
|
assert.same(kong.cache:get("555", nil, function() return "nope" end), "nope")
|
|
assert.same(kong.cache:get("777", nil, function() return "nope" end), "nope")
|
|
end)
|
|
|
|
|
|
it("warms up DNS when caching services", function()
|
|
local cache_table = {}
|
|
local db_data = {
|
|
["my_entity"] = {
|
|
{ aaa = 111, bbb = 222 },
|
|
{ aaa = 333, bbb = 444 },
|
|
},
|
|
["services"] = {
|
|
{ name = "a", host = "example.com", },
|
|
{ name = "b", host = "1.2.3.4", }, -- should be skipped by DNS caching
|
|
{ name = "c", host = "example.test", },
|
|
}
|
|
}
|
|
local dns_queries = {}
|
|
|
|
local kong = {
|
|
db = {
|
|
my_entity = mock_entity(db_data, "my_entity", "aaa"),
|
|
services = mock_entity(db_data, "services", "name"),
|
|
},
|
|
core_cache = mock_cache(cache_table),
|
|
cache = mock_cache({}),
|
|
dns = {
|
|
toip = function(query)
|
|
table.insert(dns_queries, query)
|
|
end,
|
|
}
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
local runs_old = _G.timerng:stats().sys.runs
|
|
|
|
assert.truthy(cache_warmup.execute({"my_entity", "services"}))
|
|
|
|
-- waiting async DNS cacheing
|
|
helpers.wait_until(function ()
|
|
local runs = _G.timerng:stats().sys.runs
|
|
return runs_old < runs
|
|
end)
|
|
|
|
-- `my_entity` isn't a core entity; lookup is on client cache
|
|
assert.same(kong.cache:get("111").bbb, 222)
|
|
assert.same(kong.cache:get("333").bbb, 444)
|
|
|
|
assert.same(kong.core_cache:get("a").host, "example.com")
|
|
assert.same(kong.core_cache:get("b").host, "1.2.3.4")
|
|
assert.same(kong.core_cache:get("c").host, "example.test")
|
|
|
|
-- skipped IP entry
|
|
assert.same({ "example.com", "example.test" }, dns_queries)
|
|
end)
|
|
|
|
|
|
it("does not warm up upstream names when caching services", function()
|
|
local cache_table = {}
|
|
local db_data = {
|
|
["my_entity"] = {
|
|
{ aaa = 111, bbb = 222 },
|
|
{ aaa = 333, bbb = 444 },
|
|
},
|
|
["services"] = {
|
|
{ name = "a", host = "example.com", },
|
|
{ name = "b", host = "1.2.3.4", }, -- should be skipped by DNS caching
|
|
{ name = "c", host = "example.test", },
|
|
{ name = "d", host = "thisisan.upstream.test", }, -- should be skipped by DNS caching
|
|
},
|
|
["upstreams"] = {
|
|
{ name = "thisisan.upstream.test", },
|
|
},
|
|
}
|
|
local dns_queries = {}
|
|
|
|
local kong = {
|
|
db = {
|
|
my_entity = mock_entity(db_data, "my_entity", "aaa"),
|
|
services = mock_entity(db_data, "services", "name"),
|
|
upstreams = mock_entity(db_data, "upstreams", "name"),
|
|
},
|
|
core_cache = mock_cache(cache_table),
|
|
cache = mock_cache({}),
|
|
dns = {
|
|
toip = function(query)
|
|
table.insert(dns_queries, query)
|
|
end,
|
|
}
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
local runs_old = _G.timerng:stats().sys.runs
|
|
|
|
assert.truthy(cache_warmup.execute({"my_entity", "services"}))
|
|
|
|
-- waiting async DNS caching
|
|
helpers.wait_until(function ()
|
|
local runs = _G.timerng:stats().sys.runs
|
|
return runs_old < runs
|
|
end)
|
|
|
|
-- `my_entity` isn't a core entity; lookup is on client cache
|
|
assert.same(kong.cache:get("111").bbb, 222)
|
|
assert.same(kong.cache:get("333").bbb, 444)
|
|
|
|
assert.same(kong.core_cache:get("a").host, "example.com")
|
|
assert.same(kong.core_cache:get("b").host, "1.2.3.4")
|
|
assert.same(kong.core_cache:get("c").host, "example.test")
|
|
assert.same(kong.core_cache:get("d").host, "thisisan.upstream.test")
|
|
|
|
-- skipped IP entry
|
|
assert.same({ "example.com", "example.test" }, dns_queries)
|
|
|
|
end)
|
|
|
|
|
|
it("logs a warning on bad entities", function()
|
|
local logged_warnings = {}
|
|
|
|
local kong = {
|
|
db = {},
|
|
core_cache = {},
|
|
cache = {},
|
|
log = mock_log(logged_warnings),
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
assert.truthy(cache_warmup.execute({"invalid_entity"}))
|
|
|
|
assert.match("invalid_entity is not a valid entity name", logged_warnings[1], 1, true)
|
|
end)
|
|
|
|
it("halts warmup and logs when cache is full", function()
|
|
local logged_warnings = {}
|
|
local cache_table = {}
|
|
local db_data = {
|
|
["my_entity"] = {
|
|
{ aaa = 111, bbb = 222 },
|
|
{ aaa = 333, bbb = 444 },
|
|
},
|
|
["another_entity"] = {
|
|
{ xxx = 555, yyy = 666 },
|
|
{ xxx = 777, yyy = 888 },
|
|
{ xxx = 999, yyy = 000 },
|
|
}
|
|
}
|
|
|
|
local kong = {
|
|
db = {
|
|
my_entity = mock_entity(db_data, "my_entity", "aaa"),
|
|
another_entity = mock_entity(db_data, "another_entity", "xxx"),
|
|
},
|
|
core_cache = mock_cache(cache_table, 3),
|
|
cache = mock_cache({}, 3),
|
|
log = mock_log(logged_warnings),
|
|
configuration = {
|
|
mem_cache_size = 12345,
|
|
},
|
|
}
|
|
|
|
cache_warmup._mock_kong(kong)
|
|
|
|
assert.truthy(cache_warmup.execute({"my_entity", "another_entity"}))
|
|
|
|
assert.match("cache warmup has been stopped", logged_warnings[1], 1, true)
|
|
|
|
assert.same(kong.cache:get("111").bbb, 222)
|
|
assert.same(kong.cache:get("333").bbb, 444)
|
|
assert.same(kong.cache:get("555").yyy, 666)
|
|
assert.same(kong.cache:get("777", nil, function() return "nope" end), "nope")
|
|
assert.same(kong.cache:get("999", nil, function() return "nope" end), "nope")
|
|
end)
|
|
|
|
end)
|