root@VM-96-101-ubuntu:~/apisix# PATH=/usr/local/openresty/nginx/sbin:/usr/bin:/usr/local/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/plugin/limit-count.t
t/plugin/limit-count.t .. ok
All tests successful.
Files=1, Tests=324, 26 wallclock secs ( 0.04 usr 0.01 sys + 3.17 cusr 1.68 csys = 4.90 CPU)
Result: PASS
root@VM-96-101-ubuntu:~/apisix# PATH=/usr/local/openresty/nginx/sbin:/usr/bin:/usr/local/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/plugin/limit-count.t
t/plugin/limit-count.t .. 42/?
# Failed test 't/plugin/limit-count.t TEST 6: set route(id: 1) - pattern "[error]" should not match any line in error.log but matches line "2026/04/21 15:09:34 [error] 2434300#2434300: *280 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer" (req 0)
# 2026/04/21 15:09:34 [error] 2434301#2434301: *300 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer
# 2026/04/21 15:09:34 [notice] 2434245#2434245: exiting
# 2026/04/21 15:09:34 [notice] 2434362#2434362: *359 [lua] config_etcd.lua:1059: new(): use loaded configuration /protos, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] inspect.lua:52: init(): delay=3, hooks_file=/usr/local/apisix/plugin_inspect_hooks.lua, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] plugin.lua:274: load(): load plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [warn] 2434362#2434362: *359 [lua] plugin.lua:287: load_stream(): new plugins: {"syslog":true,"traffic-split":true,"mqtt-proxy":true,"limit-conn":true,"ip-restriction":true}, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] plugin.lua:315: load_stream(): stream plugins: [{"version":0.1,"name":"ip-restriction","priority":3000,"schema":{"oneOf":[{"required":["whitelist"]},{"required":["blacklist"]}],"properties":{"message":{"maxLength":1024,"default":"Your IP address is not allowed","minLength":1,"type":"string"},"whitelist":{"minItems":1,"items":{"anyOf":[{"format":"ipv4","title":"IPv4","type":"string"},{"title":"IPv4/CIDR","pattern":"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$","type":"string"},{"format":"ipv6","title":"IPv6","type":"string"},{"title":"IPv6/CIDR","pattern":"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$","type":"string"}]},"type":"array"},"blacklist":{"minItems":1,"items":{"anyOf":"table: 0x7fde41585658"},"type":"array"},"_meta":{"properties":{"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"priority":{"description":"priority of plugins by customized order","type":"integer"},"pre_function":{"description":"function to be executed in each phase before execution of plugins. The pre_function will have access to two arguments: `conf` and `ctx`.","type":"string"},"filter":{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"},"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"},"response_code":{"minimum":403,"default":403,"maximum":404,"type":"integer"}},"$comment":"this is a mark for our injected plugin schema","type":"object"},"check_schema":"function: 0x7fde5068dd98","restrict":"function: 0x7fde5068df50","preread":"function: 0x7fde5068df50"},{"version":0.1,"name":"limit-conn","priority":1003,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"conn":{"exclusiveMinimum":0,"type":"integer"},"only_use_default_delay":{"type":"boolean","default":false},"key_type":{"enum":["var","var_combination"],"default":"var","type":"string"},"burst":{"type":"integer","minimum":0},"default_conn_delay":{"exclusiveMinimum":0,"type":"number"},"_meta":"table: 0x7fde414cdca8","key":{"type":"string"}},"type":"object","required":["conn","burst","default_conn_delay","key"]},"log":"function: 0x7fde3f4fa570","preread":"function: 0x7fde3f4fa500","check_schema":"function: 0x7fde3f4fa388"},{"version":0.1,"name":"mqtt-proxy","priority":1000,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"protocol_level":{"type":"integer"},"protocol_name":{"type":"string","default":"MQTT"},"_meta":"table: 0x7fde414cdca8"},"type":"object","required":["protocol_level"]},"log":"function: 0x7fde3f4f8fa8","preread":"function: 0x7fde3f4f8eb0","check_schema":"function: 0x7fde3f4f8b90"},{"version":0.1,"name":"traffic-split","priority":966,"check_schema":"function: 0x7fde41708d48","schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"_meta":"table: 0x7fde414cdca8","rules":{"items":{"type":"object","properties":{"match":{"items":{"type":"object","properties":{"vars":{"type":"array"}}},"type":"array"},"weighted_upstreams":{"items":{"type":"object","properties":{"weight":{"type":"integer","description":"used to split traffic between differentupstreams for plugin configuration","default":1,"minimum":0},"upstream_id":{"anyOf":[{"maxLength":64,"minLength":1,"pattern":"^[a-zA-Z0-9-_.]+$","type":"string"},{"type":"integer","minimum":1}]},"upstream":{"oneOf":[{"required":["nodes"]},{"required":["service_name","discovery_type"]}],"properties":{"pass_host":{"enum":["pass","node","rewrite"],"description":"mod of host passing","default":"pass","type":"string"},"name":{"maxLength":256,"type":"string","minLength":1},"id":"table: 0x7fde41509778","hash_on":{"enum":["vars","header","cookie","consumer","vars_combinations"],"default":"vars","type":"string"},"type":{"default":"roundrobin","description":"algorithms of load balancing","type":"string"},"timeout":{
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] plugin.lua:317: load_stream(): load stream plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [notice] 2434362#2434362: *359 [lua] config_etcd.lua:1059: new(): use loaded configuration /plugin_metadata, context: init_worker_by_lua*
# '
# at /usr/local/share/perl/5.34.0/Test/Nginx/Socket.pm line 1356.
# Failed test 't/plugin/limit-count.t TEST 6: set route(id: 1) - pattern "[error]" should not match any line in error.log but matches line "2026/04/21 15:09:34 [error] 2434301#2434301: *300 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer" (req 0)
# 2026/04/21 15:09:34 [notice] 2434245#2434245: exiting
# 2026/04/21 15:09:34 [notice] 2434362#2434362: *359 [lua] config_etcd.lua:1059: new(): use loaded configuration /protos, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] inspect.lua:52: init(): delay=3, hooks_file=/usr/local/apisix/plugin_inspect_hooks.lua, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] plugin.lua:274: load(): load plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [warn] 2434362#2434362: *359 [lua] plugin.lua:287: load_stream(): new plugins: {"syslog":true,"traffic-split":true,"mqtt-proxy":true,"limit-conn":true,"ip-restriction":true}, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] plugin.lua:315: load_stream(): stream plugins: [{"version":0.1,"name":"ip-restriction","priority":3000,"schema":{"oneOf":[{"required":["whitelist"]},{"required":["blacklist"]}],"properties":{"message":{"maxLength":1024,"default":"Your IP address is not allowed","minLength":1,"type":"string"},"whitelist":{"minItems":1,"items":{"anyOf":[{"format":"ipv4","title":"IPv4","type":"string"},{"title":"IPv4/CIDR","pattern":"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$","type":"string"},{"format":"ipv6","title":"IPv6","type":"string"},{"title":"IPv6/CIDR","pattern":"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$","type":"string"}]},"type":"array"},"blacklist":{"minItems":1,"items":{"anyOf":"table: 0x7fde41585658"},"type":"array"},"_meta":{"properties":{"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"priority":{"description":"priority of plugins by customized order","type":"integer"},"pre_function":{"description":"function to be executed in each phase before execution of plugins. The pre_function will have access to two arguments: `conf` and `ctx`.","type":"string"},"filter":{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"},"disable":{"type":"boolean"}},"additionalProperties":false,"type":"object"},"response_code":{"minimum":403,"default":403,"maximum":404,"type":"integer"}},"$comment":"this is a mark for our injected plugin schema","type":"object"},"check_schema":"function: 0x7fde5068dd98","restrict":"function: 0x7fde5068df50","preread":"function: 0x7fde5068df50"},{"version":0.1,"name":"limit-conn","priority":1003,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"conn":{"exclusiveMinimum":0,"type":"integer"},"only_use_default_delay":{"type":"boolean","default":false},"key_type":{"enum":["var","var_combination"],"default":"var","type":"string"},"burst":{"type":"integer","minimum":0},"default_conn_delay":{"exclusiveMinimum":0,"type":"number"},"_meta":"table: 0x7fde414cdca8","key":{"type":"string"}},"type":"object","required":["conn","burst","default_conn_delay","key"]},"log":"function: 0x7fde3f4fa570","preread":"function: 0x7fde3f4fa500","check_schema":"function: 0x7fde3f4fa388"},{"version":0.1,"name":"mqtt-proxy","priority":1000,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"protocol_level":{"type":"integer"},"protocol_name":{"type":"string","default":"MQTT"},"_meta":"table: 0x7fde414cdca8"},"type":"object","required":["protocol_level"]},"log":"function: 0x7fde3f4f8fa8","preread":"function: 0x7fde3f4f8eb0","check_schema":"function: 0x7fde3f4f8b90"},{"version":0.1,"name":"traffic-split","priority":966,"check_schema":"function: 0x7fde41708d48","schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"_meta":"table: 0x7fde414cdca8","rules":{"items":{"type":"object","properties":{"match":{"items":{"type":"object","properties":{"vars":{"type":"array"}}},"type":"array"},"weighted_upstreams":{"items":{"type":"object","properties":{"weight":{"type":"integer","description":"used to split traffic between differentupstreams for plugin configuration","default":1,"minimum":0},"upstream_id":{"anyOf":[{"maxLength":64,"minLength":1,"pattern":"^[a-zA-Z0-9-_.]+$","type":"string"},{"type":"integer","minimum":1}]},"upstream":{"oneOf":[{"required":["nodes"]},{"required":["service_name","discovery_type"]}],"properties":{"pass_host":{"enum":["pass","node","rewrite"],"description":"mod of host passing","default":"pass","type":"string"},"name":{"maxLength":256,"type":"string","minLength":1},"id":"table: 0x7fde41509778","hash_on":{"enum":["vars","header","cookie","consumer","vars_combinations"],"default":"vars","type":"string"},"type":{"default":"roundrobin","description":"algorithms of load balancing","type":"string"},"timeout":{
# 2026/04/21 15:09:34 [info] 2434362#2434362: *359 [lua] plugin.lua:317: load_stream(): load stream plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [notice] 2434362#2434362: *359 [lua] config_etcd.lua:1059: new(): use loaded configuration /plugin_metadata, context: init_worker_by_lua*
# 2026/04/21 15:09:34 [notice] 2434362#2434362: *359 [lua] config_etcd.lua:1059: new(): use loaded configuration /routes, context: init_worker_by_lua*
# '
# at /usr/local/share/perl/5.34.0/Test/Nginx/Socket.pm line 1356.
t/plugin/limit-count.t .. 151/?
# Failed test 't/plugin/limit-count.t TEST 22: when the count is changed, check the limit is correct(from 1 to 2) - pattern "[error]" should not match any line in error.log but matches line "2026/04/21 15:09:43 [error] 2435231#2435231: *1536 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer" (req 0)
# 2026/04/21 15:09:43 [info] 2435288#2435288: *1619 [lua] init.lua:121: http_init_worker(): random test in [1, 10000]: 5183, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435288#2435288: *1619 [lua] events.lua:38: init_resty_events(): subsystem: http listening sock: unix:/root/apisix/t/servroot/logs/worker_events.sock, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:493: common_route_data(): path: /apisix/admin operator: =, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:493: common_route_data(): path: /apisix/admin/configs/validate operator: =, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:493: common_route_data(): path: /apisix/admin/ operator: <=, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:393: insert_route(): insert route path: /apisix/admin/ dataprt: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:493: common_route_data(): path: /apisix/admin/plugins/list operator: =, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:493: common_route_data(): path: /apisix/admin/schema/validate/ operator: <=, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] radixtree.lua:393: insert_route(): insert route path: /apisix/admin/schema/validate/ dataprt: 2, context: init_worker_by_lua*
# '
# at /usr/local/share/perl/5.34.0/Test/Nginx/Socket.pm line 1356.
# Failed test 't/plugin/limit-count.t TEST 22: when the count is changed, check the limit is correct(from 1 to 2) - pattern "[error]" should not match any line in error.log but matches line "2026/04/21 15:09:43 [error] 2435232#2435232: *1556 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer" (req 0)
# 2026/04/21 15:09:43 [notice] 2435178#2435178: exiting
# 2026/04/21 15:09:43 [warn] 2435287#2435287: *1620 [lua] plugin.lua:237: load(): new plugins: {"public-api":true,"datadog":true,"lago":true,"loki-logger":true,"elasticsearch-logger":true,"echo":true,"redirect":true,"http-logger":true,"splunk-hec-logging":true,"skywalking-logger":true,"google-cloud-logging":true,"sls-logger":true,"tcp-logger":true,"kafka-logger":true,"rocketmq-logger":true,"syslog":true,"udp-logger":true,"prometheus":true,"clickhouse-logger":true,"tencent-cloud-cls":true,"inspect":true,"example-plugin":true,"aws-lambda":true,"azure-functions":true,"openwhisk":true,"openfunction":true,"serverless-post-function":true,"ext-plugin-post-req":true,"ext-plugin-post-resp":true,"ai-request-rewrite":true,"cas-auth":true,"file-logger":true,"loggly":true,"real-ip":true,"ai":true,"client-control":true,"proxy-control":true,"request-id":true,"zipkin":true,"ext-plugin-pre-req":true,"fault-injection":true,"mocking":true,"serverless-pre-function":true,"cors":true,"ip-restriction":true,"ua-restriction":true,"referer-restriction":true,"csrf":true,"uri-blocker":true,"request-validation":true,"chaitin-waf":true,"multi-auth":true,"openid-connect":true,"authz-casbin":true,"authz-casdoor":true,"wolf-rbac":true,"ldap-auth":true,"hmac-auth":true,"basic-auth":true,"jwt-auth":true,"jwe-decrypt":true,"key-auth":true,"consumer-restriction":true,"attach-consumer-label":true,"forward-auth":true,"opa":true,"authz-keycloak":true,"proxy-cache":true,"body-transformer":true,"ai-prompt-template":true,"ai-prompt-decorator":true,"ai-prompt-guard":true,"ai-rag":true,"ai-rate-limiting":true,"ai-proxy-multi":true,"ai-proxy":true,"ai-aws-content-moderation":true,"ai-aliyun-content-moderation":true,"proxy-mirror":true,"proxy-rewrite":true,"workflow":true,"api-breaker":true,"limit-conn":true,"limit-count":true,"limit-req":true,"gzip":true,"traffic-split":true,"response-rewrite":true,"mcp-bridge":true,"degraphql":true,"kafka-proxy":true,"grpc-transcode":true,"grpc-web":true,"http-dubbo":true}, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [notice] 2435178#2435178: exit
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] inspect.lua:52: init(): delay=3, hooks_file=/usr/local/apisix/plugin_inspect_hooks.lua, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [warn] 2435288#2435288: *1619 [lua] plugin.lua:237: load(): new plugins: {"public-api":true,"datadog":true,"lago":true,"loki-logger":true,"elasticsearch-logger":true,"echo":true,"redirect":true,"http-logger":true,"splunk-hec-logging":true,"skywalking-logger":true,"google-cloud-logging":true,"sls-logger":true,"tcp-logger":true,"kafka-logger":true,"rocketmq-logger":true,"syslog":true,"udp-logger":true,"prometheus":true,"clickhouse-logger":true,"tencent-cloud-cls":true,"inspect":true,"example-plugin":true,"aws-lambda":true,"azure-functions":true,"openwhisk":true,"openfunction":true,"serverless-post-function":true,"ext-plugin-post-req":true,"ext-plugin-post-resp":true,"ai-request-rewrite":true,"cas-auth":true,"file-logger":true,"loggly":true,"real-ip":true,"ai":true,"client-control":true,"proxy-control":true,"request-id":true,"zipkin":true,"ext-plugin-pre-req":true,"fault-injection":true,"mocking":true,"serverless-pre-function":true,"cors":true,"ip-restriction":true,"ua-restriction":true,"referer-restriction":true,"csrf":true,"uri-blocker":true,"request-validation":true,"chaitin-waf":true,"multi-auth":true,"openid-connect":true,"authz-casbin":true,"authz-casdoor":true,"wolf-rbac":true,"ldap-auth":true,"hmac-auth":true,"basic-auth":true,"jwt-auth":true,"jwe-decrypt":true,"key-auth":true,"consumer-restriction":true,"attach-consumer-label":true,"forward-auth":true,"opa":true,"authz-keycloak":true,"proxy-cache":true,"body-transformer":true,"ai-prompt-template":true,"ai-prompt-decorator":true,"ai-prompt-guard":true,"ai-rag":true,"ai-rate-limiting":true,"ai-proxy-multi":true,"ai-proxy":true,"ai-aws-content-moderation":true,"ai-aliyun-content-moderation":true,"proxy-mirror":true,"proxy-rewrite":true,"workflow":true,"api-breaker":true,"limit-conn":true,"limit-count":true,"limit-req":true,"gzip":true,"traffic-split":true,"response-rewrite":true,"mcp-bridge":true,"degraphql":true,"kafka-proxy":true,"grpc-transcode":true,"grpc-web":true,"http-dubbo":true}, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435231#2435231: *1628 client 127.0.0.1 closed keepalive connection
# 2026/04/21 15:09:43 [info] 2435288#2435288: *1619 [lua] inspect.lua:52: init(): delay=3, hooks_file=/usr/local/apisix/plugin_inspect_hooks.lua, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [notice] 2435287#2435287: *1620 [lua] config_etcd.lua:1059: new(): use loaded configuration /protos, context: init_worker_by_lua*
# 2026/04/21 15:09:43 [info] 2435287#2435287: *1620 [lua] plugin.lua:274: load(): load plugin times: 1, context: init_worker_by_lua*
# '
# at /usr/local/share/perl/5.34.0/Test/Nginx/Socket.pm line 1356.
t/plugin/limit-count.t .. 300/?
# Failed test 't/plugin/limit-count.t TEST 39: plugin is bound to the route and upstream is the domain name - pattern "[error]" should not match any line in error.log but matches line "2026/04/21 15:09:55 [error] 2436264#2436264: *2906 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer" (req 0)
# 2026/04/21 15:09:55 [error] 2436263#2436263: *2924 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer
# 2026/04/21 15:09:55 [notice] 2436206#2436206: exiting
# 2026/04/21 15:09:55 [notice] 2436380#2436380: *2990 [lua] config_etcd.lua:1059: new(): use loaded configuration /protos, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [info] 2436380#2436380: *2990 [lua] plugin.lua:274: load(): load plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [warn] 2436380#2436380: *2990 [lua] plugin.lua:287: load_stream(): new plugins: {"ip-restriction":true,"traffic-split":true,"mqtt-proxy":true,"limit-conn":true,"syslog":true}, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [notice] 2436206#2436206: exit
# 2026/04/21 15:09:55 [info] 2436380#2436380: *2990 [lua] plugin.lua:315: load_stream(): stream plugins: [{"priority":3000,"preread":"function: 0x7fde3ff52848","schema":{"type":"object","properties":{"whitelist":{"type":"array","items":{"anyOf":[{"type":"string","title":"IPv4","format":"ipv4"},{"type":"string","pattern":"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$","title":"IPv4/CIDR"},{"type":"string","title":"IPv6","format":"ipv6"},{"type":"string","pattern":"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$","title":"IPv6/CIDR"}]},"minItems":1},"blacklist":{"type":"array","items":{"anyOf":"table: 0x7fde5071c150"},"minItems":1},"message":{"type":"string","default":"Your IP address is not allowed","maxLength":1024,"minLength":1},"_meta":{"type":"object","properties":{"priority":{"type":"integer","description":"priority of plugins by customized order"},"disable":{"type":"boolean"},"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"pre_function":{"type":"string","description":"function to be executed in each phase before execution of plugins. The pre_function will have access to two arguments: `conf` and `ctx`."},"filter":{"type":"array","description":"filter determines whether the plugin needs to be executed at runtime"}},"additionalProperties":false},"response_code":{"type":"integer","maximum":404,"minimum":403,"default":403}},"$comment":"this is a mark for our injected plugin schema","oneOf":[{"required":["whitelist"]},{"required":["blacklist"]}]},"version":0.1,"check_schema":"function: 0x7fde3ff52690","name":"ip-restriction","restrict":"function: 0x7fde3ff52848"},{"priority":1003,"check_schema":"function: 0x7fde3f4f7b78","name":"limit-conn","version":0.1,"schema":{"type":"object","properties":{"_meta":"table: 0x7fde50785010","key":{"type":"string"},"burst":{"type":"integer","minimum":0},"default_conn_delay":{"type":"number","exclusiveMinimum":0},"conn":{"type":"integer","exclusiveMinimum":0},"only_use_default_delay":{"type":"boolean","default":false},"key_type":{"type":"string","enum":["var","var_combination"],"default":"var"}},"$comment":"this is a mark for our injected plugin schema","required":["conn","burst","default_conn_delay","key"]},"log":"function: 0x7fde3f4f7d60","preread":"function: 0x7fde3f4f7cf0"},{"priority":1000,"check_schema":"function: 0x7fde3f4f5cb8","name":"mqtt-proxy","version":0.1,"schema":{"type":"object","properties":{"_meta":"table: 0x7fde50785010","protocol_level":{"type":"integer"},"protocol_name":{"type":"string","default":"MQTT"}},"$comment":"this is a mark for our injected plugin schema","required":["protocol_level"]},"log":"function: 0x7fde3f4f60d0","preread":"function: 0x7fde3f4f5fd8"},{"priority":966,"check_schema":"function: 0x7fde3f507788","version":0.1,"schema":{"type":"object","properties":{"_meta":"table: 0x7fde50785010","rules":{"type":"array","items":{"type":"object","properties":{"match":{"type":"array","items":{"type":"object","properties":{"vars":{"type":"array"}}}},"weighted_upstreams":{"minItems":1,"default":[{"weight":1}],"type":"array","items":{"type":"object","properties":{"upstream_id":{"anyOf":[{"type":"string","pattern":"^[a-zA-Z0-9-_.]+$","maxLength":64,"minLength":1},{"type":"integer","minimum":1}]},"upstream":{"type":"object","properties":{"update_time":{"type":"integer"},"discovery_type":{"type":"string","description":"discovery type"},"discovery_args":{"type":"object","properties":{"namespace_id":{"type":"string","description":"namespace id"},"group_name":{"type":"string","description":"group name"}}},"name":{"type":"string","maxLength":256,"minLength":1},"key":{"type":"string","description":"the key of chash for dynamic load balancing"},"type":{"type":"string","description":"algorithms of load balancing","default":"roundrobin"},"desc":{"type":"string","maxLength":256},"labels":{"type":"object","description":"key/value pairs to specify attribu
# 2026/04/21 15:09:55 [info] 2436380#2436380: *2990 [lua] plugin.lua:317: load_stream(): load stream plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [notice] 2436380#2436380: *2990 [lua] config_etcd.lua:1059: new(): use loaded configuration /plugin_metadata, context: init_worker_by_lua*
# '
# at /usr/local/share/perl/5.34.0/Test/Nginx/Socket.pm line 1356.
# Failed test 't/plugin/limit-count.t TEST 39: plugin is bound to the route and upstream is the domain name - pattern "[error]" should not match any line in error.log but matches line "2026/04/21 15:09:55 [error] 2436263#2436263: *2924 [lua] worker.lua:266: communicate(): event worker failed: failed to receive the header bytes: closed, context: ngx.timer" (req 0)
# 2026/04/21 15:09:55 [notice] 2436206#2436206: exiting
# 2026/04/21 15:09:55 [notice] 2436380#2436380: *2990 [lua] config_etcd.lua:1059: new(): use loaded configuration /protos, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [info] 2436380#2436380: *2990 [lua] plugin.lua:274: load(): load plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [warn] 2436380#2436380: *2990 [lua] plugin.lua:287: load_stream(): new plugins: {"ip-restriction":true,"traffic-split":true,"mqtt-proxy":true,"limit-conn":true,"syslog":true}, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [notice] 2436206#2436206: exit
# 2026/04/21 15:09:55 [info] 2436380#2436380: *2990 [lua] plugin.lua:315: load_stream(): stream plugins: [{"priority":3000,"preread":"function: 0x7fde3ff52848","schema":{"type":"object","properties":{"whitelist":{"type":"array","items":{"anyOf":[{"type":"string","title":"IPv4","format":"ipv4"},{"type":"string","pattern":"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$","title":"IPv4/CIDR"},{"type":"string","title":"IPv6","format":"ipv6"},{"type":"string","pattern":"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$","title":"IPv6/CIDR"}]},"minItems":1},"blacklist":{"type":"array","items":{"anyOf":"table: 0x7fde5071c150"},"minItems":1},"message":{"type":"string","default":"Your IP address is not allowed","maxLength":1024,"minLength":1},"_meta":{"type":"object","properties":{"priority":{"type":"integer","description":"priority of plugins by customized order"},"disable":{"type":"boolean"},"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"pre_function":{"type":"string","description":"function to be executed in each phase before execution of plugins. The pre_function will have access to two arguments: `conf` and `ctx`."},"filter":{"type":"array","description":"filter determines whether the plugin needs to be executed at runtime"}},"additionalProperties":false},"response_code":{"type":"integer","maximum":404,"minimum":403,"default":403}},"$comment":"this is a mark for our injected plugin schema","oneOf":[{"required":["whitelist"]},{"required":["blacklist"]}]},"version":0.1,"check_schema":"function: 0x7fde3ff52690","name":"ip-restriction","restrict":"function: 0x7fde3ff52848"},{"priority":1003,"check_schema":"function: 0x7fde3f4f7b78","name":"limit-conn","version":0.1,"schema":{"type":"object","properties":{"_meta":"table: 0x7fde50785010","key":{"type":"string"},"burst":{"type":"integer","minimum":0},"default_conn_delay":{"type":"number","exclusiveMinimum":0},"conn":{"type":"integer","exclusiveMinimum":0},"only_use_default_delay":{"type":"boolean","default":false},"key_type":{"type":"string","enum":["var","var_combination"],"default":"var"}},"$comment":"this is a mark for our injected plugin schema","required":["conn","burst","default_conn_delay","key"]},"log":"function: 0x7fde3f4f7d60","preread":"function: 0x7fde3f4f7cf0"},{"priority":1000,"check_schema":"function: 0x7fde3f4f5cb8","name":"mqtt-proxy","version":0.1,"schema":{"type":"object","properties":{"_meta":"table: 0x7fde50785010","protocol_level":{"type":"integer"},"protocol_name":{"type":"string","default":"MQTT"}},"$comment":"this is a mark for our injected plugin schema","required":["protocol_level"]},"log":"function: 0x7fde3f4f60d0","preread":"function: 0x7fde3f4f5fd8"},{"priority":966,"check_schema":"function: 0x7fde3f507788","version":0.1,"schema":{"type":"object","properties":{"_meta":"table: 0x7fde50785010","rules":{"type":"array","items":{"type":"object","properties":{"match":{"type":"array","items":{"type":"object","properties":{"vars":{"type":"array"}}}},"weighted_upstreams":{"minItems":1,"default":[{"weight":1}],"type":"array","items":{"type":"object","properties":{"upstream_id":{"anyOf":[{"type":"string","pattern":"^[a-zA-Z0-9-_.]+$","maxLength":64,"minLength":1},{"type":"integer","minimum":1}]},"upstream":{"type":"object","properties":{"update_time":{"type":"integer"},"discovery_type":{"type":"string","description":"discovery type"},"discovery_args":{"type":"object","properties":{"namespace_id":{"type":"string","description":"namespace id"},"group_name":{"type":"string","description":"group name"}}},"name":{"type":"string","maxLength":256,"minLength":1},"key":{"type":"string","description":"the key of chash for dynamic load balancing"},"type":{"type":"string","description":"algorithms of load balancing","default":"roundrobin"},"desc":{"type":"string","maxLength":256},"labels":{"type":"object","description":"key/value pairs to specify attribu
# 2026/04/21 15:09:55 [info] 2436380#2436380: *2990 [lua] plugin.lua:317: load_stream(): load stream plugin times: 1, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [notice] 2436380#2436380: *2990 [lua] config_etcd.lua:1059: new(): use loaded configuration /plugin_metadata, context: init_worker_by_lua*
# 2026/04/21 15:09:55 [notice] 2436380#2436380: *2990 [lua] config_etcd.lua:1059: new(): use loaded configuration /routes, context: init_worker_by_lua*
# '
# at /usr/local/share/perl/5.34.0/Test/Nginx/Socket.pm line 1356.
t/plugin/limit-count.t .. Failed 6/327 subtests
Test Summary Report
-------------------
t/plugin/limit-count.t (Wstat: 0 Tests: 327 Failed: 6)
Failed tests: 42-43, 152-153, 302-303
Parse errors: No plan found in TAP output
Files=1, Tests=327, 26 wallclock secs ( 0.04 usr 0.01 sys + 3.16 cusr 1.72 csys = 4.93 CPU)
Result: FAIL
Current Behavior
when i execute auto-test, i frequently get err:
command:
PATH=/usr/local/openresty/nginx/sbin:/usr/bin:/usr/local/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/plugins/limit-count.tExpected Behavior
auto-test case run success
Error Logs
execute follow command to run auto-test case:
PATH=/usr/local/openresty/nginx/sbin:/usr/bin:/usr/local/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/plugins/limit-count.tfound err:
Steps to Reproduce
install enviroment:
execute follow command to run auto-test case:
PATH=/usr/local/openresty/nginx/sbin:/usr/bin:/usr/local/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/plugins/limit-count.tEnvironment