feat(apisix): add Cloudron package

- Implements Apache APISIX packaging for Cloudron platform.
- Includes Dockerfile, CloudronManifest.json, and start.sh.
- Configured to use Cloudron's etcd addon.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
This commit is contained in:
2025-09-04 09:42:47 -05:00
parent f7bae09f22
commit 54cc5f7308
1608 changed files with 388342 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
#
# 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_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /apisix/admin/routes");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: Server header for admin API
--- response_headers_like
Server: APISIX/(.*)
=== TEST 2: Server header for admin API without token
--- yaml_config
deployment:
admin:
admin_key:
- key: a
name: a
role: admin
apisix:
node_listen: 1984
enable_server_tokens: false
--- error_code: 401
--- response_headers
Server: APISIX
=== TEST 3: Version header for admin API (without apikey)
--- yaml_config
deployment:
admin:
admin_key:
- key: a
name: a
role: admin
apisix:
admin_api_version: default
--- error_code: 401
--- response_headers
! X-API-VERSION
=== TEST 4: Version header for admin API (v2)
--- yaml_config
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: ~
admin_api_version: v2
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- response_headers
X-API-VERSION: v2
=== TEST 5: Version header for admin API (v3)
--- yaml_config
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: ~
admin_api_version: v3
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- response_headers
X-API-VERSION: v3
=== TEST 6: CORS header for admin API
--- response_headers
Access-Control-Allow-Origin: *
=== TEST 7: CORS header disabled for admin API
--- yaml_config
deployment:
admin:
admin_key: ~
enable_admin_cors: false
--- response_headers
Access-Control-Allow-Origin:
=== TEST 8: Compatibility for admin API (v2)
--- yaml_config
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: ~
admin_api_version: default
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- response_headers
X-API-VERSION: v2
--- response_body_like: "/apisix/routes"
=== TEST 9: Head method support for admin API
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin',
ngx.HTTP_HEAD)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: Access with api key, and admin_key_required=true
--- yaml_config
deployment:
admin:
admin_key_required: true
admin_key:
- name: admin
role: admin
key: rDAkLJbqvoBzBOoxuYAUDbbWaSilvIca
--- more_headers
X-API-KEY: rDAkLJbqvoBzBOoxuYAUDbbWaSilvIca
--- request
GET /apisix/admin/routes
--- error_code: 200
=== TEST 11: Access with wrong api key, and admin_key_required=true
--- yaml_config
deployment:
admin:
admin_key_required: true
--- more_headers
X-API-KEY: wrong-key
--- request
GET /apisix/admin/routes
--- error_code: 401
=== TEST 12: Access without api key, and admin_key_required=true
--- yaml_config
deployment:
admin:
admin_key_required: true
--- request
GET /apisix/admin/routes
--- error_code: 401
=== TEST 13: Access with api key, but admin_key_required=false
--- yaml_config
deployment:
admin:
admin_key_required: false
admin_key:
- name: admin
role: admin
key: rDAkLJbqvoBzBOoxuYAUDbbWaSilvIca
--- more_headers
X-API-KEY: rDAkLJbqvoBzBOoxuYAUDbbWaSilvIca
--- request
GET /apisix/admin/routes
--- error_code: 200
--- error_log
Admin key is bypassed!
=== TEST 14: Access with wrong api key, but admin_key_required=false
--- yaml_config
deployment:
admin:
admin_key_required: false
--- more_headers
X-API-KEY: wrong-key
--- request
GET /apisix/admin/routes
--- error_code: 200
--- error_log
Admin key is bypassed!
=== TEST 15: Access without api key, but admin_key_required=false
--- yaml_config
deployment:
admin:
admin_key_required: false
--- request
GET /apisix/admin/routes
--- error_code: 200
--- error_log
Admin key is bypassed!

View File

@@ -0,0 +1,243 @@
#
# 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(2);
no_long_string();
no_root_location();
add_block_preprocessor(sub {
my ($block) = @_;
my $init_by_lua_block = <<_EOC_;
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
function test(route, ctx, count)
local balancer = require("apisix.balancer")
local res = {}
for i = 1, count or 12 do
ctx.balancer_try_count = 0
local server, err = balancer.pick_server(route, ctx)
if err then
ngx.say("failed: ", err)
end
core.log.warn("host: ", server.host, " port: ", server.port)
res[server.host] = (res[server.host] or 0) + 1
end
local keys = {}
for k,v in pairs(res) do
table.insert(keys, k)
end
table.sort(keys)
for _, key in ipairs(keys) do
ngx.say("host: ", key, " count: ", res[key])
end
ctx.server_picker = nil
end
_EOC_
$block->set_value("init_by_lua_block", $init_by_lua_block);
});
run_tests;
__DATA__
=== TEST 1: roundrobin with same weight
--- config
location /t {
content_by_lua_block {
local up_conf = {
type = "roundrobin",
nodes = {
{host = "39.97.63.215", port = 80, weight = 1, priority = 0},
{host = "39.97.63.216", port = 81, weight = 1, priority = 0},
{host = "39.97.63.217", port = 82, weight = 1, priority = 0},
}
}
local ctx = {conf_version = 1}
ctx.upstream_conf = up_conf
ctx.upstream_version = "ver"
ctx.upstream_key = up_conf.type .. "#route_" .. "id"
test(route, ctx)
}
}
--- request
GET /t
--- response_body
host: 39.97.63.215 count: 4
host: 39.97.63.216 count: 4
host: 39.97.63.217 count: 4
=== TEST 2: roundrobin with different weight
--- config
location /t {
content_by_lua_block {
local up_conf = {
type = "roundrobin",
nodes = {
{host = "39.97.63.215", port = 80, weight = 1, priority = 0},
{host = "39.97.63.216", port = 81, weight = 2, priority = 0},
{host = "39.97.63.217", port = 82, weight = 3, priority = 0},
}
}
local ctx = {conf_version = 1}
ctx.upstream_conf = up_conf
ctx.upstream_version = "ver"
ctx.upstream_key = up_conf.type .. "#route_" .. "id"
test(route, ctx)
}
}
--- request
GET /t
--- response_body
host: 39.97.63.215 count: 2
host: 39.97.63.216 count: 4
host: 39.97.63.217 count: 6
=== TEST 3: roundrobin, cached server picker by version
--- config
location /t {
content_by_lua_block {
local up_conf = {
type = "roundrobin",
nodes = {
{host = "39.97.63.215", port = 80, weight = 1, priority = 0},
{host = "39.97.63.216", port = 81, weight = 1, priority = 0},
{host = "39.97.63.217", port = 82, weight = 1, priority = 0},
}
}
local ctx = {}
ctx.upstream_conf = up_conf
ctx.upstream_version = 1
ctx.upstream_key = up_conf.type .. "#route_" .. "id"
test(route, ctx)
-- cached by version
up_conf.nodes = {
{host = "39.97.63.218", port = 80, weight = 1, priority = 0},
{host = "39.97.63.219", port = 80, weight = 0, priority = 0},
}
test(route, ctx)
-- update, version changed
ctx.upstream_version = 2
test(route, ctx)
}
}
--- request
GET /t
--- response_body
host: 39.97.63.215 count: 4
host: 39.97.63.216 count: 4
host: 39.97.63.217 count: 4
host: 39.97.63.215 count: 4
host: 39.97.63.216 count: 4
host: 39.97.63.217 count: 4
host: 39.97.63.218 count: 12
=== TEST 4: chash
--- config
location /t {
content_by_lua_block {
local up_conf = {
type = "chash",
key = "remote_addr",
nodes = {
{host = "39.97.63.215", port = 80, weight = 1, priority = 0},
{host = "39.97.63.216", port = 81, weight = 1, priority = 0},
{host = "39.97.63.217", port = 82, weight = 1, priority = 0},
}
}
local ctx = {
var = {remote_addr = "127.0.0.1"},
}
ctx.upstream_conf = up_conf
ctx.upstream_version = 1
ctx.upstream_key = up_conf.type .. "#route_" .. "id"
test(route, ctx)
-- cached by version
up_conf.nodes = {
{host = "39.97.63.218", port = 80, weight = 1, priority = 0},
{host = "39.97.63.219", port = 80, weight = 0, priority = 0},
}
test(route, ctx)
-- update, version changed
ctx.upstream_version = 2
test(route, ctx)
}
}
--- request
GET /t
--- response_body
host: 39.97.63.215 count: 12
host: 39.97.63.215 count: 12
host: 39.97.63.218 count: 12
=== TEST 5: return item directly if only have one item in `nodes`
--- config
location /t {
content_by_lua_block {
local up_conf = {
type = "roundrobin",
nodes = {
{host = "39.97.63.215", port = 80, weight = 1, priority = 0},
{host = "39.97.63.216", port = 81, weight = 1, priority = 0},
{host = "39.97.63.217", port = 82, weight = 1, priority = 0},
}
}
local ctx = {}
ctx.upstream_conf = up_conf
ctx.upstream_version = 1
ctx.upstream_key = up_conf.type .. "#route_" .. "id"
test(route, ctx)
-- one item in nodes, return it directly
up_conf.nodes = {
{host = "39.97.63.218", port = 80, weight = 1, priority = 0},
}
test(route, ctx)
}
}
--- request
GET /t
--- response_body
host: 39.97.63.215 count: 4
host: 39.97.63.216 count: 4
host: 39.97.63.217 count: 4
host: 39.97.63.218 count: 12

View File

@@ -0,0 +1,163 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set consumer_group(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 200,
"time_window": 60,
"rejected_code": 503,
"group": "consumer_group_1"
}
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 201
--- response_body
passed
=== TEST 2: add consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumers/1',
ngx.HTTP_PUT,
[[{
"username": "1",
"plugins": {
"key-auth": {
"key": "auth-one"
}
},
"group_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 3: delete consumer_group(wrong header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumer_groups/1?force=anyvalue',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this consumer group, consumer [1] is still using it now"}
=== TEST 4: delete consumer_group(without force delete header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumer_groups/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this consumer group, consumer [1] is still using it now"}
=== TEST 5: delete consumer_group(force delete)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumer_groups/1?force=true',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed
=== TEST 6: delete consumer
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/consumers/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed

View File

@@ -0,0 +1,549 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: PUT
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/consumer_groups/company_a"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/consumer_groups/company_a'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 2: GET
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_GET,
nil,
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/consumer_groups/company_a"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: GET all
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups',
ngx.HTTP_GET,
nil,
[[{
"total": 1,
"list": [
{
"key": "/apisix/consumer_groups/company_a",
"value": {
"plugins": {
"limit-count": {
"time_window": 60,
"policy": "local",
"count": 2,
"key": "remote_addr",
"rejected_code": 503
}
}
}
}
]
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: PATCH
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumer_groups/company_a'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_PATCH,
[[{
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/consumer_groups/company_a"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/consumer_groups/company_a'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- response_body
passed
=== TEST 5: PATCH (sub path)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumer_groups/company_a'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/consumer_groups/company_a/plugins',
ngx.HTTP_PATCH,
[[{
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/consumer_groups/company_a"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/consumer_groups/company_a'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- response_body
passed
=== TEST 6: invalid plugin
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"rejected_code": 503,
"time_window": 60,
"key": "remote_addr"
}
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- response_body
{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" is required"}
--- error_code: 400
=== TEST 7: PUT (with non-plugin fields)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"labels": {
"你好": "世界"
},
"desc": "blah"
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"labels": {
"你好": "世界"
},
"desc": "blah"
},
"key": "/apisix/consumer_groups/company_a"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/consumer_groups/company_a'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 8: GET (with non-plugin fields)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_GET,
nil,
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"labels": {
"你好": "世界"
},
"desc": "blah"
},
"key": "/apisix/consumer_groups/company_a"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: invalid non-plugin fields
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_PUT,
[[{
"labels": "a",
"plugins": {
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- response_body
{"error_msg":"invalid configuration: property \"labels\" validation failed: wrong type: expected object, got string"}
--- error_code: 400
=== TEST 10: set consumer-group
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/consumer_groups/company_a'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 11: add consumer with group
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/foobar',
ngx.HTTP_PUT,
[[{
"username": "foobar",
"plugins": {
"key-auth": {
"key": "auth-two"
}
},
"group_id": "company_a"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: delete-consumer group failed
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_DELETE
)
ngx.print(body)
}
}
--- response_body
{"error_msg":"can not delete this consumer group, consumer [foobar] is still using it now"}
=== TEST 13: delete consumer
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/foobar',
ngx.HTTP_DELETE
)
ngx.say(body)
}
}
--- response_body
passed
=== TEST 14: delete consumer-group
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumer_groups/company_a',
ngx.HTTP_DELETE
)
ngx.say(body)
}
}
--- response_body
passed
=== TEST 15: add consumer with invalid group
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/foobar',
ngx.HTTP_PUT,
[[{
"username": "foobar",
"plugins": {
"key-auth": {
"key": "auth-two"
}
},
"group_id": "invalid_group"
}]]
)
assert(code >= 300)
ngx.say(body)
}
}
--- response_body_like
.*failed to fetch consumer group info by consumer group id.*

View File

@@ -0,0 +1,362 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: add consumer with username
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack",
"desc": "new consumer"
}]],
[[{
"value": {
"username": "jack",
"desc": "new consumer"
},
"key": "/apisix/consumers/jack"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: update consumer with username and plugins
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/jack'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "jack",
"desc": "new consumer",
"plugins": {
"key-auth": {
"key": "auth-one"
}
}
}]],
[[{
"value": {
"username": "jack",
"desc": "new consumer",
"plugins": {
"key-auth": {
"key": "4y+JvURBE6ZwRbbgaryrhg=="
}
}
},
"key": "/apisix/consumers/jack"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/consumers/jack'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: get consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_GET,
nil,
[[{
"value": {
"username": "jack",
"desc": "new consumer",
"plugins": {
"key-auth": {
"key": "auth-one"
}
}
},
"key": "/apisix/consumers/jack"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: delete consumer
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_DELETE
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: delete consumer(id: not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/consumers/not_found',
ngx.HTTP_DELETE,
nil
)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 6: missing username
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"id":"jack"
}]],
[[{
"value": {
"id": "jack"
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"username\" is required"}
=== TEST 7: consumer username allows '-' in it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"Jack-and-Rose_123"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 201
=== TEST 8: add consumer with labels
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack",
"desc": "new consumer",
"labels": {
"build":"16",
"env":"production",
"version":"v2"
}
}]],
[[{
"value": {
"username": "jack",
"desc": "new consumer",
"labels": {
"build":"16",
"env":"production",
"version":"v2"
}
},
"key": "/apisix/consumers/jack"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: invalid format of label value: set consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack",
"desc": "new consumer",
"labels": {
"env": ["production", "release"]
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
=== TEST 10: post consumers
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_POST,
""
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 405
--- response_body
{"error_msg":"not supported `POST` method for consumer"}
=== TEST 11: add consumer with create_time and update_time(pony)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"pony",
"desc": "new consumer",
"create_time": 1602883670,
"update_time": 1602893670
}]],
[[{
"value": {
"username": "pony",
"desc": "new consumer",
"create_time": 1602883670,
"update_time": 1602893670
},
"key": "/apisix/consumers/pony"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"the property is forbidden:.*"\}/

View File

@@ -0,0 +1,176 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/consumers/jack","value":{"username":"jack"}}
=== TEST 2: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/consumers/jack',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/consumers/jack","value":{"username":"jack"}}
=== TEST 3: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/consumers/jack',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/consumers/jack"}
=== TEST 4: list empty resources
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/consumers',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"list":[],"total":0}
=== TEST 5: mismatched username, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/consumers/jack1',
ngx.HTTP_PUT,
[[{
"username":"jack"
}]]
)
ngx.print(message)
}
}
--- response_body
{"error_msg":"wrong username"}

View File

@@ -0,0 +1,494 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: create a credential for invalid consumer: consumer not found error
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_a',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {
"key": "the-key"
}
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 404
--- response_body
{"error_msg":"consumer not found"}
=== TEST 2: add a consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack",
"desc": "new consumer",
"plugins": {
"basic-auth": {
"username": "the-user",
"password": "the-password"
}
}
}]],
[[{
"key": "/apisix/consumers/jack",
"value":
{
"username":"jack",
"desc": "new consumer",
"plugins": {
"basic-auth": {
"username": "the-user",
"password": "WvF5kpaLvIzjuk4GNIMTJg=="
}
}
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: add a credentials with basic-auth for the consumer jack, should success
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_a',
ngx.HTTP_PUT,
[[{
"desc": "basic-auth for jack",
"plugins": {
"basic-auth": {
"username": "the-user",
"password": "the-password"
}
}
}]],
[[{
"value":{
"desc":"basic-auth for jack",
"id":"credential_a",
"plugins":{"basic-auth":{"username":"the-user","password":"WvF5kpaLvIzjuk4GNIMTJg=="}}
},
"key":"/apisix/consumers/jack/credentials/credential_a"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: add a credential with key-auth for the consumer jack, should success
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_b',
ngx.HTTP_PUT,
[[{
"desc": "key-auth for jack",
"plugins": {
"key-auth": {
"key": "the-key"
}
}
}]],
[[{
"value":{
"desc":"key-auth for jack",
"id":"credential_b",
"plugins":{"key-auth":{"key":"JCX7x1qN5e9kHt0GuJfWpw=="}}
},
"key":"/apisix/consumers/jack/credentials/credential_b"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: add a credential with a plugin which is not a auth plugin, should fail
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_b',
ngx.HTTP_PUT,
[[{
"desc": "limit-conn for jack",
"plugins": {
"limit-conn": {
"conn": 1,
"burst": 0,
"default_conn_delay": 0.1,
"rejected_code": 503,
"key_type": "var",
"key": "http_a"
}
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"only supports auth type plugins in consumer credential"}
=== TEST 6: list consumers: should not contain credential
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, body, res = t('/apisix/admin/consumers', ngx.HTTP_GET)
ngx.status = code
res = json.decode(res)
assert(res.total == 1)
assert(res.list[1].key == "/apisix/consumers/jack")
}
}
--- request
GET /t
--- response_body
=== TEST 7: list credentials: should contain credential_a and credential_b
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, body, res = t('/apisix/admin/consumers/jack/credentials', ngx.HTTP_GET)
ngx.status = code
res = json.decode(res)
assert(res.total == 2)
assert(res.list[1].key == "/apisix/consumers/jack/credentials/credential_a")
assert(res.list[2].key == "/apisix/consumers/jack/credentials/credential_b")
}
}
--- request
GET /t
--- response_body
=== TEST 8: get a credential
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_b',
ngx.HTTP_GET,
nil,
[[{
"key": "/apisix/consumers/jack/credentials/credential_b",
"value": {
"desc": "key-auth for jack",
"plugins": {"key-auth": {"key": "the-key"}
}}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: update credential: should ok
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_b',
ngx.HTTP_PUT,
[[{
"desc": "new description",
"plugins": {
"key-auth": {
"key": "new-key"
}
}
}]],
[[{
"key": "/apisix/consumers/jack/credentials/credential_b",
"value": {
"desc": "new description",
"plugins": {
"key-auth": {
"key": "523EisB/dvqlIT9RzfF3ZQ=="
}
}
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: delete credential
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/credential_a', ngx.HTTP_DELETE)
assert(code == 200)
ngx.status = code
code, body, res = t('/apisix/admin/consumers/jack/credentials', ngx.HTTP_GET)
res = json.decode(res)
assert(res.total == 1)
assert(res.list[1].key == "/apisix/consumers/jack/credentials/credential_b")
}
}
--- request
GET /t
--- response_body
=== TEST 11: create a credential has more than one plugin: should not ok
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/xxx-yyy-zzz',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {"key": "the-key"},
"basic-auth": {"username": "the-user", "password": "the-password"}
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"plugins\" validation failed: expect object to have at most 1 properties"}
=== TEST 12: delete consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_DELETE
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: list credentials: should get 404 because the consumer is deleted
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials', ngx.HTTP_GET)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 404
--- response_body
{"message":"Key not found"}
=== TEST 14: add a consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack"
}]]
)
if ngx.status >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 15: add a credential with key-auth for the consumer jack (id in the payload but not in uri), should success
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials',
ngx.HTTP_PUT,
[[{
"id": "d79a5aa3",
"desc": "key-auth for jack",
"plugins": {
"key-auth": {
"key": "the-key"
}
}
}]],
[[{
"value":{
"desc":"key-auth for jack",
"id":"d79a5aa3",
"plugins":{"key-auth":{"key":"JCX7x1qN5e9kHt0GuJfWpw=="}}
},
"key":"/apisix/consumers/jack/credentials/d79a5aa3"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 16: add a credential with key-auth for the consumer jack but missing id in uri and payload, should fail
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials',
ngx.HTTP_PUT,
[[{
"desc": "key-auth for jack",
"plugins": {
"key-auth": {
"key": "the-key"
}
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"missing credential id"}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,506 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set global rules
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/global_rules/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/global_rules/1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get global rules
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/global_rules/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: list global rules
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules',
ngx.HTTP_GET,
nil,
[[{
"total": 1,
"list": [
{
"key": "/apisix/global_rules/1",
"value": {
"plugins": {
"limit-count": {
"time_window": 60,
"policy": "local",
"count": 2,
"key": "remote_addr",
"rejected_code": 503
}
}
}
}
]
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: PATCH global rules
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/global_rules/1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_PATCH,
[[{
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/global_rules/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/global_rules/1'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: PATCH global rules (sub path)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/global_rules/1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/global_rules/1/plugins',
ngx.HTTP_PATCH,
[[{
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/global_rules/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/global_rules/1'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: delete global rules
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/global_rules/1',
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 7: delete global rules(not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/global_rules/1',
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 8: set global rules(missing plugins)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"plugins\" is required"}
=== TEST 9: string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: string id(DELETE)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules/a-b-c-ABC_0123',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-rewrite": {
"uri": "/"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/global_rules/1","value":{"id":"1","plugins":{"proxy-rewrite":{"uri":"/","use_real_request_uri_unsafe":false}}}}
--- request
GET /t
=== TEST 12: not unwanted data, PATCH
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules/1',
ngx.HTTP_PATCH,
[[{
"plugins": {
"proxy-rewrite": {
"uri": "/"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/global_rules/1","value":{"id":"1","plugins":{"proxy-rewrite":{"uri":"/","use_real_request_uri_unsafe":false}}}}
--- request
GET /t
=== TEST 13: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/global_rules/1","value":{"id":"1","plugins":{"proxy-rewrite":{"uri":"/","use_real_request_uri_unsafe":false}}}}
--- request
GET /t
=== TEST 14: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules/1',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/global_rules/1"}
--- request
GET /t

View File

@@ -0,0 +1,146 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: list empty resources
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"list":[],"total":0}
=== TEST 2: set global rule
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-rewrite": {
"uri": "/"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/global_rules/1","value":{"id":"1","plugins":{"proxy-rewrite":{"uri":"/","use_real_request_uri_unsafe":false}}}}
=== TEST 3: list global rules
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/global_rules',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.total == 1)
assert(#res.list == 1)
assert(res.list[1].createdIndex ~= nil)
assert(res.list[1].modifiedIndex ~= nil)
assert(res.list[1].key == "/apisix/global_rules/1")
assert(res.list[1].value ~= nil)
ngx.say(message)
}
}
--- response_body_like
passed
=== TEST 4: delete global rules
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/global_rules/1',
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 200 message: passed

View File

@@ -0,0 +1,521 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
my $init_by_lua_block = <<_EOC_;
require "resty.core"
apisix = require("apisix")
apisix.http_init()
json = require("toolkit.json")
req_data = json.decode([[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"checks": {}
},
"uri": "/index.html"
}]])
exp_data = {
value = req_data,
key = "/apisix/routes/1",
}
_EOC_
$block->set_value("init_by_lua_block", $init_by_lua_block);
if (!defined $block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests;
__DATA__
=== TEST 1: active
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 2,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body, res = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: passive
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 2,
"successes": 1
}
},
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 1
},
"unhealthy": {
"http_statuses": [500],
"http_failures": 2
}
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: invalid route: active.healthy.successes counter exceed maximum value
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"healthy": {
"successes": 255
}
}
}]])
local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, req_data)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"active\" validation failed: property \"healthy\" validation failed: property \"successes\" validation failed: expected 255 to be at most 254"}
=== TEST 4: invalid route: active.healthy.successes counter below the minimum value
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"healthy": {
"successes": 0
}
}
}]])
local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, req_data)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"active\" validation failed: property \"healthy\" validation failed: property \"successes\" validation failed: expected 0 to be at least 1"}
=== TEST 5: invalid route: wrong passive.unhealthy.http_statuses
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"passive": {
"unhealthy": {
"http_statuses": [500, 600]
}
}
}]])
local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, req_data)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"passive\" validation failed: property \"unhealthy\" validation failed: property \"http_statuses\" validation failed: failed to validate item 2: expected 600 to be at most 599"}
=== TEST 6: invalid route: wrong active.type
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"type": "udp"
}
}]])
local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, req_data)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"active\" validation failed: property \"type\" validation failed: matches none of the enum values"}
=== TEST 7: invalid route: duplicate items in active.healthy.http_statuses
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"healthy": {
"http_statuses": [200, 200]
}
}
}]])
local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, req_data)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"active\" validation failed: property \"healthy\" validation failed: property \"http_statuses\" validation failed: expected unique items but items 1 and 2 are equal"}
=== TEST 8: invalid route: active.unhealthy.http_failure is a floating point value
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"unhealthy": {
"http_failures": 3.1
}
}
}]])
local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, req_data)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"active\" validation failed: property \"unhealthy\" validation failed: property \"http_failures\" validation failed: wrong type: expected integer, got number"}
=== TEST 9: valid req_headers
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 2,
"successes": 1
},
"req_headers": ["User-Agent: curl/7.29.0"]
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 10: multiple request headers
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 2,
"successes": 1
},
"req_headers": ["User-Agent: curl/7.29.0", "Accept: */*"]
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: invalid req_headers
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 2,
"successes": 1
},
"req_headers": ["User-Agent: curl/7.29.0", 2233]
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: property \"active\" validation failed: property \"req_headers\" validation failed: failed to validate item 2: wrong type: expected string, got number"}
=== TEST 12: only passive
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 1
},
"unhealthy": {
"http_statuses": [500],
"http_failures": 2
}
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: object matches none of the required: [\"active\"] or [\"active\",\"passive\"]"}
=== TEST 13: only active
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 2,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}]])
exp_data.value.upstream.checks.active = req_data.upstream.checks.active
exp_data.value.upstream.checks.passive = {
type = "http",
healthy = {
http_statuses = { 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
300, 301, 302, 303, 304, 305, 306, 307, 308 },
successes = 0,
},
unhealthy = {
http_statuses = { 429, 500, 503 },
tcp_failures = 0,
timeouts = 0,
http_failures = 0,
}
}
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 14: number type timeout
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
req_data.upstream.checks = json.decode([[{
"active": {
"http_path": "/status",
"host": "foo.com",
"timeout": 1.01,
"healthy": {
"interval": 2,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}]])
exp_data.value.upstream.checks = req_data.upstream.checks
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
req_data,
exp_data
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed

View File

@@ -0,0 +1,170 @@
/*
* 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.
*/
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { request as requestAdminAPI } from '../ts/admin_api';
describe('Resource Metadata', () => {
describe('Consumer', () => {
it('should ensure additionalProperties is false', () =>
expect(
requestAdminAPI(
'/apisix/admin/consumers/jack',
'PUT',
{
username: 'jack',
invalid: true,
},
undefined,
{ validateStatus: () => true },
),
).resolves.toMatchObject({ status: 400 }));
it('should accept desc field', () =>
expect(
requestAdminAPI('/apisix/admin/consumers/jack', 'PUT', {
username: 'jack',
desc: 'test_desc',
}),
).resolves.not.toThrow());
});
describe('Consumer Credentials', () => {
it('should ensure additionalProperties is false', () =>
expect(
requestAdminAPI(
'/apisix/admin/consumers/jack/credentials/cred1',
'PUT',
{
plugins: { 'key-auth': { key: 'test' } },
invalid: true,
},
undefined,
{ validateStatus: () => true },
),
).resolves.toMatchObject({ status: 400 }));
it('should accept name field', () =>
expect(
requestAdminAPI(
'/apisix/admin/consumers/jack/credentials/cred1',
'PUT',
{
name: 'test_name',
plugins: { 'key-auth': { key: 'test' } },
},
),
).resolves.not.toThrow());
});
describe('SSL', () => {
const path = resolve(__dirname, '../certs/');
let cert: string;
let key: string;
beforeAll(async () => {
cert = await readFile(resolve(path, 'apisix.crt'), 'utf-8');
key = await readFile(resolve(path, 'apisix.key'), 'utf-8');
});
it('should ensure additionalProperties is false', () =>
expect(
requestAdminAPI(
'/apisix/admin/ssls/ssl1',
'PUT',
{ sni: 'test.com', cert, key, invalid: true },
undefined,
{ validateStatus: () => true },
),
).resolves.toMatchObject({ status: 400 }));
it('should accept desc field', () =>
expect(
requestAdminAPI('/apisix/admin/ssls/ssl1', 'PUT', {
desc: 'test_desc',
sni: 'test.com',
cert,
key,
}),
).resolves.not.toThrow());
});
describe('Proto', () => {
it('should ensure additionalProperties is false', () =>
expect(
requestAdminAPI(
'/apisix/admin/protos/proto1',
'PUT',
{ content: 'syntax = "proto3";', invalid: true },
undefined,
{ validateStatus: () => true },
),
).resolves.toMatchObject({ status: 400 }));
it('should accept name/labels field', () =>
expect(
requestAdminAPI('/apisix/admin/protos/proto1', 'PUT', {
name: 'test_name',
labels: { test: 'test' },
content: 'syntax = "proto3";',
}),
).resolves.not.toThrow());
});
describe('Stream Route', () => {
it('should ensure additionalProperties is false', () =>
expect(
requestAdminAPI(
'/apisix/admin/stream_routes/sr1',
'PUT',
{ upstream: { nodes: { '127.0.0.1:5432': 1 } }, invalid: true },
undefined,
{ validateStatus: () => true },
),
).resolves.toMatchObject({ status: 400 }));
it('should accept name field', () =>
expect(
requestAdminAPI('/apisix/admin/stream_routes/sr1', 'PUT', {
name: 'test_name',
upstream: { nodes: { '127.0.0.1:5432': 1 } },
}),
).resolves.not.toThrow());
});
describe('Consumer Group', () => {
it('should ensure additionalProperties is false', () =>
expect(
requestAdminAPI(
'/apisix/admin/consumer_groups/cg1',
'PUT',
{ plugins: {}, invalid: true },
undefined,
{ validateStatus: () => true },
),
).resolves.toMatchObject({ status: 400 }));
it('should accept name field', () =>
expect(
requestAdminAPI('/apisix/admin/consumer_groups/cg1', 'PUT', {
name: 'test_name',
plugins: {},
}),
).resolves.not.toThrow());
});
});

View File

@@ -0,0 +1,36 @@
#
# 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();
use_hup();
run_tests();
__DATA__
=== TEST 1: test
--- timeout: 15
--- max_size: 204800
--- exec
cd t && pnpm test admin/metadata.spec.ts 2>&1
--- no_error_log
failed to execute the script with status
--- response_body eval
qr/PASS admin\/metadata.spec.ts/

View File

@@ -0,0 +1,163 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set plugin_configs(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503
}
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 201
--- response_body
passed
=== TEST 2: add route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugin_config_id": 1,
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 3: delete plugin_configs(wrong header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/plugin_configs/1?force=anyvalue',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this plugin config, route [1] is still using it now"}
=== TEST 4: delete plugin_configs(without force delete header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this plugin config, route [1] is still using it now"}
=== TEST 5: delete plugin_configs(force delete)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/plugin_configs/1?force=true',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed
=== TEST 6: delete route
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed

View File

@@ -0,0 +1,523 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: PUT
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/plugin_configs/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/plugin_configs/1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 2: GET
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/plugin_configs/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: GET all
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs',
ngx.HTTP_GET,
nil,
[[{
"total": 1,
"list": [
{
"key": "/apisix/plugin_configs/1",
"value": {
"plugins": {
"limit-count": {
"time_window": 60,
"policy": "local",
"count": 2,
"key": "remote_addr",
"rejected_code": 503
}
}
}
}
]
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: PATCH
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/plugin_configs/1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PATCH,
[[{
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 3,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/plugin_configs/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/plugin_configs/1'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- response_body
passed
=== TEST 5: PATCH (sub path)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/plugin_configs/1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/plugin_configs/1/plugins',
ngx.HTTP_PATCH,
[[{
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/plugin_configs/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/plugin_configs/1'))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- response_body
passed
=== TEST 6: invalid plugin
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"rejected_code": 503,
"time_window": 60,
"key": "remote_addr"
}
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- response_body
{"error_msg":"failed to check the configuration of plugin limit-count err: property \"count\" is required"}
--- error_code: 400
=== TEST 7: PUT (with non-plugin fields)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"labels": {
"你好": "世界"
},
"desc": "blah"
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"labels": {
"你好": "世界"
},
"desc": "blah"
},
"key": "/apisix/plugin_configs/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/plugin_configs/1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 8: GET (with non-plugin fields)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"labels": {
"你好": "世界"
},
"desc": "blah"
},
"key": "/apisix/plugin_configs/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: invalid non-plugin fields
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"labels": "a",
"plugins": {
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- response_body
{"error_msg":"invalid configuration: property \"labels\" validation failed: wrong type: expected object, got string"}
--- error_code: 400
=== TEST 10: set plugin-configs(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/plugin_configs/1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 11: set route(id: 1)
--- 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,
[[{
"plugin_config_id": 1,
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: delete-plugin configs failed(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_DELETE
)
ngx.print(body)
}
}
--- response_body
{"error_msg":"can not delete this plugin config, route [1] is still using it now"}
=== TEST 13: delete route(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
ngx.say(body)
}
}
--- response_body
passed
=== TEST 14: delete plugin-configs(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_DELETE
)
ngx.say(body)
}
}
--- response_body
passed

View File

@@ -0,0 +1,335 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: add plugin metadata
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/example-plugin',
ngx.HTTP_PUT,
[[{
"skey": "val",
"ikey": 1
}]],
[[{
"value": {
"skey": "val",
"ikey": 1
},
"key": "/apisix/plugin_metadata/example-plugin"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: update plugin metadata
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/example-plugin',
ngx.HTTP_PUT,
[[{
"skey": "val2",
"ikey": 2
}]],
[[{
"value": {
"skey": "val2",
"ikey": 2
}
}]]
)
ngx.status = code
ngx.say(body)
-- hit again
local code, body = t('/apisix/admin/plugin_metadata/example-plugin',
ngx.HTTP_PUT,
[[{
"skey": "val2",
"ikey": 2
}]],
[[{
"value": {
"skey": "val2",
"ikey": 2
}
}]]
)
ngx.say(code)
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
200
passed
=== TEST 3: get plugin metadata
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/example-plugin',
ngx.HTTP_GET,
nil,
[[{
"value": {
"skey": "val2",
"ikey": 2
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: delete plugin metadata
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/example-plugin', ngx.HTTP_DELETE)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: delete plugin metadata(key: not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/plugin_metadata/not_found', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 6: missing plugin name
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata',
ngx.HTTP_PUT,
[[{"k": "v"}]],
[[{
"value": "sdf"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"missing plugin name"}
=== TEST 7: invalid plugin name
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/test',
ngx.HTTP_PUT,
[[{"k": "v"}]],
[[{
"value": "sdf"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid plugin name"}
=== TEST 8: verify metadata schema fail
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/example-plugin',
ngx.HTTP_PUT,
[[{
"skey": "val"
}]],
[[{
"value": {
"skey": "val",
"ikey": 1
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"invalid configuration: property \\"ikey\\" is required"\}/
=== TEST 9: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugin_metadata/example-plugin',
ngx.HTTP_PUT,
[[{
"skey": "val",
"ikey": 1
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/plugin_metadata/example-plugin","value":{"id":"example-plugin","ikey":1,"skey":"val"}}
--- request
GET /t
=== TEST 10: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugin_metadata/example-plugin', ngx.HTTP_GET)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/plugin_metadata/example-plugin","value":{"id":"example-plugin","ikey":1,"skey":"val"}}
--- request
GET /t
=== TEST 11: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugin_metadata/example-plugin', ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/plugin_metadata/example-plugin"}
--- request
GET /t

View File

@@ -0,0 +1,61 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: list empty resources
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugin_metadata', ngx.HTTP_GET)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"list":[],"total":0}

View File

@@ -0,0 +1,429 @@
#
# 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();
no_shuffle();
log_level("info");
workers(2);
add_block_preprocessor(sub {
my ($block) = @_;
$block;
});
run_tests;
__DATA__
=== TEST 1: reload plugins
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- now the plugin will be loaded twice,
-- one during startup and the other one by reload
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.status = code
ngx.say(org_body)
ngx.sleep(1)
}
}
--- request
GET /t
--- response_body
done
--- grep_error_log eval
qr/sync local conf to etcd/
--- grep_error_log_out
sync local conf to etcd
--- error_log
load plugin times: 2
load plugin times: 2
start to hot reload plugins
start to hot reload plugins
=== TEST 2: reload plugins triggers plugin list sync
--- config
location /t {
content_by_lua_block {
local core = require "apisix.core"
local config_util = require("apisix.core.config_util")
ngx.sleep(1) -- make sure the sync happened when admin starts is already finished
local before_reload = true
local plugins_conf, err
plugins_conf, err = core.config.new("/plugins", {
automatic = true,
single_item = true,
filter = function(item)
-- called once before reload for sync data from admin
ngx.log(ngx.WARN, "reload plugins on node ",
before_reload and "before reload" or "after reload")
ngx.log(ngx.WARN, require("toolkit.json").encode(item.value))
end,
})
if not plugins_conf then
error("failed to create etcd instance for fetching /plugins : "
.. err)
end
ngx.sleep(1)
local data = [[
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: null
apisix:
node_listen: 1984
plugins:
- jwt-auth
stream_plugins:
- mqtt-proxy
]]
require("lib.test_admin").set_config_yaml(data)
before_reload = false
local t = require("lib.test_admin").test
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.status = code
ngx.say(org_body)
ngx.sleep(1)
}
}
--- request
GET /t
--- response_body
done
--- grep_error_log eval
qr/reload plugins on node \w+ reload/
--- grep_error_log_out
reload plugins on node before reload
reload plugins on node after reload
--- error_log
filter(): [{"name":"jwt-auth"},{"name":"mqtt-proxy","stream":true}]
=== TEST 3: reload plugins when attributes changed
--- yaml_config
apisix:
node_listen: 1984
plugins:
- example-plugin
plugin_attr:
example-plugin:
val: 0
--- config
location /t {
content_by_lua_block {
local core = require "apisix.core"
ngx.sleep(0.1)
local data = [[
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: null
apisix:
node_listen: 1984
plugins:
- example-plugin
plugin_attr:
example-plugin:
val: 1
]]
require("lib.test_admin").set_config_yaml(data)
local t = require("lib.test_admin").test
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.status = code
ngx.say(org_body)
ngx.sleep(0.1)
local data = [[
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: null
apisix:
node_listen: 1984
plugins:
- example-plugin
plugin_attr:
example-plugin:
val: 1
]]
require("lib.test_admin").set_config_yaml(data)
local t = require("lib.test_admin").test
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.say(org_body)
ngx.sleep(0.1)
}
}
--- request
GET /t
--- response_body
done
done
--- grep_error_log eval
qr/example-plugin get plugin attr val: \d+/
--- grep_error_log_out
example-plugin get plugin attr val: 0
example-plugin get plugin attr val: 0
example-plugin get plugin attr val: 0
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
=== TEST 4: reload plugins to change prometheus' export uri
--- yaml_config
apisix:
node_listen: 1984
plugins:
- public-api
- prometheus
plugin_attr:
prometheus:
export_uri: /metrics
--- config
location /t {
content_by_lua_block {
local core = require "apisix.core"
ngx.sleep(0.1)
local t = require("lib.test_admin").test
-- setup public API route
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"public-api": {}
},
"uri": "/apisix/metrics"
}]]
)
ngx.say(code)
local code, _, org_body = t('/apisix/metrics',
ngx.HTTP_GET)
ngx.say(code)
local data = [[
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: null
apisix:
node_listen: 1984
plugins:
- public-api
- prometheus
plugin_attr:
prometheus:
export_uri: /apisix/metrics
]]
require("lib.test_admin").set_config_yaml(data)
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.say(org_body)
ngx.sleep(0.1)
local code, _, org_body = t('/apisix/metrics',
ngx.HTTP_GET)
ngx.say(code)
}
}
--- request
GET /t
--- response_body
201
404
done
200
=== TEST 5: reload plugins to disable skywalking
--- yaml_config
apisix:
node_listen: 1984
plugins:
- skywalking
plugin_attr:
skywalking:
service_name: APISIX
service_instance_name: "APISIX Instance Name"
endpoint_addr: http://127.0.0.1:12801
report_interval: 1
--- config
location /t {
content_by_lua_block {
local core = require "apisix.core"
ngx.sleep(1.2)
local t = require("lib.test_admin").test
local data = [[
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: null
apisix:
node_listen: 1984
plugins:
- prometheus
]]
require("lib.test_admin").set_config_yaml(data)
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.say(org_body)
ngx.sleep(2)
}
}
--- request
GET /t
--- response_body
done
--- no_error_log
[alert]
--- grep_error_log eval
qr/Instance report fails/
--- grep_error_log_out
Instance report fails
=== TEST 6: check disabling plugin via etcd
--- 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": {
"echo": {
"body":"hello upstream\n"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
ngx.sleep(0.1)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: hit
--- yaml_config
apisix:
node_listen: 1984
enable_admin: false
--- request
GET /hello
--- response_body
hello upstream
=== TEST 8: hit after disabling echo
--- yaml_config
apisix:
node_listen: 1984
enable_admin: false
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
assert(etcd.set("/plugins", {{name = "jwt-auth"}}))
ngx.sleep(0.2)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
}
}
--- request
GET /t
--- response_body
hello world
=== TEST 9: wrong method to reload plugins
--- request
GET /apisix/admin/plugins/reload
--- error_code: 405
--- response_body
{"error_msg":"please use PUT method to reload the plugins, GET method is not allowed."}

View File

@@ -0,0 +1,480 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!defined $block->request) {
$block->set_value("request", "GET /t");
}
$block;
});
run_tests;
__DATA__
=== TEST 1: get plugins' name
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json = require('cjson')
local code, _, body = t("/apisix/admin/plugins/list", "GET")
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local tab = json.decode(body)
for _, v in ipairs(tab) do
ngx.say(v)
end
}
}
--- response_body
real-ip
ai
client-control
proxy-control
request-id
zipkin
ext-plugin-pre-req
fault-injection
mocking
serverless-pre-function
cors
ip-restriction
ua-restriction
referer-restriction
csrf
uri-blocker
request-validation
chaitin-waf
multi-auth
openid-connect
cas-auth
authz-casbin
authz-casdoor
wolf-rbac
ldap-auth
hmac-auth
basic-auth
jwt-auth
jwe-decrypt
key-auth
consumer-restriction
attach-consumer-label
forward-auth
opa
authz-keycloak
proxy-cache
body-transformer
ai-request-rewrite
ai-prompt-guard
ai-prompt-template
ai-prompt-decorator
ai-rag
ai-aws-content-moderation
ai-proxy-multi
ai-proxy
ai-rate-limiting
proxy-mirror
proxy-rewrite
workflow
api-breaker
limit-conn
limit-count
limit-req
gzip
traffic-split
redirect
response-rewrite
mcp-bridge
degraphql
kafka-proxy
grpc-transcode
grpc-web
http-dubbo
public-api
prometheus
datadog
lago
loki-logger
elasticsearch-logger
echo
loggly
http-logger
splunk-hec-logging
skywalking-logger
google-cloud-logging
sls-logger
tcp-logger
kafka-logger
rocketmq-logger
syslog
udp-logger
file-logger
clickhouse-logger
tencent-cloud-cls
inspect
example-plugin
aws-lambda
azure-functions
openwhisk
openfunction
serverless-post-function
ext-plugin-post-req
ext-plugin-post-resp
=== TEST 2: invalid plugin
--- request
GET /apisix/admin/plugins/asdf
--- error_code: 404
--- response_body
{"error_msg":"plugin not found in subsystem http"}
=== TEST 3: get plugin schema
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugins/limit-req',
ngx.HTTP_GET,
nil,
[[
{"type":"object","required":["rate","burst","key"],"properties":{"rate":{"type":"number","exclusiveMinimum":0},"key_type":{"type":"string","enum":["var","var_combination"],"default":"var"},"burst":{"type":"number","minimum":0},"nodelay":{"type":"boolean","default":false},"key":{"type":"string"},"rejected_code":{"type":"integer","minimum":200,"maximum":599,"default":503},"rejected_msg":{"type":"string","minLength":1},"allow_degradation":{"type":"boolean","default":false}}}
]]
)
ngx.status = code
}
}
=== TEST 4: get plugin node-status schema
--- extra_yaml_config
plugins:
- node-status
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugins/node-status',
ngx.HTTP_GET,
nil,
[[
{"properties":{},"type":"object"}
]]
)
ngx.status = code
}
}
=== TEST 5: get plugin prometheus schema
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugins/prometheus',
ngx.HTTP_GET,
nil,
[[
{"properties":{},"type":"object"}
]]
)
ngx.status = code
}
}
=== TEST 6: get plugin basic-auth schema
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugins/basic-auth',
ngx.HTTP_GET,
nil,
[[
{"properties":{},"title":"work with route or service object","type":"object"}
]]
)
ngx.status = code
}
}
=== TEST 7: get plugin basic-auth schema by schema_type
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugins/basic-auth?schema_type=consumer',
ngx.HTTP_GET,
nil,
[[
{"title":"work with consumer object","required":["username","password"],"properties":{"username":{"type":"string"},"password":{"type":"string"}},"type":"object"}
]]
)
ngx.status = code
}
}
=== TEST 8: confirm the name, priority, schema, type and version of plugin
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugins?all=true',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
for k, v in pairs(res) do
if k == "example-plugin" then
ngx.say(json.encode(v))
end
end
}
}
--- response_body eval
qr/\{"metadata_schema":\{"properties":\{"ikey":\{"minimum":0,"type":"number"\},"skey":\{"type":"string"\}\},"required":\["ikey","skey"\],"type":"object"\},"priority":0,"schema":\{"\$comment":"this is a mark for our injected plugin schema","properties":\{"_meta":\{"additionalProperties":false,"properties":\{"disable":\{"type":"boolean"\},"error_response":\{"oneOf":\[\{"type":"string"\},\{"type":"object"\}\]\},"filter":\{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"\},"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"\},"priority":\{"description":"priority of plugins by customized order","type":"integer"\}\},"type":"object"\},"i":\{"minimum":0,"type":"number"\},"ip":\{"type":"string"\},"port":\{"type":"integer"\},"s":\{"type":"string"\},"t":\{"minItems":1,"type":"array"\}\},"required":\["i"\],"type":"object"\},"version":0.1\}/
=== TEST 9: confirm the plugin of auth type
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugins?all=true',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
local auth_plugins = {}
for k, v in pairs(res) do
if v.type == "auth" then
local plugin = {}
plugin.name = k
plugin.priority = v.priority
table.insert(auth_plugins, plugin)
end
end
table.sort(auth_plugins, function(l, r)
return l.priority > r.priority
end)
ngx.say(json.encode(auth_plugins))
}
}
--- response_body eval
qr/\[\{"name":"multi-auth","priority":2600\},\{"name":"wolf-rbac","priority":2555\},\{"name":"ldap-auth","priority":2540\},\{"name":"hmac-auth","priority":2530\},\{"name":"basic-auth","priority":2520\},\{"name":"jwt-auth","priority":2510\},\{"name":"jwe-decrypt","priority":2509\},\{"name":"key-auth","priority":2500\}\]/
=== TEST 10: confirm the consumer_schema of plugin
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugins?all=true',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
local consumer_schema
for k, v in pairs(res) do
if k == "basic-auth" then
consumer_schema = v.consumer_schema
end
end
ngx.say(json.encode(consumer_schema))
}
}
--- response_body eval
qr/\{"encrypt_fields":\["password"\],"properties":\{"password":\{"type":"string"\},"username":\{"type":"string"\}\},"required":\["username","password"\],"title":"work with consumer object","type":"object"\}/
=== TEST 11: confirm the name, priority, schema, type and version of stream plugin
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugins?all=true&subsystem=stream',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
for k, v in pairs(res) do
if k == "limit-conn" then
ngx.say(json.encode(v))
end
end
}
}
--- response_body
{"priority":1003,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"_meta":{"additionalProperties":false,"properties":{"disable":{"type":"boolean"},"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"filter":{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"},"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"},"priority":{"description":"priority of plugins by customized order","type":"integer"}},"type":"object"},"burst":{"minimum":0,"type":"integer"},"conn":{"exclusiveMinimum":0,"type":"integer"},"default_conn_delay":{"exclusiveMinimum":0,"type":"number"},"key":{"type":"string"},"key_type":{"default":"var","enum":["var","var_combination"],"type":"string"},"only_use_default_delay":{"default":false,"type":"boolean"}},"required":["conn","burst","default_conn_delay","key"],"type":"object"},"version":0.1}
=== TEST 12: confirm the scope of plugin
--- extra_yaml_config
plugins:
- batch-requests
- error-log-logger
- server-info
- example-plugin
- node-status
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/plugins?all=true',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
local global_plugins = {}
for k, v in pairs(res) do
if v.scope == "global" then
global_plugins[k] = v.scope
end
end
ngx.say(json.encode(global_plugins))
}
}
--- response_body
{"batch-requests":"global","error-log-logger":"global","node-status":"global","server-info":"global"}
=== TEST 13: check with wrong plugin subsystem
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local _, message, _ = t('/apisix/admin/plugins?subsystem=asdf',
ngx.HTTP_GET
)
ngx.say(message)
}
}
--- response_body eval
qr/\{"error_msg":"unsupported subsystem: asdf"\}/
=== TEST 14: check with right plugin in wrong subsystem
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local _, message, _ = t('/apisix/admin/plugins/http-logger?subsystem=stream',
ngx.HTTP_GET
)
ngx.say(message)
}
}
--- response_body eval
qr/\{"error_msg":"plugin not found in subsystem stream"\}/
=== TEST 15: check with right plugin in right subsystem
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local _, _ , message = t('/apisix/admin/plugins/http-logger?subsystem=http',
ngx.HTTP_GET
)
ngx.say(message)
}
}
--- response_body eval
qr/this is a mark for our injected plugin schema/

