diff --git a/apisix/plugins/ai-rate-limiting.lua b/apisix/plugins/ai-rate-limiting.lua index c674bbef8460..2bbfa8acac40 100644 --- a/apisix/plugins/ai-rate-limiting.lua +++ b/apisix/plugins/ai-rate-limiting.lua @@ -27,8 +27,18 @@ local instance_limit_schema = { type = "object", properties = { name = {type = "string"}, - limit = {type = "integer", minimum = 1}, - time_window = {type = "integer", minimum = 1} + limit = { + oneOf = { + {type = "integer", minimum = 1}, + {type = "string"}, + }, + }, + time_window = { + oneOf = { + {type = "integer", minimum = 1}, + {type = "string"}, + }, + } }, required = {"name", "limit", "time_window"} } @@ -36,8 +46,18 @@ local instance_limit_schema = { local schema = { type = "object", properties = { - limit = {type = "integer", exclusiveMinimum = 0}, - time_window = {type = "integer", exclusiveMinimum = 0}, + limit = { + oneOf = { + {type = "integer", exclusiveMinimum = 0}, + {type = "string"}, + }, + }, + time_window = { + oneOf = { + {type = "integer", exclusiveMinimum = 0}, + {type = "string"}, + }, + }, show_limit_quota_header = {type = "boolean", default = true}, limit_strategy = { type = "string", diff --git a/apisix/plugins/limit-conn.lua b/apisix/plugins/limit-conn.lua index 6fdefd1f40d5..dd88162aff6a 100644 --- a/apisix/plugins/limit-conn.lua +++ b/apisix/plugins/limit-conn.lua @@ -24,8 +24,18 @@ local workflow = require("apisix.plugins.workflow") local schema = { type = "object", properties = { - conn = {type = "integer", exclusiveMinimum = 0}, -- limit.conn max - burst = {type = "integer", minimum = 0}, + conn = { + oneOf = { + {type = "integer", exclusiveMinimum = 0}, + {type = "string"}, + }, + }, + burst = { + oneOf = { + {type = "integer", minimum = 0}, + {type = "string"}, + }, + }, default_conn_delay = {type = "number", exclusiveMinimum = 0}, only_use_default_delay = {type = "boolean", default = false}, key = {type = "string"}, diff --git a/apisix/plugins/limit-conn/init.lua b/apisix/plugins/limit-conn/init.lua index 22ce44a120a3..6c5c823e11e1 100644 --- a/apisix/plugins/limit-conn/init.lua +++ b/apisix/plugins/limit-conn/init.lua @@ -18,6 +18,9 @@ local limit_conn_new = require("resty.limit.conn").new local core = require("apisix.core") local is_http = ngx.config.subsystem == "http" local sleep = core.sleep +local tonumber = tonumber +local type = type +local tostring = tostring local shdict_name = "plugin-limit-conn" if ngx.config.subsystem == "stream" then shdict_name = shdict_name .. "-stream" @@ -34,30 +37,55 @@ do end -local lrucache = core.lrucache.new({ - type = "plugin", -}) local _M = {} -local function create_limit_obj(conf) +local function create_limit_obj(ctx, conf) core.log.info("create new limit-conn plugin instance") + local conn = conf.conn + if type(conn) == "string" then + local err, _ + conn, err, _ = core.utils.resolve_var(conn, ctx.var) + if err then + return nil, "could not resolve vars in conn: " .. err + end + conn = tonumber(conn) + if not conn then + return nil, "resolved conn is not a number: " .. tostring(conn) + end + end + + local burst = conf.burst + if type(burst) == "string" then + local err, _ + burst, err, _ = core.utils.resolve_var(burst, ctx.var) + if err then + return nil, "could not resolve vars in burst: " .. err + end + burst = tonumber(burst) + if not burst then + return nil, "resolved burst is not a number: " .. tostring(burst) + end + end + + core.log.info("limit conn: ", conn, ", burst: ", burst) + if conf.policy == "redis" then core.log.info("create new limit-conn redis plugin instance") - return redis_single_new("plugin-limit-conn", conf, conf.conn, conf.burst, + return redis_single_new("plugin-limit-conn", conf, conn, burst, conf.default_conn_delay) elseif conf.policy == "redis-cluster" then core.log.info("create new limit-conn redis-cluster plugin instance") - return redis_cluster_new("plugin-limit-conn", conf, conf.conn, conf.burst, + return redis_cluster_new("plugin-limit-conn", conf, conn, burst, conf.default_conn_delay) else core.log.info("create new limit-conn plugin instance") - return limit_conn_new(shdict_name, conf.conn, conf.burst, + return limit_conn_new(shdict_name, conn, burst, conf.default_conn_delay) end end @@ -65,7 +93,7 @@ end function _M.increase(conf, ctx) core.log.info("ver: ", ctx.conf_version) - local lim, err = lrucache(conf, nil, create_limit_obj, conf) + local lim, err = create_limit_obj(ctx, conf) if not lim then core.log.error("failed to instantiate a resty.limit.conn object: ", err) if conf.allow_degradation then diff --git a/apisix/plugins/limit-count/init.lua b/apisix/plugins/limit-count/init.lua index c7b8579d0ffd..7d5fe7ca9baf 100644 --- a/apisix/plugins/limit-count/init.lua +++ b/apisix/plugins/limit-count/init.lua @@ -22,6 +22,9 @@ local pairs = pairs local redis_schema = require("apisix.utils.redis-schema") local policy_to_additional_properties = redis_schema.schema local get_phase = ngx.get_phase +local tonumber = tonumber +local type = type +local tostring = tostring local limit_redis_cluster_new local limit_redis_new @@ -36,9 +39,6 @@ do local cluster_src = "apisix.plugins.limit-count.limit-count-redis-cluster" limit_redis_cluster_new = require(cluster_src).new end -local lrucache = core.lrucache.new({ - type = 'plugin', serial_creating = true, -}) local group_conf_lru = core.lrucache.new({ type = 'plugin', }) @@ -70,8 +70,18 @@ local metadata_schema = { local schema = { type = "object", properties = { - count = {type = "integer", exclusiveMinimum = 0}, - time_window = {type = "integer", exclusiveMinimum = 0}, + count = { + oneOf = { + {type = "integer", exclusiveMinimum = 0}, + {type = "string"}, + }, + }, + time_window = { + oneOf = { + {type = "integer", exclusiveMinimum = 0}, + {type = "string"}, + }, + }, group = {type = "string"}, key = {type = "string", default = "remote_addr"}, key_type = {type = "string", @@ -174,22 +184,47 @@ function _M.check_schema(conf, schema_type) end -local function create_limit_obj(conf, plugin_name) +local function create_limit_obj(conf, ctx, plugin_name) core.log.info("create new " .. plugin_name .. " plugin instance") + local count = conf.count + if type(count) == "string" then + local err, _ + count, err, _ = core.utils.resolve_var(count, ctx.var) + if err then + return nil, "could not resolve vars in count: " .. err + end + count = tonumber(count) + if not count then + return nil, "resolved count is not a number: " .. tostring(count) + end + end + + local time_window = conf.time_window + if type(time_window) == "string" then + local err, _ + time_window, err, _ = core.utils.resolve_var(time_window, ctx.var) + if err then + return nil, "could not resolve vars in time_window: " .. err + end + time_window = tonumber(time_window) + if not time_window then + return nil, "resolved time_window is not a number: " .. tostring(time_window) + end + end + + core.log.info("limit count: ", count, ", time_window: ", time_window) + if not conf.policy or conf.policy == "local" then - return limit_local_new("plugin-" .. plugin_name, conf.count, - conf.time_window) + return limit_local_new("plugin-" .. plugin_name, count, time_window) end if conf.policy == "redis" then - return limit_redis_new("plugin-" .. plugin_name, - conf.count, conf.time_window, conf) + return limit_redis_new("plugin-" .. plugin_name, count, time_window, conf) end if conf.policy == "redis-cluster" then - return limit_redis_cluster_new("plugin-" .. plugin_name, conf.count, - conf.time_window, conf) + return limit_redis_cluster_new("plugin-" .. plugin_name, count, time_window, conf) end return nil @@ -223,26 +258,11 @@ local function gen_limit_key(conf, ctx, key) end -local function gen_limit_obj(conf, ctx, plugin_name) - if conf.group then - return lrucache(conf.group, "", create_limit_obj, conf, plugin_name) - end - - local extra_key - if conf._vid then - extra_key = conf.policy .. '#' .. conf._vid - else - extra_key = conf.policy - end - - return core.lrucache.plugin_ctx(lrucache, ctx, extra_key, create_limit_obj, conf, plugin_name) -end - function _M.rate_limit(conf, ctx, name, cost, dry_run) core.log.info("ver: ", ctx.conf_version) core.log.info("conf: ", core.json.delay_encode(conf, true)) - local lim, err = gen_limit_obj(conf, ctx, name) + local lim, err = create_limit_obj(conf, ctx, name) if not lim then core.log.error("failed to fetch limit.count object: ", err) @@ -307,7 +327,7 @@ function _M.rate_limit(conf, ctx, name, cost, dry_run) if err == "rejected" then -- show count limit header when rejected if conf.show_limit_quota_header and set_header then - core.response.set_header(set_limit_headers.limit_header, conf.count, + core.response.set_header(set_limit_headers.limit_header, lim.limit, set_limit_headers.remaining_header, 0, set_limit_headers.reset_header, reset) end @@ -326,7 +346,7 @@ function _M.rate_limit(conf, ctx, name, cost, dry_run) end if conf.show_limit_quota_header and set_header then - core.response.set_header(set_limit_headers.limit_header, conf.count, + core.response.set_header(set_limit_headers.limit_header, lim.limit, set_limit_headers.remaining_header, remaining, set_limit_headers.reset_header, reset) end diff --git a/apisix/plugins/limit-count/limit-count-local.lua b/apisix/plugins/limit-count/limit-count-local.lua index b6f319ae0106..9ad33d89cf61 100644 --- a/apisix/plugins/limit-count/limit-count-local.lua +++ b/apisix/plugins/limit-count/limit-count-local.lua @@ -57,7 +57,9 @@ function _M.new(plugin_name, limit, window) local self = { limit_count = limit_count.new(plugin_name, limit, window), - dict = ngx.shared[plugin_name .. "-reset-header"] + dict = ngx.shared[plugin_name .. "-reset-header"], + limit = limit, + window = window, } return setmetatable(self, mt) @@ -67,8 +69,8 @@ function _M.incoming(self, key, commit, conf, cost) local delay, remaining = self.limit_count:incoming(key, commit, cost) local reset - if remaining == conf.count - cost then - reset = set_endtime(self, key, conf.time_window) + if remaining == self.limit - cost then + reset = set_endtime(self, key, self.window) else reset = read_reset(self, key) end diff --git a/t/plugin/ai-rate-limiting.t b/t/plugin/ai-rate-limiting.t index 66aa0b07f164..c6112b9ab638 100644 --- a/t/plugin/ai-rate-limiting.t +++ b/t/plugin/ai-rate-limiting.t @@ -984,3 +984,209 @@ passed Authorization: Bearer token --- error_code eval [200, 200, 200, 200, 200, 200, 200, 503, 503] + + + +=== TEST 21: use variable in count and time_window with default value +--- config + location /t { + content_by_lua_block { + local core = require("apisix.core") + local data = { + uri = "/ai", + plugins = { + ["ai-proxy-multi"] = { + fallback_strategy = "instance_health_and_rate_limiting", + instances = { + { + name = "deepseek", + provider = "openai", + weight = 1, + priority = 1, + auth = { + header = { + Authorization = "Bearer token" + } + }, + override = { + endpoint = "http://localhost:16724" + } + }, + { + name = "openai", + provider = "openai", + weight = 1, + priority = 0, + auth = { + header = { + Authorization = "Bearer token" + } + }, + override = { + endpoint = "http://localhost:16724" + } + } + }, + ssl_verify = false + }, + ["ai-rate-limiting"] = { + limit = "${http_count ?? 10}", + time_window = "${http_time_window ?? 60}", + instances = { + { + name = "openai", + limit = "${http_openai_count ?? 20}", + time_window = "${http_time_window ?? 60}" + } + } + } + }, + upstream = { + type = "roundrobin", + nodes = { + ["canbeanything.com"] = 1 + } + } + } + + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + core.json.encode(data) + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 22: request with default variable values +--- config + location /t { + content_by_lua_block { + local http = require("resty.http") + + local test_cases = { + { code = 200 }, + { code = 200 }, + { code = 200 }, + { code = 503 }, + } + + local httpc = http.new() + for i, case in ipairs(test_cases) do + local res = httpc:request_uri( + "http://127.0.0.1:" .. ngx.var.server_port .. "/ai", + { + method = "POST", + body = [[{ + "messages": [ + { "role": "system", "content": "You are a mathematician" }, + { "role": "user", "content": "What is 1+1?" } + ] + }]], + headers = { + ["Content-Type"] = "application/json", + } + } + ) + if res.status ~= case.code then + ngx.say( i .. "th request should return " .. case.code .. ", but got " .. res.status) + return + end + end + + ngx.say("passed") + } + } +--- request +GET /t +--- timeout: 10 +--- response_body +passed +--- grep_error_log eval +qr/picked instance: [^,]+/ +--- grep_error_log_out +picked instance: deepseek +picked instance: openai +picked instance: openai +picked instance: nil + + + +=== TEST 23: request with custom count/time_window headers +--- config + location /t { + content_by_lua_block { + local http = require("resty.http") + + local test_cases = { + { count = 20, openai_count = 30, time_window = 2, code = 200 }, + { count = 20, openai_count = 30, time_window = 2, code = 200 }, + { count = 20, openai_count = 30, time_window = 2, code = 200 }, + { count = 20, openai_count = 30, time_window = 2, code = 200 }, + { count = 20, openai_count = 30, time_window = 2, code = 200 }, + { count = 20, openai_count = 30, time_window = 2, code = 503 }, + } + + local run_tests = function() + local httpc = http.new() + for i, case in ipairs(test_cases) do + local res = httpc:request_uri( + "http://127.0.0.1:" .. ngx.var.server_port .. "/ai", + { + method = "POST", + body = [[{ + "messages": [ + { "role": "system", "content": "You are a mathematician" }, + { "role": "user", "content": "What is 1+1?" } + ] + }]], + headers = { + ["Content-Type"] = "application/json", + ["count"] = tostring(case.count), + ["time-window"] = tostring(case.time_window), + ["openai-count"] = tostring(case.openai_count), + } + } + ) + if res.status ~= case.code then + ngx.say( i .. "th request should return " .. case.code .. ", but got " .. res.status) + ngx.exit(500) + end + end + end + + run_tests() + ngx.sleep(2) + run_tests() + + ngx.say("passed") + } + } +--- request +GET /t +--- timeout: 10 +--- response_body +passed +--- grep_error_log eval +qr/picked instance: [^,]+/ +--- grep_error_log_out +picked instance: deepseek +picked instance: deepseek +picked instance: openai +picked instance: openai +picked instance: openai +picked instance: nil +picked instance: deepseek +picked instance: deepseek +picked instance: openai +picked instance: openai +picked instance: openai +picked instance: nil diff --git a/t/plugin/limit-conn-variable.t b/t/plugin/limit-conn-variable.t new file mode 100644 index 000000000000..8c82100e48ef --- /dev/null +++ b/t/plugin/limit-conn-variable.t @@ -0,0 +1,178 @@ +# +# 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. +# + +BEGIN { + if ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable for the hup tests"; + + } else { + $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; + } +} + +use t::APISIX 'no_plan'; + +repeat_each(1); +no_long_string(); +no_shuffle(); +no_root_location(); +log_level('info'); + + +add_block_preprocessor(sub { + my ($block) = @_; + my $port = $ENV{TEST_NGINX_SERVER_PORT}; + + my $config = $block->config // <<_EOC_; + location /access_root_dir { + content_by_lua_block { + local httpc = require "resty.http" + local hc = httpc:new() + + local res, err = hc:request_uri('http://127.0.0.1:$port/limit_conn', { + headers = ngx.req.get_headers() + }) + if res then + ngx.exit(res.status) + end + } + } + + location /test_concurrency { + content_by_lua_block { + local reqs = {} + for i = 1, 10 do + reqs[i] = { "/access_root_dir" } + end + local resps = { ngx.location.capture_multi(reqs) } + for i, resp in ipairs(resps) do + ngx.say(resp.status) + end + } + } +_EOC_ + + $block->set_value("config", $config); +}); + +run_tests; + +__DATA__ + +=== TEST 1: use variable in conn and burst with default value +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "limit-conn": { + "conn": "${http_conn ?? 5}", + "burst": "${http_burst ?? 2}", + "default_conn_delay": 0.1, + "rejected_code": 503, + "key": "remote_addr" + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/limit_conn" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed + + + +=== TEST 2: request without conn/burst headers +--- request +GET /test_concurrency +--- timeout: 10s +--- response_body +200 +200 +200 +200 +200 +200 +200 +503 +503 +503 +--- error_log +limit conn: 5, burst: 2 + + + +=== TEST 3: request with conn header +--- request +GET /test_concurrency +--- more_headers +conn: 3 +--- timeout: 10s +--- response_body +200 +200 +200 +200 +200 +503 +503 +503 +503 +503 +--- error_log +limit conn: 3, burst: 2 + + + +=== TEST 4: request with conn and burst header +--- request +GET /test_concurrency +--- more_headers +conn: 3 +burst: 4 +--- timeout: 10s +--- response_body +200 +200 +200 +200 +200 +200 +200 +503 +503 +503 +--- error_log +limit conn: 3, burst: 4 diff --git a/t/plugin/limit-conn.t b/t/plugin/limit-conn.t index 0182019ee6d4..364282f49cfd 100644 --- a/t/plugin/limit-conn.t +++ b/t/plugin/limit-conn.t @@ -362,7 +362,7 @@ GET /t GET /t --- error_code: 400 --- response_body -{"error_msg":"failed to check the configuration of plugin limit-conn err: property \"conn\" validation failed: expected -1 to be greater than 0"} +{"error_msg":"failed to check the configuration of plugin limit-conn err: property \"conn\" validation failed: value should match only one schema, but matches none"} @@ -441,7 +441,7 @@ GET /t GET /t --- error_code: 400 --- response_body -{"error_msg":"failed to check the configuration of plugin limit-conn err: property \"conn\" validation failed: expected -1 to be greater than 0"} +{"error_msg":"failed to check the configuration of plugin limit-conn err: property \"conn\" validation failed: value should match only one schema, but matches none"} @@ -868,7 +868,7 @@ GET /test_concurrency --- request GET /t --- response_body -property "conn" validation failed: expected 0 to be greater than 0 +property "conn" validation failed: value should match only one schema, but matches none property "default_conn_delay" validation failed: expected 0 to be greater than 0 done diff --git a/t/plugin/limit-count-redis-cluster.t b/t/plugin/limit-count-redis-cluster.t index 7a4798a60e48..1263f80a3682 100644 --- a/t/plugin/limit-count-redis-cluster.t +++ b/t/plugin/limit-count-redis-cluster.t @@ -167,9 +167,6 @@ passed === TEST 4: up the limit --- request GET /hello ---- error_log -try to lock with key route#1#redis-cluster -unlock with key route#1#redis-cluster diff --git a/t/plugin/limit-count-redis.t b/t/plugin/limit-count-redis.t index d06188050df2..db13ba4e45c5 100644 --- a/t/plugin/limit-count-redis.t +++ b/t/plugin/limit-count-redis.t @@ -169,9 +169,6 @@ passed === TEST 4: up the limit --- request GET /hello ---- error_log -try to lock with key route#1#redis -unlock with key route#1#redis diff --git a/t/plugin/limit-count-variable.t b/t/plugin/limit-count-variable.t new file mode 100644 index 000000000000..ad021c2d5284 --- /dev/null +++ b/t/plugin/limit-count-variable.t @@ -0,0 +1,145 @@ +# +# 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'; + +no_long_string(); +no_shuffle(); +no_root_location(); +log_level('info'); + +add_block_preprocessor(sub { + my ($block) = @_; + + if (!$block->request) { + $block->set_value("request", "GET /t"); + } + + if (!$block->error_log && !$block->no_error_log) { + $block->set_value("no_error_log", "[error]\n[alert]"); + } +}); + +run_tests; + +__DATA__ + +=== TEST 1: use variable in count and time_window with default value +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "plugins": { + "limit-count": { + "count": "${http_count ?? 2}", + "time_window": "${http_time_window ?? 5}", + "rejected_code": 503, + "key_type": "var", + "key": "remote_addr", + "policy": "local" + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 2: request without count/time_window headers +--- pipelined_requests eval +["GET /hello", "GET /hello", "GET /hello"] +--- error_code eval +[200, 200, 503] + + + +=== TEST 3: request with count header +--- pipelined_requests eval +["GET /hello", "GET /hello", "GET /hello"] +--- more_headers +count: 5 +--- error_code eval +[200, 200, 200, 200, 200, 503] + + + +=== TEST 4: request with count and time_window header +--- config + location /t { + content_by_lua_block { + local http = require("resty.http") + local core = require("apisix.core") + + local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello" + local opt = {method = "GET", headers = { ["count"] = 3, ["time-window"] = "2" }} + local httpc = http.new() + + for i = 1, 3, 1 do + local res = httpc:request_uri(uri, opt) + if res.status ~= 200 then + ngx.say("first two requests should return 200, but got " .. res.status) + return + end + if res.headers["X-RateLimit-Limit"] ~= "3" then + ngx.say("X-RateLimit-Limit should be 3, but got " .. core.json.encode(res.headers)) + return + end + end + local res = httpc:request_uri(uri, opt) + if res.status ~= 503 then + ngx.say("third requests should return 503, but got " .. res.status) + return + end + + ngx.sleep(2) + + for i = 1, 3, 1 do + local res = httpc:request_uri(uri, opt) + if res.status ~= 200 then + ngx.say("two requests after sleep 2s should return 200, but got " .. res.status) + return + end + end + ngx.say("passed") + } + } +--- request +GET /t +--- timeout: 10 +--- response_body +passed +--- error_log +limit count: 3, time_window: 2 diff --git a/t/plugin/limit-count.t b/t/plugin/limit-count.t index f150c01d020d..402c93dd2008 100644 --- a/t/plugin/limit-count.t +++ b/t/plugin/limit-count.t @@ -253,7 +253,7 @@ passed } --- error_code: 400 --- response_body -{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: expected -100 to be greater than 0"} +{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: value should match only one schema, but matches none"} @@ -291,7 +291,7 @@ passed } --- error_code: 400 --- response_body -{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: expected -100 to be greater than 0"} +{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: value should match only one schema, but matches none"} @@ -363,7 +363,7 @@ passed } --- error_code: 400 --- response_body -{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: expected -100 to be greater than 0"} +{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: value should match only one schema, but matches none"} @@ -400,7 +400,7 @@ passed } --- error_code: 400 --- response_body -{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: expected -100 to be greater than 0"} +{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" validation failed: value should match only one schema, but matches none"} @@ -1171,7 +1171,7 @@ passed } } --- response_body eval -qr/property \"count\" validation failed: expected 0 to be greater than 0/ +qr/property \"count\" validation failed: value should match only one schema, but matches none/ @@ -1189,4 +1189,4 @@ qr/property \"count\" validation failed: expected 0 to be greater than 0/ } } --- response_body eval -qr/property \"time_window\" validation failed: expected 0 to be greater than 0/ +qr/property \"time_window\" validation failed: value should match only one schema, but matches none/