Files
kong--kong/spec/01-unit/01-db/11-declarative_lmdb_spec.lua
2026-07-13 12:32:21 +08:00

253 lines
6.9 KiB
Lua

local helpers
local buffer
local kong_global
local conf_loader
local declarative
local DB
local kong
local ngx_log = ngx.log
local ngx_debug = ngx.DEBUG
local lmdb_mlcache
do
local resty_mlcache = require "kong.resty.mlcache"
lmdb_mlcache = assert(resty_mlcache.new("lmdb_mlcache", "lmdb_mlcache", {
lru_size = 1000,
ttl = 0,
neg_ttl = 0,
resurrect_ttl = 30,
ipc = {
register_listeners = function(events)
ngx_log(ngx_debug, "register lmdb worker events ", tostring(events))
end,
broadcast = function(channel, data)
ngx_log(ngx_debug, "broadcast lmdb worker events ", tostring(channel), tostring(data))
end
},
}))
lmdb_mlcache:purge(true)
_G.lmdb_mlcache = lmdb_mlcache
end
local function mocking_lmdb_transaction()
local _lmdb_txn = {}
local _lmdb_txn_mt = { __index = _lmdb_txn }
function _lmdb_txn.begin(x)
ngx_log(ngx_debug, "new lmdb: ", x)
local self = {
cache = lmdb_mlcache,
DEFAULT_DB = "_default",
}
return setmetatable(self, _lmdb_txn_mt)
end
function _lmdb_txn:db_drop(delete, db)
ngx_log(ngx_debug, "drop db = ", db or self.DEFAULT_DB, ", delete = ", delete)
return true
end
function _lmdb_txn:set(key, value, db)
ngx_log(ngx_debug, "set db = ", db or self.DEFAULT_DB, ", ", key, " = ", value)
self.cache:set(key, nil, value)
return true
end
function _lmdb_txn:get(key, db)
ngx_log(ngx_debug, "get db = ", db or self.DEFAULT_DB, ", key = ", key)
return self.cache:get(key)
end
function _lmdb_txn:commit()
ngx_log(ngx_debug, "commit lmdb transactions")
return true
end
_G.package.loaded["resty.lmdb.transaction"] = _lmdb_txn
end
local function mocking_lmdb()
local _lmdb = {
cache = lmdb_mlcache,
DEFAULT_DB = "_default"
}
local _lmdb_mt = { __index = _lmdb, }
function _lmdb.get(key, db)
ngx_log(ngx_debug, "get db = ", db or _lmdb.DEFAULT_DB, ", key = ", key)
return _lmdb.cache:get(key)
end
setmetatable(_lmdb, _lmdb_mt)
_G.package.loaded["resty.lmdb"] = _lmdb
end
local function unmocking()
_G.package.loaded["resty.lmdb.transaction"] = nil
_G["resty.lmdb.transaction"] = nil
_G.package.loaded["resty.lmdb"] = nil
_G["resty.lmdb"] = nil
end
describe("#off preserve nulls", function()
local PLUGIN_NAME = "preserve-nulls"
local PASSWORD = "fti-110"
local YAML_CONTENTS = string.format([=[
_format_version: '3.0'
services:
- name: fti-110
url: http://localhost/ip
routes:
- name: fti-110
paths:
- /fti-110
plugins:
- name: basic-auth
config:
hide_credentials: false
- name: preserve-nulls
config:
request_header: "Hello-Foo"
response_header: "Bye-Bar"
large: ~
ttl: null
consumers:
- username: fti-110
custom_id: fti-110-cid
basicauth_credentials:
- username: fti-110
password: %s
keyauth_credentials:
- key: fti-5260
]=], PASSWORD)
lazy_setup(function()
mocking_lmdb_transaction()
require "resty.lmdb.transaction"
mocking_lmdb()
require "resty.lmdb"
helpers = require "spec.helpers"
kong = _G.kong
kong.core_cache = nil
buffer = require "string.buffer"
kong_global = require "kong.global"
conf_loader = require "kong.conf_loader"
declarative = require "kong.db.declarative"
DB = require "kong.db"
end)
lazy_teardown(function()
unmocking()
end)
it("when loading into LMDB", function()
local null = ngx.null
local concat = table.concat
local kong_config = assert(conf_loader(helpers.test_conf_path, {
database = "off",
plugins = "bundled," .. PLUGIN_NAME,
}))
local db = assert(DB.new(kong_config))
assert(db:init_connector())
db.plugins:load_plugin_schemas(kong_config.loaded_plugins)
db.vaults:load_vault_schemas(kong_config.loaded_vaults)
kong.db = db
local dc = assert(declarative.new_config(kong_config))
local dc_table, _, _, current_hash = assert(dc:unserialize(YAML_CONTENTS, "yaml"))
assert.are_equal(PASSWORD, dc_table.consumers[1].basicauth_credentials[1].password)
local entities, _, _, meta, new_hash = assert(dc:parse_table(dc_table, current_hash))
assert.is_not_falsy(meta._transform)
assert.are_equal(current_hash, new_hash)
for _,v in pairs(entities.plugins) do
if v.name == PLUGIN_NAME then
assert.are_equal(v.config.large, null)
assert.are_equal(v.config.ttl, null)
break
end
end
kong.configuration = kong_config
kong.worker_events = kong.worker_events or
kong.cache and kong.cache.worker_events or
assert(kong_global.init_worker_events(kong.configuration))
kong.cluster_events = kong.cluster_events or
kong.cache and kong.cache.cluster_events or
assert(kong_global.init_cluster_events(kong.configuration, kong.db))
kong.cache = kong.cache or
assert(kong_global.init_cache(kong.configuration, kong.cluster_events, kong.worker_events))
kong.core_cache = assert(kong_global.init_core_cache(kong.configuration, kong.cluster_events, kong.worker_events))
kong.cache.worker_events = kong.cache.worker_events or kong.worker_events
kong.cache.cluster_events = kong.cache.cluster_events or kong.cluster_events
assert(declarative.load_into_cache(entities, meta, current_hash))
local id, item = next(entities.basicauth_credentials)
-- format changed after rpc sync
-- item key
local cache_key = concat({
"I|",
"basicauth_credentials|",
item.ws_id,
"|",
id
})
local lmdb = require "resty.lmdb"
local value, err, hit_lvl = lmdb.get(cache_key)
assert.is_nil(err)
assert.are_equal(hit_lvl, 1)
local cached_item = buffer.decode(value)
assert.are_not_same(cached_item, item)
assert.are_equal(cached_item.id, item.id)
assert.are_equal(cached_item.username, item.username)
assert.are_not_equal(PASSWORD, cached_item.password)
assert.are_not_equal(cached_item.password, item.password)
for _, plugin in pairs(entities.plugins) do
if plugin.name == PLUGIN_NAME then
-- format changed after rpc sync
-- foreign key:
cache_key = concat({
"F|",
"plugins|",
"route|",
plugin.route.id,
"|",
plugin.ws_id,
"|",
plugin.id,
})
value, err, hit_lvl = lmdb.get(cache_key)
assert.is_nil(err)
assert.are_equal(hit_lvl, 1)
-- get value by the index key
cached_item = buffer.decode(lmdb.get(value))
assert.are_same(cached_item, plugin)
assert.are_equal(cached_item.config.large, null)
assert.are_equal(cached_item.config.ttl, null)
break
end
end
end)
end)