View File

@@ -0,0 +1,175 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set proto(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/protos/1',
ngx.HTTP_PUT,
[[{
"content" : "syntax = \"proto3\";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 201
--- response_body
passed
=== TEST 2: add route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"uri": "/grpctest",
"plugins": {
"grpc-transcode": {
"proto_id": "1",
"service": "helloworld.Greeter",
"method": "SayHello"
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:10051": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 3: delete proto(wrong header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/1?force=anyvalue',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this proto, route [1] is still using it now"}
=== TEST 4: delete proto(without force delete header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this proto, route [1] is still using it now"}
=== TEST 5: delete proto(force delete)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/1?force=true',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed
=== TEST 6: delete route
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed

View File

@@ -0,0 +1,216 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: put proto (id:1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/1',
ngx.HTTP_PUT,
[[{
"content": "syntax = \"proto3\";
package proto;
message HelloRequest{
string name = 1;
}
message HelloResponse{
int32 code = 1;
string msg = 2;
}
// The greeting service definition.
service Hello {
// Sends a greeting
rpc SayHi (HelloRequest) returns (HelloResponse){}
}"
}]]
)
if code ~= 201 then
ngx.status = code
ngx.say("[put proto] code: ", code, " message: ", message)
return
end
ngx.say("[put proto] code: ", code, " message: ", message)
}
}
--- response_body
[put proto] code: 201 message: passed
=== TEST 2: delete proto(id:1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/1',
ngx.HTTP_DELETE
)
if code ~= 200 then
ngx.status = code
ngx.say("[delete proto] code: ", code, " message: ", message)
return
end
ngx.say("[delete proto] code: ", code, " message: ", message)
}
}
--- response_body
[delete proto] code: 200 message: passed
=== TEST 3: put proto (id:2) + route refer proto(proto id 2) + delete proto(proto id 2)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/2',
ngx.HTTP_PUT,
[[{
"content": "syntax = \"proto3\";
package proto;
message HelloRequest{
string name = 1;
}
message HelloResponse{
int32 code = 1;
string msg = 2;
}
// The greeting service definition.
service Hello {
// Sends a greeting
rpc SayHi (HelloRequest) returns (HelloResponse){}
}"
}]]
)
if code ~= 201 then
ngx.status = code
ngx.say("[put proto] code: ", code, " message: ", message)
return
end
ngx.say("[put proto] code: ", code, " message: ", message)
code, message = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"plugins": {
"grpc-transcode": {
"_meta": {
"disable": false
},
"method": "SayHi",
"proto_id": 2,
"service": "proto.Hello"
}
},
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/grpc/sayhi",
"name": "hi-grpc"
}]]
)
if code ~= 201 then
ngx.status = code
ngx.say("[route refer proto] code: ", code, " message: ", message)
return
end
ngx.say("[route refer proto] code: ", code, " message: ", message)
ngx.sleep(0.1) -- ensure reference is synced from etcd
code, message = t('/apisix/admin/protos/2',
ngx.HTTP_DELETE
)
ngx.say("[delete proto] code: ", code)
}
}
--- response_body
[put proto] code: 201 message: passed
[route refer proto] code: 201 message: passed
[delete proto] code: 400
=== TEST 4: reject invalid proto
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/protos/1',
ngx.HTTP_PUT,
[[{
"content": "syntax = \"proto3\";
package proto;
message HelloRequest{
string name = 1;
}
message HelloResponse{
int32 code = 1;
string msg = 1;
}"
}]]
)
if code ~= 200 then
ngx.status = code
end
ngx.say(message)
}
}
--- error_code: 400
--- response_body eval
qr/invalid content:/

View File

@@ -0,0 +1,55 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: invalid resource type: 'routs'
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routs/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]]
)
ngx.say(body)
}
}
--- request
GET /t
--- response_body_like
{"error_msg":"Unsupported resource type: routs"}

View File

@@ -0,0 +1,255 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
my $user_yaml_config = <<_EOC_;
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: ~
admin_api_version: v3
apisix:
node_listen: 1984
_EOC_
$block->set_value("yaml_config", $user_yaml_config);
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: use v3 admin api, no action in response body
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"desc": "new route",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: response body format only have total and list (total is 1)
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes', ngx.HTTP_GET)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.total == 1)
assert(res.total == #res.list)
assert(res.action == nil)
assert(res.node == nil)
assert(res.list.key == nil)
assert(res.list.dir == nil)
assert(res.list[1].createdIndex ~= nil)
assert(res.list[1].modifiedIndex ~= nil)
assert(res.list[1].key == "/apisix/routes/1")
ngx.say(message)
}
}
--- response_body
passed
=== TEST 3: response body format only have total and list (total is 2)
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
end
local code, message, res = t('/apisix/admin/routes',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.total == 2)
assert(res.total == #res.list)
assert(res.action == nil)
assert(res.node == nil)
assert(res.list.key == nil)
assert(res.list.dir == nil)
assert(res.list[1].createdIndex ~= nil)
assert(res.list[1].modifiedIndex ~= nil)
assert(res.list[1].key == "/apisix/routes/1")
assert(res.list[2].createdIndex ~= nil)
assert(res.list[2].modifiedIndex ~= nil)
assert(res.list[2].key == "/apisix/routes/2")
ngx.say(message)
}
}
--- response_body
passed
=== TEST 4: response body format (test services)
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"desc": "new service 001"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
local code, body = t('/apisix/admin/services/2',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"desc": "new service 002"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
local code, message, res = t('/apisix/admin/services', ngx.HTTP_GET)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.total == 2)
assert(res.total == #res.list)
assert(res.action == nil)
assert(res.node == nil)
assert(res.list.key == nil)
assert(res.list.dir == nil)
assert(res.list[1].createdIndex ~= nil)
assert(res.list[1].modifiedIndex ~= nil)
assert(res.list[1].key == "/apisix/services/1")
assert(res.list[2].createdIndex ~= nil)
assert(res.list[2].modifiedIndex ~= nil)
assert(res.list[2].key == "/apisix/services/2")
ngx.say(message)
}
}
--- response_body
passed
passed
passed

View File

