blob: 1da3e4b2799d874ba42f0d2679cb7b45b2feb0a7 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use t::APISIX 'no_plan';
repeat_each(1);
no_long_string();
no_root_location();
log_level("info");
run_tests;
__DATA__
=== TEST 1: negative cache basic functionality
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local call_count = 0
local function create_obj_fail()
call_count = call_count + 1
return nil, "simulated failure"
end
-- create LRU cache with negative caching
local lru_get = core.lrucache.new({
ttl = 1,
count = 256,
neg_ttl = 0.5, -- shorter TTL for failures
neg_count = 128
})
-- First call should execute the function and cache the failure
local obj, err = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("call_count after first call: ", call_count)
ngx.say("first call result: obj=", tostring(obj), ", err=", tostring(err))
-- Second call should return from negative cache without calling create_obj_fail
obj, err = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("call_count after second call: ", call_count)
ngx.say("second call result: obj=", tostring(obj), ", err=", tostring(err))
-- Different version should bypass negative cache
obj, err = lru_get("fail_key", "v2", create_obj_fail)
ngx.say("call_count after different version: ", call_count)
ngx.say("different version result: obj=", tostring(obj), ", err=", tostring(err))
}
}
--- request
GET /t
--- response_body
call_count after first call: 1
first call result: obj=nil, err=simulated failure
call_count after second call: 1
second call result: obj=nil, err=simulated failure
call_count after different version: 2
different version result: obj=nil, err=simulated failure
=== TEST 2: negative cache TTL expiration
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local call_count = 0
local function create_obj_fail()
call_count = call_count + 1
return nil, "simulated failure"
end
-- Create LRU cache with very short negative TTL
local lru_get = core.lrucache.new({
ttl = 10,
count = 256,
neg_ttl = 0.1, -- very short TTL for failures
neg_count = 128
})
-- First call
local obj, err = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("call_count after first call: ", call_count)
-- Immediate second call - should use negative cache
obj, err = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("call_count after immediate call: ", call_count)
-- Wait for negative cache to expire
ngx.sleep(0.15)
-- This should call create_obj_fail again
obj, err = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("call_count after TTL expiration: ", call_count)
}
}
--- request
GET /t
--- response_body
call_count after first call: 1
call_count after immediate call: 1
call_count after TTL expiration: 2
=== TEST 3: mixed success and failure caching
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local success_count = 0
local fail_count = 0
local function create_obj_success()
success_count = success_count + 1
return {value = "success_" .. success_count}
end
local function create_obj_fail()
fail_count = fail_count + 1
return nil, "failure_" .. fail_count
end
local lru_get = core.lrucache.new({
ttl = 1,
count = 256,
neg_ttl = 0.5,
neg_count = 128
})
-- Test success caching
local obj1 = lru_get("success_key", "v1", create_obj_success)
ngx.say("success_count after first success: ", success_count)
ngx.say("success value: ", obj1.value)
local obj2 = lru_get("success_key", "v1", create_obj_success)
ngx.say("success_count after cached success: ", success_count)
ngx.say("cached success value: ", obj2.value)
-- Test failure caching
local obj3, err3 = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("fail_count after first failure: ", fail_count)
ngx.say("failure error: ", err3)
local obj4, err4 = lru_get("fail_key", "v1", create_obj_fail)
ngx.say("fail_count after cached failure: ", fail_count)
ngx.say("cached failure error: ", err4)
}
}
--- request
GET /t
--- response_body
success_count after first success: 1
success value: success_1
success_count after cached success: 1
cached success value: success_1
fail_count after first failure: 1
failure error: failure_1
fail_count after cached failure: 1
cached failure error: failure_1
=== TEST 4: negative cache with different keys
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local call_count = 0
local function create_obj_fail(key)
call_count = call_count + 1
return nil, "failed for " .. key
end
local lru_get = core.lrucache.new({
ttl = 1,
count = 256,
neg_ttl = 0.5,
neg_count = 128
})
-- First key
local obj1, err1 = lru_get("key1", "v1", create_obj_fail, "key1")
ngx.say("call_count after key1: ", call_count)
-- Second key
local obj2, err2 = lru_get("key2", "v1", create_obj_fail, "key2")
ngx.say("call_count after key2: ", call_count)
-- Repeat key1 - should use negative cache
local obj3, err3 = lru_get("key1", "v1", create_obj_fail, "key1")
ngx.say("call_count after key1 repeat: ", call_count)
ngx.say("key1 error: ", err3)
-- Repeat key2 - should use negative cache
local obj4, err4 = lru_get("key2", "v1", create_obj_fail, "key2")
ngx.say("call_count after key2 repeat: ", call_count)
ngx.say("key2 error: ", err4)
}
}
--- request
GET /t
--- response_body
call_count after key1: 1
call_count after key2: 2
call_count after key1 repeat: 2
key1 error: failed for key1
call_count after key2 repeat: 2
key2 error: failed for key2
=== TEST 5: negative cache respects version changes
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local call_count = 0
local function create_obj_fail(version)
call_count = call_count + 1
return nil, "failed for version " .. version
end
local lru_get = core.lrucache.new({
ttl = 10,
count = 256,
neg_ttl = 10,
neg_count = 128
})
-- Call with version 1
local obj1, err1 = lru_get("version_key", "v1", create_obj_fail, "v1")
ngx.say("call_count after v1: ", call_count)
-- Call with version 1 again - should use negative cache
local obj2, err2 = lru_get("version_key", "v1", create_obj_fail, "v1")
ngx.say("call_count after v1 repeat: ", call_count)
-- Call with version 2 - should bypass negative cache
local obj3, err3 = lru_get("version_key", "v2", create_obj_fail, "v2")
ngx.say("call_count after v2: ", call_count)
-- Call with version 2 again - should use negative cache
local obj4, err4 = lru_get("version_key", "v2", create_obj_fail, "v2")
ngx.say("call_count after v2 repeat: ", call_count)
}
}
--- request
GET /t
--- response_body
call_count after v1: 1
call_count after v1 repeat: 1
call_count after v2: 2
call_count after v2 repeat: 2