Skip to content

Commit 74d8587

Browse files
Add tests
1 parent d60f099 commit 74d8587

File tree

3 files changed

+226
-1
lines changed

3 files changed

+226
-1
lines changed

apisix/plugins/limit-req/util.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ local _M = {version = 0.1}
2727

2828

2929
local script = core.string.compress_script([=[
30-
local state_key = KEYS[1] -- state_key (hash), fields: "excess", "last"
30+
local state_key = KEYS[1] -- state_key (hash), fields: "excess", "last"
3131
local rate = tonumber(ARGV[1]) -- req/s
3232
local now = tonumber(ARGV[2]) -- ms
3333
local burst = tonumber(ARGV[3]) -- req/s

t/plugin/limit-req-redis-cluster.t

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,3 +603,116 @@ passed
603603
GET /t
604604
--- response_body eval
605605
qr/property \"rate\" validation failed: expected 0 to be greater than 0/
606+
607+
608+
609+
=== TEST 22: verify atomic Redis cluster operations with hash key structure
610+
--- config
611+
location /t {
612+
content_by_lua_block {
613+
local redis_cluster = require "resty.rediscluster"
614+
local red_c = redis_cluster:new({
615+
name = "test",
616+
serv_list = {
617+
{ ip = "127.0.0.1", port = 5000 },
618+
{ ip = "127.0.0.1", port = 5002 }
619+
}
620+
}, "plugin-limit-req-redis-cluster-slot-lock")
621+
622+
-- Clean up any existing keys
623+
red_c:del("limit_req:{test_key}:state")
624+
625+
-- Test the new hash-based key structure
626+
local util = require("apisix.plugins.limit-req.util")
627+
local limiter = {
628+
rate = 10, -- 10 req/s
629+
burst = 1000 -- 1000 req/s burst
630+
}
631+
632+
-- First request should succeed (use non-pipeline client)
633+
local delay, excess = util.incoming(limiter, red_c, "test_key", true)
634+
if delay then
635+
ngx.say("first request: delay=", delay, " excess=", excess)
636+
else
637+
ngx.say("first request failed: ", excess)
638+
end
639+
640+
-- Verify the Redis hash was created with correct key format
641+
local vals, err = red_c:hmget("limit_req:{test_key}:state", "excess", "last")
642+
if vals and vals[1] and vals[2] then
643+
ngx.say("hash key created: excess=", vals[1], " last=", vals[2])
644+
else
645+
ngx.say("hash key not found")
646+
end
647+
648+
-- Verify TTL was set
649+
local ttl = red_c:ttl("limit_req:{test_key}:state")
650+
if ttl and ttl > 0 then
651+
ngx.say("TTL set: ", ttl, " seconds")
652+
else
653+
ngx.say("TTL not set")
654+
end
655+
656+
-- Clean up
657+
red_c:del("limit_req:{test_key}:state")
658+
}
659+
}
660+
--- request
661+
GET /t
662+
--- response_body_like
663+
first request: delay=\d+\.?\d* excess=\d+\.?\d*
664+
hash key created: excess=\d+ last=\d+
665+
TTL set: \d+ seconds
666+
667+
668+
669+
=== TEST 23: verify atomic behavior prevents race conditions in cluster
670+
--- config
671+
location /t {
672+
content_by_lua_block {
673+
local t = require("lib.test_admin").test
674+
local code, body = t('/apisix/admin/routes/1',
675+
ngx.HTTP_PUT,
676+
[[{
677+
"plugins": {
678+
"limit-req": {
679+
"rate": 1,
680+
"burst": 0,
681+
"rejected_code": 503,
682+
"key": "remote_addr",
683+
"policy": "redis-cluster",
684+
"redis_cluster_name": "test",
685+
"redis_cluster_nodes": [
686+
"127.0.0.1:5000",
687+
"127.0.0.1:5002"
688+
]
689+
}
690+
},
691+
"upstream": {
692+
"nodes": {
693+
"127.0.0.1:1980": 1
694+
},
695+
"type": "roundrobin"
696+
},
697+
"uri": "/hello"
698+
}]]
699+
)
700+
701+
if code >= 300 then
702+
ngx.status = code
703+
end
704+
ngx.say(body)
705+
}
706+
}
707+
--- request
708+
GET /t
709+
--- response_body
710+
passed
711+
712+
713+
714+
=== TEST 24: test atomic rate limiting with rapid requests in cluster
715+
--- pipelined_requests eval
716+
["GET /hello", "GET /hello"]
717+
--- error_code eval
718+
[200, 503]

t/plugin/limit-req-redis.t

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,115 @@ passed
651651
GET /t
652652
--- response_body eval
653653
qr/property \"rate\" validation failed: expected 0 to be greater than 0/
654+
655+
656+
657+
=== TEST 24: verify atomic Redis operations with hash key structure
658+
--- config
659+
location /t {
660+
content_by_lua_block {
661+
local redis = require "resty.redis"
662+
local red = redis:new()
663+
red:set_timeout(1000)
664+
665+
local ok, err = red:connect("127.0.0.1", 6379)
666+
if not ok then
667+
ngx.say("failed to connect: ", err)
668+
return
669+
end
670+
671+
-- Clean up any existing keys
672+
red:del("limit_req:{test_key}:state")
673+
674+
-- Test the new hash-based key structure
675+
local util = require("apisix.plugins.limit-req.util")
676+
local limiter = {
677+
rate = 10, -- 10 req/s
678+
burst = 1000 -- 1000 req/s burst
679+
}
680+
681+
-- First request should succeed
682+
local delay, excess = util.incoming(limiter, red, "test_key", true)
683+
if delay then
684+
ngx.say("first request: delay=", delay, " excess=", excess)
685+
else
686+
ngx.say("first request failed: ", excess)
687+
end
688+
689+
-- Verify the Redis hash was created with correct key format
690+
local vals = red:hmget("limit_req:{test_key}:state", "excess", "last")
691+
if vals[1] and vals[2] then
692+
ngx.say("hash key created: excess=", vals[1], " last=", vals[2])
693+
else
694+
ngx.say("hash key not found")
695+
end
696+
697+
-- Verify TTL was set
698+
local ttl = red:ttl("limit_req:{test_key}:state")
699+
if ttl and ttl > 0 then
700+
ngx.say("TTL set: ", ttl, " seconds")
701+
else
702+
ngx.say("TTL not set")
703+
end
704+
705+
-- Clean up
706+
red:del("limit_req:{test_key}:state")
707+
red:close()
708+
}
709+
}
710+
--- request
711+
GET /t
712+
--- response_body_like
713+
first request: delay=\d+\.?\d* excess=\d+\.?\d*
714+
hash key created: excess=\d+ last=\d+
715+
TTL set: \d+ seconds
716+
717+
718+
719+
=== TEST 25: verify atomic behavior prevents race conditions
720+
--- config
721+
location /t {
722+
content_by_lua_block {
723+
local t = require("lib.test_admin").test
724+
local code, body = t('/apisix/admin/routes/1',
725+
ngx.HTTP_PUT,
726+
[[{
727+
"plugins": {
728+
"limit-req": {
729+
"rate": 1,
730+
"burst": 0,
731+
"rejected_code": 503,
732+
"key": "remote_addr",
733+
"policy": "redis",
734+
"redis_host": "127.0.0.1"
735+
}
736+
},
737+
"upstream": {
738+
"nodes": {
739+
"127.0.0.1:1980": 1
740+
},
741+
"type": "roundrobin"
742+
},
743+
"uri": "/hello"
744+
}]]
745+
)
746+
747+
if code >= 300 then
748+
ngx.status = code
749+
end
750+
ngx.say(body)
751+
}
752+
}
753+
--- request
754+
GET /t
755+
--- response_body
756+
passed
757+
758+
759+
760+
=== TEST 26: test atomic rate limiting with rapid requests
761+
--- pipelined_requests eval
762+
["GET /hello", "GET /hello"]
763+
--- error_code eval
764+
[200, 503]
765+

0 commit comments

Comments
 (0)