local helpers = require "spec.helpers" local declarative = require "kong.db.declarative" local cycle_aware_deep_copy = require("kong.tools.table").cycle_aware_deep_copy local uuid = require("kong.tools.uuid").uuid -- Note: include "off" strategy here as well for _, strategy in helpers.all_strategies() do describe("db.dao #" .. strategy, function() local bp, db local consumer, service, service2, plugin, plugin2, acl local group = "The A Team" lazy_setup(function() bp, db = helpers.get_db_utils(strategy, { "plugins", "services", "consumers", "acls", "keyauth_credentials", }) _G.kong.db = db consumer = bp.consumers:insert { username = "andru", custom_id = "donalds", } service = bp.services:insert { name = "abc", url = "http://localhost", } service2 = bp.services:insert { name = "def", url = "http://2-localhost", } plugin = bp.plugins:insert { enabled = true, name = "acl", service = service, config = { allow = { "*" }, }, } plugin2 = bp.plugins:insert { enabled = true, name = "rate-limiting", instance_name = 'rate-limiting-instance-1', service = service, config = { minute = 100, policy = "redis", redis = { host = "localhost" } }, } -- Note: bp in off strategy returns service=id instead of a table plugin.service = { id = service.id } acl = bp.acls:insert { consumer = consumer, group = group, } -- Note: bp in off strategy returns consumer=id instead of a table acl.consumer = { id = consumer.id } if strategy == "off" then -- dc_blueprint stores entities in memory -- and helpers export it to file in start_kong -- since this test requires entities to load -- into current nginx's shdict instead of the -- Kong nginx started by start_kong, we need -- to manually load the config local cfg = bp.done() local dc = declarative.new_config(kong.configuration) local entities = assert(dc:parse_table(cfg)) local kong_global = require("kong.global") local kong = _G.kong kong.worker_events = assert(kong_global.init_worker_events(kong.configuration)) kong.cluster_events = assert(kong_global.init_cluster_events(kong.configuration, kong.db)) kong.cache = 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)) assert(declarative.load_into_cache(entities)) end end) lazy_teardown(function() db.acls:truncate() db.consumers:truncate() db.plugins:truncate() db.services:truncate() db.keyauth_credentials:truncate() end) it("select_by_cache_key()", function() local cache_key = kong.db.acls:cache_key(consumer.id, group) local read_acl, err = kong.db.acls:select_by_cache_key(cache_key) assert.is_nil(err) assert.same(acl, read_acl) -- cache_key = { "name", "route", "service", "consumer" }, cache_key = kong.db.plugins:cache_key("acl", nil, service.id, nil) local read_plugin, err = kong.db.plugins:select_by_cache_key(cache_key) assert.is_nil(err) assert.same(plugin, read_plugin) cache_key = kong.db.plugins:cache_key("rate-limiting", nil, service.id, nil) read_plugin, err = kong.db.plugins:select_by_cache_key(cache_key) assert.is_nil(err) assert.same(plugin2, read_plugin) end) it("page_for_route", function() local plugins_for_service, err = kong.db.plugins:page_for_service(service) assert.is_nil(err) assert.equal(2, #plugins_for_service) for _, read_plugin in ipairs(plugins_for_service) do if read_plugin.name == 'acl' then assert.same(plugin, read_plugin) elseif read_plugin.name == 'rate-limiting' then assert.same(plugin2, read_plugin) end end end) it("select_by_instance_name", function() local read_plugin, err = kong.db.plugins:select_by_instance_name(plugin2.instance_name) assert.is_nil(err) assert.same(plugin2, read_plugin) end) it("update_by_instance_name", function() local newhost = "newhost" local updated_plugin = cycle_aware_deep_copy(plugin2) updated_plugin.config.redis.host = newhost updated_plugin.config.redis_host = newhost local read_plugin, err = kong.db.plugins:update_by_instance_name(plugin2.instance_name, updated_plugin) assert.is_nil(err) assert.same(updated_plugin, read_plugin) end) it("upsert_by_instance_name", function() -- existing plugin upsert (update part of upsert) local newhost = "newhost" local updated_plugin = cycle_aware_deep_copy(plugin2) updated_plugin.config.redis.host = newhost updated_plugin.config.redis_host = newhost local read_plugin, err = kong.db.plugins:upsert_by_instance_name(plugin2.instance_name, updated_plugin) assert.is_nil(err) assert.same(updated_plugin, read_plugin) -- new plugin upsert (insert part of upsert) local new_plugin_config = { id = uuid(), enabled = true, name = "rate-limiting", instance_name = 'rate-limiting-instance-2', service = service2, config = { minute = 200, policy = "redis", redis = { host = "new-host-2" } }, } local read_plugin, err = kong.db.plugins:upsert_by_instance_name(new_plugin_config.instance_name, new_plugin_config) assert.is_nil(err) assert.same(new_plugin_config.id, read_plugin.id) assert.same(new_plugin_config.instance_name, read_plugin.instance_name) assert.same(new_plugin_config.service.id, read_plugin.service.id) assert.same(new_plugin_config.config.minute, read_plugin.config.minute) assert.same(new_plugin_config.config.redis.host, read_plugin.config.redis.host) assert.same(new_plugin_config.config.redis.host, read_plugin.config.redis_host) -- legacy field is included end) it("keyauth_credentials can be deleted or selected before run ttl cleanup in background timer", function() local key = uuid() local original_keyauth_credentials = bp.keyauth_credentials:insert({ consumer = { id = consumer.id }, key = key, }, { ttl = 5 }) -- wait for 5 seconds. ngx.sleep(5) -- select or delete keyauth_credentials after ttl expired. local expired_keyauth_credentials helpers.wait_until(function() expired_keyauth_credentials = kong.db.keyauth_credentials:select_by_key(key) return not expired_keyauth_credentials end, 1) assert.is_nil(expired_keyauth_credentials) kong.db.keyauth_credentials:delete_by_key(key) -- select or delete keyauth_credentials with skip_ttl=true after ttl expired. expired_keyauth_credentials = kong.db.keyauth_credentials:select_by_key(key, { skip_ttl = true }) assert.not_nil(expired_keyauth_credentials) assert.same(expired_keyauth_credentials.id, original_keyauth_credentials.id) kong.db.keyauth_credentials:delete_by_key(key, { skip_ttl = true }) -- check again expired_keyauth_credentials = kong.db.keyauth_credentials:select_by_key(key, { skip_ttl = true }) assert.is_nil(expired_keyauth_credentials) end) it("should not preserve expired entities as nil in the result of page method", function() bp.keyauth_credentials:insert({ consumer = { id = consumer.id }, key = uuid(), }, { }) bp.keyauth_credentials:insert({ consumer = { id = consumer.id }, key = uuid(), }, { ttl = 2 }) bp.keyauth_credentials:insert({ consumer = { id = consumer.id }, key = uuid(), }, { }) local res = kong.db.keyauth_credentials:page() assert.equal(3, #res) -- wait for 2+1 seconds. ngx.sleep(3) res = kong.db.keyauth_credentials:page() assert.equal(2, #res) for _, entity in ipairs(res) do assert.is_table(entity) end end) end) end