@@ -0,0 +1,115 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set route(id: 1)
--- 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"],
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"desc": "new route",
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"desc": "new route",
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,788 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set route(id: 1)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"desc": "new route",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"desc": "new route",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: delete route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 4: delete route(id: not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/routes/not_found',
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 5: post route + delete
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, message, res = t('/apisix/admin/routes',
ngx.HTTP_POST,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local id = string.sub(res.key, #"/apisix/routes/" + 1)
local res = assert(etcd.get('/routes/' .. id))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
code, message = t('/apisix/admin/routes/' .. id,
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
[delete] code: 200 message: passed
=== TEST 6: uri + upstream
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
[[{
"value": {
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local res = assert(etcd.get('/routes/1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
=== TEST 7: uri + plugins
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"uri": "/index.html"
}]],
[[{
"value": {
"uri": "/index.html",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
=== TEST 8: invalid route: duplicate method
--- 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", "GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like
=== TEST 9: invalid method
--- 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": ["invalid_method"],
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"methods\" validation failed: failed to validate item 1: matches none of the enum values"}
=== TEST 10: invalid service id
--- 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,
[[{
"service_id": "invalid_id$",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"service_id\" validation failed: object matches none of the required"}
=== TEST 11: service id: not exist
--- 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,
[[{
"service_id": "99999999999999",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to fetch service info by service id [99999999999999], response code: 404"}
=== TEST 12: invalid id
--- 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,
[[{
"id": 3,
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong route id"}
=== TEST 13: id in the rule
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes',
ngx.HTTP_PUT,
[[{
"id": "1",
"plugins":{},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: integer id less than 1
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes',
ngx.HTTP_PUT,
[[{
"id": -100,
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"id\" validation failed: object matches none of the required"}
=== TEST 15: invalid upstream_id
--- 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,
[[{
"upstream_id": "invalid$",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream_id\" validation failed: object matches none of the required"}
=== TEST 16: not exist upstream_id
--- 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,
[[{
"upstream_id": "99999999",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to fetch upstream info by upstream id [99999999], response code: 404"}
=== TEST 17: wrong route id, do not need it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes',
ngx.HTTP_POST,
[[{
"id": 1,
"plugins":{},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong route id, do not need it"}
=== TEST 18: wrong route id, do not need it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_POST,
[[{
"plugins":{},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong route id, do not need it"}
=== TEST 19: limit-count with `disable` option
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr",
"_meta": {
"disable": true
}
}
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
=== TEST 20: host: *.foo.com
--- 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,
[[{
"host": "*.foo.com",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
[[{
"value": {
"host": "*.foo.com",
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 21: invalid host: a.*.foo.com
--- 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,
[[{
"host": "a.*.foo.com",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like
{"error_msg":"invalid configuration: property \\"host\\" validation failed: failed to match pattern .*
=== TEST 22: invalid host: *.a.*.foo.com
--- 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,
[[{
"host": "*.a.*.foo.com",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like
{"error_msg":"invalid configuration: property \\"host\\" validation failed: failed to match pattern .*
=== TEST 23: removing the init_dir key from etcd can still list all routes
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json = require("toolkit.json")
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/routes/del_init_dir_1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
assert(code == 200 or code == 201, "failed to add route")
local code, body = t('/apisix/admin/routes/del_init_dir_2',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
assert(code == 200 or code == 201, "failed to add route")
-- remove the init_dir key from etcd
assert(etcd.delete("/routes/"))
-- list all routes and check them
local code, body, res = t('/apisix/admin/routes', ngx.HTTP_GET)
ngx.status = code
ngx.say(res)
}
}
--- request
GET /t
--- response_body eval
qr/del_init_dir_1.*del_init_dir_2/

View File

@@ -0,0 +1,653 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: invalid route: bad remote_addrs
--- 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"],
"remote_addrs": [""],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/property \\"remote_addrs\\" validation failed:/
=== TEST 2: invalid route: bad remote_addrs cidr
--- 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"],
"remote_addrs": ["/16"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/property \\"remote_addrs\\" validation failed:/
=== TEST 3: valid route with remote_addrs
--- 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"],
"remote_addrs": ["::1/16", "::1", "::", "1.1.1.1", "1.1.1.1/32"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: invalid route: bad vars operator
--- 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"],
"vars": [["remote_addr", "=", "127.0.0.1"]],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]=]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to validate the 'vars' expression: invalid operator '='"}
=== TEST 5: not unwanted data, POST
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes',
ngx.HTTP_POST,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/not_unwanted_data_post"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.key = nil
res.value.create_time = nil
res.value.update_time = nil
assert(res.value.id ~= nil)
res.value.id = nil
ngx.say(json.encode(res))
}
}
--- request
GET /t
--- response_body
{"value":{"methods":["GET"],"priority":0,"status":1,"upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"},"uri":"/not_unwanted_data_post"}}
=== TEST 6: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes',
ngx.HTTP_PUT,
[[{
"id": 1,
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- request
GET /t
--- response_body
{"key":"/apisix/routes/1","value":{"id":1,"methods":["GET"],"priority":0,"status":1,"upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"},"uri":"/index.html"}}
=== TEST 7: not unwanted data, PATCH
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- request
GET /t
--- response_body
{"key":"/apisix/routes/1","value":{"id":"1","methods":["GET"],"priority":0,"status":1,"upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"},"uri":"/index"}}
=== TEST 8: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- request
GET /t
--- response_body
{"key":"/apisix/routes/1","value":{"id":"1","methods":["GET"],"priority":0,"status":1,"upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"},"uri":"/index"}}
=== TEST 9: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- request
GET /t
--- response_body
{"deleted":"1","key":"/apisix/routes/1"}
=== TEST 10: invalid route: empty remote_addrs
--- 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"],
"remote_addrs": [],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/property \\"remote_addrs\\" validation failed:/
=== TEST 11: invalid route: empty uris
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uris": []
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/property \\"uris\\" validation failed:/
=== TEST 12: invalid route: empty hosts
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"hosts": [],
"uri": "/"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/property \\"hosts\\" validation failed:/
=== TEST 13: invalid route: uris & uri
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uris": ["/"],
"uri": "/"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/value should match only one schema/
=== TEST 14: enable remote_addrs and remote_addr together
--- 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,
[[{
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"remote_addr": "127.0.0.1",
"remote_addrs": ["127.0.0.1"]
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"only one of remote_addr or remote_addrs is allowed"}
=== TEST 15: labels in Chinese
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"labels": {
"您好": "世界"
},
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"labels": {
"您好": "世界"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 16: labels value with whitespace
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"labels": {
"您好": "世 界"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like eval
qr/invalid configuration: property \\"labels\\" validation failed/
=== TEST 17: route with plugin_config_id (not found)
--- 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"],
"plugin_config_id": "not_found",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to fetch plugin config info by plugin config id [not_found], response code: 404"}
=== TEST 18: valid route with timeout
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"timeout": {
"connect": 3,
"send": 3,
"read": 3
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,743 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: list empty resources
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"list":[],"total":0}
=== TEST 2: remote_addr: 127.0.0.1
--- 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,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
[[{
"value": {
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
},
"key": "/apisix/routes/1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: remote_addr: 127.0.0.1/24
--- 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,
[[{
"remote_addr": "127.0.0.0/24",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
[[{
"value": {
"remote_addr": "127.0.0.0/24",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
},
"key": "/apisix/routes/1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: remote_addr: 127.0.0.33333
--- 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,
[[{
"remote_addr": "127.0.0.33333",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"remote_addr\" validation failed: object matches none of the required"}
=== TEST 5: all method
--- 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", "POST", "PUT", "DELETE", "PATCH",
"HEAD", "OPTIONS", "CONNECT", "TRACE", "PURGE"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 6: patch route(new uri)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local id = 1
local res = assert(etcd.get('/routes/' .. id))
local prev_create_time = res.body.node.value.create_time
local prev_update_time = res.body.node.value.update_time
ngx.sleep(1)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
[[{
"uri": "/patch_test"
}]],
[[{
"value": {
"uri": "/patch_test"
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/routes/' .. id))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- response_body
passed
=== TEST 7: patch route(multi)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": null,
"127.0.0.2:8080": 1
}
},
"desc": "new route"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/patch_test",
"desc": "new route",
"upstream": {
"nodes": {
"127.0.0.2:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: patch route(new methods)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
[[{
"methods": ["GET", "DELETE", "PATCH", "POST", "PUT"]
}]],
[[{
"value": {
"methods": ["GET", "DELETE", "PATCH", "POST", "PUT"]
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: patch route(minus methods)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
[[{
"methods": ["GET", "POST"]
}]],
[[{
"value": {
"methods": ["GET", "POST"]
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 10: patch route(new methods - sub path way)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1/methods',
ngx.HTTP_PATCH,
'["POST"]',
[[{
"value": {
"methods": [
"POST"
]
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: patch route(new uri)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1/uri',
ngx.HTTP_PATCH,
'"/patch_uri_test"',
[[{
"value": {
"uri": "/patch_uri_test"
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: patch route(whole)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1/',
ngx.HTTP_PATCH,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"desc": "new route",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 13: multiple hosts
--- 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,
[[{
"uri": "/index.html",
"hosts": ["foo.com", "*.bar.com"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]],
[[{
"value": {
"hosts": ["foo.com", "*.bar.com"]
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 14: enable hosts and host together
--- 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,
[[{
"uri": "/index.html",
"host": "xxx.com",
"hosts": ["foo.com", "*.bar.com"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"only one of host or hosts is allowed"}
=== TEST 15: multiple remote_addrs
--- 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,
[[{
"uri": "/index.html",
"remote_addrs": ["127.0.0.1", "192.0.0.1/8", "::1", "fe80::/32"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]],
[[{
"value": {
"remote_addrs": ["127.0.0.1", "192.0.0.1/8", "::1", "fe80::/32"]
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 16: multiple vars
--- 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,
[=[{
"uri": "/index.html",
"vars": [["arg_name", "==", "json"], ["arg_age", ">", 18]],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]=],
[=[{
"value": {
"vars": [["arg_name", "==", "json"], ["arg_age", ">", 18]]
}
}]=]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 17: filter function
--- 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,
[=[{
"uri": "/index.html",
"filter_func": "function(vars) return vars.arg_name == 'json' end",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]=],
[=[{
"value": {
"filter_func": "function(vars) return vars.arg_name == 'json' end"
}
}]=]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 18: filter function (invalid)
--- 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,
[=[{
"uri": "/index.html",
"filter_func": "function(vars) ",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]=]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"failed to load 'filter_func' string: [string \"return function(vars) \"]:1: 'end' expected near '<eof>'"}
=== TEST 19: Support for multiple URIs
--- 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,
[=[{
"uris": ["/index.html","/index2.html"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]=]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 20: set route(id: 1, parameters with boolean values)
--- 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,
[[{
"uri": "/index.html",
"enable_websocket": true,
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:8080":1
}
}
}]])
ngx.say(body)
}
}
--- response_body
passed
=== TEST 21: patch route(modify the boolean value of parameters to false)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1/enable_websocket',
ngx.HTTP_PATCH,
'false',
[[{
"value": {
"enable_websocket": false
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 22: patch route(modify the boolean value of parameters to true)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1/enable_websocket',
ngx.HTTP_PATCH,
'true',
[[{
"value": {
"enable_websocket": true
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed

View File

@@ -0,0 +1,795 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set route with ttl
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local core = require("apisix.core")
-- set
local code, body, res = t('/apisix/admin/routes/1?ttl=1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
-- get
code, body = t('/apisix/admin/routes/1?ttl=1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"uri": "/index.html"
},
"key": "/apisix/routes/1"
}]]
)
ngx.say("code: ", code)
ngx.say(body)
-- etcd v3 would still get the value at 2s, don't know why yet
ngx.sleep(2.5)
-- get again
code, body, res = t('/apisix/admin/routes/1', ngx.HTTP_GET)
ngx.say("code: ", code)
ngx.say("message: ", core.json.decode(body).message)
}
}
--- response_body
code: 200
passed
code: 404
message: Key not found
--- timeout: 5
=== TEST 2: post route with ttl
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local core = require("apisix.core")
local code, body, res = t('/apisix/admin/routes?ttl=1',
ngx.HTTP_POST,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
[[{}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.say("[push] succ: ", body)
ngx.sleep(2.5)
local id = string.sub(res.key, #"/apisix/routes/" + 1)
code, body = t('/apisix/admin/routes/' .. id, ngx.HTTP_GET)
ngx.say("code: ", code)
ngx.say("message: ", core.json.decode(body).message)
}
}
--- response_body
[push] succ: passed
code: 404
message: Key not found
--- timeout: 5
=== TEST 3: invalid argument: ttl
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body, res = t('/apisix/admin/routes?ttl=xxx',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
ngx.say("[push] succ: ", body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid argument ttl: should be a number"}
=== TEST 4: set route(id: 1, check priority)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html"
}]],
[[{
"value": {
"priority": 0
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 5: set route(id: 1 + priority: 0)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route",
"uri": "/index.html",
"priority": 1
}]],
[[{
"value": {
"priority": 1
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 6: set route(id: 1) and upstream(type:chash, default hash_on: vars, missing key)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
},
"desc": "new route",
"uri": "/index.html"
}]])
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 7: set route(id: 1) and upstream(type:chash, hash_on: header, missing key)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on":"header"
},
"desc": "new route",
"uri": "/index.html"
}]])
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 8: set route(id: 1) and upstream(type:chash, hash_on: cookie, missing key)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on":"cookie"
},
"desc": "new route",
"uri": "/index.html"
}]])
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 9: set route(id: 1) and upstream(type:chash, hash_on: consumer, missing key is ok)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on":"consumer"
},
"desc": "new route",
"uri": "/index.html"
}]])
ngx.say(body)
}
}
--- response_body
passed
=== TEST 10: set route(id: 1 + name: test name)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"name": "test name",
"uri": "/index.html"
}]],
[[{
"value": {
"name": "test name"
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: string id(delete)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/a-b-c-ABC_0123',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 13: invalid string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/*invalid',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- error_code: 400
=== TEST 14: Verify Response Content-Type=application/json
--- config
location /t {
content_by_lua_block {
local http = require("resty.http")
local httpc = http.new()
httpc:set_timeout(500)
httpc:connect(ngx.var.server_addr, ngx.var.server_port)
local res, err = httpc:request(
{
path = '/apisix/admin/routes/1?ttl=1',
method = "GET",
}
)
ngx.header["Content-Type"] = res.headers["Content-Type"]
ngx.status = 200
ngx.say("passed")
}
}
--- response_headers
Content-Type: application/json
=== TEST 15: set route with size 36k (temporary file to store request body)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local core = require("apisix.core")
local s = string.rep("a", 1024 * 35)
local req_body = [[{
"upstream": {
"nodes": {
"]] .. s .. [[": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT, req_body)
if code >= 300 then
ngx.status = code
end
ngx.say("req size: ", #req_body)
ngx.say(body)
}
}
--- response_body
req size: 36066
passed
--- error_log
a client request body is buffered to a temporary file
=== TEST 16: route size more than 1.5 MiB
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local s = string.rep( "a", 1024 * 1024 * 1.6 )
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "]] .. s .. [[",
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid request body: request size 1678025 is greater than the maximum size 1572864 allowed"}
--- error_log
failed to read request body: request size 1678025 is greater than the maximum size 1572864 allowed
=== TEST 17: uri + plugins + script failed
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"script": "local _M = {} \n function _M.access(api_ctx) \n ngx.log(ngx.INFO,\"hit access phase\") \n end \nreturn _M",
"uri": "/index.html"
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
}
}
--- error_code: 400
--- response_body_like
{"error_msg":"invalid configuration: value wasn't supposed to match schema"}
=== TEST 18: invalid route: multi nodes with `node` mode to pass host
--- 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", "GET"],
"upstream": {
"nodes": {
"apisix.com:8080": 1,
"test.com:8080": 1
},
"type": "roundrobin",
"pass_host": "node"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
=== TEST 19: set route(with labels)
--- 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"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"labels": {
"build": "16",
"env": "production",
"version": "v2"
},
"uri": "/index.html"
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"labels": {
"build": "16",
"env": "production",
"version": "v2"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 20: patch route(change labels)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
[[{
"labels": {
"build": "17"
}
}]],
[[{
"value": {
"methods": [
"GET"
],
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"labels": {
"env": "production",
"version": "v2",
"build": "17"
}
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 21: invalid format of label value: set route
--- 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"],
"uri": "/index.html",
"labels": {
"env": ["production", "release"]
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
=== TEST 22: create route with create_time and update_time(id : 1)
--- 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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html",
"create_time": 1602883670,
"update_time": 1602893670
}]],
[[{
"value": {
"uri": "/index.html",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"create_time": 1602883670,
"update_time": 1602893670
},
"key": "/apisix/routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"the property is forbidden:.*"\}/

View File

@@ -0,0 +1,274 @@
#
# 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';
log_level("info");
repeat_each(1);
no_long_string();
no_root_location();
add_block_preprocessor(sub {
my ($block) = @_;
if (!defined $block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: set route in request body vars
--- 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,
[[{
"uri": "/hello",
"vars": [
[
["post_arg.model","==", "deepseek"]
]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"vars": [
[
["post_arg.model","==","openai"]
]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}]]
)
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: send request with model == deepseek
--- request
POST /hello
{ "model":"deepseek", "messages": [ { "role": "system", "content": "You are a mathematician" }] }
--- more_headers
Content-Type: application/json
--- error_code: 404
=== TEST 3: send request with model == openai and content-type == application/json
--- request
POST /hello
{ "model":"openai", "messages": [ { "role": "system", "content": "You are a mathematician" }] }
--- more_headers
Content-Type: application/json
--- error_code: 200
=== TEST 4: send request with model == openai and content-type == application/x-www-form-urlencoded
--- request
POST /hello
model=openai&messages[0][role]=system&messages[0][content]=You%20are%20a%20mathematician
--- more_headers
Content-Type: application/x-www-form-urlencoded
--- error_code: 200
=== TEST 5: multipart/form-data with model=openai
--- request
POST /hello
--testboundary
Content-Disposition: form-data; name="model"
openai
--testboundary--
--- more_headers
Content-Type: multipart/form-data; boundary=testboundary
--- error_code: 200
=== TEST 6: no match without content type
--- request
POST /hello
--testboundary
Content-Disposition: form-data; name="model"
openai
--testboundary--
--- error_code: 404
--- error_log
unsupported content-type in header:
=== TEST 7: use array in request body vars
--- 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,
[[{
"uri": "/hello",
"vars": [
[
["post_arg.messages[*].content[*].type","has","image_url"]
]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: send request with type not image_url
--- request
POST /hello
{ "model":"deepseek", "messages": [ { "role": "system", "content": [{"text":"You are a mathematician","type":"text"}] }] }
--- more_headers
Content-Type: application/json
--- error_code: 404
=== TEST 9: send request with type has image_url
--- request
POST /hello
{ "model":"deepseek", "messages": [ { "role": "system", "content": [{"text":"You are a mathematician","type":"text"},{"text":"You are a mathematician","type":"image_url"}] }] }
--- more_headers
Content-Type: application/json
--- error_code: 200
=== TEST 10: use invalid jsonpath input
--- 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,
[[{
"uri": "/hello",
"vars": [
[
["post_arg.messages[.content[*].type","has","image_url"]
]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body eval
qr/.*failed to validate the 'vars' expression: invalid expression.*/
--- error_code: 400
=== TEST 11: use non array in request body vars
--- 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,
[[{
"uri": "/hello",
"vars": [
[
["post_arg.model.name","==","deepseek"]
]
],
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: send request
--- request
POST /hello
{ "model":{"name": "deepseek"}, "messages": [ { "role": "system", "content": [{"text":"You are a mathematician","type":"text"},{"text":"You are a mathematician","type":"image_url"}] }] }
--- more_headers
Content-Type: application/json
--- error_code: 200

View File

@@ -0,0 +1,441 @@
#
# 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();
no_shuffle();
log_level("warn");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests;
__DATA__
=== TEST 1: validate ok
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"uri": "/httpbin/*",
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 200
=== TEST 2: validate failed, wrong uri type
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"uri": 666,
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg": {"property \"uri\" validation failed: wrong type: expected string, got number"}}
=== TEST 3: validate failed, length limit
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"uri": "",
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"property \"uri\" validation failed: string too short, expected at least 1, got 0"}
=== TEST 4: validate failed, array type expected
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"uris": "foobar",
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"property \"uris\" validation failed: wrong type: expected array, got string"}
=== TEST 5: validate failed, array size limit
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"uris": [],
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"property \"uris\" validation failed: expect array to have at least 1 items"}
=== TEST 6: validate failed, array unique items
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"uris": ["/foo", "/foo"],
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"property \"uris\" validation failed: expected unique items but items 1 and 2 are equal"}
=== TEST 7: validate failed, uri or uris is mandatory
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"allOf 1 failed: value should match only one schema, but matches none"}
=== TEST 8: validate failed, enum check
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"status": 3,
"uri": "/foo",
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"property \"status\" validation failed: matches none of the enum values"}
=== TEST 9: validate failed, wrong combination
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"script": "xxxxxxxxxxxxxxxxxxxxx",
"plugin_config_id": "foo"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"allOf 1 failed: value should match only one schema, but matches none"}
=== TEST 10: validate failed, id_schema check
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/routes',
ngx.HTTP_POST,
[[{
"plugin_config_id": "@@@@@@@@@@@@@@@@",
"uri": "/foo",
"upstream": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"nghttp2.org": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"property \"plugin_config_id\" validation failed: object matches none of the required"}
=== TEST 11: upstream ok
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/upstreams',
ngx.HTTP_POST,
[[{
"nodes":{
"nghttp2.org":100
},
"type":"roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 200
=== TEST 12: upstream failed, wrong nodes format
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/validate/upstreams',
ngx.HTTP_POST,
[[{
"nodes":[
"nghttp2.org"
],
"type":"roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- error_code: 400
--- response
{"error_msg":"allOf 1 failed: value should match only one schema, but matches none"}
=== TEST 13: Check node_schema optional port
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes',
ngx.HTTP_POST,
{
uri = "/hello",
upstream = {
type = "roundrobin",
nodes = {
{ host = "127.0.0.1:1980", weight = 1,}
}
},
methods = {"GET"},
}
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: Test route upstream
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,250 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: get route schema
--- request
GET /apisix/admin/schema/route
--- response_body eval
qr/"plugins":\{"type":"object"}/
=== TEST 2: get service schema and check if it contains `anyOf`
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, _, res_body = t('/apisix/admin/schema/service', ngx.HTTP_GET)
local res_data = core.json.decode(res_body)
if res_data["anyOf"] then
ngx.say("found `anyOf`")
return
end
ngx.say("passed")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: get not exist schema
--- request
GET /apisix/admin/schema/noexits
--- error_code: 400
=== TEST 4: wrong method
--- request
PUT /apisix/admin/schema/service
--- error_code: 404
=== TEST 5: wrong method
--- request
POST /apisix/admin/schema/service
--- error_code: 404
=== TEST 6: ssl
--- config
location /t {
content_by_lua_block {
local ssl = require("apisix.schema_def").ssl
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/ssl',
ngx.HTTP_GET,
nil,
ssl
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: get plugin's schema
--- request
GET /apisix/admin/schema/plugins/limit-count
--- response_body eval
qr/"required":\["count","time_window"\]/
=== TEST 8: get not exist plugin
--- request
GET /apisix/admin/schema/plugins/no-exist
--- error_code: 404
=== TEST 9: serverless-pre-function
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/plugins/serverless-pre-function',
ngx.HTTP_GET,
nil,
[[{
"properties": {
"phase": {
"enum": ["rewrite", "access", "header_filter", "body_filter", "log", "before_proxy"],
"type": "string"
},
"functions": {
"minItems": 1,
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["functions"],
"type": "object"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: serverless-post-function
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/schema/plugins/serverless-post-function',
ngx.HTTP_GET,
nil,
[[{
"properties": {
"phase": {
"enum": ["rewrite", "access", "header_filter", "body_filter", "log", "before_proxy"],
"type": "string"
},
"functions": {
"minItems": 1,
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["functions"],
"type": "object"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: get plugin udp-logger schema
--- request
GET /apisix/admin/schema/plugins/udp-logger
--- response_body eval
qr/"properties":/
=== TEST 12: get plugin grpc-transcode schema
--- request
GET /apisix/admin/schema/plugins/grpc-transcode
--- response_body eval
qr/("proto_id".*additionalProperties|additionalProperties.*"proto_id")/
=== TEST 13: get plugin prometheus schema
--- request
GET /apisix/admin/schema/plugins/prometheus
--- response_body eval
qr/"disable":\{"type":"boolean"\}/
=== TEST 14: get plugin node-status schema
--- extra_yaml_config
plugins:
- node-status
--- request
GET /apisix/admin/schema/plugins/node-status
--- response_body eval
qr/"disable":\{"type":"boolean"\}/
=== TEST 15: get global_rule schema to check if it contains `create_time` and `update_time`
--- request
GET /apisix/admin/schema/global_rule
--- response_body eval
qr/("update_time":\{"type":"integer"\}.*"create_time":\{"type":"integer"\}|"create_time":\{"type":"integer"\}.*"update_time":\{"type":"integer"\})/
=== TEST 16: get proto schema to check if it contains `create_time` and `update_time`
--- request
GET /apisix/admin/schema/proto
--- response_body eval
qr/("update_time":\{"type":"integer"\}.*"create_time":\{"type":"integer"\}|"create_time":\{"type":"integer"\}.*"update_time":\{"type":"integer"\})/
=== TEST 17: get stream_route schema to check if it contains `create_time` and `update_time`
--- request
GET /apisix/admin/schema/stream_route
--- response_body eval
qr/("update_time":\{"type":"integer"\}.*"create_time":\{"type":"integer"\}|"create_time":\{"type":"integer"\}.*"update_time":\{"type":"integer"\})/

View File

@@ -0,0 +1,279 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests;
__DATA__
=== TEST 1: PUT
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/secrets/vault/test1',
ngx.HTTP_PUT,
[[{
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
}]],
[[{
"value": {
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
},
"key": "/apisix/secrets/vault/test1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/secrets/vault/test1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed
=== TEST 2: GET
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/secrets/vault/test1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
},
"key": "/apisix/secrets/vault/test1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: GET all
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/secrets',
ngx.HTTP_GET,
nil,
[[{
"total": 1,
"list": [
{
"key": "/apisix/secrets/vault/test1",
"value": {
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
}
}
]
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: PATCH on path
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/secrets/vault/test1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/secrets/vault/test1/token',
ngx.HTTP_PATCH,
[["unknown"]],
[[{
"value": {
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "unknown"
},
"key": "/apisix/secrets/vault/test1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/secrets/vault/test1'))
assert(res.body.node.value.token == "unknown")
}
}
--- response_body
passed
=== TEST 5: PATCH
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/secrets/vault/test1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local prev_update_time = res.body.node.value.update_time
assert(prev_update_time ~= nil, "update_time is nil")
ngx.sleep(1)
local code, body = t('/apisix/admin/secrets/vault/test1',
ngx.HTTP_PATCH,
[[{
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
}]],
[[{
"value": {
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
},
"key": "/apisix/secrets/vault/test1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/secrets/vault/test1'))
assert(res.body.node.value.token == "apisix")
}
}
--- response_body
passed
=== TEST 6: PATCH without id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/secrets/vault',
ngx.HTTP_PATCH,
[[{}]],
[[{}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"no secret id"}
=== TEST 7: DELETE
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/secrets/vault/test1',
ngx.HTTP_DELETE
)
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: PUT with invalid format
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/secrets/vault/test1',
ngx.HTTP_PUT,
[[{
"uri": "/get",
"prefix" : "apisix",
"token" : "apisix"
}]],
[[{
"value": {
"uri": "http://127.0.0.1:12800/get",
"prefix" : "apisix",
"token" : "apisix"
},
"key": "/apisix/secrets/vault/test1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 400
--- response_body eval
qr/validation failed: failed to match pattern/

View File

@@ -0,0 +1,105 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set service(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
},
"desc": "new service"
}]],
[[{
"value": {
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
},
"desc": "new service"
},
"key": "/apisix/services/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get service(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
},
"desc": "new service"
},
"key": "/apisix/services/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,156 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set service(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 201
--- response_body
passed
=== TEST 2: add route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"service_id": 1,
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 3: delete service(wrong header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/1?force=anyvalue',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this service directly, route [1] is still using it now"}
=== TEST 4: delete service(without force delete header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this service directly, route [1] is still using it now"}
=== TEST 5: delete service(force delete)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/1?force=true',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed
=== TEST 6: delete route
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed

View File

@@ -0,0 +1,745 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set service(id: 5eeb3dc90f747328b2930b0b)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new service"
}]],
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new service"
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get service(id: 5eeb3dc90f747328b2930b0b)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_GET,
nil,
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new service"
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: delete service(id: 5eeb3dc90f747328b2930b0b)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 4: delete service(id: not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/services/not_found', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 5: post service + delete
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services',
ngx.HTTP_POST,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]],
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local id = string.sub(res.key, #"/apisix/services/" + 1)
code, message = t('/apisix/admin/services/' .. id, ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
[delete] code: 200 message: passed
=== TEST 6: uri + upstream
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]],
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
=== TEST 7: uri + plugins
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]],
[[{
"value": {
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
=== TEST 8: invalid service id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/*invalid_id$',
ngx.HTTP_PUT,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]]
)
ngx.exit(code)
}
}
--- request
GET /t
--- error_code: 400
=== TEST 9: invalid id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"id": "3",
"plugins": {}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong service id"}
=== TEST 10: id in the rule
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services',
ngx.HTTP_PUT,
[[{
"id": "5eeb3dc90f747328b2930b0b",
"plugins": {}
}]],
[[{
"value": {
"plugins": {}
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: integer id less than 1
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services',
ngx.HTTP_PUT,
[[{
"id": -100,
"plugins": {}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"id\" validation failed: object matches none of the required"}
=== TEST 12: invalid service id: contains symbols value
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services',
ngx.HTTP_PUT,
[[{
"id": "*invalid_id$",
"plugins": {}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"id\" validation failed: object matches none of the required"}
=== TEST 13: invalid upstream_id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services',
ngx.HTTP_PUT,
[[{
"id": "5eeb3dc90f747328b2930b0b",
"upstream_id": "invalid$"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream_id\" validation failed: object matches none of the required"}
=== TEST 14: not exist upstream_id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services',
ngx.HTTP_PUT,
[[{
"id": "5eeb3dc90f747328b2930b0b",
"upstream_id": "9999999999"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to fetch upstream info by upstream id [9999999999], response code: 404"}
=== TEST 15: wrong service id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_POST,
[[{
"plugins": {}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong service id, do not need it"}
=== TEST 16: wrong service id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services',
ngx.HTTP_POST,
[[{
"id": "5eeb3dc90f747328b2930b0b",
"plugins": {}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong service id, do not need it"}
=== TEST 17: patch service(whole)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PATCH,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new 20 service"
}]],
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new 20 service"
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 18: patch service(new desc)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PATCH,
[[{
"desc": "new 19 service"
}]],
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new 19 service"
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 19: patch service(new nodes)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PATCH,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8081": 3,
"127.0.0.1:8082": 4
},
"type": "roundrobin"
}
}]],
[[{
"value": {
"upstream": {
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8081": 3,
"127.0.0.1:8082": 4
},
"type": "roundrobin"
}
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 20: set service(id: 5eeb3dc90f747328b2930b0b) and upstream(type:chash, default hash_on: vars, missing key)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
},
"desc": "new service"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 21: set service(id: 5eeb3dc90f747328b2930b0b) and upstream(type:chash, hash_on: header, missing key)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "header"
},
"desc": "new service"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 22: set service(id: 5eeb3dc90f747328b2930b0b) and upstream(type:chash, hash_on: cookie, missing key)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "cookie"
},
"desc": "new service"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 23: set service(id: 5eeb3dc90f747328b2930b0b) and upstream(type:chash, hash_on: consumer, missing key is ok)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/5eeb3dc90f747328b2930b0b',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "consumer"
},
"desc": "new service"
}]]
)
ngx.status = code
ngx.say(code .. " " .. body)
}
}
--- request
GET /t
--- response_body
200 passed

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: not unwanted data, POST
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services',
ngx.HTTP_POST,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.key = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.id ~= nil)
res.value.id = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"value":{"upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
=== TEST 2: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/services/1","value":{"id":"1","upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
=== TEST 3: not unwanted data, PATCH
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services/1',
ngx.HTTP_PATCH,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
res.value.create_time = nil
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/services/1","value":{"id":"1","upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
=== TEST 4: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services/1', ngx.HTTP_GET)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/services/1","value":{"id":"1","upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
=== TEST 5: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/services/1',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/services/1"}
=== TEST 6: set service(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 7: set route(id: 1)
--- 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,
[[{
"service_id": 1,
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: delete service(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/1', ngx.HTTP_DELETE)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this service directly, route [1] is still using it now"}
=== TEST 9: delete route(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 200 message: passed
=== TEST 10: delete service(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 200 message: passed

View File

@@ -0,0 +1,802 @@
#
# 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_root_location();
run_tests;
__DATA__
=== TEST 1: set ssl(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local etcd = require("apisix.core.etcd")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/ssls/1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get ssl(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/ssls/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"sni": "test.com",
"key": null
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: delete ssl(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/ssls/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 4: delete ssl(id: 99999999999999)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/ssls/99999999999999', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 5: push ssl + delete
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "foo.com"}
local code, message, res = t.test('/apisix/admin/ssls',
ngx.HTTP_POST,
core.json.encode(data),
[[{
"value": {
"sni": "foo.com"
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local id = string.sub(res.key, #"/apisix/ssls/" + 1)
code, message = t.test('/apisix/admin/ssls/' .. id, ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
[delete] code: 200 message: passed
=== TEST 6: missing certificate information
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {sni = "foo.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "foo.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: then clause did not match"}
=== TEST 7: wildcard host name
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "*.foo.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "*.foo.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: store sni in `snis`
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {
cert = ssl_cert, key = ssl_key,
snis = {"*.foo.com", "bar.com"},
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"snis": ["*.foo.com", "bar.com"]
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: string id
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/a-b-c-ABC_0123',
ngx.HTTP_PUT,
core.json.encode(data)
)
if code > 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: string id(delete)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/a-b-c-ABC_0123',
ngx.HTTP_DELETE
)
if code > 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: invalid id
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/*invalid',
ngx.HTTP_PUT,
core.json.encode(data)
)
if code > 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
=== TEST 12: set ssl with multicerts(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local ssl_ecc_cert = t.read_file("t/certs/apisix_ecc.crt")
local ssl_ecc_key = t.read_file("t/certs/apisix_ecc.key")
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
certs = {ssl_ecc_cert},
keys = {ssl_ecc_key}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: mismatched certs and keys
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_ecc_cert = t.read_file("t/certs/apisix_ecc.crt")
local data = {
sni = "test.com",
certs = { ssl_ecc_cert },
keys = {},
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: then clause did not match"}
=== TEST 14: set ssl(with labels)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com", labels = { version = "v2", build = "16", env = "production"}}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"labels": {
"version": "v2",
"build": "16",
"env": "production"
}
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 15: invalid format of label value: set ssl
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com", labels = { env = {"production", "release"}}}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"labels": {
"env": ["production", "release"]
}
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
=== TEST 16: create ssl with manage fields(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com"
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 17: delete test ssl(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/ssls/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 18: create/patch ssl
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local etcd = require("apisix.core.etcd")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body, res = t.test('/apisix/admin/ssls',
ngx.HTTP_POST,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(body)
return
end
local id = string.sub(res.key, #"/apisix/ssls/" + 1)
local res = assert(etcd.get('/ssls/' .. id))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
local code, body = t.test('/apisix/admin/ssls/' .. id,
ngx.HTTP_PATCH,
core.json.encode({create_time = 0, update_time = 1})
)
if code ~= 200 then
ngx.status = code
ngx.say(body)
return
end
local res = assert(etcd.get('/ssls/' .. id))
local create_time = res.body.node.value.create_time
assert(create_time == 0, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(update_time == 1, "update_time mismatched")
-- clean up
local code, body = t.test('/apisix/admin/ssls/' .. id, ngx.HTTP_DELETE)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 19: missing sni information
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: then clause did not match"}
=== TEST 20: type client, missing sni information
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {type = "client", cert = ssl_cert, key = ssl_key}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- response_body chomp
passed
=== TEST 21: set ssl with sercret
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local data = {
sni = "test.com",
cert = "$secret://vault/test/ssl/test.com.crt",
key = "$secret://vault/test/ssl/test.com.key",
certs = {"$secret://vault/test/ssl/test.com.2.crt"},
keys = {"$secret://vault/test/ssl/test.com.2.key"}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"cert": "$secret://vault/test/ssl/test.com.crt",
"key": "$secret://vault/test/ssl/test.com.key",
"certs": ["$secret://vault/test/ssl/test.com.2.crt"],
"keys": ["$secret://vault/test/ssl/test.com.2.key"]
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 22: set ssl with env, and prefix is all uppercase or lowercase
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local data = {
sni = "test.com",
cert = "$ENV://APISIX_TEST_SSL_CERT",
key = "$env://APISIX_TEST_SSL_KEY",
certs = {"$env://APISIX_TEST_SSL_CERTS"},
keys = {"$ENV://APISIX_TEST_SSL_KEYS"},
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"cert": "$ENV://APISIX_TEST_SSL_CERT",
"key": "$env://APISIX_TEST_SSL_KEY",
"certs": ["$env://APISIX_TEST_SSL_CERTS"],
"keys": ["$ENV://APISIX_TEST_SSL_KEYS"]
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 23: set ssl with invalid prefix
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local data = {
sni = "test.com",
cert = "$ENV://APISIX_TEST_SSL_CERT",
key = "$env://APISIX_TEST_SSL_KEY",
certs = {"https://APISIX_TEST_SSL_CERTS"},
keys = {"$ENV://APISIX_TEST_SSL_KEYS"},
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"certs\" validation failed: failed to validate item 1: value should match only one schema, but matches none"}

View File

@@ -0,0 +1,496 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: not unwanted data, POST
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "not-unwanted-post.com"}
local code, message, res = t.test('/apisix/admin/ssls',
ngx.HTTP_POST,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.key ~= nil)
res.key = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.cert ~= nil)
res.value.cert = ""
assert(res.value.key ~= nil)
res.value.key = ""
assert(res.value.id ~= nil)
res.value.id = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"value":{"cert":"","key":"","sni":"not-unwanted-post.com","status":1,"type":"server"}}
=== TEST 2: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.cert ~= nil)
res.value.cert = ""
assert(res.value.key ~= nil)
res.value.key = ""
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/ssls/1","value":{"cert":"","id":"1","key":"","sni":"test.com","status":1,"type":"server"}}
=== TEST 3: not unwanted data, PATCH
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "t.com"}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PATCH,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.cert ~= nil)
res.value.cert = ""
assert(res.value.key ~= nil)
res.value.key = ""
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/ssls/1","value":{"cert":"","id":"1","key":"","sni":"t.com","status":1,"type":"server"}}
=== TEST 4: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.cert ~= nil)
res.value.cert = ""
assert(res.value.key == nil)
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/ssls/1","value":{"cert":"","id":"1","sni":"t.com","status":1,"type":"server"}}
=== TEST 5: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/ssls/1"}
=== TEST 6: bad cert
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = [[-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----
]], key = ssl_key, sni = "test.com"}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(res)
}
}
--- error_code: 400
--- response_body
{"error_msg":"failed to parse cert: PEM_read_bio_X509_AUX() failed"}
=== TEST 7: bad key
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local data = {cert = ssl_cert, key = [[
-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEAyCM0rqJecvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5
jhZB3W6BkWUWR4oNFLLSqcVbVDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfo
wzarryret/7GFW1/3cz+hTj9/d45i25zArr3Pocfpur5mfz3fJO8jg==
-----END RSA PRIVATE KEY-----]], sni = "test.com"}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(res)
}
}
--- error_code: 400
--- response_body
{"error_msg":"failed to parse key: PEM_read_bio_PrivateKey() failed"}
=== TEST 8: bad certs
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "t.com",
certs = {
[[-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----]]
},
keys = {ssl_key}
}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(res)
}
}
--- error_code: 400
--- response_body
{"error_msg":"failed to handle cert-key pair[1]: failed to parse cert: PEM_read_bio_X509_AUX() failed"}
=== TEST 9: bad keys
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "t.com",
certs = {ssl_cert},
keys = {[[-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEAyCM0rqJecvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5
jhZB3W6BkWUWR4oNFLLSqcVbVDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfo
wzarryret/7GFW1/3cz+hTj9/d45i25zArr3Pocfpur5mfz3fJO8jg==
-----END RSA PRIVATE KEY-----]]}
}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(res)
}
}
--- error_code: 400
--- response_body
{"error_msg":"failed to handle cert-key pair[1]: failed to parse key: PEM_read_bio_PrivateKey() failed"}
=== TEST 10: empty snis
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, snis = {}}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(res)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"snis\" validation failed: expect array to have at least 1 items"}
=== TEST 11: update snis, PATCH with sub path
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, snis = {"test.com"}}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
local data = {"update1.com", "update2.com"}
local code, message, res = t.test('/apisix/admin/ssls/1/snis',
ngx.HTTP_PATCH,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res)
}
}
--- response_body_like eval
qr/"snis":\["update1.com","update2.com"\]/
=== TEST 12: PATCH encrypt ssl key
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: "qeddd145sfvddff3"
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, certs = {ssl_cert}, keys = {ssl_key}}
local code, message, res = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PATCH,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(res.value.key == ssl_key)
ngx.say(res.value.keys[1] == ssl_key)
}
}
--- response_body
false
false
=== TEST 13: PATCH encrypt ssl key, sub_path
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: "qeddd145sfvddff3"
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local ssl_key = t.read_file("t/certs/apisix.key")
local code, message, res = t.test('/apisix/admin/ssls/1/keys',
ngx.HTTP_PATCH,
json.encode({ssl_key})
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(res.value.keys[1] == ssl_key)
}
}
--- response_body
false

View File

@@ -0,0 +1,63 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: list empty resources
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/ssls',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"list":[],"total":0}

View File

@@ -0,0 +1,510 @@
#
# 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';
log_level('debug');
no_root_location();
add_block_preprocessor( sub{
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
my $TEST_NGINX_HTML_DIR ||= html_dir();
my $config = <<_EOC_;
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
location /t {
content_by_lua_block {
-- etcd sync
ngx.sleep(0.2)
do
local sock = ngx.socket.tcp()
sock:settimeout(2000)
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
local sess, err = sock:sslhandshake(nil, "www.test.com", true)
if not sess then
sock = ngx.socket.tcp()
sock:settimeout(2000)
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
sess, err = sock:sslhandshake(nil, "www.test.com", true)
if not sess then
ngx.say("failed to do SSL handshake: ", err)
return
end
end
ngx.say("ssl handshake: ", sess ~= nil)
local req = "GET /hello HTTP/1.0\\r\\nHost: www.test.com\\r\\nConnection: close\\r\\n\\r\\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send http request: ", err)
return
end
ngx.say("sent http request: ", bytes, " bytes.")
while true do
local line, err = sock:receive()
if not line then
break
end
ngx.say("received: ", line)
end
local ok, err = sock:close()
ngx.say("close: ", ok, " ", err)
end -- do
-- collectgarbage()
}
}
_EOC_
if (!$block->config) {
$block->set_value("config", $config)
}
}
);
run_tests;
__DATA__
=== TEST 1: set ssl(sni: www.test.com), encrypt with the first keyring
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- edd1c9f0985e76a1
- qeddd145sfvddff3
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "www.test.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "www.test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: set route(id: 1)
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: "edd1c9f0985e76a1"
--- 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,
[[{
"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 3: client request with the old style keyring
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: "edd1c9f0985e76a1"
--- response_body eval
qr{connected: 1
ssl handshake: true
sent http request: 62 bytes.
received: HTTP/1.1 200 OK
received: Content-Type: text/plain
received: Content-Length: 12
received: Connection: close
received: Server: APISIX/\d\.\d+(\.\d+)?
received: \nreceived: hello world
close: 1 nil}
--- error_log
server name: "www.test.com"
--- no_error_log
[error]
[alert]
=== TEST 4: client request with the new style keyring
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- edd1c9f0985e76a1
--- response_body eval
qr{connected: 1
ssl handshake: true
sent http request: 62 bytes.
received: HTTP/1.1 200 OK
received: Content-Type: text/plain
received: Content-Length: 12
received: Connection: close
received: Server: APISIX/\d\.\d+(\.\d+)?
received: \nreceived: hello world
close: 1 nil}
--- error_log
server name: "www.test.com"
--- no_error_log
[error]
[alert]
=== TEST 5: client request failed with the wrong keyring
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- qeddd145sfvddff3
--- error_log
decrypt ssl key failed
=== TEST 6: client request successfully, use the two keyring to decrypt in turn
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- qeddd145sfvddff3
- edd1c9f0985e76a1
--- response_body eval
qr{connected: 1
ssl handshake: true
sent http request: 62 bytes.
received: HTTP/1.1 200 OK
received: Content-Type: text/plain
received: Content-Length: 12
received: Connection: close
received: Server: APISIX/\d\.\d+(\.\d+)?
received: \nreceived: hello world
close: 1 nil}
--- ignore_error_log
=== TEST 7: remove test ssl certs
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- edd1c9f0985e76a1
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
t.test('/apisix/admin/ssls/1', ngx.HTTP_DELETE)
}
}
=== TEST 8: set ssl(sni: www.test.com), do not encrypt
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "www.test.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "www.test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: client request without keyring
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: null
--- response_body eval
qr{connected: 1
ssl handshake: true
sent http request: 62 bytes.
received: HTTP/1.1 200 OK
received: Content-Type: text/plain
received: Content-Length: 12
received: Connection: close
received: Server: APISIX/\d\.\d+(\.\d+)?
received: \nreceived: hello world
close: 1 nil}
--- error_log
server name: "www.test.com"
--- no_error_log
[error]
[alert]
=== TEST 10: remove test ssl certs
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
t.test('/apisix/admin/ssls/1', ngx.HTTP_DELETE)
}
}
=== TEST 11: set ssl(sni: www.test.com) with long label
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "www.test.com",
labels = {secret = "js-design-test-bigdata-data-app-service-router-my-secret-number-123456"}}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "www.test.com",
"labels": {
"secret": "js-design-test-bigdata-data-app-service-router-my-secret-number-123456"
},
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: set ssl(sni: www.test.com), encrypt with the first keyring
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- edd1c9f0985e76a1
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 13: update encrypt keyring, and set ssl(sni: test2.com)
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- qeddd145sfvddff3
- edd1c9f0985e76a1
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/test2.crt")
local ssl_key = t.read_file("t/certs/test2.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test2.com"}
local code, body = t.test('/apisix/admin/ssls/2',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test2.com"
},
"key": "/apisix/ssls/2"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 14: Successfully access test.com
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- qeddd145sfvddff3
- edd1c9f0985e76a1
--- exec
curl -k -s --resolve "test2.com:1994:127.0.0.1" https://test2.com:1994/hello 2>&1 | cat
--- response_body
hello world
=== TEST 15: Successfully access test2.com
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring:
- qeddd145sfvddff3
- edd1c9f0985e76a1
--- exec
curl -k -s --resolve "test2.com:1994:127.0.0.1" https://test2.com:1994/hello 2>&1 | cat
--- response_body
hello world

View File

@@ -0,0 +1,86 @@
#
# 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_root_location();
run_tests;
__DATA__
=== TEST 1: Not supported set TLSv1.0 for ssl_protocols
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com", ssl_protocols = {"TLSv1.0", "TLSv1.2"}}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"ssl_protocols\" validation failed: failed to validate item 1: matches none of the enum values"}
=== TEST 2: The default value for the ssl_protocols is null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"ssl_protocols": null,
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,75 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: test /apisix/admin/ssls/{id}
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local etcd = require("apisix.core.etcd")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com"
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/ssls/1'))
local prev_create_time = res.body.node.value.create_time
assert(prev_create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- response_body
passed

View File

@@ -0,0 +1,128 @@
#
# 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 {
# restarts cause the memory cache to be emptied, don't do this
$ENV{TEST_NGINX_FORCE_RESTART_ON_TEST} = 0;
}
use t::APISIX 'no_plan';
repeat_each(1);
no_long_string();
no_root_location();
use_hup();
add_block_preprocessor(sub {
my ($block) = @_;
if (!defined $block->yaml_config) {
$block->set_value("yaml_config", <<'EOF');
deployment:
role: traditional
role_traditional:
config_provider: yaml
admin:
admin_key:
- name: admin
key: edd1c9f034335f136f87ad84b625c8f1
role: admin
EOF
}
if (!defined $block->no_error_log) {
$block->set_value("no_error_log", "");
}
});
run_tests();
__DATA__
=== TEST 1: test
--- timeout: 15
--- max_size: 204800
--- exec
cd t && pnpm test admin/standalone.spec.ts 2>&1
--- no_error_log
failed to execute the script with status
--- response_body eval
qr/PASS admin\/standalone.spec.ts/
=== TEST 2: send /healthcheck should fail because config is not loaded yet
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
local shared_dict = ngx.shared["standalone-config"]
shared_dict:delete("config")
--- config
location /t {
content_by_lua_block {
local http = require("resty.http")
local healthcheck_uri = "http://127.0.0.1:7085" .. "/status/ready"
local httpc = http.new()
local res, _ = httpc:request_uri(healthcheck_uri, {method = "GET", keepalive = false})
ngx.status = res.status
}
}
--- request
GET /t
--- error_code: 503
=== TEST 3: configure route and send /healthcheck should pass
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/configs',
ngx.HTTP_PUT,
[[{"routes":[{"id":"r1","uri":"/r1","upstream":{"nodes":{"127.0.0.1:1980":1},"type":"roundrobin"},"plugins":{"proxy-rewrite":{"uri":"/hello"}}}]}]],
nil,
{
["X-API-KEY"] = "edd1c9f034335f136f87ad84b625c8f1"
}
)
if code >= 300 then
ngx.status = code
end
local code, body = t('/apisix/admin/configs',
ngx.HTTP_PUT,
[[{"routes":[{"id":"r1","uri":"/r1","upstream":{"nodes":{"127.0.0.1:1980":1},"type":"roundrobin"},"plugins":{"proxy-rewrite":{"uri":"/hello"}}}]}]],
nil,
{
["X-API-KEY"] = "edd1c9f034335f136f87ad84b625c8f1"
}
)
if code >= 300 then
ngx.status = code
end
ngx.sleep(1)
local http = require("resty.http")
local healthcheck_uri = "http://127.0.0.1:7085" .. "/status/ready"
local httpc = http.new()
local res, _ = httpc:request_uri(healthcheck_uri, {method = "GET", keepalive = false})
ngx.status = res.status
}
}
--- request
GET /t
--- error_code: 200

View File

@@ -0,0 +1,442 @@
/*
* 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.
*/
import axios from "axios";
import YAML from "yaml";
const ENDPOINT = "/apisix/admin/configs";
const clientConfig = {
baseURL: "http://localhost:1984",
headers: {
"X-API-KEY": "edd1c9f034335f136f87ad84b625c8f1",
},
};
const config1 = {
routes: [
{
id: "r1",
uri: "/r1",
upstream: {
nodes: { "127.0.0.1:1980": 1 },
type: "roundrobin",
},
plugins: { "proxy-rewrite": { uri: "/hello" } },
},
],
};
const config2 = {
routes: [
{
id: "r2",
uri: "/r2",
upstream: {
nodes: { "127.0.0.1:1980": 1 },
type: "roundrobin",
},
plugins: { "proxy-rewrite": { uri: "/hello" } },
},
],
};
const invalidConfVersionConfig1 = {
routes_conf_version: -1,
};
const invalidConfVersionConfig2 = {
routes_conf_version: "adc",
};
const routeWithModifiedIndex = {
routes: [
{
id: "r1",
uri: "/r1",
modifiedIndex: 1,
upstream: {
nodes: { "127.0.0.1:1980": 1 },
type: "roundrobin",
},
plugins: { "proxy-rewrite": { uri: "/hello" } },
},
],
};
const routeWithKeyAuth = {
routes: [
{
id: "r1",
uri: "/r1",
upstream: {
nodes: { "127.0.0.1:1980": 1 },
type: "roundrobin",
},
plugins: {
"proxy-rewrite": { uri: "/hello" },
"key-auth": {},
},
},
]
}
const consumerWithModifiedIndex = {
routes: routeWithKeyAuth.routes,
consumers: [
{
modifiedIndex: 10,
username: "jack",
plugins: {
"key-auth": {
key: "jack-key",
}
},
},
],
}
const credential1 = {
routes: routeWithKeyAuth.routes,
consumers: [
{
"username": "john_1"
},
{
"id": "john_1/credentials/john-a",
"plugins": {
"key-auth": {
"key": "auth-a"
}
}
},
{
"id": "john_1/credentials/john-b",
"plugins": {
"key-auth": {
"key": "auth-b"
}
}
}
]
}
describe("Admin - Standalone", () => {
const client = axios.create(clientConfig);
client.interceptors.response.use((response) => {
const contentType = response.headers["content-type"] || "";
if (
contentType.includes("application/yaml") &&
typeof response.data === "string" &&
response.config.responseType !== "text"
)
response.data = YAML.parse(response.data);
return response;
});
describe("Normal", () => {
it("dump empty config (default json format)", async () => {
const resp = await client.get(ENDPOINT);
expect(resp.status).toEqual(200);
expect(resp.data.routes_conf_version).toEqual(0);
expect(resp.data.ssls_conf_version).toEqual(0);
expect(resp.data.services_conf_version).toEqual(0);
expect(resp.data.upstreams_conf_version).toEqual(0);
expect(resp.data.consumers_conf_version).toEqual(0);
});
it("dump empty config (yaml format)", async () => {
const resp = await client.get(ENDPOINT, {
headers: { Accept: "application/yaml" },
});
expect(resp.status).toEqual(200);
expect(resp.headers["content-type"]).toEqual("application/yaml");
expect(resp.data.routes_conf_version).toEqual(0);
expect(resp.data.ssls_conf_version).toEqual(0);
expect(resp.data.services_conf_version).toEqual(0);
expect(resp.data.upstreams_conf_version).toEqual(0);
expect(resp.data.consumers_conf_version).toEqual(0);
});
it("update config (add routes, by json)", async () => {
const resp = await client.put(ENDPOINT, config1);
expect(resp.status).toEqual(202);
});
it("dump config (json format)", async () => {
const resp = await client.get(ENDPOINT);
expect(resp.status).toEqual(200);
expect(resp.data.routes_conf_version).toEqual(1);
expect(resp.data.ssls_conf_version).toEqual(1);
expect(resp.data.services_conf_version).toEqual(1);
expect(resp.data.upstreams_conf_version).toEqual(1);
expect(resp.data.consumers_conf_version).toEqual(1);
});
it("check default value", async () => {
const resp = await client.get(ENDPOINT);
expect(resp.status).toEqual(200);
expect(resp.data.routes).toEqual(config1.routes);
});
it("dump config (yaml format)", async () => {
const resp = await client.get(ENDPOINT, {
headers: { Accept: "application/yaml" },
responseType: 'text',
});
expect(resp.status).toEqual(200);
expect(resp.data).toContain("routes:")
expect(resp.data).toContain("id: r1")
expect(resp.data.startsWith('---')).toBe(false);
expect(resp.data.endsWith('...')).toBe(false);
});
it('check route "r1"', async () => {
const resp = await client.get("/r1");
expect(resp.status).toEqual(200);
expect(resp.data).toEqual("hello world\n");
});
it("update config (add routes, by yaml)", async () => {
const resp = await client.put(
ENDPOINT,
YAML.stringify(config2),
{
headers: { "Content-Type": "application/yaml" },
}
);
expect(resp.status).toEqual(202);
});
it("dump config (json format)", async () => {
const resp = await client.get(ENDPOINT);
expect(resp.status).toEqual(200);
expect(resp.data.routes_conf_version).toEqual(2);
expect(resp.data.ssls_conf_version).toEqual(2);
expect(resp.data.services_conf_version).toEqual(2);
expect(resp.data.upstreams_conf_version).toEqual(2);
expect(resp.data.consumers_conf_version).toEqual(2);
});
it('check route "r1"', () =>
expect(client.get("/r1")).rejects.toThrow(
"Request failed with status code 404"
));
it('check route "r2"', async () => {
const resp = await client.get("/r2");
expect(resp.status).toEqual(200);
expect(resp.data).toEqual("hello world\n");
});
it("update config (delete routes)", async () => {
const resp = await client.put(
ENDPOINT,
{},
{ params: { conf_version: 3 } }
);
expect(resp.status).toEqual(202);
});
it('check route "r2"', () =>
expect(client.get("/r2")).rejects.toThrow(
"Request failed with status code 404"
));
it("only set routes_conf_version", async () => {
const resp = await client.put(
ENDPOINT,
YAML.stringify({ routes_conf_version: 15 }),
{
headers: { "Content-Type": "application/yaml" },
});
expect(resp.status).toEqual(202);
const resp_1 = await client.get(ENDPOINT);
expect(resp_1.status).toEqual(200);
expect(resp_1.data.routes_conf_version).toEqual(15);
expect(resp_1.data.ssls_conf_version).toEqual(4);
expect(resp_1.data.services_conf_version).toEqual(4);
expect(resp_1.data.upstreams_conf_version).toEqual(4);
expect(resp_1.data.consumers_conf_version).toEqual(4);
const resp2 = await client.put(
ENDPOINT,
YAML.stringify({ routes_conf_version: 17 }),
{
headers: { "Content-Type": "application/yaml" },
});
expect(resp2.status).toEqual(202);
const resp2_1 = await client.get(ENDPOINT);
expect(resp2_1.status).toEqual(200);
expect(resp2_1.data.routes_conf_version).toEqual(17);
expect(resp2_1.data.ssls_conf_version).toEqual(5);
expect(resp2_1.data.services_conf_version).toEqual(5);
expect(resp2_1.data.upstreams_conf_version).toEqual(5);
expect(resp2_1.data.consumers_conf_version).toEqual(5);
});
it("control resource changes using modifiedIndex", async () => {
const c1 = structuredClone(routeWithModifiedIndex);
c1.routes[0].modifiedIndex = 1;
const c2 = structuredClone(c1);
c2.routes[0].uri = "/r2";
const c3 = structuredClone(c2);
c3.routes[0].modifiedIndex = 2;
// Update with c1
const resp = await client.put(ENDPOINT, c1);
expect(resp.status).toEqual(202);
// Check route /r1 exists
const resp_1 = await client.get("/r1");
expect(resp_1.status).toEqual(200);
// Update with c2
const resp2 = await client.put(ENDPOINT, c2);
expect(resp2.status).toEqual(202);
// Check route /r1 exists
// But it is not applied because the modifiedIndex is the same as the old value
const resp2_2 = await client.get("/r1");
expect(resp2_2.status).toEqual(200);
// Check route /r2 not exists
const resp2_1 = await client.get("/r2").catch((err) => err.response);
expect(resp2_1.status).toEqual(404);
// Update with c3
const resp3 = await client.put(ENDPOINT, c3);
expect(resp3.status).toEqual(202);
// Check route /r1 not exists
const resp3_1 = await client.get("/r1").catch((err) => err.response);
expect(resp3_1.status).toEqual(404);
// Check route /r2 exists
const resp3_2 = await client.get("/r2");
expect(resp3_2.status).toEqual(200);
});
it("apply consumer with modifiedIndex", async () => {
const resp = await client.put(ENDPOINT, consumerWithModifiedIndex);
expect(resp.status).toEqual(202);
const resp_1 = await client.get("/r1", { headers: { "apikey": "invalid-key" } }).catch((err) => err.response);
expect(resp_1.status).toEqual(401);
const resp_2 = await client.get("/r1", { headers: { "apikey": "jack-key" } });
expect(resp_2.status).toEqual(200);
const updatedConsumer = structuredClone(consumerWithModifiedIndex);
// update key of key-auth plugin, but modifiedIndex is not changed
updatedConsumer.consumers[0].plugins["key-auth"] = { "key": "jack-key-updated" };
const resp2 = await client.put(ENDPOINT, updatedConsumer);
expect(resp2.status).toEqual(202);
const resp2_1 = await client.get("/r1", { headers: { "apikey": "jack-key-updated" } }).catch((err) => err.response);
expect(resp2_1.status).toEqual(401);
const resp2_2 = await client.get("/r1", { headers: { "apikey": "jack-key" } });
expect(resp2_2.status).toEqual(200);
// update key of key-auth plugin, and modifiedIndex is changed
updatedConsumer.consumers[0].modifiedIndex++;
const resp3 = await client.put(ENDPOINT, updatedConsumer);
const resp3_1 = await client.get("/r1", { headers: { "apikey": "jack-key-updated" } });
expect(resp3_1.status).toEqual(200);
const resp3_2 = await client.get("/r1", { headers: { "apikey": "jack-key" } }).catch((err) => err.response);
expect(resp3_2.status).toEqual(401);
});
it("apply consumer with credentials", async () => {
const resp = await client.put(ENDPOINT, credential1);
expect(resp.status).toEqual(202);
const resp_1 = await client.get("/r1", { headers: { "apikey": "auth-a" } });
expect(resp_1.status).toEqual(200);
const resp_2 = await client.get("/r1", { headers: { "apikey": "auth-b" } });
expect(resp_2.status).toEqual(200);
const resp_3 = await client.get("/r1", { headers: { "apikey": "invalid-key" } }).catch((err) => err.response);
expect(resp_3.status).toEqual(401);
});
});
describe("Exceptions", () => {
const clientException = axios.create({
...clientConfig,
validateStatus: () => true,
});
it("update config (lower conf_version)", async () => {
const resp = await clientException.put(
ENDPOINT,
{ routes_conf_version: 100 },
{ headers: { "Content-Type": "application/yaml" } }
);
const resp2 = await clientException.put(
ENDPOINT,
YAML.stringify(invalidConfVersionConfig1),
{ headers: { "Content-Type": "application/yaml" } }
);
expect(resp2.status).toEqual(400);
expect(resp2.data).toEqual({
error_msg:
"routes_conf_version must be greater than or equal to (100)",
});
});
it("update config (invalid conf_version)", async () => {
const resp = await clientException.put(
ENDPOINT,
YAML.stringify(invalidConfVersionConfig2),
{
headers: {
"Content-Type": "application/yaml",
},
}
);
expect(resp.status).toEqual(400);
expect(resp.data).toEqual({
error_msg: "routes_conf_version must be a number",
});
});
it("update config (invalid json format)", async () => {
const resp = await clientException.put(ENDPOINT, "{abcd", {
params: { conf_version: 4 },
});
expect(resp.status).toEqual(400);
expect(resp.data).toEqual({
error_msg:
"invalid request body: Expected object key string but found invalid token at character 2",
});
});
it("update config (not compliant with jsonschema)", async () => {
const data = structuredClone(config1);
(data.routes[0].uri as unknown) = 123;
const resp = await clientException.put(ENDPOINT, data);
expect(resp.status).toEqual(400);
expect(resp.data).toMatchObject({
error_msg:
'invalid routes at index 0, err: property "uri" validation failed: wrong type: expected string, got number',
});
});
it("update config (empty request body)", async () => {
const resp = await clientException.put(ENDPOINT, "");
expect(resp.status).toEqual(400);
expect(resp.data).toEqual({
error_msg: "invalid request body: empty request body",
});
});
});
});

View File

@@ -0,0 +1,258 @@
#
# 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 {
# restarts cause the memory cache to be emptied, don't do this
$ENV{TEST_NGINX_FORCE_RESTART_ON_TEST} = 0;
}
use t::APISIX 'no_plan';
repeat_each(1);
no_long_string();
no_root_location();
use_hup();
add_block_preprocessor(sub {
my ($block) = @_;
if (!defined $block->yaml_config) {
$block->set_value("yaml_config", <<'EOF');
deployment:
role: traditional
role_traditional:
config_provider: yaml
admin:
admin_key:
- name: admin
key: edd1c9f034335f136f87ad84b625c8f1
role: admin
EOF
}
if (!defined $block->no_error_log) {
$block->set_value("no_error_log", "");
}
});
run_tests();
__DATA__
=== TEST 1: test
--- timeout: 15
--- max_size: 204800
--- exec
cd t && pnpm test admin/standalone.spec.ts 2>&1
--- no_error_log
failed to execute the script with status
--- response_body eval
qr/PASS admin\/standalone.spec.ts/
=== TEST 2: init conf_version
--- config
location /t {} # force the worker to restart by changing the configuration
--- request
PUT /apisix/admin/configs
{
"consumer_groups_conf_version": 1000,
"consumers_conf_version": 1000,
"global_rules_conf_version": 1000,
"plugin_configs_conf_version": 1000,
"plugin_metadata_conf_version": 1000,
"protos_conf_version": 1000,
"routes_conf_version": 1000,
"secrets_conf_version": 1000,
"services_conf_version": 1000,
"ssls_conf_version": 1000,
"upstreams_conf_version": 1000
}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 202
=== TEST 3: get config
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")
local code, body = t.test('/apisix/admin/configs',
ngx.HTTP_GET,
nil,
[[{
"consumer_groups_conf_version": 1000,
"consumers_conf_version": 1000,
"global_rules_conf_version": 1000,
"plugin_configs_conf_version": 1000,
"plugin_metadata_conf_version": 1000,
"protos_conf_version": 1000,
"routes_conf_version": 1000,
"secrets_conf_version": 1000,
"services_conf_version": 1000,
"ssls_conf_version": 1000,
"upstreams_conf_version": 1000
}]],
{
["X-API-KEY"] = "edd1c9f034335f136f87ad84b625c8f1"
}
)
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: configure route
--- config
location /t {} # force the worker to restart by changing the configuration
--- request
PUT /apisix/admin/configs
{"routes":[{"id":"r1","uri":"/r1","upstream":{"nodes":{"127.0.0.1:1980":1},"type":"roundrobin"},"plugins":{"proxy-rewrite":{"uri":"/hello"}}}]}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 202
=== TEST 5: test route
--- config
location /t1 {}
--- request
GET /r1
--- error_code: 200
--- response_body
hello world
=== TEST 6: remove route
--- config
location /t2 {}
--- request
PUT /apisix/admin/configs
{}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 202
=== TEST 7: test non-exist route
--- config
location /t3 {}
--- request
GET /r1
--- error_code: 404
=== TEST 8: route references upstream, but only updates the route
--- config
location /t6 {}
--- pipelined_requests eval
[
"PUT /apisix/admin/configs\n" . "{\"routes_conf_version\":1060,\"upstreams_conf_version\":1060,\"routes\":[{\"id\":\"r1\",\"uri\":\"/r1\",\"upstream_id\":\"u1\",\"plugins\":{\"proxy-rewrite\":{\"uri\":\"/hello\"}}}],\"upstreams\":[{\"id\":\"u1\",\"nodes\":{\"127.0.0.1:1980\":1},\"type\":\"roundrobin\"}]}",
"PUT /apisix/admin/configs\n" . "{\"routes_conf_version\":1062,\"upstreams_conf_version\":1060,\"routes\":[{\"id\":\"r1\",\"uri\":\"/r2\",\"upstream_id\":\"u1\",\"plugins\":{\"proxy-rewrite\":{\"uri\":\"/hello\"}}}],\"upstreams\":[{\"id\":\"u1\",\"nodes\":{\"127.0.0.1:1980\":1},\"type\":\"roundrobin\"}]}"
]
--- more_headers eval
[
"X-API-KEY: edd1c9f034335f136f87ad84b625c8f1",
"X-API-KEY: edd1c9f034335f136f87ad84b625c8f1\n" . "x-apisix-conf-version-routes: 100",
]
--- error_code eval
[202, 202]
=== TEST 9: hit r2
--- config
location /t3 {}
--- pipelined_requests eval
["GET /r1", "GET /r2"]
--- error_code eval
[404, 200]
=== TEST 10: routes_conf_version < 1062 is not allowed
--- config
location /t {}
--- request
PUT /apisix/admin/configs
{"routes_conf_version":1,"routes":[{"id":"r1","uri":"/r2","upstream_id":"u1","plugins":{"proxy-rewrite":{"uri":"/hello"}}}]}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
x-apisix-conf-version-routes: 100
--- error_code: 400
--- response_body
{"error_msg":"routes_conf_version must be greater than or equal to (1062)"}
=== TEST 11: duplicate route id found
--- config
location /t11 {}
--- request
PUT /apisix/admin/configs
{"routes_conf_version":1063,"routes":[{"id":"r1","uri":"/r2","upstream_id":"u1","plugins":{"proxy-rewrite":{"uri":"/hello"}}},
{"id":"r1","uri":"/r2","upstream_id":"u1","plugins":{"proxy-rewrite":{"uri":"/hello"}}}]}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 400
--- response_body
{"error_msg":"found duplicate id r1 in routes"}
=== TEST 12: duplicate consumer username found
--- config
location /t12 {}
--- request
PUT /apisix/admin/configs
{"consumers_conf_version":1064,"consumers":[{"username":"consumer1","plugins":{"key-auth":{"key":"consumer1"}}},
{"username":"consumer1","plugins":{"key-auth":{"key":"consumer1"}}}]}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 400
--- response_body
{"error_msg":"found duplicate username consumer1 in consumers"}
=== TEST 13: duplicate consumer credential id found
--- config
location /t13 {}
--- request
PUT /apisix/admin/configs
{"consumers_conf_version":1065,"consumers":[
{"username": "john_1"},
{"id":"john_1/credentials/john-a","plugins":{"key-auth":{"key":"auth-a"}}},
{"id":"john_1/credentials/john-a","plugins":{"key-auth":{"key":"auth-a"}}}
]}
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 400
--- response_body
{"error_msg":"found duplicate credential id john_1/credentials/john-a in consumers"}

View File

@@ -0,0 +1,66 @@
#
# 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';
use Cwd qw(cwd);
repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
my $user_yaml_config = <<_EOC_;
apisix:
node_listen: 1984
_EOC_
$block->set_value("yaml_config", $user_yaml_config);
});
run_tests;
__DATA__
=== TEST 1: set route(disabled stream model)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400

View File

@@ -0,0 +1,653 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"desc": "test-desc",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]],
[[{
"value": {
"remote_addr": "127.0.0.1",
"desc": "test-desc",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
},
"key": "/apisix/stream_routes/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/stream_routes/1'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
},
"key": "/apisix/stream_routes/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: delete route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/stream_routes/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 4: post route + delete
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, message, res = t('/apisix/admin/stream_routes',
ngx.HTTP_POST,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}]],
[[{
"value": {
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"desc": "new route"
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local id = string.sub(res.key, #"/apisix/stream_routes/" + 1)
local ret = assert(etcd.get('/stream_routes/' .. id))
local create_time = ret.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = ret.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
id = ret.body.node.value.id
assert(id ~= nil, "id is nil")
code, message = t('/apisix/admin/stream_routes/' .. id, ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
[delete] code: 200 message: passed
=== TEST 5: set route with plugin
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
},
"upstream": {
"type": "chash",
"key": "mqtt_client_id",
"nodes": [
{
"host": "127.0.0.1",
"port": 1980,
"weight": 1
}
]
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: set route with server_addr and server_port
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"server_addr": "127.0.0.1",
"server_port": 1982,
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
},
"upstream": {
"type": "chash",
"key": "mqtt_client_id",
"nodes": [
{
"host": "127.0.0.1",
"port": 1980,
"weight": 1
}
]
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: delete route(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/stream_routes/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 8: string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: string id(delete)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/a-b-c-ABC_0123', ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: invalid string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/*invalid',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
=== TEST 11: not unwanted data, POST
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/stream_routes',
ngx.HTTP_POST,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
-- clean data
local id = string.sub(res.key, #"/apisix/stream_routes/" + 1)
local code, message = t('/apisix/admin/stream_routes/' .. id,
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
assert(res.key ~= nil)
res.key = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.id ~= nil)
res.value.id = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"value":{"remote_addr":"127.0.0.1","upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
--- request
GET /t
=== TEST 12: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/stream_routes/1","value":{"id":"1","remote_addr":"127.0.0.1","upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
--- request
GET /t
=== TEST 13: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/stream_routes/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/stream_routes/1","value":{"id":"1","remote_addr":"127.0.0.1","upstream":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}}
--- request
GET /t
=== TEST 14: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/stream_routes/1',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/stream_routes/1"}
--- request
GET /t
=== TEST 15: set route with unknown plugin
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "127.0.0.1",
"plugins": {
"mqttt-proxy": {
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"unknown plugin [mqttt-proxy]"}
=== TEST 16: validate protocol
--- extra_yaml_config
xrpc:
protocols:
- name: pingpong
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
for _, case in ipairs({
{input = {
name = "xxx",
}},
{input = {
name = "pingpong",
}},
{input = {
name = "pingpong",
conf = {
faults = "a",
}
}},
}) do
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
{
protocol = case.input,
upstream = {
nodes = {
["127.0.0.1:8080"] = 1
},
type = "roundrobin"
}
}
)
if code > 300 then
ngx.print(body)
else
ngx.say(body)
end
end
}
}
--- request
GET /t
--- response_body
{"error_msg":"unknown protocol [xxx]"}
passed
{"error_msg":"property \"faults\" validation failed: wrong type: expected array, got string"}
=== TEST 17: set route with remote_addr and server_addr in IPV6
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/stream_routes/1',
ngx.HTTP_PUT,
[[{
"remote_addr": "::1",
"server_addr": "::1",
"server_port": 1982,
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
},
"upstream": {
"type": "chash",
"key": "mqtt_client_id",
"nodes": [
{
"host": "127.0.0.1",
"port": 1980,
"weight": 1
}
]
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,179 @@
#
# 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';
use Cwd qw(cwd);
repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
my $user_yaml_config = <<_EOC_;
deployment:
admin:
admin_key:
- name: admin
role: admin
key: edd1c9f034335f136f87ad84b625c8f1
apisix:
node_listen: 1984
_EOC_
$block->set_value("yaml_config", $user_yaml_config);
});
run_tests;
__DATA__
=== TEST 1: set route without token
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").req_self_with_http
local res, err = t('/apisix/admin/routes/1',
"PUT",
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = res.status
ngx.print(res.body)
}
}
--- request
GET /t
--- error_code: 401
=== TEST 2: set route with wrong token
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").req_self_with_http
local res, err = t(
'/apisix/admin/routes/1',
"PUT",
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
{apikey = "wrong_key"}
)
ngx.status = res.status
ngx.print(res.body)
}
}
--- request
GET /t
--- error_code: 401
=== TEST 3: set route with correct token
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").req_self_with_http
local res, err = t(
'/apisix/admin/routes/1',
"PUT",
[[{
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"uri": "/index.html"
}]],
{x_api_key = "edd1c9f034335f136f87ad84b625c8f1"}
)
if res.status > 299 then
ngx.status = res.status
end
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
=== TEST 4: get plugins name
--- request
GET /apisix/admin/plugins/list
--- error_code: 401
=== TEST 5: reload plugins
--- request
PUT /apisix/admin/plugins/reload
--- error_code: 401
=== TEST 6: reload plugins with api key(arguments)
--- request
PUT /apisix/admin/plugins/reload?api_key=edd1c9f034335f136f87ad84b625c8f1
--- error_code: 200
=== TEST 7: reload plugins with api key(cookie)
--- request
PUT /apisix/admin/plugins/reload
--- more_headers
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
--- error_code: 200
=== TEST 8: reload plugins with api key(viewer role)
--- request
PUT /apisix/admin/plugins/reload?api_key=4054f7cf07e344346cd3f287985e76a2
--- error_code: 401
=== TEST 9: fetch with api key(viewer role)
--- request
GET /apisix/admin/routes??api_key=4054f7cf07e344346cd3f287985e76a2
--- error_code: 401

View File

@@ -0,0 +1,435 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin",
"desc": "new upstream"
}]],
[[{
"value": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin",
"desc": "new upstream"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin",
"desc": "new upstream"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: delete upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 4: delete upstream(id: not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/upstreams/not_found', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 5: push upstream + delete
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams',
ngx.HTTP_POST,
[[{
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
}]],
[[{
"value": {
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin"
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local id = string.sub(res.key, #"/apisix/upstreams/" + 1)
code, message = t('/apisix/admin/upstreams/' .. id, ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
[delete] code: 200 message: passed
=== TEST 6: empty nodes
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": [],
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: refer to empty nodes upstream
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream_id": "1",
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit empty nodes upstream
--- request
GET /index.html
--- error_code: 503
--- error_log
no valid upstream node
=== TEST 9: additional properties is invalid
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": 1
}],
"type": "roundrobin",
"_service_name": "xyz",
"_discovery_type": "nacos"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"invalid configuration: additional properties forbidden, found .*"\}/
=== TEST 10: invalid weight of node
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": "1"
}],
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"nodes\" validation failed: object matches none of the required"}
=== TEST 11: invalid weight of node
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": [{
"host": "127.0.0.1",
"port": 8080,
"weight": -100
}],
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"nodes\" validation failed: object matches none of the required"}
=== TEST 12: invalid port of node
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": [{
"host": "127.0.0.1",
"port": 0,
"weight": 1
}],
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"nodes\" validation failed: object matches none of the required"}
=== TEST 13: invalid host of node
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": [{
"host": "127.#.%.1",
"port": 8080,
"weight": 1
}],
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"nodes\" validation failed: object matches none of the required"}
=== TEST 14: nodes host include ipv6 addr
--- 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,
[[{
"upstream": {
"nodes": [
{
"host":"[::1]",
"port":8082,
"weight":1
}
],
"type": "roundrobin"
},
"uri": "/index.html"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,154 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 201
--- response_body
passed
=== TEST 2: add route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream_id": 1,
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 3: delete upstream(wrong header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1?force=anyvalue',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this upstream, route [1] is still using it now"}
=== TEST 4: delete upstream(without force delete header)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this upstream, route [1] is still using it now"}
=== TEST 5: delete upstream(force delete)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1?force=true',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed
=== TEST 6: delete route
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_DELETE
)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body chomp
[delete] code: 200 message: passed

View File

@@ -0,0 +1,725 @@
#
# 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();
no_shuffle();
log_level("info");
run_tests;
__DATA__
=== TEST 1: set upstream (use an id can't be referred by other route
so that we can delete it later)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/upstreams/admin_up',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream"
},
"key": "/apisix/upstreams/admin_up"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/upstreams/admin_up'))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: get upstream
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/admin_up',
ngx.HTTP_GET,
nil,
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream"
},
"key": "/apisix/upstreams/admin_up"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: delete upstream
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/admin_up', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 4: delete upstream(id: not_found)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code = t('/apisix/admin/upstreams/not_found', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 5: push upstream + delete
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, message, res = t('/apisix/admin/upstreams',
ngx.HTTP_POST,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}
}]]
)
if code ~= 200 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("[push] code: ", code, " message: ", message)
local id = string.sub(res.key, #"/apisix/upstreams/" + 1)
local res = assert(etcd.get('/upstreams/' .. id))
local create_time = res.body.node.value.create_time
assert(create_time ~= nil, "create_time is nil")
local update_time = res.body.node.value.update_time
assert(update_time ~= nil, "update_time is nil")
code, message = t('/apisix/admin/upstreams/' .. id, ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[push] code: 200 message: passed
[delete] code: 200 message: passed
=== TEST 6: invalid upstream id in uri
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/invalid_id$',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.exit(code)
}
}
--- request
GET /t
--- error_code: 400
=== TEST 7: different id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"id": 3,
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong upstream id"}
=== TEST 8: id in the rule
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": "1",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: integer id less than 1
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": -100,
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"id\" validation failed: object matches none of the required"}
=== TEST 10: invalid upstream id: string value
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": "invalid_id$",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"id\" validation failed: object matches none of the required"}
=== TEST 11: additional properties is invalid
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"_service_name": "xyz",
"_discovery_type": "nacos"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"invalid configuration: additional properties forbidden, found .*"\}/
=== TEST 12: set upstream(type: chash)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "remote_addr",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
}]],
[[{
"value": {
"key": "remote_addr",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: unknown type
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": {
"127.0.0.1:8080": 1
},
"type": "unknown"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- response_body chomp
passed
=== TEST 14: invalid weight of node
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": {
"127.0.0.1:8080": "1"
},
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"nodes\" validation failed: object matches none of the required"}
=== TEST 15: invalid weight of node
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_PUT,
[[{
"id": 1,
"nodes": {
"127.0.0.1:8080": -100
},
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"nodes\" validation failed: object matches none of the required"}
=== TEST 16: set upstream (missing key)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"missing key"}
=== TEST 17: wrong upstream id, do not need it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_POST,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong upstream id, do not need it"}
=== TEST 18: wrong upstream id, do not need it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams',
ngx.HTTP_POST,
[[{
"id": 1,
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"wrong upstream id, do not need it"}
=== TEST 19: client_cert/client_key and client_cert_id cannot appear at the same time
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local ssl_cert = t.read_file("t/certs/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {
nodes = {
["127.0.0.1:8080"] = 1
},
type = "roundrobin",
tls = {
client_cert_id = 1,
client_cert = ssl_cert,
client_key = ssl_key
}
}
local code, body = t.test('/apisix/admin/upstreams',
ngx.HTTP_POST,
core.json.encode(data)
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/{"error_msg":"invalid configuration: property \\\"tls\\\" validation failed: failed to validate dependent schema for \\\"client_cert|client_key\\\": value wasn't supposed to match schema"}/
=== TEST 20: tls.client_cert_id does not exist
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local data = {
nodes = {
["127.0.0.1:8080"] = 1
},
type = "roundrobin",
tls = {
client_cert_id = 9999999
}
}
local code, body = t.test('/apisix/admin/upstreams',
ngx.HTTP_POST,
core.json.encode(data)
)
ngx.status = code
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to fetch ssl info by ssl id [9999999], response code: 404"}
=== TEST 21: tls.client_cert_id exist with wrong ssl type
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
sni = "test.com",
cert = ssl_cert,
key = ssl_key
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1
},
tls = {
client_cert_id = 1
}
},
uri = "/hello"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to fetch ssl info by ssl id [1], wrong ssl type"}
=== TEST 22: type with default vale
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/upstreams/admin_up',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"desc": "new upstream"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream"
},
"key": "/apisix/upstreams/admin_up"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,295 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: not unwanted data, POST
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams',
ngx.HTTP_POST,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.key ~= nil)
res.key = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
assert(res.value.id ~= nil)
res.value.id = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"value":{"hash_on":"vars","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}
=== TEST 2: not unwanted data, PUT
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams/unwanted',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/upstreams/unwanted","value":{"hash_on":"vars","id":"unwanted","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}
=== TEST 3: not unwanted data, PATCH
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams/unwanted',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/upstreams/unwanted","value":{"hash_on":"vars","id":"unwanted","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}
=== TEST 4: not unwanted data, GET
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams/unwanted', ngx.HTTP_GET)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
assert(res.createdIndex ~= nil)
res.createdIndex = nil
assert(res.modifiedIndex ~= nil)
res.modifiedIndex = nil
assert(res.value.create_time ~= nil)
res.value.create_time = nil
assert(res.value.update_time ~= nil)
res.value.update_time = nil
ngx.say(json.encode(res))
}
}
--- response_body
{"key":"/apisix/upstreams/unwanted","value":{"hash_on":"vars","id":"unwanted","nodes":{"127.0.0.1:8080":1},"pass_host":"pass","scheme":"http","type":"roundrobin"}}
=== TEST 5: not unwanted data, DELETE
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams/unwanted', ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"deleted":"1","key":"/apisix/upstreams/unwanted"}
=== TEST 6: empty nodes
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 7: refer to empty nodes upstream
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream_id": "1",
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(message)
return
end
ngx.say(message)
}
}
--- response_body
passed
=== TEST 8: hit empty nodes upstream
--- request
GET /index.html
--- error_code: 503
--- error_log
no valid upstream node
=== TEST 9: upstream timeouts equal to zero
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"timeout": {
"connect": 0,
"send": 0,
"read": 0
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body_like eval
qr/{"error_msg":"invalid configuration: property \\\"timeout\\\" validation failed: property \\\"(connect|send|read)\\\" validation failed: expected 0 to be greater than 0"}/

View File

@@ -0,0 +1,768 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: list empty resources
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, message, res = t('/apisix/admin/upstreams',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
res = json.decode(res)
ngx.say(json.encode(res))
}
}
--- response_body
{"list":[],"total":0}
=== TEST 2: retry_timeout is -1 (INVALID)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8090": 1
},
"retry_timeout": -1,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"retry_timeout\" validation failed: expected -1 to be at least 0"}
=== TEST 3: provide upstream for patch
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8090": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
=== TEST 4: patch upstream(whole)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local id = 1
local res = assert(etcd.get('/upstreams/' .. id))
local prev_create_time = res.body.node.value.create_time
local prev_update_time = res.body.node.value.update_time
ngx.sleep(1)
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
local res = assert(etcd.get('/upstreams/' .. id))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
--- response_body
passed
=== TEST 5: patch upstream(new desc)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"desc": "new 21 upstream"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new 21 upstream"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 6: patch upstream(new nodes)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8081": 3,
"127.0.0.1:8082": 4
}
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8081": 3,
"127.0.0.1:8082": 4
},
"type": "roundrobin",
"desc": "new 21 upstream"
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 7: patch upstream(weight is 0)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8081": 3,
"127.0.0.1:8082": 0
}
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8081": 3,
"127.0.0.1:8082": 0
},
"type": "roundrobin",
"desc": "new 21 upstream"
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: patch upstream(whole - sub path)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1/',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream 24"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream 24"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: patch upstream(new desc - sub path)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1/desc',
ngx.HTTP_PATCH,
'"new 25 upstream"',
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new 25 upstream"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 10: patch upstream(new nodes)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1/nodes',
ngx.HTTP_PATCH,
[[{
"127.0.0.6:8081": 3,
"127.0.0.7:8082": 4
}]],
[[{
"value": {
"nodes": {
"127.0.0.6:8081": 3,
"127.0.0.7:8082": 4
},
"type": "roundrobin",
"desc": "new 25 upstream"
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: patch upstream(weight is 0 - sub path)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1/nodes',
ngx.HTTP_PATCH,
[[{
"127.0.0.7:8081": 0,
"127.0.0.8:8082": 4
}]],
[[{
"value": {
"nodes": {
"127.0.0.7:8081": 0,
"127.0.0.8:8082": 4
},
"type": "roundrobin",
"desc": "new 25 upstream"
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: set upstream(type: chash)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "server_name",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 13: wrong upstream key, hash_on default vars
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8081": 2
},
"type": "chash",
"key": "not_support",
"desc": "new upstream"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: failed to match pattern \"^((uri|server_name|server_addr|request_uri|remote_port|remote_addr|query_string|host|hostname|mqtt_client_id)|arg_[0-9a-zA-z_-]+)$\" with \"not_support\""}
=== TEST 14: set upstream with args(type: chash)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "arg_device_id",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 15: set upstream(type: chash)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "server_name",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 16: wrong upstream key, hash_on default vars
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8081": 2
},
"type": "chash",
"key": "not_support",
"desc": "new upstream"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: failed to match pattern \"^((uri|server_name|server_addr|request_uri|remote_port|remote_addr|query_string|host|hostname|mqtt_client_id)|arg_[0-9a-zA-z_-]+)$\" with \"not_support\""}
=== TEST 17: set upstream with args(type: chash)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "arg_device_id",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 18: type chash, hash_on: vars
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "arg_device_id",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "vars",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 19: type chash, hash_on: header, header name with '_', underscores_in_headers on
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "custom_header",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "header",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 20: type chash, hash_on: header, header name with invalid character
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "$#^@",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "header",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: failed to match pattern \"^[a-zA-Z0-9-_]+$\" with \"$#^@\""}
=== TEST 21: type chash, hash_on: cookie
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "custom_cookie",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "cookie",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 22: type chash, hash_on: cookie, cookie name with invalid character
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "$#^@abc",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "cookie",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: failed to match pattern \"^[a-zA-Z0-9-_]+$\" with \"$#^@abc\""}
=== TEST 23: type chash, hash_on: consumer, do not need upstream key
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "consumer",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 24: type chash, hash_on: consumer, set key but invalid
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "consumer",
"key": "invalid-key",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 25: type chash, invalid hash_on type
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"key": "dsadas",
"nodes": {
"127.0.0.1:8080": 1
},
"type": "chash",
"hash_on": "aabbcc",
"desc": "new chash upstream"
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"hash_on\" validation failed: matches none of the enum values"}

View File

@@ -0,0 +1,668 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set upstream(id: 1 + name: test name)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"name": "test upstream name"
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"name": "test upstream name"
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: string id(delete)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/a-b-c-ABC_0123', ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: invalid string id
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/*invalid',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"id\" validation failed: object matches none of the required"}
=== TEST 5: retries is 0
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8090": 1
},
"retries": 0,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 6: retries is -1 (INVALID)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/a-b-c-ABC_0123',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1,
"127.0.0.1:8090": 1
},
"retries": -1,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"retries\" validation failed: expected -1 to be at least 0"}
=== TEST 7: invalid route: empty `upstream_host` when `pass_host` is `rewrite`
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"apisix.com:8080": 1,
"test.com:8080": 1
},
"type": "roundrobin",
"pass_host": "rewrite",
"upstream_host": ""
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
=== TEST 8: set upstream(with labels)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"labels": {
"build":"16",
"env":"production",
"version":"v2"
}
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"labels": {
"build":"16",
"env":"production",
"version":"v2"
}
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: get upstream(with labels)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_GET,
nil,
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"labels": {
"version":"v2",
"build":"16",
"env":"production"
}
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 10: patch upstream(only labels)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"labels": {
"build": "17"
}
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"labels": {
"version":"v2",
"build":"17",
"env":"production"
}
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: invalid format of label value: set upstream
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"labels": {
"env": ["production", "release"]
}
}]]
)
ngx.status = code
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
=== TEST 12: patch upstream(whole, create_time)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream",
"create_time": 1705252779
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream",
"create_time": 1705252779
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
if code >= 300 then
return
end
local res = assert(etcd.get('/upstreams/1'))
local create_time = res.body.node.value.create_time
assert(create_time == 1705252779, "create_time mismatched")
}
}
--- response_body
passed
=== TEST 13: patch upstream(whole, update_time)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PATCH,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream",
"update_time": 1705252779
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"desc": "new upstream",
"create_time": 1705252779
},
"key": "/apisix/upstreams/1"
}]]
)
ngx.status = code
ngx.say(body)
if code >= 300 then
return
end
local res = assert(etcd.get('/upstreams/1'))
local update_time = res.body.node.value.update_time
assert(update_time == 1705252779, "update_time mismatched")
}
}
--- response_body
passed
=== TEST 14: create upstream with create_time and update_time
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/up_create_update_time',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"create_time": 1602883670,
"update_time": 1602893670
}]],
[[{
"value": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin",
"create_time": 1602883670,
"update_time": 1602893670
},
"key": "/apisix/upstreams/up_create_update_time"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"the property is forbidden:.*"\}/
=== TEST 15: patch upstream with sub_path, the data is number
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, message = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
local id = 1
local res = assert(etcd.get('/upstreams/' .. id))
local prev_create_time = res.body.node.value.create_time
local prev_update_time = res.body.node.value.update_time
ngx.sleep(1)
local code, message = t('/apisix/admin/upstreams/1/retries',
ngx.HTTP_PATCH,
json.encode(1)
)
if code >= 300 then
ngx.status = code
end
ngx.say(message)
local res = assert(etcd.get('/upstreams/' .. id))
local create_time = res.body.node.value.create_time
assert(prev_create_time == create_time, "create_time mismatched")
local update_time = res.body.node.value.update_time
assert(prev_update_time ~= update_time, "update_time should be changed")
}
}
=== TEST 16: set upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- response_body
passed
=== TEST 17: set service(id: 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"upstream_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 18: set route(id: 1)
--- 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,
[[{
"upstream_id": 1,
"uri": "/index.html"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 19: delete upstream(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1', ngx.HTTP_DELETE)
ngx.print("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this upstream, route [1] is still using it now"}
=== TEST 20: delete route(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/routes/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 200 message: passed
=== TEST 21: delete service(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/services/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 200 message: passed
=== TEST 22: delete upstream(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local t = require("lib.test_admin").test
local code, message = t('/apisix/admin/upstreams/1', ngx.HTTP_DELETE)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- response_body
[delete] code: 200 message: passed

View File

@@ -0,0 +1,599 @@
#
# 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();
no_shuffle();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: set upstream(kafka scheme)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local code, body = t.test("/apisix/admin/upstreams/kafka", ngx.HTTP_PUT, [[{
"nodes": {
"127.0.0.1:9092": 1
},
"type": "none",
"scheme": "kafka"
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: set upstream(empty tls)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local code, body = t.test("/apisix/admin/upstreams/kafka", ngx.HTTP_PUT, [[{
"nodes": {
"127.0.0.1:9092": 1
},
"type": "none",
"scheme": "kafka",
"tls": {}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 3: set upstream(tls without verify)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local code, body = t.test("/apisix/admin/upstreams/kafka", ngx.HTTP_PUT, [[{
"nodes": {
"127.0.0.1:9092": 1
},
"type": "none",
"scheme": "kafka",
"tls": {
"verify": false
}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: prepare upstream
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_PUT, [[{
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 5: prepare route
--- 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": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 1,
"weight": 1
},
{
"weight": 1
}
]
}
]
}
},
"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 6: delete upstream when plugin in route still refer it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, plugin in route [1] is still using it now"}
=== TEST 7: delete route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/routes/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: prepare service
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/services/1", ngx.HTTP_PUT, [[{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 1,
"weight": 1
},
{
"weight": 1
}
]
}
]
}
}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 9: delete upstream when plugin in service still refer it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, plugin in service [1] is still using it now"}
=== TEST 10: delete service
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/services/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: prepare global_rule
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/global_rules/1", ngx.HTTP_PUT, [[{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 1,
"weight": 1
},
{
"weight": 1
}
]
}
]
}
}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 12: delete upstream when plugin in global_rule still refer it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, plugin in global_rules [1] is still using it now"}
=== TEST 13: delete global_rule
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/global_rules/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 14: prepare plugin_config
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/plugin_configs/1", ngx.HTTP_PUT, [[{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 1,
"weight": 1
},
{
"weight": 1
}
]
}
]
}
}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 15: delete upstream when plugin in plugin_config still refer it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, plugin in plugin_config [1] is still using it now"}
=== TEST 16: delete plugin_config
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/plugin_configs/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 17: prepare consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/consumers", ngx.HTTP_PUT, [[{
"username": "test",
"plugins": {
"key-auth": {
"key": "auth-one"
},
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 1,
"weight": 1
},
{
"weight": 1
}
]
}
]
}
}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 18: delete upstream when plugin in consumer still refer it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, plugin in consumer [test] is still using it now"}
=== TEST 19: delete consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/consumers/test", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 20: prepare consumer_group
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/consumer_groups/1", ngx.HTTP_PUT, [[{
"plugins": {
"key-auth": {
"key": "auth-one"
},
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 1,
"weight": 1
},
{
"weight": 1
}
]
}
]
}
}
}]])
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 21: delete upstream when plugin in consumer_group still refer it
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, plugin in consumer_group [1] is still using it now"}
=== TEST 22: delete consumer_group
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/consumer_groups/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 23: delete upstream
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed

View File

@@ -0,0 +1,38 @@
--
-- 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.
--
return {
modules = {
["lua.*"] = "lua",
["apisix/*"] = "apisix",
["apisix/admin/*"] = "admin",
["apisix/core/*"] = "core",
["apisix/http/*"] = "http",
["apisix/http/router/*"] = "http/router",
["apisix/plugins/*"] = "plugins",
["apisix/plugins/grpc-transcode/*"] = "plugins/grpc-transcode",
["apisix/plugins/limit-count/*"] = "plugins/limit-count",
["apisix/plugins/prometheus/*"] = "plugins/prometheus",
["apisix/plugins/zipkin/*"] = "plugins/zipkin",
["apisix/utils/*"] = "utils",
["apisix/discovery/*"] = "discovery",
-- can not enable both at http and stream, will fix it later.
-- ["apisix/stream/*"] = "stream",
-- ["apisix/stream/plugins/*"] = "stream/plugins",
-- ["apisix/stream/router/*"] = "stream/router",
},
}

View File

@@ -0,0 +1,15 @@
{
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": { "content": "1 + 1 = 2.", "role": "assistant" }
}
],
"created": 1723780938,
"id": "chatcmpl-9wiSIg5LYrrpxwsr2PubSQnbtod1P",
"model": "gpt-4o-2024-05-13",
"object": "chat.completion",
"system_fingerprint": "fp_abc28019ad",
"usage": { "completion_tokens": 8, "prompt_tokens": 23, "total_tokens": 31 }
}

View File

@@ -0,0 +1,224 @@
{
"good_request": {
"ResultList": [
{
"Toxicity": 0.02150000333786,
"Labels": [
{
"Name": "PROFANITY",
"Score": 0.00589999556541
},
{
"Name": "HATE_SPEECH",
"Score": 0.01729999780655
},
{
"Name": "INSULT",
"Score": 0.00519999861717
},
{
"Name": "GRAPHIC",
"Score": 0.00520000338554
},
{
"Name": "HARASSMENT_OR_ABUSE",
"Score": 0.00090001106262
},
{
"Name": "SEXUAL",
"Score": 0.00810000061989
},
{
"Name": "VIOLENCE_OR_THREAT",
"Score": 0.00570000290871
}
]
}
]
},
"profane": {
"ResultList": [
{
"Toxicity": 0.62150000333786,
"Labels": [
{
"Name": "PROFANITY",
"Score": 0.55589999556541
},
{
"Name": "HATE_SPEECH",
"Score": 0.21729999780655
},
{
"Name": "INSULT",
"Score": 0.25519999861717
},
{
"Name": "GRAPHIC",
"Score": 0.12520000338554
},
{
"Name": "HARASSMENT_OR_ABUSE",
"Score": 0.27090001106262
},
{
"Name": "SEXUAL",
"Score": 0.44810000061989
},
{
"Name": "VIOLENCE_OR_THREAT",
"Score": 0.27570000290871
}
]
}
]
},
"profane_but_not_toxic": {
"ResultList": [
{
"Toxicity": 0.12150000333786,
"Labels": [
{
"Name": "PROFANITY",
"Score": 0.55589999556541
},
{
"Name": "HATE_SPEECH",
"Score": 0.21729999780655
},
{
"Name": "INSULT",
"Score": 0.25519999861717
},
{
"Name": "GRAPHIC",
"Score": 0.12520000338554
},
{
"Name": "HARASSMENT_OR_ABUSE",
"Score": 0.27090001106262
},
{
"Name": "SEXUAL",
"Score": 0.44810000061989
},
{
"Name": "VIOLENCE_OR_THREAT",
"Score": 0.27570000290871
}
]
}
]
},
"very_profane": {
"ResultList": [
{
"Toxicity": 0.72150000333786,
"Labels": [
{
"Name": "PROFANITY",
"Score": 0.85589999556541
},
{
"Name": "HATE_SPEECH",
"Score": 0.21729999780655
},
{
"Name": "INSULT",
"Score": 0.25519999861717
},
{
"Name": "GRAPHIC",
"Score": 0.12520000338554
},
{
"Name": "HARASSMENT_OR_ABUSE",
"Score": 0.27090001106262
},
{
"Name": "SEXUAL",
"Score": 0.94810000061989
},
{
"Name": "VIOLENCE_OR_THREAT",
"Score": 0.27570000290871
}
]
}
]
},
"toxic": {
"ResultList": [
{
"Toxicity": 0.72150000333786,
"Labels": [
{
"Name": "PROFANITY",
"Score": 0.25589999556541
},
{
"Name": "HATE_SPEECH",
"Score": 0.21729999780655
},
{
"Name": "INSULT",
"Score": 0.75519999861717
},
{
"Name": "GRAPHIC",
"Score": 0.12520000338554
},
{
"Name": "HARASSMENT_OR_ABUSE",
"Score": 0.27090001106262
},
{
"Name": "SEXUAL",
"Score": 0.64810000061989
},
{
"Name": "VIOLENCE_OR_THREAT",
"Score": 0.27570000290871
}
]
}
]
},
"very_toxic": {
"ResultList": [
{
"Toxicity": 0.92150000333786,
"Labels": [
{
"Name": "PROFANITY",
"Score": 0.25589999556541
},
{
"Name": "HATE_SPEECH",
"Score": 0.21729999780655
},
{
"Name": "INSULT",
"Score": 0.25519999861717
},
{
"Name": "GRAPHIC",
"Score": 0.12520000338554
},
{
"Name": "HARASSMENT_OR_ABUSE",
"Score": 0.27090001106262
},
{
"Name": "SEXUAL",
"Score": 0.44810000061989
},
{
"Name": "VIOLENCE_OR_THREAT",
"Score": 0.27570000290871
}
]
}
]
}
}

View File

@@ -0,0 +1,25 @@
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [
123456789,
0.01902593,
0.008967914,
-0.013226582,
-0.026961878,
-0.017892223,
-0.0007785152,
-0.011031842,
0.0068531134
]
}
],
"model": "text-embedding-3-small",
"usage": {
"prompt_tokens": 4,
"total_tokens": 4
}
}

View File

@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
A1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa
GA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n
RG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM
CHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe
cvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb
VDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR
2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr
abf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2
WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/
Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1
/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh
/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj
cTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ
tSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl
c3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC
tC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY
1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl
PYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob
rJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy
hme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1
7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y
IJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG5AIBAAKCAYEAyCM0rqJecvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5
jhZB3W6BkWUWR4oNFLLSqcVbVDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfo
eLj0efMiOepOSZflj9Ob4yKR2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5s
mPtW1Oc/BV5terhscJdOgmRrabf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt
6iMWEGeQU6mwPENgvj1olji2WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiy
Vt1TmtMWn1ztk6FfLRqwJWR/Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1o
npRVeXhrBajbCRDRBMwaNw/1/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2
fzaqpIfyUbPST4GdqNG9NyIh/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI
1cGrGwyXbrieNp63AgMBAAECggGBAJM8g0duoHmIYoAJzbmKe4ew0C5fZtFUQNmu
O2xJITUiLT3ga4LCkRYsdBnY+nkK8PCnViAb10KtIT+bKipoLsNWI9Xcq4Cg4G3t
11XQMgPPgxYXA6m8t+73ldhxrcKqgvI6xVZmWlKDPn+CY/Wqj5PA476B5wEmYbNC
GIcd1FLl3E9Qm4g4b/sVXOHARF6iSvTR+6ol4nfWKlaXSlx2gNkHuG8RVpyDsp9c
z9zUqAdZ3QyFQhKcWWEcL6u9DLBpB/gUjyB3qWhDMe7jcCBZR1ALyRyEjmDwZzv2
jlv8qlLFfn9R29UI0pbuL1eRAz97scFOFme1s9oSU9a12YHfEd2wJOM9bqiKju8y
DZzePhEYuTZ8qxwiPJGy7XvRYTGHAs8+iDlG4vVpA0qD++1FTpv06cg/fOdnwshE
OJlEC0ozMvnM2rZ2oYejdG3aAnUHmSNa5tkJwXnmj/EMw1TEXf+H6+xknAkw05nh
zsxXrbuFUe7VRfgB5ElMA/V4NsScgQKBwQDmMRtnS32UZjw4A8DsHOKFzugfWzJ8
Gc+3sTgs+4dNIAvo0sjibQ3xl01h0BB2Pr1KtkgBYB8LJW/FuYdCRS/KlXH7PHgX
84gYWImhNhcNOL3coO8NXvd6+m+a/Z7xghbQtaraui6cDWPiCNd/sdLMZQ/7LopM
RbM32nrgBKMOJpMok1Z6zsPzT83SjkcSxjVzgULNYEp03uf1PWmHuvjO1yELwX9/
goACViF+jst12RUEiEQIYwr4y637GQBy+9cCgcEA3pN9W5OjSPDVsTcVERig8++O
BFURiUa7nXRHzKp2wT6jlMVcu8Pb2fjclxRyaMGYKZBRuXDlc/RNO3uTytGYNdC2
IptU5N4M7iZHXj190xtDxRnYQWWo/PR6EcJj3f/tc3Itm1rX0JfuI3JzJQgDb9Z2
s/9/ub8RRvmQV9LM/utgyOwNdf5dyVoPcTY2739X4ZzXNH+CybfNa+LWpiJIVEs2
txXbgZrhmlaWzwA525nZ0UlKdfktdcXeqke9eBghAoHARVTHFy6CjV7ZhlmDEtqE
U58FBOS36O7xRDdpXwsHLnCXhbFu9du41mom0W4UdzjgVI9gUqG71+SXrKr7lTc3
dMHcSbplxXkBJawND/Q1rzLG5JvIRHO1AGJLmRgIdl8jNgtxgV2QSkoyKlNVbM2H
Wy6ZSKM03lIj74+rcKuU3N87dX4jDuwV0sPXjzJxL7NpR/fHwgndgyPcI14y2cGz
zMC44EyQdTw+B/YfMnoZx83xaaMNMqV6GYNnTHi0TO2TAoHBAKmdrh9WkE2qsr59
IoHHygh7Wzez+Ewr6hfgoEK4+QzlBlX+XV/9rxIaE0jS3Sk1txadk5oFDebimuSk
lQkv1pXUOqh+xSAwk5v88dBAfh2dnnSa8HFN3oz+ZfQYtnBcc4DR1y2X+fVNgr3i
nxruU2gsAIPFRnmvwKPc1YIH9A6kIzqaoNt1f9VM243D6fNzkO4uztWEApBkkJgR
4s/yOjp6ovS9JG1NMXWjXQPcwTq3sQVLnAHxZRJmOvx69UmK4QKBwFYXXjeXiU3d
bcrPfe6qNGjfzK+BkhWznuFUMbuxyZWDYQD5yb6ukUosrj7pmZv3BxKcKCvmONU+
CHgIXB+hG+R9S2mCcH1qBQoP/RSm+TUzS/Bl2UeuhnFZh2jSZQy3OwryUi6nhF0u
LDzMI/6aO1ggsI23Ri0Y9ZtqVKczTkxzdQKR9xvoNBUufjimRlS80sJCEB3Qm20S
wzarryret/7GFW1/3cz+hTj9/d45i25zArr3Pocfpur5mfz3fJO8jg==
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFsTCCA5mgAwIBAgIUODyT8W4gAxf8uwMNmtj5M1ANoUwwDQYJKoZIhvcNAQEL
BQAwVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzEPMA0GA1UEBwwG
Wmh1SGFpMQ0wCwYDVQQKDARhcGk3MRMwEQYDVQQDDAphcGlzaXguZGV2MCAXDTIw
MDYwNDAzMzc1MFoYDzIxMjAwNTExMDMzNzUwWjBWMQswCQYDVQQGEwJDTjESMBAG
A1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxDTALBgNVBAoMBGFwaTcx
EzARBgNVBAMMCmFwaXNpeC5kZXYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQDQveSdplH49Lr+LsLWpGJbNRhf2En0V4SuFKpzGFP7mXaI7rMnpdH3BUVY
S3juMgPOdNh6ho4BeSbGZGfU3lG1NwIOXiPNA1mrTWGNGV97crJDVZeWTuDpqNHJ
4ATrnF6RnRbg0en8rjVtce6LBMrDJVyGbi9VAqBUPrCmzT/l0V1jPL6KNSN8mQog
ladrJuzUanfhWM9K9xyM+/SUt1MNUYFLNsVHasPzsi5/YDRBiwuzTtiT56O6yge2
lvrdPFvULrCxlGteyvhtrFJwqjN//YtnQFooNR0CXBfXs0a7WGgMjawupuP1JKiY
t9KEcGHWGZDeLfsGGKgQ9G+PaP4y+gHjLr5xQvwt68otpoafGy+BpOoHZZFoLBpx
TtJKA3qnwyZg9zr7lrtqr8CISO/SEyh6xkAOUzb7yc2nHu9UpruzVIR7xI7pjc7f
2T6WyCVy6gFYQwzFLwkN/3O+ZJkioxXsnwaYWDj61k3d9ozVDkVkTuxmNJjXV8Ta
htGRAHo0/uHmpFTcaQfDf5o+iWi4z9B5kgfA/A1XWFQlCH1kl3mHKg7JNCN9qGF8
rG+YzdiLQfo5OqJSvzGHRXbdGI2JQe/zyJHsMO7d0AhwXuPOWGTTAODOPlaBCxNB
AgjuUgt+3saqCrK4eaOo8sPt055AYJhZlaTH4EeD4sv7rJGm7wIDAQABo3UwczAd
BgNVHQ4EFgQUPS1LXZMqgQvH/zQHHzgTzrd7PIIwHwYDVR0jBBgwFoAUPS1LXZMq
gQvH/zQHHzgTzrd7PIIwDAYDVR0TBAUwAwEB/zAjBgNVHREEHDAaggphcGlzaXgu
ZGV2ggwqLmFwaXNpeC5kZXYwDQYJKoZIhvcNAQELBQADggIBAMlwNS8uo3JkkshI
rpYobdjCZfr74PBl+LhoihvzHs25/in3+CxETRA8cYo5pRotqdA63po3wiCCPs6a
mZiELQxyGHhFcqoYxnoURR4nyogRZLA6jjLGkbG4H+CA4ApmZmvGnP3X5uQW4v5q
IdqIXL3BvoUBln8GMEC7Rz5SGUjWG03JPkl6MdeziFyHkwdBCOrtK5m7icRncvq+
iL8CMUx024LLI6A5hTBPwfVfgbWJTSv7tEu85q54ZZoYQhiD8dde4D7g5/noPvXM
ZyA9C3Sl981+pUhhazad9j9k8DCcqf9e8yH9lPY26tjiEcShv4YnwbErWzJU1F9s
ZI5Z6nj5PU66upnBWAWV7fWCOrlouB4GjNaznSNrmpn4Bb2+FinDK3t4AfWDPS5s
ljQBGQNXOd30DC7BdNAF5dQAUhVfz1EgQGqYa+frMQLiv8rNMs7h6gKQEqU+jC/1
jbGe4/iwc0UeTtSgTPHMofqjqc99/R/ZqtJ3qFPJmoWpyu0NlNINw2KWRQaMoGLo
WgDCS0YA5/hNXVFcWnZ73jY62yrVSoj+sFbkUpGWhEFnO+uSmBv8uwY3UeCOQDih
X7Yazs3TZRqEPU+25QATf0kbxyzlWbGkwvyRD8x+n3ZHs5Ilhrc6jWHqM/S3ir7i
m9GcWiwg++EbusQsqs3w3uKAHAdT
-----END CERTIFICATE-----

View File

@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEA0L3knaZR+PS6/i7C1qRiWzUYX9hJ9FeErhSqcxhT+5l2iO6z
J6XR9wVFWEt47jIDznTYeoaOAXkmxmRn1N5RtTcCDl4jzQNZq01hjRlfe3KyQ1WX
lk7g6ajRyeAE65xekZ0W4NHp/K41bXHuiwTKwyVchm4vVQKgVD6wps0/5dFdYzy+
ijUjfJkKIJWnaybs1Gp34VjPSvccjPv0lLdTDVGBSzbFR2rD87Iuf2A0QYsLs07Y
k+ejusoHtpb63Txb1C6wsZRrXsr4baxScKozf/2LZ0BaKDUdAlwX17NGu1hoDI2s
Lqbj9SSomLfShHBh1hmQ3i37BhioEPRvj2j+MvoB4y6+cUL8LevKLaaGnxsvgaTq
B2WRaCwacU7SSgN6p8MmYPc6+5a7aq/AiEjv0hMoesZADlM2+8nNpx7vVKa7s1SE
e8SO6Y3O39k+lsglcuoBWEMMxS8JDf9zvmSZIqMV7J8GmFg4+tZN3faM1Q5FZE7s
ZjSY11fE2obRkQB6NP7h5qRU3GkHw3+aPolouM/QeZIHwPwNV1hUJQh9ZJd5hyoO
yTQjfahhfKxvmM3Yi0H6OTqiUr8xh0V23RiNiUHv88iR7DDu3dAIcF7jzlhk0wDg
zj5WgQsTQQII7lILft7GqgqyuHmjqPLD7dOeQGCYWZWkx+BHg+LL+6yRpu8CAwEA
AQKCAgBNsbBLAWHXYPfMrgj1LUAypIOLAQ0dtgl7ZdO/fRmdNxSIiRgDtNN+tuaF
o6nCNrl1+cWtbTGj2L0W8L442/rbkTrhsCZxI0MX4HhjtUL1xs4VA+GlH3zVW3Gi
SxBpxczpM+gVC+ykkQ7vyo04DzONCPX0T0Ssxop4cND9dL3Iw3GYAz8EYBzyPmAn
mqwy1M0nju1J4e1eALYOv6TcSZPPDDwsi5lIKLQAm5x06pDoqGFVfw5blsc5OgM+
8dkzyUiApFQ99Hk2UiO/ZnlU1/TNOcjOSISGHKbMfwycy2yTRKeNrJmez51fXCKo
nRrtEotHzkI+gCzDqx+7F9ACN9kM4f4JO5ca0/My6tCY+mH8TA/nVzMnUpL7329w
NobuNTpyA6x5nmB3QqElrzQCRtTj7Nw5ytMdRbByJhXww9C5tajUysdq8oGoZdz5
94kXr6qCC5Qm3CkgyF2RjqZyg9tHUEEdaFKouHgziiqG9P2Nk1SHk7Jd7bF4rleI
i93u/f0fdVK7aMksofgUbOmfhnS+o1NxerVcbdX+E/iv6yfkrYDb46y3//4dcpwk
TeUEMCjc7ShwvYPq350q3jmzgwxeTK8ZdXwJymdJ7MaGcnMXPqd9A43evYM6nG6f
i3l2tYhH4cp6misGChnGORR68qsRkY8ssvSFNFzjcFHhnPyoCQKCAQEA8isIC1IJ
Iq9kB4mDVh0QdiuoBneNOEHy/8fASeZsqedu0OZPyoXU96iOhXuqf8sQ33ydvPef
iRwasLLkgw8sDeWILUjS36ZzwGP2QNxWfrapCFS8VfKl7hTPMVp0Wzxh8qqpGLSh
O0W7EEAJCgzzULagfupaO0Chmb3LZqXRp8m5oubnmE+9z0b5GrCIT1S8Yay2mEw9
jxqZJGBhV7QnupyC2DIxLXlGmQk7Qs1+1mCCFwyfugHXclWYa+fet/79SkkADK0/
ysxfy+FdZgGT/Ba5odsEpt1zH+tw4WXioJsX9mU3zAHbpPqtcfuVU+2xyKfQYrRG
NSm9MMNmart0wwKCAQEA3Koaj/0gNxLLslLIES50KmmagzU8CkEmCa/WLoVy02xr
qp42hvj+PzBTf3rIno3KEpRhMmnAtswozbV3P4l/VSZdfY+pwWsx7/5+Cf1R9nAP
vp6YCjGcLcbASazYNOWf0FRInt3pxdgT9DWjJDi99FGKA+UbI2yxHwzE+cE8r9Od
Iy42uhzCjJBqdg+an+q63k6yrOwv18KP69LlU/4vknhw4g3WxF4yTwVmXU8WKmux
aOrJv2ED8pfA7k+zwv0rPyN+F2nOySxoChaFfeu6ntBCX7zK/nV0DsMQImOycfzO
yN8WB9lRZTJVzU2r6PaGAI359uLHEmURy0069g+yZQKCAQAbECwJ99UFh0xKe1eu
G/lm+2H/twSVMOmTJCOdHp8uLar4tYRdQa+XLcMfr75SIcN09lw6bgHqNLXW4Wcg
LmXh97DMPsMyM0vkSEeQ4A7agldJkw6pHEDm5nRxM4alW44mrGPRWv5ZvWU2X7Gi
6eeXMZGmHVKQJJzqrYc5pXZUpfqU9fET2HWB4JCeJvRUyUd0MvUE+CA5CePraMn4
Hy4BcNQ+jP1p84+sMpfo00ZFduuS39pJ00LciCxMgtElBt4PmzDiOcpTQ5vBESJ6
79o15eRA7lUKwNzIyGsJBXXaNPrskks2BU8ilNElV9RMWNfxcK+dGEBwWIXIGU4s
x145AoIBAQCst9R8udNaaDLaTGNe126DuA8B/kwVdrLwSBqsZTXgeO+5J4dklEZl
bU0d7hxTxoXRjySZEh+OtTSG9y/0oonxO0tYOXfU9jOrNxaueQKLk2EvgfFdoUEu
r2/Y+xpsJQO3TBFfkDEn856Cuu0MMAG214/gxpY8XxowRI11NCRtN4S6gbTCbjp1
TaCW8lXEMDW+Rfki0ugLyLVgD74CxWW1DuLEfbKKF3TnV0GtbXbbE1pU1dm+G5C8
dL3FissYp5MPI5fRebcqzcBNjR1F15pGLpqVVy/IhmSmHVZmpISLJicxITScRiSo
wgJY5R/XBAcVLgvmi9Dn/AY2jCfHa7flAoIBAQCbnZ6ivZg81g6/X9qdo9J61hX0
Y7Fn7bLvcs1L0ARGTsfXMvegA806XyZThqjpY47nHpQtoz4z62kiTTsdpAZUeA3z
9HUWr0b3YEpsvZpgyMNHgwq1vRDPjw4AWz0pBoDWMxx8Ck5nP1A//c1zyu9pgYEU
R+OutDeCJ+0VAc6JSH9WMA08utGPGs3t02Zhtyt2sszE9vzz4hTi5340/AYG72p7
YGlikUxvbyylYh9wR4YUYa/klikvKLHEML1P0BCr8Vex+wLSGS1h1F5tW1Xr2CZQ
dVxFmfGmPDmwWbCQR6Rvt6FHRwNMpMrLr011h2RBcHBpdQl7XpUENDoopIh0
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB8jCCAZmgAwIBAgIJALwxr+GMOgSKMAoGCCqGSM49BAMCMFYxCzAJBgNVBAYT
AkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0GA1UE
CgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAeFw0yMDA4MTgwODI0MzdaFw0y
MTA4MTgwODI0MzdaMFYxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0Rvbmcx
DzANBgNVBAcMBlpodUhhaTEPMA0GA1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0
LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEJACTxb5qYd4v9VaNKlv2fe
XlZSTDYe+0fZwT4l9sifmPzmpwjiVTB2wLiCYYzy+BPrb29r5ubgtXIflsWKRBKj
UDBOMB0GA1UdDgQWBBQPXxOYAHfboUjsoo1xm6/GJ1qHijAfBgNVHSMEGDAWgBQP
XxOYAHfboUjsoo1xm6/GJ1qHijAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cA
MEQCICQ70LiJ+Z2lv9ZF+FQL+VEdVQ938rz6RGXBmnl2oEvkAiBY2eeTl//JanNX
GsSV104WrpHjcBjcY24jb11Y1H3R9g==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,8 @@
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBlQqVD3bK6CQT5puOOngrb50+3K66MKJdhtpWQoUw2poAoGCCqGSM49
AwEHoUQDQgAEQkAJPFvmph3i/1Vo0qW/Z95eVlJMNh77R9nBPiX2yJ+Y/OanCOJV
MHbAuIJhjPL4E+tvb2vm5uC1ch+WxYpEEg==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIB2TCCAX6gAwIBAgIBBTAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEPMA0GA1UEAwwGc3Vi
IGNhMB4XDTIyMTEwMjAzMTkzNloXDTMyMTAzMDAzMTkzNlowSTELMAkGA1UEBhMC
QUExCzAJBgNVBAgMAkJCMQswCQYDVQQKDAJDQzELMAkGA1UECwwCREQxEzARBgNV
BAMMCmNsaWVudCBlbmMwWjAUBggqgRzPVQGCLQYIKoEcz1UBgi0DQgAEYYuPPz5e
0QMSGPeBfVbK02GwYhSieSCuc12WsNw+ZQEiaN3NJ2Mh0EAH95eWVutKAeMwKwQZ
q7QgnSoo3io8hKNaMFgwCQYDVR0TBAIwADALBgNVHQ8EBAMCAzgwHQYDVR0OBBYE
FEL0AwvahirH+kdK5Poq+e0yhii1MB8GA1UdIwQYMBaAFCTrpmbUig3JfveqAIGJ
6n+vAk2AMAoGCCqBHM9VAYN1A0kAMEYCIQDx+KxdaJ7YX5gR492EgiGn7//HsjOU
B7+jyTVvkNzN2AIhAIbDKNJQ2i5Edcw/nDIWJQLec7NZui3QfC/gr9AuCfHN
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgq7+Y1ql10Uvv2vTf
AHR26o4B3RJTJO5XTh0BNLdtB7OhRANCAARhi48/Pl7RAxIY94F9VsrTYbBiFKJ5
IK5zXZaw3D5lASJo3c0nYyHQQAf3l5ZW60oB4zArBBmrtCCdKijeKjyE
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIB2TCCAX+gAwIBAgIBBDAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEPMA0GA1UEAwwGc3Vi
IGNhMB4XDTIyMTEwMjAzMTkzNloXDTMyMTAzMDAzMTkzNlowSjELMAkGA1UEBhMC
QUExCzAJBgNVBAgMAkJCMQswCQYDVQQKDAJDQzELMAkGA1UECwwCREQxFDASBgNV
BAMMC2NsaWVudCBzaWduMFowFAYIKoEcz1UBgi0GCCqBHM9VAYItA0IABFZcc94m
hTZRKis639AnlAbS0cKQv73GP5RzBdNlLpAaUwi4hqAh0ZUIcTH/5ZbOTal9MvHA
gOLjVxv197o+fNejWjBYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgbAMB0GA1UdDgQW
BBTkdzyphRCxqD6m6j/AUhMSEBASRDAfBgNVHSMEGDAWgBQk66Zm1IoNyX73qgCB
iep/rwJNgDAKBggqgRzPVQGDdQNIADBFAiB2rcm1UI84yPYT5q6vjucBNPw01cHM
3/Hc9fhiuYPyHwIhAIiPPPj4XI2l98C+DBaqoZtSiwDK2IA6Q8lf9SmHdFPN
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgIsAr+s4TL7K4AQWO
PbXrJfHoO5yE2V7oYQxUBsieOQOhRANCAARWXHPeJoU2USorOt/QJ5QG0tHCkL+9
xj+UcwXTZS6QGlMIuIagIdGVCHEx/+WWzk2pfTLxwIDi41cb9fe6PnzX
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCf6sMQke4OUrPf
lZXqKZC4uaQLMxJB2DgacBf4Q3kXcVNCNHtc2U3U5cMD8tr3/Jt5MKKun5jQrbXV
FF4eVr4Iv9jgPBwQc2kBUC9QL/alsMhEuXMeqdGQcCK3F0CLJdV3zUlKUDU0kg+O
Exnbl1CHXrIbpD7zLy1i3s8p39v1pYFYf4WlrQxvfa/xo97gXY5dJv8RryryLzRc
uhHYBvX5MHCGpbrY61JxpfZqBo8CmLuHl1tmbeXpdHdQB11LKiuL6HtKflNjc6rg
5r8bXl1nZbM/KOZEE+muA1LVoaTyHzY/aGXz0bNy4QRUO+De9JFcTDgnXnNZVG5x
cyyDBpc9AgMBAAECggEAatcEtehZPJaCeClPPF/Cwbe9YoIfe4BCk186lHI3z7K1
5nB7zt+bwVY0AUpagv3wvXoB5lrYVOsJpa9y5iAb3GqYMc/XDCKfD/KLea5hwfcn
BctEn0LjsPVKLDrLs2t2gBDWG2EU+udunwQh7XTdp2Nb6V3FdOGbGAg2LgrSwP1g
0r4z14F70oWGYyTQ5N8UGuyryVrzQH525OYl38Yt7R6zJ/44FVi/2TvdfHM5ss39
SXWi00Q30fzaBEf4AdHVwVCRKctwSbrIOyM53kiScFDmBGRblCWOxXbiFV+d3bjX
gf2zxs7QYZrFOzOO7kLtHGua4itEB02497v+1oKDwQKBgQDOBvCVGRe2WpItOLnj
SF8iz7Sm+jJGQz0D9FhWyGPvrN7IXGrsXavA1kKRz22dsU8xdKk0yciOB13Wb5y6
yLsr/fPBjAhPb4h543VHFjpAQcxpsH51DE0b2oYOWMmz+rXGB5Jy8EkP7Q4njIsc
2wLod1dps8OT8zFx1jX3Us6iUQKBgQDGtKkfsvWi3HkwjFTR+/Y0oMz7bSruE5Z8
g0VOHPkSr4XiYgLpQxjbNjq8fwsa/jTt1B57+By4xLpZYD0BTFuf5po+igSZhH8s
QS5XnUnbM7d6Xr/da7ZkhSmUbEaMeHONSIVpYNgtRo4bB9Mh0l1HWdoevw/w5Ryt
L/OQiPhfLQKBgQCh1iG1fPh7bbnVe/HI71iL58xoPbCwMLEFIjMiOFcINirqCG6V
LR91Ytj34JCihl1G4/TmWnsH1hGIGDRtJLCiZeHL70u32kzCMkI1jOhFAWqoutMa
7obDkmwraONIVW/kFp6bWtSJhhTQTD4adI9cPCKWDXdcCHSWj0Xk+U8HgQKBgBng
t1HYhaLzIZlP/U/nh3XtJyTrX7bnuCZ5FhKJNWrYjxAfgY+NXHRYCKg5x2F5j70V
be7pLhxmCnrPTMKZhik56AaTBOxVVBaYWoewhUjV4GRAaK5Wc8d9jB+3RizPFwVk
V3OU2DJ1SNZ+W2HBOsKrEfwFF/dgby6i2w6MuAP1AoGBAIxvxUygeT/6P0fHN22P
zAHFI4v2925wYdb7H//D8DIADyBwv18N6YH8uH7L+USZN7e4p2k8MGGyvTXeC6aX
IeVtU6fH57Ddn59VPbF20m8RCSkmBvSdcbyBmqlZSBE+fKwCliKl6u/GH0BNAWKz
r8yiEiskqRmy7P7MY9hDmEbG
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIJAI3Meu/gJVTLMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV
BAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL
BgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl
ci5sb2NhbDAeFw0yMDEwMjgwMzMzMDJaFw0yMTEwMjgwMzMzMDJaMG4xCzAJBgNV
BAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL
BgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl
ci5sb2NhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ/qwxCR7g5S
s9+VleopkLi5pAszEkHYOBpwF/hDeRdxU0I0e1zZTdTlwwPy2vf8m3kwoq6fmNCt
tdUUXh5Wvgi/2OA8HBBzaQFQL1Av9qWwyES5cx6p0ZBwIrcXQIsl1XfNSUpQNTSS
D44TGduXUIdeshukPvMvLWLezynf2/WlgVh/haWtDG99r/Gj3uBdjl0m/xGvKvIv
NFy6EdgG9fkwcIalutjrUnGl9moGjwKYu4eXW2Zt5el0d1AHXUsqK4voe0p+U2Nz
quDmvxteXWdlsz8o5kQT6a4DUtWhpPIfNj9oZfPRs3LhBFQ74N70kVxMOCdec1lU
bnFzLIMGlz0CAwEAAaNQME4wHQYDVR0OBBYEFFHeljijrr+SPxlH5fjHRPcC7bv2
MB8GA1UdIwQYMBaAFFHeljijrr+SPxlH5fjHRPcC7bv2MAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQELBQADggEBAG6NNTK7sl9nJxeewVuogCdMtkcdnx9onGtCOeiQ
qvh5Xwn9akZtoLMVEdceU0ihO4wILlcom3OqHs9WOd6VbgW5a19Thh2toxKidHz5
rAaBMyZsQbFb6+vFshZwoCtOLZI/eIZfUUMFqMXlEPrKru1nSddNdai2+zi5rEnM
HCot43+3XYuqkvWlOjoi9cP+C4epFYrxpykVbcrtbd7TK+wZNiK3xtDPnVzjdNWL
geAEl9xrrk0ss4nO/EreTQgS46gVU+tLC+b23m2dU7dcKZ7RDoiA9bdVc4a2IsaS
2MvLL4NZ2nUh8hAEHiLtGMAV3C6xNbEyM07hEpDW6vk6tqk=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIB3zCCAYWgAwIBAgIBADAKBggqgRzPVQGDdTBGMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEQMA4GA1UEAwwHcm9v
dCBjYTAeFw0yMjExMDIwMzE5MzZaFw0zMjEwMzAwMzE5MzZaMEYxCzAJBgNVBAYT
AkFBMQswCQYDVQQIDAJCQjELMAkGA1UECgwCQ0MxCzAJBgNVBAsMAkREMRAwDgYD
VQQDDAdyb290IGNhMFowFAYIKoEcz1UBgi0GCCqBHM9VAYItA0IABB+V1+bwQsP4
IMZEVCu3LSekz9SIhxWVVtlqdQYZG55S46PmAqICzrO3KFJ/IPtMx9wKn3L6V5M8
hAc/UwOAnKCjYzBhMB0GA1UdDgQWBBRV7bTJ6vT1fliZR42/+E+fEBfTSjAfBgNV
HSMEGDAWgBRV7bTJ6vT1fliZR42/+E+fEBfTSjAPBgNVHRMBAf8EBTADAQH/MA4G
A1UdDwEB/wQEAwIBhjAKBggqgRzPVQGDdQNIADBFAiEA1SGACV1wj158Spgh+HOW
oOr7rTO2fR4cK9Zx7eUvmAECIHbKbsw5szaC/EH7CdsHdFgrj2tWaXiQUnx/rxM/
upAQ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIBATAKBggqgRzPVQGDdTBGMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEQMA4GA1UEAwwHcm9v
dCBjYTAeFw0yMjExMDIwMzE5MzZaFw0zMjEwMzAwMzE5MzZaMEUxCzAJBgNVBAYT
AkFBMQswCQYDVQQIDAJCQjELMAkGA1UECgwCQ0MxCzAJBgNVBAsMAkREMQ8wDQYD
VQQDDAZzdWIgY2EwWjAUBggqgRzPVQGCLQYIKoEcz1UBgi0DQgAElA5ey1dYWNkT
zfvwcKEhX1vHL+Kjil+egM6QssbNrts2S0M07L77XDe1q2zPpHjo0MR05x862/tZ
j87OgmEE0KNmMGQwHQYDVR0OBBYEFCTrpmbUig3JfveqAIGJ6n+vAk2AMB8GA1Ud
IwQYMBaAFFXttMnq9PV+WJlHjb/4T58QF9NKMBIGA1UdEwEB/wQIMAYBAf8CAQAw
DgYDVR0PAQH/BAQDAgGGMAoGCCqBHM9VAYN1A0gAMEUCIArKNHWYLmd3thQmJv89
o0wr6O2q26WJuy6y7Eu14rdFAiEA7XNZ0JGMXPKiG5Hl7nmL8ooTrVhrmRrvs9No
Y8rH88Y=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,12 @@
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt
test not base64 encoded crt

View File

@@ -0,0 +1,12 @@
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key
test not base64 encoded key

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDcjCCAdoCFCS4ndwl6lusO7yj4zxbngp17nNUMA0GCSqGSIb3DQEBCwUAMFYx
CzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhh
aTEPMA0GA1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0yMzA4MDMw
NjM3NDhaGA8yMTA1MDkyMjA2Mzc0OFowEzERMA8GA1UEAwwIdGVzdC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4mQik/vxL1bdjXcXWNT6DBVGL
A87CeVYleNE5Fx5KROU5Y388h80VgSTmV3ytu9ZuNEB8hcZqmAttZXcipMyNm9PI
vTXaDFaQVclYNJ27hy7rpaJ29WkeLKlUx/pRUpOCg3lbafSmURf5C234LZL1qe5O
0CIvY3uAzkGWMUE8ABYnef+ucULZPLa2+Y9wIx76oP5tfmcM/pQhDXt+GK/bZyat
1sUmEHCVC2gjvHoZO8T7n4ccpi5v06Klj8BKVxRlGVkO2w4hlDbNyh6FWKK31nF8
BLu/TKF70xSOzX4OFNT6/GJ8R9AyeK52f6OzNmlNUY3UsMEeX8Y2qL4hNrFhAgMB
AAEwDQYJKoZIhvcNAQELBQADggGBAL6g7NZfVTEVklJPmTFSqwQfuu0YXmIvUQIF
jvbNOmwC+nHSq6yuJFC+83R/on/IPWrkP489bEVwqaBQXnZnIMOTjIk8k9elBm/N
1BBpzWUiKNp+HqRjPCanvRCIPUZ9hWpmJy6uzG6VodEtxZgJ7lsArj0AlOYlkHHa
Ctmnl5g6H4m8sNACZaAixesb9wM8Slvn1zhpAeIYZsvIaBZOZnWuwHD1R7seh4ob
BDhDaUfXOYb0VJaKNWnJ5ItPxh4/YMSuS7mG5o2ELnzWN6OeDEQrqKFW17qWLXko
DXEfyrQnODDI+fXvasJhQ62hH33rQF/Q4yJQOEEr7gQUxtMYCxtGCumx2/5MFTuB
E8sf8FykV5jGjwdwMHhPGAmhpMJwM6i65P9GwZguqVmeFv2l4eSTmMinURlkwaAw
cx+LrigAxSKOCcnnnC6Uza1VShyDAuj+XKPglwwJd99UJlk1VG/9TXp3WZTOvSt+
KttglpiMHyqzCYcMDTGbjPm/UsjFTw==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4mQik/vxL1bdj
XcXWNT6DBVGLA87CeVYleNE5Fx5KROU5Y388h80VgSTmV3ytu9ZuNEB8hcZqmAtt
ZXcipMyNm9PIvTXaDFaQVclYNJ27hy7rpaJ29WkeLKlUx/pRUpOCg3lbafSmURf5
C234LZL1qe5O0CIvY3uAzkGWMUE8ABYnef+ucULZPLa2+Y9wIx76oP5tfmcM/pQh
DXt+GK/bZyat1sUmEHCVC2gjvHoZO8T7n4ccpi5v06Klj8BKVxRlGVkO2w4hlDbN
yh6FWKK31nF8BLu/TKF70xSOzX4OFNT6/GJ8R9AyeK52f6OzNmlNUY3UsMEeX8Y2
qL4hNrFhAgMBAAECggEAKO9euGAHCLYS3ckcpvzVqO5T/9TPU9beYJ7jHprez69p
eYlz3LNsqhkiWqYJ8ujVi0ixCCwOLPMcjZzTh24uIjTtCPXUbE8SHx228YVxePVo
VT88wM55CgTzY+aYvtHl/iozji733q3a+BItx7wre6i8POPwwLt51r1mU+0GP0yQ
+spwGR3POjRZeXiWYKSwhfu/STBpQXLANHCpQOmYFCbjTVpCzJ03msQUfYJNmETd
DqyLGbE4aBoPmekrk8GQa/gn04SIsOi8WZeNhsUT9WXyeLFV0DEwnx0sv6IwOk2o
Fqymr71fKNMIvTpCt8wB0Q/rmvPzrprC+hHIZyX5AQKBgQDol5SYzTijZQasV+2d
DqO5IxE8xl8z10bLgsExKcHC6xyhk+el0XFO1fWs0SJ9ptNuKH32C8IlfEr6M3EE
XovQcRfT4crtnWhLmGPAFYKo91f5fiKy1YWggEtsnY+OODo34RCtORtKD6+iC+XE
LFbLMNQA6sHXVONthiEQ6fhIkQKBgQDLLPHgFFL8kSj+Tt/7ctRnwA7qPTUtAwWG
b2QzDMEpifu4O9DJWoE3sfMYkQhyz2g6S+O5XXm56CDtkV+Miazt29z0dM2Jz7uV
NLtymba/s6wBiWFUggHA4Dro1vYa4MJ94ampqi+XPJaJP/j6WoYIu/JhKQDIBtlP
ARaG0O3D0QKBgQCYMyB8wMXQPfqY6kzFml/OdUEBWPnRTYy4/U34Is/1Aa7RmJxb
6GrR4LaLqKp+OJ1gF0UdrWIU73mMsf7BkjDBbE/gSX9l77vgw856UlkWwgwiacTA
63IureUtJQlcUjTefftQru7JjuwqCMkIjs8Y1VHVa8j+ZEESWVPn4oKi0QKBgQCT
4YnHlGN2q91PhG9ooILTZSo1+gj7UyixWeBve8gYiPMrfHYSKIrG1AHhjqa8khQF
4njE0bGoy7kz0UzfiNHSauYfE+kKdqXNCw2ocxNd4tO+ZpTuIpZOIacfFF8a3x8Q
6rBH6rQq+xGCooqBBmRqdQoNCAAmlz2SUHNp+yYkEQKBgQDNBbH7WPjiggahF0TI
oweS86hQ9tDlUFMg/On2eMOY0juSU1yPsPA/JsIglSTDWGRasjFDhd29FVrnGGY5
5GHy/Gh/6ZZUdrJVsypGw/Dy9amLgmkKTJU4SWDYOb6s1ocGvNPFSYgw0yFe56nx
TU+2zHJo/t2FXssGfnbFWrQAxA==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDNzCCAh8CFHIjXWyzoKYAEb8cJgTxRYdhZDu0MA0GCSqGSIb3DQEBDQUAMFgx
CzAJBgNVBAYTAmNuMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhh
aTEWMBQGA1UEAwwNY2EuYXBpc2l4LmRldjEMMAoGA1UECwwDb3BzMB4XDTIyMTIw
MTEwMTY0OFoXDTQyMTIwMzEwMTY0OFowWDELMAkGA1UEBhMCY24xEjAQBgNVBAgM
CUd1YW5nRG9uZzEPMA0GA1UEBwwGWmh1SGFpMRYwFAYDVQQDDA1jYS5hcGlzaXgu
ZGV2MQwwCgYDVQQLDANvcHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQC6QRtbK1qZg1gUuaVWn0M8hw73H360hH6EvHtEil8meni3W000HpCsi/JdDSr3
tD6Z88O7x0IToPCT0NsAWA0B2LK1oshFkiyIXiq4CWgfwM9qd5GIwA71WUzJ6Jkq
kz0r3M3/ogo0+Z7RKoKilvBinqVjTZhRpd63Dg5cLrgPBKFGUBMfRPmKSgwPSWfV
V85SuHlzpcgcK09NHgSLu2DlFGK+lXGWTLLsrb4F0GAAwL/lk4kplcHK0IZCxfJJ
puXynmoOmgWKcZcHipgv4+LY6+8K+8Lh9FF6ZXOuW7RLwTY1woLMKK2u40fG4C0I
Wcyh+vzTivCrJ72pSC3rYGX5AgMBAAEwDQYJKoZIhvcNAQENBQADggEBAG6RnAvo
AMQPog3TIAtIrXi1JPfJ5kuI26KOn/yUlVIoUjbqxkeELwmoUF/K4eg5sT6RX/8U
0gFVuBi5FZXfPZUt/JSN+fVRSoMP9d1K8ImVpu5gxdp5UZSINlCLvessMx9vafjQ
EwDcACseel511LIe0rOlVvwHeM2P9pNIMfoexGP0U2U5ubZIO8Ye4ZbNieHYgNCN
UgJpadvBOC8I3eML2hx79di5y4R1niRXhAd1IYnL9eK4xUoHwyMtl/1kXtq/nrXB
0njzpqb0GQg0badsF+7v+QM/zrbSSwDTzriCCTWSrd9ze4HYoRqCV6Dc3DjqmHq2
j4wg2QntJBQWmSc=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAukEbWytamYNYFLmlVp9DPIcO9x9+tIR+hLx7RIpfJnp4t1tN
NB6QrIvyXQ0q97Q+mfPDu8dCE6Dwk9DbAFgNAdiytaLIRZIsiF4quAloH8DPaneR
iMAO9VlMyeiZKpM9K9zN/6IKNPme0SqCopbwYp6lY02YUaXetw4OXC64DwShRlAT
H0T5ikoMD0ln1VfOUrh5c6XIHCtPTR4Ei7tg5RRivpVxlkyy7K2+BdBgAMC/5ZOJ
KZXBytCGQsXySabl8p5qDpoFinGXB4qYL+Pi2OvvCvvC4fRRemVzrlu0S8E2NcKC
zCitruNHxuAtCFnMofr804rwqye9qUgt62Bl+QIDAQABAoIBABfHXiW6mDuHIESt
GuW/OYdNuuRj+foz/C8YHSi3/cPc2PKXznh7+n5883lbyAON2HwxOekMXGxDHNPS
U1Ns6mQ09UPpP2ZabiMO2qdaVBfRtulh0IvD8WTzfLE+Z+eemq2x5/7eAi2XPOZ5
Zeo6GQCOPpE6A9tQsOlv+vdb45XPCsDdyC2WukeUfB2wsFBFEgMmcW7HLuzMYp9W
JUuQ6OcOf52ePkGnmEuXIK8Wc3RXitivHlkPLO49Y1LG8t4f61HfG9b2pvgNbHn2
YdkzemCkBMSjzV4oAoIuG56IWBwuqXETRj2xduVcoxd0t2vLK9qlPADBMCa0hcnW
uCBqGM0CgYEA3ZjZQuQqer7XrA0qVbXdOdNXal/efUpqfxdxlwMug5sFqt3rSwVF
S9ZbbtGFeQZp4UAG41o2bWvXuWg59QnKOkKleVQ8zlQdPPjHSOz/7YwXcf/gNYqN
WHSaT8MqaDYY2m0bo3t9SwSMIBxas05guYuBenisOh3jjcaRPYJELucCgYEA1yuY
vlIVksPGN+vx6RBaOyY86B8MuXyvi0jVf96UvnL7soUIZDDWojGZvlq3r7ol8Ljj
LF4Wqdg3MxoOfmUDNWCnSZPjsFo1AUFP/2MJiyCDq75yO0CoVj54QsVYkDTnTosp
at3CKWTueIeOOtXUAKTObMjrWi9A7cF4rS+siB8CgYBOO2UQcX7xwKhhjHBSvBbz
EEK/QkNJFlmMrtkiSDRGsBcLILetz5mMUYwMDppBhNsic7k60KGAdd8+DKbRdHhZ
oyfKMswYx6de3DF29HzR/3BThdNA87486UWFPVCeY+LYUka8q58rOdrCh2AaB2Ss
fKzkcO/UwLKSXfTusyuhJwKBgEIEslzSuqPJRawqzJKB3e2AEff2buUKiKHnuvn8
xQ6aIPfpMWXsRi6FoXJySyGzr6hoUetvAu0h1e3r9L57J7zc5vcAVT/qrZCxBWaK
cIcrdrrfOBVOBVhQ2n1CJ6Y3VTEYKaEMYWJqAXEhxlXu/Zkk9+EQ1IVbMkTAs9IP
apRpAoGBALd3ZhaP9WvAUVVFs489CKFEP14dZi+SRM6pCsqaQ+zxkW7Cc3Vt72rt
d+CwIiUMJlac/Efk2Za8MKn/ctMngvRrym8SxGjxJq9jhGo/jSOkHnTy9W//hE/X
SqlmnJHek5EXl+w0HjgFdukyIo8athDj0jS2ch3OPG4tgavRpKAI
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDUzCCAjugAwIBAgIURw+Rc5FSNUQWdJD+quORtr9KaE8wDQYJKoZIhvcNAQEN
BQAwWDELMAkGA1UEBhMCY24xEjAQBgNVBAgMCUd1YW5nRG9uZzEPMA0GA1UEBwwG
Wmh1SGFpMRYwFAYDVQQDDA1jYS5hcGlzaXguZGV2MQwwCgYDVQQLDANvcHMwHhcN
MjIxMjAxMTAxOTU3WhcNNDIwODE4MTAxOTU3WjBOMQswCQYDVQQGEwJjbjESMBAG
A1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxGjAYBgNVBAMMEWNsaWVu
dC5hcGlzaXguZGV2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzypq
krsJ8MaqpS0kr2SboE9aRKOJzd6mY3AZLq3tFpio5cK5oIHkQLfeaaLcd4ycFcZw
FTpxc+Eth6I0X9on+j4tEibc5IpDnRSAQlzHZzlrOG6WxcOza4VmfcrKqj27oodr
oqXv05r/5yIoRrEN9ZXfA8n2OnjhkP+C3Q68L6dBtPpv+e6HaAuw8MvcsEo+MQwu
cTZyWqWT2UzKVzToW29dHRW+yZGuYNWRh15X09VSvx+E0s+uYKzN0Cyef2C6VtBJ
KmJ3NtypAiPqw7Ebfov2Ym/zzU9pyWPi3P1mYPMKQqUT/FpZSXm4iSy0a5qTYhkF
rFdV1YuYYZL5YGl9aQIDAQABox8wHTAbBgNVHREEFDASghBhZG1pbi5hcGlzaXgu
ZGV2MA0GCSqGSIb3DQEBDQUAA4IBAQBepRpwWdckZ6QdL5EuufYwU7p5SIqkVL/+
N4/l5YSjPoAZf/M6XkZu/PsLI9/kPZN/PX4oxjZSDH14dU9ON3JjxtSrebizcT8V
aQ13TeW9KSv/i5oT6qBmj+V+RF2YCUhyzXdYokOfsSVtSlA1qMdm+cv0vkjYcImV
l3L9nVHRPq15dY9sbmWEtFBWvOzqNSuQYax+iYG+XEuL9SPaYlwKRC6eS/dbXa1T
PPWDQad2X/WmhxPzEHvjSl2bsZF1u0GEdKyhXWMOLCLiYIJo15G7bMz8cTUvkDN3
6WaWBd6bd2g13Ho/OOceARpkR/ND8PU78Y8cq+zHoOSqH+1aly5H
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAzypqkrsJ8MaqpS0kr2SboE9aRKOJzd6mY3AZLq3tFpio5cK5
oIHkQLfeaaLcd4ycFcZwFTpxc+Eth6I0X9on+j4tEibc5IpDnRSAQlzHZzlrOG6W
xcOza4VmfcrKqj27oodroqXv05r/5yIoRrEN9ZXfA8n2OnjhkP+C3Q68L6dBtPpv
+e6HaAuw8MvcsEo+MQwucTZyWqWT2UzKVzToW29dHRW+yZGuYNWRh15X09VSvx+E
0s+uYKzN0Cyef2C6VtBJKmJ3NtypAiPqw7Ebfov2Ym/zzU9pyWPi3P1mYPMKQqUT
/FpZSXm4iSy0a5qTYhkFrFdV1YuYYZL5YGl9aQIDAQABAoIBAD7tUG//lnZnsj/4
JXONaORaFj5ROrOpFPuRemS+egzqFCuuaXpC2lV6RHnr+XHq6SKII1WfagTb+lt/
vs760jfmGQSxf1mAUidtqcP+sKc/Pr1mgi/SUTawz8AYEFWD6PHmlqBSLTYml+La
ckd+0pGtk49wEnYSb9n+cv640hra9AYpm9LXUFaypiFEu+xJhtyKKWkmiVGrt/X9
3aG6MuYeZplW8Xq1L6jcHsieTOB3T+UBfG3O0bELBgTVexOQYI9O4Ejl9/n5/8WP
AbIw7PaAYc7fBkwOGh7/qYUdHnrm5o9MiRT6dPxrVSf0PZVACmA+JoNjCPv0Typf
3MMkHoECgYEA9+3LYzdP8j9iv1fP5hn5K6XZAobCD1mnzv3my0KmoSMC26XuS71f
vyBhjL7zMxGEComvVTF9SaNMfMYTU4CwOJQxLAuT69PEzW6oVEeBoscE5hwhjj6o
/lr5jMbt807J9HnldSpwllfj7JeiTuqRcCu/cwqKQQ1aB3YBZ7h5pZkCgYEA1ejo
KrR1hN2FMhp4pj0nZ5+Ry2lyIVbN4kIcoteaPhyQ0AQ0zNoi27EBRnleRwVDYECi
XAFrgJU+laKsg1iPjvinHibrB9G2p1uv3BEh6lPl9wPFlENTOjPkqjR6eVVZGP8e
VzxYxIo2x/QLDUeOpxySdG4pdhEHGfvmdGmr2FECgYBeknedzhCR4HnjcTSdmlTA
wI+p9gt6XYG0ZIewCymSl89UR9RBUeh++HQdgw0z8r+CYYjfH3SiLUdU5R2kIZeW
zXiAS55OO8Z7cnWFSI17sRz+RcbLAr3l4IAGoi9MO0awGftcGSc/QiFwM1s3bSSz
PAzYbjHUpKot5Gae0PCeKQKBgQCHfkfRBQ2LY2WDHxFc+0+Ca6jF17zbMUioEIhi
/X5N6XowyPlI6MM7tRrBsQ7unX7X8Rjmfl/ByschsTDk4avNO+NfTfeBtGymBYWX
N6Lr8sivdkwoZZzKOSSWSzdos48ELlThnO/9Ti706Lg3aSQK5iY+aakJiC+fXdfT
1TtsgQKBgQDRYvtK/Cpaq0W6wO3I4R75lHGa7zjEr4HA0Kk/FlwS0YveuTh5xqBj
wQz2YyuQQfJfJs7kbWOITBT3vuBJ8F+pktL2Xq5p7/ooIXOGS8Ib4/JAS1C/wb+t
uJHGva12bZ4uizxdL2Q0/n9ziYTiMc/MMh/56o4Je8RMdOMT5lTsRQ==
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDYDCCAkigAwIBAgIURw+Rc5FSNUQWdJD+quORtr9KaE4wDQYJKoZIhvcNAQEN
BQAwWDELMAkGA1UEBhMCY24xEjAQBgNVBAgMCUd1YW5nRG9uZzEPMA0GA1UEBwwG
Wmh1SGFpMRYwFAYDVQQDDA1jYS5hcGlzaXguZGV2MQwwCgYDVQQLDANvcHMwHhcN
MjIxMjAxMTAxNzI0WhcNNDIwODE4MTAxNzI0WjBbMQswCQYDVQQGEwJjbjESMBAG
A1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxGTAXBgNVBAMMEGFkbWlu
LmFwaXNpeC5kZXYxDDAKBgNVBAsMA29wczCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAONlOihn9AtXWay72aPDFbwm2zJOe+5ngV1D3B4f2q+KlkAnjAPx
1GWO1buRDEALL8g5NfbZF3gU9v+wjsEsFK/Sn8ejtziVwJUFVmvRr+PCm/2DEARN
Re1cp0cwRVQJAKLVFpy19ALlSSTQRoCAjLVXC8tEsIxrvN3DVVet9g6AxnPPd4oR
LosDGQ+p+qbriQdx20gg5MHmjZX+/ByZq4BIQkshmQW2LnwxAS3xOpqPmFHmdn56
RXw8JlyvYS3KRiGU3z59uph4wnIic4r/11Puj1LoGd+YtFJash6ZRU/rM6JSdPS7
b53m8HdRcjGdBG+EnsqN67qZUWbGBntmu2cCAwEAAaMfMB0wGwYDVR0RBBQwEoIQ
YWRtaW4uYXBpc2l4LmRldjANBgkqhkiG9w0BAQ0FAAOCAQEAMAxCZmKwWEDHuAzW
PHJUyrdK1eos2UExmeq9TY8c7IluIMClTxS8ui3+7+oc6ZqffyrZL4jx7oe8Ua6V
bat75H+OF05f9ziGJjJY5PM3wxOP1QvR7HePSkwBkNPhGOQf3bi7rQEhBuqhpRfr
GfPmzKejaUm9m8IiHnFKxjTfQ7pm3hR8/+P9LKDO21i5Ua3ec+rKv0Y1jsCuv3t/
APMN7MTDsFqxudqbOG3dufOSe1E7qs16/ygTRvYpIe+kz4rldGWmo0joOrrti43T
Oi1BAGaC3znJe3aaihr08c37NZ/A6WHiX+h5wBEdboOJc4Htytkicd8jBvU2Svjq
dZS3wQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA42U6KGf0C1dZrLvZo8MVvCbbMk577meBXUPcHh/ar4qWQCeM
A/HUZY7Vu5EMQAsvyDk19tkXeBT2/7COwSwUr9Kfx6O3OJXAlQVWa9Gv48Kb/YMQ
BE1F7VynRzBFVAkAotUWnLX0AuVJJNBGgICMtVcLy0SwjGu83cNVV632DoDGc893
ihEuiwMZD6n6puuJB3HbSCDkweaNlf78HJmrgEhCSyGZBbYufDEBLfE6mo+YUeZ2
fnpFfDwmXK9hLcpGIZTfPn26mHjCciJziv/XU+6PUugZ35i0UlqyHplFT+szolJ0
9Ltvnebwd1FyMZ0Eb4Seyo3ruplRZsYGe2a7ZwIDAQABAoIBAEgQ8sePenaFrnPh
7O3Li/3fSqS83uYFg6gtM3uQmNv9TfTzE5rEb43oILCbHYjGgtQv3Xxn/Nofus/6
AqQR9lRqqhy5M/4I58nSsTrmb5n9OTa07MSQQNMjBBi5oZ8qYzs30TzFJZotVGsI
Xu+mzfFCrwgysskt8+NMXqW1CkA50pvipVLtjULZ0p8XQqggV8kQpDGUr4eQ36OH
ekImj4K54GbO4z9IkuiBS/b+J687/hGMPYj5XPS18OU+hQaZnjzWPviAcnsGy8l7
1dDL9bgUFjGvyVLtK+g4meRYRshymq93e4CdSwssTt/Gnbmc6UxsOhTAW5vzn/e2
GDShxJECgYEA+1pKXkMdqaj0aIYmGpiaX8FgZvnxruwDXwDIFE4p9zIdrqDAtAk6
xBBUM6f1+IvvhyqeADOGr78AHFGz8YG0Vcp2+2cw8sRM9ibceIBRwJ/QwW/P1R7q
N0phykACW+fcGYhb/gyu6HWT9B8NSPBBGggL0LA745E3rSnsIeXGvJUCgYEA55mK
mwuBzU1yusfb24cYJQqBmb9YleWouEDerrHbFoYCHFi3/E3OyGbuBy2n2wYTS0k5
PTX8tOWmqM4TsH2JawwMdtNJ+6B8qvAYHSacwLIr4GcZzyJd/ikF3ujXm0da0NA0
f7rz20kRj8GhcksQTMtWtOXCXJyonNNxZgrQ3QsCgYBjaBcnZoXRtpdKy1tAg3/y
ROlacJlr472FkiqPFUa1k+V3Te5IhanvJsIWV+QIs1c87tbkH3yx/ukNSibPacun
blZWIT6TlJ0XcNEa+yzZ8JrAFfdtQzfAPDOmqGAGdxFuK6auN9fo6a9lCe7YHOSy
ZeI+W6Sj4KfTXVQdJ+HMbQKBgE8DlEU3VM6NSMIuo3SvD267ueGRZZCmbLyH7TEe
nsd9asTvA75BcXXvn++1BNp1pSl/TtbyT0gMPaLDw/XnrnVmA+6aQVhmtYHALgnr
/XjEkLGbmzOO3xByQH1/ZOemHXa2QeL+DmpW8HXiMsmCkIoSqX9ID9p23BO9E6gj
soRnAoGBAPkmGcoz96/pb52QyMKcEo1pBK0sqRsfZW1Cpz2/hg2hA3BLLaZIBCEj
gtXcknib9CLwh4DxBiew3/41pMq1fq1aGTWwf0c9PjolOB4E+Z2NQsqEydTso7jP
B6M4+3xrWaHkrHFOhOT4hoBgyUJPzQ1fOiSn/0mXHxjfJ2pRF3Xk
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,45 @@
-----BEGIN CERTIFICATE-----
MIIC+jCCAWKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjES
MBAGA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxDzANBgNVBAoMBmly
ZXN0eTERMA8GA1UEAwwIdGVzdC5jb20wHhcNMjQwMTEyMTQ1OTUwWhcNMzQwMTA5
MTQ1OTUwWjA9MQswCQYDVQQGEwJDTjEWMBQGA1UECwwNQXBhY2hlIEFQSVNJWDEW
MBQGA1UEAwwNb2NzcC50ZXN0LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BIuZCmq/vmX5LqFrpa9ot5SboEhNyS/r5UGT7akjIOAXBVwZkn1vm/EsQp9VMF8y
rWZkGKFmElo0ZAXAyhjn9D6jNzA1MDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcw
AYYXaHR0cDovLzEyNy4wLjAuMToxMTQ1MS8wDQYJKoZIhvcNAQELBQADggGBAIEm
LKKS+eGBazPpSRvq2agnqmjM+PHVWRB/O/+LNOO69Lji3wRtq6T2zNHPZQXw1OMA
3C9HcIwaawTyb+hm+vX8yBr5mgS1UOtmDYzbnlpERjJBjxmPXTZLDbzogHshbabp
227p/IAjWm/2F2VPXjiX+aV1pYrhCcO7zUtBEu9KaoG3Amxg8T2WVamTV+J6r0SL
fkvYItZwbawSfwQlZ+22H4Mttu/bd2USTusT4zLAflv9UFh20bA1PizvcKK1brWS
IH2rxxSLCvu2wmrGsrLVn+9yD6xNsn4m6DyCWx9S/Tas7KLub8BjnCzP8YEvrVpV
fotefEMY5h0waj9Zc32l+6gk8Ntyp2ozWi+iu4eo0Y5SUqHlPjuGUXOivp5o/6b0
gF5M9jtkXvbH2ffrOiz9YUo4fVwk6ws5OQTr9WsildEHZH4ADOW6HqPYkOnuxhdM
p6JP0LmnO/S60/k/ZH8nMTcSUfE+qcDg3LlH5ay2fv6IKz5BaVkyHPNreRi9qg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
A1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa
GA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n
RG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM
CHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe
cvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb
VDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR
2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr
abf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2
WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/
Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1
/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh
/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj
cTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ
tSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl
c3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC
tC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY
1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl
PYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob
rJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy
hme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1
7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y
IJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,8 @@
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHMwGqSAcIFnsy8Sa6NxlSmGuOXV13SbZbZVIobN+3xboAoGCCqGSM49
AwEHoUQDQgAEi5kKar++ZfkuoWulr2i3lJugSE3JL+vlQZPtqSMg4BcFXBmSfW+b
8SxCn1UwXzKtZmQYoWYSWjRkBcDKGOf0Pg==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,4 @@
V 340109124821Z 1 unknown /C=CN/OU=Apache APISIX/CN=ocsp.test.com1
V 340109125024Z 2 unknown /C=CN/OU=Apache APISIX/CN=ocsp.test.com2
R 340109125151Z 240109125151Z 3 unknown /C=CN/OU=Apache APISIX/CN=ocsp-revoked.test.com
V 340109125746Z 5 unknown /C=CN/OU=Apache APISIX/CN=ocsp test CA signer

View File

@@ -0,0 +1,50 @@
-----BEGIN CERTIFICATE-----
MIIDxTCCAi2gAwIBAgIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjES
MBAGA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxDzANBgNVBAoMBmly
ZXN0eTERMA8GA1UEAwwIdGVzdC5jb20wHhcNMjQwMTEyMTQ1OTA4WhcNMzQwMTA5
MTQ1OTA4WjA9MQswCQYDVQQGEwJDTjEWMBQGA1UECwwNQXBhY2hlIEFQSVNJWDEW
MBQGA1UEAwwNb2NzcC50ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAPPXWs5Bb+OuZv8D1dxReaZYiNN3gTCi6QuC7ABKq9ScufBFhdvT5K3I
6QbzphGJSetio9AS46ztX4tp2vXA20Wyw/R97reVt1lYRNCSaDqVqmdLqBDeG8RP
loLHAA+wq5fCJSm4DTHKPgN2t/KPb/D6f7x4mmNBQ7wdlxa0i4r9lWESWGC7maq1
Skf9W6iMyYxP4OhDaOekMaHDA3zDijq4tO10JTHG+4L5WsZ6qFxfqJmrfsr9uwgG
zuX4m3PEau3KqSWcgPosm2vxSOJJWUja5PQi6W0xbCOtrRyF/HEWBaxBJB9CayXC
hFvmTrViaazW7OuBNcqSeIoLktQqGOMCAwEAAaM3MDUwMwYIKwYBBQUHAQEEJzAl
MCMGCCsGAQUFBzABhhdodHRwOi8vMTI3LjAuMC4xOjExNDUxLzANBgkqhkiG9w0B
AQsFAAOCAYEAkHi0FLFQbPANUxXIIYjR0dVt5xb0SoAet0TxAAzoJaO1v7jrXok+
DBZu9dOftDIX5jB8vne7JSKCl1ibpsYqpOW9AjFjUTtKkirXcsKQKs+sW1Vue0uu
xPx1IAbI475X8emIB3vH5S/eqe8ep31pJkFxoiWSafKB9gpXzpD6NEteLr6oK67F
bdIZHEdxIuiu1SQEeN8ShSoIWcVkWavsP5ziXhi+PxK4CKYQoHyFoBFWk7SXhCCA
mKhnvcOjR9Cq/ZtkAe/G31x9nYQ6blJejRDxHOqgK+eke9+8qPx2oTLwraodPRVv
0O5NpI0SQw8+5KcWpz/vq0NZFHh0SqSh82/IJvgxSab51VLdU2lxNxsllTNpDN9F
LtXT5SRgRy/gXs6bOq6tszHTNE7t6hlCGlWfaRNUHfRsdyOfim0JwOpusmE0yR7R
v6jYCk8LyJM+1oppp71cUtzrMxWEn/bC0M9TQuwb9fHFgEFU1VWjJrcaSfFGf61m
uzgYQtn5uERq
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
A1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa
GA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n
RG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM
CHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe
cvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb
VDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR
2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr
abf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2
WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/
Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1
/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh
/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj
cTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ
tSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl
c3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC
tC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY
1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl
PYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob
rJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy
hme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1
7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y
IJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA89dazkFv465m/wPV3FF5pliI03eBMKLpC4LsAEqr1Jy58EWF
29PkrcjpBvOmEYlJ62Kj0BLjrO1fi2na9cDbRbLD9H3ut5W3WVhE0JJoOpWqZ0uo
EN4bxE+WgscAD7Crl8IlKbgNMco+A3a38o9v8Pp/vHiaY0FDvB2XFrSLiv2VYRJY
YLuZqrVKR/1bqIzJjE/g6ENo56QxocMDfMOKOri07XQlMcb7gvlaxnqoXF+omat+
yv27CAbO5fibc8Rq7cqpJZyA+iyba/FI4klZSNrk9CLpbTFsI62tHIX8cRYFrEEk
H0JrJcKEW+ZOtWJprNbs64E1ypJ4iguS1CoY4wIDAQABAoIBABV8oZzROVnX0W2h
WeQLLewRmyT/P9wYTu7bv44bBl863Eum5K/FUT5bGOWq7LRY47GhRIweTf+7/xJa
5peHQgs3QHs36aQ1xi1SUOYMMLEQ5S4rBYlO+SVoWfv2KzQ2vjgmPH4boNYFW0eU
24q9RwD2IfFqszgR1TUralfu2ukJWWi1zuNN4jJZfXZWcPLV26wMAdQrGhf7CnQ7
1QN6SFNBKxpiKIXCs7ki2VmzAVg01FpmVsHkuRvn80dZ1FkkfXXaAYqNEulisAq0
+Zv+QWXrK7IpmRpJQszr7VBGLlBrMTp9wFq+ep+Bui9e26pGXYETPnchUqtBFk5k
yylxduECgYEA/v8cJEX/W8H2//Dl2tOq+F6RKwxX56dlrs6LBSpYh9982CXrALG4
Xuq8VmnjYYpdVxSyxMkex+Dih06BpQMmQci3mzHPGAPzkiFSxsogQBlB1MF4RphD
4UutZNdsmQb+l2NTGIyQR9TgLXjwKfEesia91HQGCTDPFzku/Xg0WBECgYEA9M0B
s9sLb4DC6LDoGlSlmIfKmJgZgbwjRhUI3Foplpzzrc+A23MaYbuhwVszch7S0Tib
OtEtJWTjryGAG5a/eCsVHtyAnJWxJiHV8yJ+xN1MTXIh9T6Xlablip8cBaHKZxLC
vhu5ZEIyGddYa2B6hG/x1ydMoz5pdMFGjKkFNbMCgYEA55HNgLOAn1eac/vVAdDP
pxZaRvnCqsE+em1fmqVGGL5AphppPAwpHymVN/SZZe89rONDJapvpZz4m2AUJEKj
74HUG8A0Dd8ox0Az6AuPFibZvdik3ZdRrbwID1gDa0UK13h/8f9U16benu0BTVWH
RsogAlwLTzVgG/r2TYFoJ8ECgYBa/u14Fp88lmddKY1NZFOdzDQh3r/0eqO+BEmj
5xv4cWUfIbfrWvDejWmGP0lzTUPeI6WICoM2mDcOPWyqVLHdkF4sd5iTHA2aeA9Y
bmUi9oPLcfZvfBHKvhwrGBPJgCeFgvLCyfly7CxFcMfcOiOwoRALgv842xVGIiYA
WT+ngwKBgAk1xBsENJlEGz6aeoby6ELx3QP9cQX5GG7YtPrrl9BziRIPc5YNJZfA
guw8rBxO72ilChrJIMfE8PZx6L4LJ+N1VTRgZ9T8F9ZGopqUtquc4OErmAYR0rH2
ll/i9QPgHzUYm4L7kN2J/cejJnzhANnBiJbgE5wHUHsjT5sv3trO
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,50 @@
-----BEGIN CERTIFICATE-----
MIIDzTCCAjWgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjES
MBAGA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxDzANBgNVBAoMBmly
ZXN0eTERMA8GA1UEAwwIdGVzdC5jb20wHhcNMjQwMTEyMTUwMDA5WhcNMzQwMTA5
MTUwMDA5WjBFMQswCQYDVQQGEwJDTjEWMBQGA1UECwwNQXBhY2hlIEFQSVNJWDEe
MBwGA1UEAwwVb2NzcC1yZXZva2VkLnRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAtjAaX6JtUhjXkxqtOrwvpehS53gXxRioiY9sbklUKflH
63efdi4BY0IBs7IVLMo4JUbQPe4FFWFTBMDSOoyaECSSw7AJear3XZCB9H+b41rG
EXi574WNnMmRITwXDr7fJvA9QIvZK1rotUXqNNHwb5tP1VvJJh3jCRj9mzv51MQb
8HtleMntGSRGLSxEdo2bL/u33FwALV5Ayqgg6bf0gPPGc4Lqc2xwFO0HvF6ooiLj
lQjmsqkI4/jE0ElCJSHuRcbq4H0Q1riCROnmSrLRiSdEFnAUT/cf2sR5NZKsTAzO
VwIkKjigdUjyEUN4xWberGtGzwxgfG4iiSlVht4pRQIDAQABozcwNTAzBggrBgEF
BQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly8xMjcuMC4wLjE6MTE0NTEvMA0G
CSqGSIb3DQEBCwUAA4IBgQBBbfOcWr20MQLWjijsOPiQGWa6Z+z8qMkgSB1Ukhqj
qhuYA/bVcMcftqCCcjeAW4fgN+xBuLnHwS+iIdCjUSV8kbN19KGJNR27kDI/ShgY
HiFNqEjDOq46jo/CMJap3VO4ZdvH8+3Dk3KuOCNBej/Oe3XD5Aw4jedHxHgfGWqt
FD3nA+lZOvUVe7qgSkOOPtWsyX3xx7cvWziXHFd6TUWhSfcRIORO0ZHMF80ipNgd
KgUe7t2pOuIN8sOx98j2MHNMFQVEPZ+EweznVOvWVqbGzW5wf3pUz/Vbb+uCR1LQ
otNEEbENAEEZQ6sKpZ0pe2xuuHT+KOQ20Ty79Fs2ji9R4maiD0NTaVy2/oqYrs3G
OFA7OrPSJ+HYKCq9QP6Cu/wY5kiG328SeoHNaXGltzCxvqE3DZNzevKh9s88SBjL
pZ1hHUH++Co3pCss+ZPDjkWUFnbg7v8altE37ksdYMXOjY1OStHUzfZ4uYeC9orx
Gm5X8AE3zIgpNdiANrO/ook=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
A1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa
GA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n
RG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM
CHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe
cvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb
VDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR
2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr
abf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2
WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/
Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1
/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh
/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj
cTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ
tSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl
c3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC
tC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY
1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl
PYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob
rJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy
hme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1
7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y
IJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAtjAaX6JtUhjXkxqtOrwvpehS53gXxRioiY9sbklUKflH63ef
di4BY0IBs7IVLMo4JUbQPe4FFWFTBMDSOoyaECSSw7AJear3XZCB9H+b41rGEXi5
74WNnMmRITwXDr7fJvA9QIvZK1rotUXqNNHwb5tP1VvJJh3jCRj9mzv51MQb8Htl
eMntGSRGLSxEdo2bL/u33FwALV5Ayqgg6bf0gPPGc4Lqc2xwFO0HvF6ooiLjlQjm
sqkI4/jE0ElCJSHuRcbq4H0Q1riCROnmSrLRiSdEFnAUT/cf2sR5NZKsTAzOVwIk
KjigdUjyEUN4xWberGtGzwxgfG4iiSlVht4pRQIDAQABAoIBAQCQ5Sz0hl/ffTZm
Hj9LiUNz9ZOJ1+8/p97SmKiqBdPUFhfm45qFCQ29fU+RNL62gpWov+r6dgTA/khi
bWBFhHE7CXtX+vduNlTJqxZP9/VpGlaQqq1mG5eG7KBqCDpmVdNwSnzMiuzLGGAf
W11raNSKTsFtdLRDhl18bM212jtVxNHVJ6itFZa5Ls0/VrD2KH9PXP0J5jugKYqi
GzHmt9RfmjhOPcAIOTYNP/5n1CiHERj5KytfXjN1BHWc3rx5uakaUntBkdevXWj+
ZSspRi/ReuVCXWeldmi6Pg9hQSX3MGVndAx8J6ilmtqSrRvaCBRU6x9KLfuTVEz8
UXap8UkBAoGBAOkjowQb/nWI5oqDs3SduXwVE+0yn8kBCk5x48ee1Vt0eCxtnuRs
qdPuldh6czsBj3ijmJ8Ny6aHQaaVuIlUbPjBDZGf7IVc0hj7sQ6o5Jcu9KmLLOBH
62fQDeuzM+EkGOcnH8aPvs31p5bMklhycyyyTXvmZba3hvST+Ske/3olAoGBAMgN
dtFrvAQoZMIV61kNTml3ehhUeWas/ry0WUHa4iaDnVMoJ0fwiMKk7kQDvJH8gxx3
Cr7dSnI17yBYEn0HkXlTMq0IgjJp+K40temMFwMFOWrTtGUVcbibv1Yjx+8i7m2+
pWnfGXGd6tolWRHAMe7B68q+x1iJEjQD/Ujx3XihAoGACJg3uj8N8mdJmHGie/oU
jG56fZQQL+jJ6HpqW0GPu/9fLsQbx2/6EsYI4CIjfVlhYKEnTzXC/DCgSvPaCbYD
DmiPh37NyVzSofklXdT8GFayzk1DKkF8fCc/XCEPGI2sHVlj4n4KGq2jr/t6qagO
dudb0+V6enHpl7qcxNdPs8ECgYBYM8+CUAzKjIC4Le/hCIPc7kePuJb6FSYPTzjX
V0lEj9zqkBaZmkzB/PPsWvVmLD4ma7n6Ixkyt+LhkNM9+vtB0dPTBKBa1+xD6ouW
GCUBOOly1zp/IvBL46d9tDLvlagoDNljj3DpbiXg3nyh3epmCWwLrQe5Wl4DPwsK
gVETYQKBgDvVy2JvG51tmrqg3bEkJ+8RWELK3DeJphVmlD+unkA6ONwJTB8gvDIE
mkrxulta1cgg+u3+oJ1Pbo6P19v6xOj9vr1NHmHTd6shpfx8cHVbOYo7tBX0zKcv
cPlhtyGb3LUmaHXc22qI3ooYAKUo6r0bsK6ixBQEQUyxxHOt2fz7
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,50 @@
-----BEGIN CERTIFICATE-----
MIIDzTCCAjWgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjES
MBAGA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxDzANBgNVBAoMBmly
ZXN0eTERMA8GA1UEAwwIdGVzdC5jb20wHhcNMjQwMTEyMTUwMDM0WhcNMzQwMTA5
MTUwMDM0WjBFMQswCQYDVQQGEwJDTjEWMBQGA1UECwwNQXBhY2hlIEFQSVNJWDEe
MBwGA1UEAwwVb2NzcC11bmtub3duLnRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEApuHmwZFhVmjPhNRmQtZwDpVa6BesX6Y6mBJknQVRZN52
5Ac9usp6cGBiYY+2iNV3T5EcC0yTgJhrKK0Oz1WDEAYSH3I3TwMYmFdx4r/cuaHE
sxXZggkGHPaVmzFOX9wSfrB+/TERByO4FIiY1/pTa/vDWy8cNYUYMqZzeJq52zpt
XSk1njVgjQ9pJIyZmTMADqfpc/OTdiG8kXXbrAnMuMYyNExDDcTd6eJtRmks+Vjg
95IbM8x8E/hn+QpXRCb1Nj6Fj7D0t9yC2/bQVdBJNkAxjEofuCbpR3Pn/p82Y84y
OuhORvdXmBWm7RchOf773cxat4R+I1Dec3GU8vpQAwIDAQABozcwNTAzBggrBgEF
BQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly8xMjcuMC4wLjE6MTE0NTEvMA0G
CSqGSIb3DQEBCwUAA4IBgQBSK6ACelC4GVbyyaN8QKwtzOkQJtbn5lMyo6YmgqAD
00vyrjPIc5GbuA69Jinu9mty3AMMn+UFqudWHfLXGSAl0M1LUWrxg0Qa6llEB+Kh
f6EmDNciWUK7kijuraqPxVxB4G8ZebS+SjaeptgqIW54fMQMOOzmG9DldOvIc5FF
ZMzHYNP5QTHaeGki9KxZmfxt89lTYi6ZvViW7mjpxSbecY5H2DTFWIKD7P8seHVZ
Jp4laPyAWDA157zpIvyK/zTNqnE+85ZJ2c0MrVWFXwL/7InViHASZriIOaOUBs/g
pE6RTrwpU9JhjmdYtv39SgdLAInoaxmoPeNZmr4tefLrXwn9oRHnk6RInQNSffam
vxNxD/ZKNPDZwf40ybWH5JG/SyrQr0UJAT3PWlKxHwbAz/4f6z0E/byR5nJrdFSh
dLTbfJZ5h0vaBrcBeg/NXSvW7znJWtX3NBiUq3Ns3gAJ1y8usKKWwbCsbKzUl9j4
NoG6Jv5toAlmtCmhVuUkX5g=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G
A1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa
GA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n
RG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM
CHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe
cvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb
VDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR
2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr
abf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2
WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/
Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1
/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh
/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj
cTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ
tSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl
c3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC
tC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY
1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl
PYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob
rJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy
hme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1
7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y
IJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve
U/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApuHmwZFhVmjPhNRmQtZwDpVa6BesX6Y6mBJknQVRZN525Ac9
usp6cGBiYY+2iNV3T5EcC0yTgJhrKK0Oz1WDEAYSH3I3TwMYmFdx4r/cuaHEsxXZ
ggkGHPaVmzFOX9wSfrB+/TERByO4FIiY1/pTa/vDWy8cNYUYMqZzeJq52zptXSk1
njVgjQ9pJIyZmTMADqfpc/OTdiG8kXXbrAnMuMYyNExDDcTd6eJtRmks+Vjg95Ib
M8x8E/hn+QpXRCb1Nj6Fj7D0t9yC2/bQVdBJNkAxjEofuCbpR3Pn/p82Y84yOuhO
RvdXmBWm7RchOf773cxat4R+I1Dec3GU8vpQAwIDAQABAoIBAGVK6siFGKLdPVBv
p55cEGoZp7MGY38vI5OYXm+cgboK+fkQmBxfuA+rwStckrvdbezitDX7hfBhE3H+
EOYyDjpUpP1nU0DnLS+SrDKoqC4YjY7x7TLrjUVZOpeXRu4SYzt4n6vI83/040+7
VaKKc8Ywa3RWVPX7UiO0OpRyverdQgXKxaIKukO8v1IhMQ5cshvLStFpJSLlN+Cy
2BO3uGSth7dLHG/OIz8SoGp/m5ofpBUny5FAb2EWZM/eGP/VZN2hVrYfbx5d3dVs
8AtuboH/LRCbh9IE0P5mOIZFc4r1VodozkGP83fMYiEP61pyEVDvTFcvZizJRN6h
LDNlm/kCgYEA0FdQvOjKjpogUHBJkYrH9yuSlFIwzqp+I1ZsPBUORt/czfOQapf4
HjFtUj6JvqZW3xn7rPiwTnXys9x6KP5xzjbia6or7dL/D1q7bk0oKvqhVF1LiQ2X
545a3zErLpkMmH9fSVVyTC4x+hIfN0PlrhXh0mH2urT2+K3v7j/4408CgYEAzQ64
tzs1zVGdIgRmiQV0eP9qoB7y3vmcxZq0NKjNyoMbXhuo3muGY33AzCY6qSdFLigI
8LLZms/7o5VYp9ckaYPnuYwABzXrxN4fz1vSAe0y64X8i7P09W+pB8uh07nJVTpJ
rSC+E4fNgvnvnaVp30G0gRj29OmxMrWQt8gvqw0CgYB88mCxastQCo8mrrDwYFLc
oX0fBsvOpeFQQBxZTCdrygYaXeBWjR14vhvaHzds50ViN6sAaYUTCRmtVKTOwQpv
qerQtxXxY4EkLD4MQKm+XOE0P191qnlXncBR6qMDJzaunnT+/ge2OF4wo32lH0s3
xFfSXH4kKzOSoH4sXKFfcQKBgHeB8+9+B54wyYZQ0D1dO4NlQIwvXVbMXSzhO9NQ
6hbzkBipwCJYwkrruFiCkz+QToZW+NbnNWE/g6XT3YZ8IZGJOZzu1fld2Jm05w8f
sWZECqAvR39YExSTzgxoBllx9r/AJ75Jzd1uET0bUyYqiGiAT6XJmewk4ovuO3iQ
qA9lAoGBAKKmSj69vgldBUuLQx5AGOb5ivIou8M4f6yJBKkU/fSuUjxy5EVvAOTe
YYtZVcNymzSdk8SXEg9krCK6QHDa/H6M8bLu/aJHk6pXwPFRWPG2TyQcYDg/ItlV
FK6rvRA+dxwFMi5p1TwZIE4gVkqExSWD77jgxfA8wfbSh2B/BCNi
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDqzCCAhOgAwIBAgIBBTANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjES
MBAGA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxDzANBgNVBAoMBmly
ZXN0eTERMA8GA1UEAwwIdGVzdC5jb20wHhcNMjQwMTEyMTUwMDU1WhcNMzQwMTA5
MTUwMDU1WjBDMQswCQYDVQQGEwJDTjEWMBQGA1UECwwNQXBhY2hlIEFQSVNJWDEc
MBoGA1UEAwwTb2NzcCB0ZXN0IENBIHNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAML7FQ6P5418DkSmB6tG7Rlhc9C2rfuu+xDOZIUW2tm++6xS
m4nh+9ZeDaOX5c9oBSN93VNaeKtd8ZAAaRjToJKFJbTQ+/ELGbUm8mISMIKrpebk
BWp/S+VavLYZiGjj3FiFtIZ0+RL+z2XarQcnTqcR2qlYWVDTETzHmxJiDBJ82+if
/L5VffS2RagCDUGuAfm/XcwI8pIkHNS6Bs4TL5ik7OTuX0e5YvkwCDiIhfzLm0fM
a54Z4ImvLFfGtTQRILkTltr1RGioPRQAzvpy8zpSgux5Qd96HAT6hF/xlJKHCCkr
xBiBUUtMX5fdw2AI6sUHig5v0u+bbU3nsMF9aiECAwEAAaMXMBUwEwYDVR0lBAww
CgYIKwYBBQUHAwkwDQYJKoZIhvcNAQELBQADggGBALd3mJXvzu9TDTqfGZMkfGqD
hv/GdV0uaPpNlPZyOkS31t+iLd5R1EZz8wKLegvOdm3uKA8NFx9uB7O6mWSneJ4R
VbrcJnFzl5C/SbgWIAt/N0uujO8xuC5YWlHeig5IJc8pmnacJ4y7FhTVfsw1u93d
evGyCIJ3TyYcZTDVuZruaW+xIRa+QJt3Q+CvkMn+aaxs1ji08ZjodGVu9+jsbb7f
DLgl3FuLf8DlKqhRh+hoOPUTI496m3ZTozb7cs0TfHFPSL0pZ2Rdbz4WGHfX0LRF
E8lweAsyd12OySr2PwiRY8m18t9HrPNbk7bAaVJLqehUjvB1Am5+Lgjicdy4HNhh
gDlt5hjLV2criJpq9QmKz7Veu2V42FNJR7DumnJsbUjBVlh+rgN42j8QnPAqylZ4
4gcjhu1cGJd0miEN+TjzzqdZqjVvINepBR1j6pOF3fdfea8IFtJ1dzTpkU4Bq2P5
CYqmKqhkAkEIYbwQ4fqehrcMrAAno3/ikW5PqxetnQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAwvsVDo/njXwORKYHq0btGWFz0Lat+677EM5khRba2b77rFKb
ieH71l4No5flz2gFI33dU1p4q13xkABpGNOgkoUltND78QsZtSbyYhIwgqul5uQF
an9L5Vq8thmIaOPcWIW0hnT5Ev7PZdqtBydOpxHaqVhZUNMRPMebEmIMEnzb6J/8
vlV99LZFqAINQa4B+b9dzAjykiQc1LoGzhMvmKTs5O5fR7li+TAIOIiF/MubR8xr
nhngia8sV8a1NBEguROW2vVEaKg9FADO+nLzOlKC7HlB33ocBPqEX/GUkocIKSvE
GIFRS0xfl93DYAjqxQeKDm/S75ttTeewwX1qIQIDAQABAoIBAF5EUBDjSBriYG+W
Kd0IBHeh4wGEYKdvGNkuP/EMdLCTok/U/Hf0NvKUNFnkhWn6K4nWP1weQHrxh2mM
mUM0hcxw7SL3audF657mfoclrihu3l273lZ3xvTTIquTupyjlZOCyR28jfM+GH1w
9Piha2hgvGvlWAE4mnvdMT75AkcpGEDvKrJec3Kkq7DfnW/AotVc8yJG0Q2JwkRJ
y0ITJBWkA+WtLscqRyp4tvSAtAByBdynuMpEskIrOOC7WtxLJD+JJtzO7H31irC1
ON3x4czwiVKbVjxworoD5R/2Gy7JKK+pou0TNTcFrFm/+mU0Ig3VkcZTlDSTWJio
4D3CinECgYEA62fnLuxVOP9X/lgkKjN/xtTMqcDHOXz/1tyMewj6jRzFWu42b8k1
ECDtzx1Aug8cqsA7pUvBxeC7DzyZmo3zybHRsUf9mQzUA7WK7RN4SK0O4FOZ6PbZ
1116aZqwIiYpMhXL5syC+5yVWEJkbtClMciCbDlp5Y/+PISHl24assUCgYEA1AnU
AsDKWysYoVqePfBoLDaep+5Q9VQr8T9AyXlvrqtpmLiBZR8Oh4iOGDJmFSsQOQWP
peYIuf9eTXh6DH0BhIr/wSbhleiS/ibuOPEUosnwUzC64rkcgXzofbKOyHig5o8y
45XGUzVSJQPBQM3fVEyuGV1vZKZ/2CVhnFBl360CgYBP1bMPtNLKO77J4XaSYVjK
Q80NHPXzxzK02aNC7q6aQNGlnvgTPTejuqcsAI29C/b66arQyjpzM139Mt4dDltJ
Yebtqq6Uw0b74wu0j0/Rxe8voOqnmWATq/4h5nYpfqul8sJuCZm6X0Y+4nVRJ61+
jrO8pFQHqKfeOkwJzSt8yQKBgGCNAR8nznzpCNQgQUIPAEBxtpjdKbwsUb4OgV+8
jiBJKVJDYZg8Jg+NHLbj7BvjegWdBKYUMxEOuVApddnN6i0CZib7n2j1eEmGTJ9d
F3pw3Z/j5pVqmRJVYEAsWFvsoceamR+MibxF4Vu9c/ggRntKV1RxeVGphzlS/DmD
WoAZAoGBAL9bHijnEzrijuWa1M9LV1eTCQyr0bihL86Z4pEI+B2NX5lWpcOQi8IU
W4wbN02e8g2u9DGgm6yg2eNbkVg4XWuaXUV7a3fGwnmtuWnxGhU/37Lrcou34bsM
3TvP055+kATwZ98X2MzvAUDIKdO9k+/s41H33frdJQgwCH5ArWGp
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,40 @@
#
# 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.
#
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = GuangDong
L = ZhuHai
O = iresty
CN = test2.com
[v3_req]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:TRUE
subjectAltName = @alt_names
[alt_names]
DNS.1 = test2.com
DNS.2 = *.test2.com
## openssl genrsa -out test2.key 3072
## openssl req -new -x509 -key test2.key -sha256 -config openssl-test2.conf -out test2.crt -days 36500

View File

@@ -0,0 +1,40 @@
#
# 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.
#
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = GuangDong
L = ZhuHai
O = iresty
CN = test.com
[v3_req]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:TRUE
subjectAltName = @alt_names
[alt_names]
DNS.1 = test.com
DNS.2 = *.test.com
## openssl genrsa -out apisix.key 3072 -nodes
## openssl req -new -x509 -key apisix.key -sha256 -config openssl.conf -out apisix.crt -days 36500

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA79XYBopfnVMKxI533oU2VFQbEdSPtWRD+xSl73lHLVboGP1l
SIZtnEj5AcTN2uDW6AYPiWL2iA3lEEsDTs7JBUXyl6pysBPfrqC8n/MOXKaD4e8U
5GAHFiwHWg2WzHlfFSlFkLjzp0vPkDK+fQ4Clrd7shAyitB7use6DHcVCKuI4bFO
oFbdI5sBGeyoD833g+ql9bRkH/vf8O+rPwHAM+47r1iv3lY3ex0P45PRd7U7rq8P
8UIw6qOI1tiYuKlFJmjFdcwtYG0dctxWwgL1+7njrVQoWvuOTSsc9TDMhZkmmSsU
3wXjaPxJpydck1C/w9ZLqsctKK5swYWhIcbcBQIDAQABAoIBADHXy1FwqHZVr8Mx
qI/CN4xG/mkyN7uG3unrXKDsH3K4wPuQjeAIr/bu43EOqYl3eLI3sDrpKjsUSCqe
rE1QhE5oPwZuEe+t8aqlFQ5YwP9YS8hEm57qpg5hkBWTBWfxQWVwclilV13JT5W0
NgpfQwJ3l2lmHFrlARHMOEom5WQrewKvLh2YXeJBFQc0shHcjC2Pt7cjR9oAUVi6
M5h6I+eB5xd9jj2a2fXaFL1SKZXEBVT6agSQqdB0tSuVTUsTBzNnuTL5ngS1wdLa
lEdrw8klOYWrUihKJgYH7rnQrVEVNxGyO6fVs1S9CxMwu/nW2MPcbRBY0WKYCcAO
QFJ4j4ECgYEA+yaEEPp/SH1E+DJi3U35pGdlHqg8yP0R7sik2cvvPUk4VbPrYVDD
NQ8gt2H+06keycfRqJTPptS79db9LpKjG59yYP3aWj2YbGsH1H3XxA3sZiWHkNl0
7i0ZE0GSCmEMbPe3C0Z3726tD9ZyVdaE5RdvRWdz1IloA+rYr3ypnH0CgYEA9Hdl
KY8qSthtgWsTuthpExcvfppS3Dijgd23+oZJY2JLKf8/yctuBv6rBgqDCwpnUmGR
tnkxPD/igaBnFtaMjDKNMwWwGHyarWkI7Zc+6HUdNcA/BkI3MCxwYQg2fr7HXY0h
FalewOHeJz2Tldaue9DrVIO49jfLtBh2DYZFvCkCgYBV7OmGPY3KqUEtgV+dw43D
l7Ra9shFI4A9J9xuv30MhL6HY9UGKHGA97oDw71BgT0NYBX1DWS1+VaNV46rnnO7
gaPKV0+bTDOX9E5rftqRMwpMME7fWebNjhRkKCzk7CsqJN41N1jVTBJdtsrLX2d8
UbY6EpjogFJb9L9J2ubUqQKBgQCk6oKJJbZfJV/CJaz6qBFCOqrkmlD5lQ/ghOUf
EUYi0GVqYHH0vNJtz5EqEx9R7GPFNGLrGRi4z1QLJF1HD9dioJuWZujjq/NgtnG6
bgSXJqJc52Lc4wB99AyfuL2ihSrTFmjSRx7Puc9241hTha7Rgh+vNOkq2HsH9FR3
TTRv+QKBgG5ph+SFenSE7MgYXm2NRfG1k8bp86hrt9C8vHJ7DSO2Rr833RtqEiDJ
nD4FbR0IObaBpS2VJdOn/jBYXCG0hFuj+Shxiyg/mZN0fwPVaRWDls7jzqqPsA+b
x3XKRAn57LY8UbsNpOIqZ8kjVLPZhgfYwfOI3yAeSMv4ZnRY/MWe
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA79XYBopfnVMKxI533oU2
VFQbEdSPtWRD+xSl73lHLVboGP1lSIZtnEj5AcTN2uDW6AYPiWL2iA3lEEsDTs7J
BUXyl6pysBPfrqC8n/MOXKaD4e8U5GAHFiwHWg2WzHlfFSlFkLjzp0vPkDK+fQ4C
lrd7shAyitB7use6DHcVCKuI4bFOoFbdI5sBGeyoD833g+ql9bRkH/vf8O+rPwHA
M+47r1iv3lY3ex0P45PRd7U7rq8P8UIw6qOI1tiYuKlFJmjFdcwtYG0dctxWwgL1
+7njrVQoWvuOTSsc9TDMhZkmmSsU3wXjaPxJpydck1C/w9ZLqsctKK5swYWhIcbc
BQIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBrTCCARYCFGohAv7D46F+kSOf08X/MLwtazC7MA0GCSqGSIb3DQEBCwUAMBcx
FTATBgNVBAMMDGNhLmxvY2FsaG9zdDAeFw0yMzA1MjIwMjQ3MzZaFw0zMzA1MTkw
MjQ3MzZaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOB
jQAwgYkCgYEA2YEV7+FWPl2R9EOSvi2iPyymiUnSaYhIaTuSoqRISOjCSmgrmKpJ
yDN1Cg2hqBHPkWW8BuphpV405ja+94xvOEc0qcP/Or6zDhDfWcaoqxGRAcdwHDgQ
XYMfOxlhwWCp5+vWKep3FPXpHamE09PqUbKWqIa/16aK/1sFR7Q+JJkCAwEAATAN
BgkqhkiG9w0BAQsFAAOBgQCA5aSfk4lZjAEFQ9mWN7Z97b9bnwLw2bv4PgAhDtas
0IxIvhuwR4ZTFv+Pe4PNNNvfnMgTRUWFVpjywUX7Km+k9WFavrikPgAGEfzkR2HR
WE4ETNuS7sGxczosqD+00An4lZ+58uYGEitUOJ6xO80NIhNnOGgo5N/d4fFUTyYH
bw==
-----END CERTIFICATE-----

Some files were not shown because too many files have changed in this diff Show More