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

View File

@@ -0,0 +1,656 @@
#
# 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);
log_level('info');
no_root_location();
worker_connections(1024);
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set route(two upstream node)
--- 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": "/server_port",
"upstream": {
"key": "remote_addr",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
=== TEST 3: set route(three upstream node)
--- 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": "/server_port",
"upstream": {
"key": "remote_addr",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1,
"127.0.0.1:1982": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1982"}]
=== TEST 5: set route(three upstream node)
--- 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": "/server_port",
"upstream": {
"key": "remote_addr",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 0,
"127.0.0.1:1982": 0
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
=== TEST 7 set route(three upstream node with querystring)
--- 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": "/server_port",
"upstream": {
"key": "query_string",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1,
"127.0.0.1:1982": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes with querystring
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port?var=2&var2="
local t = {}
local ports_count = {}
for i = 1, 180 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
local res, err = httpc:request_uri(uri..i, {method = "GET"})
if not res then
ngx.log(ngx.ERR, err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.count > b.count
end
table.sort(ports_arr, cmd)
if (ports_arr[1].count - ports_arr[3].count) / ports_arr[2].count > 0.2 then
ngx.say(require("toolkit.json").encode(ports_arr))
else
ngx.say('ok')
end
}
}
--- request
GET /t
--- wait: 5
--- response_body
ok
=== TEST 9: set route(three upstream node with arg_xxx)
--- 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": "/server_port",
"upstream": {
"key": "arg_device_id",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1,
"127.0.0.1:1982": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: hit routes with args
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port?device_id="
local t = {}
local ports_count = {}
for i = 1, 180 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
local res, err = httpc:request_uri(uri..i, {method = "GET"})
if not res then
ngx.log(ngx.ERR, err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.count > b.count
end
table.sort(ports_arr, cmd)
if (ports_arr[1].count - ports_arr[3].count) / ports_arr[2].count > 0.2 then
ngx.say(require("toolkit.json").encode(ports_arr))
else
ngx.say('ok')
end
}
}
--- request
GET /t
--- wait: 5
--- response_body
ok
=== TEST 11: set route(weight 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,
[[{
"uri": "/server_port",
"upstream": {
"key": "arg_device_id",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1981": 0
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 12: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port?device_id=1"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ngx.status = res.status
ngx.say(res.body)
}
}
--- request
GET /t
--- error_code_like: ^(?:50\d)$
--- error_log
failed to find valid upstream server, no valid upstream node
=== TEST 13: set route(ensure retry can try every node)
--- 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": "/server_port",
"upstream": {
"key": "arg_device_id",
"type": "chash",
"nodes": {
"127.0.0.1:1979": 1000,
"127.0.0.1:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port?device_id=1"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
200
--- error_log
Connection refused
=== TEST 15: set routes with very big weights
--- 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": "/server_port",
"upstream": {
"key": "arg_device_id",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1000000000,
"127.0.0.1:1981": 2000000000,
"127.0.0.1:1982": 1000000000
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 16: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port?device_id=1"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
-- a `size too large` error will be thrown if we don't reduce the weight
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
200
=== TEST 17: set routes with very big weights, some nodes have zero weight
--- 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": "/server_port",
"upstream": {
"key": "arg_device_id",
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1000000000,
"127.0.0.1:1981": 0,
"127.0.0.1:1982": 4000000000
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 18: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port?device_id=1"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
-- a `size too large` error will be thrown if we don't reduce the weight
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
200

View File

@@ -0,0 +1,742 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: add two consumer with username and plugins
--- 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",
"plugins": {
"key-auth": {
"key": "auth-jack"
}
}
}]],
[[{
"value": {
"username": "jack",
"plugins": {
"key-auth": {
"key": "re62sf0vRJqOBjvJJ6RUcA=="
}
}
}
}]]
)
if code ~= 200 then
ngx.say("create consumer jack failed")
return
end
ngx.say(code .. " " ..body)
code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "tom",
"plugins": {
"key-auth": {
"key": "auth-tom"
}
}
}]],
[[{
"value": {
"username": "tom",
"plugins": {
"key-auth": {
"key": "RAL/niDfEUpx+ynsoqWDuA=="
}
}
}
}]]
)
ngx.say(code .. " " ..body)
}
}
--- request
GET /t
--- response_body
200 passed
200 passed
=== TEST 2: add key auth plugin, chash hash_on consumer
--- 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": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"type": "chash",
"hash_on": "consumer"
},
"uri": "/server_port"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: hit routes, hash_on one consumer
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
request_headers["apikey"] = "auth-jack"
local ports_count = {}
for i = 1, 4 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1981"}]
--- grep_error_log eval
qr/hash_on: consumer|chash_key: "jack"|chash_key: "tom"/
--- grep_error_log_out
hash_on: consumer
chash_key: "jack"
hash_on: consumer
chash_key: "jack"
hash_on: consumer
chash_key: "jack"
hash_on: consumer
chash_key: "jack"
=== TEST 4: hit routes, hash_on two consumer
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
local ports_count = {}
for i = 1, 4 do
if i%2 == 0 then
request_headers["apikey"] = "auth-tom"
else
request_headers["apikey"] = "auth-jack"
end
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":2,"port":"1981"},{"count":2,"port":"1980"}]
--- grep_error_log eval
qr/hash_on: consumer|chash_key: "jack"|chash_key: "tom"/
--- grep_error_log_out
hash_on: consumer
chash_key: "jack"
hash_on: consumer
chash_key: "tom"
hash_on: consumer
chash_key: "jack"
hash_on: consumer
chash_key: "tom"
=== TEST 5: set route(two upstream node, type chash), hash_on header
--- 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": "/server_port",
"upstream": {
"key": "custom_header",
"type": "chash",
"hash_on": "header",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit routes, hash_on custom header
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
request_headers["custom_header"] = "custom-one"
local ports_count = {}
for i = 1, 4 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1980"}]
--- grep_error_log eval
qr/hash_on: header|chash_key: "custom-one"/
--- grep_error_log_out
hash_on: header
chash_key: "custom-one"
hash_on: header
chash_key: "custom-one"
hash_on: header
chash_key: "custom-one"
hash_on: header
chash_key: "custom-one"
=== TEST 7: hit routes, hash_on custom header miss, use default
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
request_headers["miss-custom-header"] = "custom-one"
local ports_count = {}
for i = 1, 4 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1980"}]
--- grep_error_log eval
qr/chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1/
--- grep_error_log_out
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
=== TEST 8: set route(two upstream node, 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/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/server_port",
"upstream": {
"key": "custom-cookie",
"type": "chash",
"hash_on": "cookie",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: hit routes, hash_on custom cookie
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
request_headers["Cookie"] = "custom-cookie=cuscookie"
local ports_count = {}
for i = 1, 4 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1981"}]
--- grep_error_log eval
qr/hash_on: cookie|chash_key: "cuscookie"/
--- grep_error_log_out
hash_on: cookie
chash_key: "cuscookie"
hash_on: cookie
chash_key: "cuscookie"
hash_on: cookie
chash_key: "cuscookie"
hash_on: cookie
chash_key: "cuscookie"
=== TEST 10: hit routes, hash_on custom cookie miss, use default
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
request_headers["Cookie"] = "miss-custom-cookie=cuscookie"
local ports_count = {}
for i = 1, 4 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1980"}]
--- grep_error_log eval
qr/chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1/
--- grep_error_log_out
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
=== TEST 11: set route(key contains uppercase letters and hyphen)
--- 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": "/server_port",
"upstream": {
"key": "X-Sessionid",
"type": "chash",
"hash_on": "header",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 12: hit routes with header
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 6 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {
method = "GET",
headers = {
["X-Sessionid"] = "chash_val_" .. i
}
})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":3,"port":"1981"},{"count":3,"port":"1980"}]
--- error_log
chash_key: "chash_val_1"
chash_key: "chash_val_2"
chash_key: "chash_val_3"
chash_key: "chash_val_4"
chash_key: "chash_val_5"
chash_key: "chash_val_6"
=== TEST 13: set route(two upstream nodes, type chash), hash_on vars_combinations
--- 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": "/server_port",
"upstream": {
"key": "$http_custom_header-$http_custom_header_second",
"type": "chash",
"hash_on": "vars_combinations",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: hit routes, hash_on custom header combinations
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local request_headers = {}
request_headers["custom_header"] = "custom-one"
request_headers["custom_header_second"] = "custom-two"
local ports_count = {}
for i = 1, 4 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1980"}]
--- grep_error_log eval
qr/hash_on: vars_combinations|chash_key: "custom-one-custom-two"/
--- grep_error_log_out
hash_on: vars_combinations
chash_key: "custom-one-custom-two"
hash_on: vars_combinations
chash_key: "custom-one-custom-two"
hash_on: vars_combinations
chash_key: "custom-one-custom-two"
hash_on: vars_combinations
chash_key: "custom-one-custom-two"
=== TEST 15: hit routes, hash_on custom header combinations
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 2 do
local httpc = http.new()
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
}
}
--- request
GET /t
--- response_body
[{"count":2,"port":"1980"}]
--- grep_error_log eval
qr/chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1/
--- grep_error_log_out
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1

View File

@@ -0,0 +1,272 @@
#
# 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;
my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
my $version = eval { `$nginx_binary -V 2>&1` };
if ($version !~ m/\/apisix-nginx-module/) {
plan('no_plan');
} else {
plan(skip_all => "for vanilla OpenResty only");
}
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
});
run_tests();
__DATA__
=== TEST 1: set verification
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
client = {
ca = ssl_ca_cert,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 2: hit
--- exec
curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello
--- response_body
hello world
=== TEST 3: no client certificate
--- exec
curl -k https://localhost:1994/hello
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate was not present
=== TEST 4: wrong client certificate
--- exec
curl --cert t/certs/apisix.crt --key t/certs/apisix.key -k https://localhost:1994/hello
--- response_body eval
qr/400 Bad Request/
--- error_log eval
qr/client certificate verification is not passed: FAILED:self[- ]signed certificate/
=== TEST 5: hit with different host which doesn't require mTLS
--- exec
curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello -H "Host: test.com"
--- response_body
hello world
=== TEST 6: set verification (2 ssl objects)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
ca = ssl_ca_cert,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
return
end
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
}
local code, body = t.test('/apisix/admin/ssls/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 7: hit without mTLS verify, with Host requires mTLS verification
--- exec
curl -k https://localhost:1994/hello -H "Host: test.com"
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate was not present
=== TEST 8: set verification (2 ssl objects, both have mTLS)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_ca_cert2 = t.read_file("t/certs/apisix.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
client = {
ca = ssl_ca_cert,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
return
end
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
ca = ssl_ca_cert2,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 9: hit with mTLS verify, with Host requires different mTLS verification
--- exec
curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello -H "Host: test.com"
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate verified with SNI localhost, but the host is test.com

View File

@@ -0,0 +1,655 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX;
my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
my $version = eval { `$nginx_binary -V 2>&1` };
if ($version !~ m/\/apisix-nginx-module/) {
plan(skip_all => "apisix-nginx-module not installed");
} else {
plan('no_plan');
}
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
});
run_tests();
__DATA__
=== TEST 1: bad client certificate
--- 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 = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
ca = ("test.com"):rep(128),
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to validate client_cert: failed to parse cert: PEM_read_bio_X509_AUX() failed"}
=== TEST 2: missing client certificate
--- 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 = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"client\" validation failed: property \"ca\" is required"}
=== TEST 3: set verification
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1994"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
plugins = {
["proxy-rewrite"] = {
uri = "/hello"
}
},
uri = "/mtls"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/2',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
client = {
ca = ssl_ca_cert,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 4: hit
--- request
GET /mtls
--- more_headers
Host: localhost
--- response_body
hello world
=== TEST 5: no client certificate
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1994"] = 1,
},
},
plugins = {
["proxy-rewrite"] = {
uri = "/hello"
}
},
uri = "/mtls2"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 6: hit
--- request
GET /mtls2
--- more_headers
Host: localhost
--- error_code: 502
--- error_log
peer did not return a certificate
=== TEST 7: wrong client certificate
--- 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/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1994"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
plugins = {
["proxy-rewrite"] = {
uri = "/hello"
}
},
uri = "/mtls3"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 8: hit
--- request
GET /mtls3
--- more_headers
Host: localhost
--- error_code: 502
--- error_log
certificate verify failed
=== TEST 9: set verification
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 10: hit with different host which doesn't require mTLS
--- exec
curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello -H "Host: x.com"
--- response_body
hello world
=== TEST 11: set verification (2 ssl objects)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
ca = ssl_ca_cert,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
return
end
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
}
local code, body = t.test('/apisix/admin/ssls/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 12: hit without mTLS verify, with Host requires mTLS verification
--- exec
curl -k https://localhost:1994/hello -H "Host: test.com"
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate verified with SNI localhost, but the host is test.com
=== TEST 13: set verification (2 ssl objects, both have mTLS)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_ca_cert2 = t.read_file("t/certs/apisix.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/hello"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
client = {
ca = ssl_ca_cert,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
return
end
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
ca = ssl_ca_cert2,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 14: hit with mTLS verify, with Host requires different mTLS verification
--- exec
curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello -H "Host: test.com"
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate verified with SNI localhost, but the host is test.com
=== TEST 15: request localhost and save tls session to reuse
--- max_size: 1048576
--- exec
echo "GET /hello HTTP/1.1\r\nHost: localhost\r\n" | \
timeout 1 openssl s_client -ign_eof -connect 127.0.0.1:1994 \
-servername localhost -cert t/certs/mtls_client.crt -key t/certs/mtls_client.key \
-sess_out session.dat || true
--- response_body eval
qr/200 OK/
=== TEST 16: request test.com with saved tls session
--- max_size: 1048576
--- exec
echo "GET /hello HTTP/1.1\r\nHost: test.com\r\n" | \
openssl s_client -ign_eof -connect 127.0.0.1:1994 -servername test.com \
-sess_in session.dat
--- response_body eval
qr/400 Bad Request/
--- error_log
sni in client hello mismatch hostname of ssl session, sni: test.com, hostname: localhost
=== TEST 17: set verification (2 ssl objects, both have mTLS)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
local ssl_ca_cert2 = t.read_file("t/certs/apisix.crt")
local ssl_cert = t.read_file("t/certs/mtls_client.crt")
local ssl_key = t.read_file("t/certs/mtls_client.key")
local data = {
upstream = {
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
},
uri = "/*"
}
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
))
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "localhost",
client = {
ca = ssl_ca_cert,
depth = 2,
skip_mtls_uri_regex = {
"/hello[0-9]+",
}
}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
return
end
local data = {
cert = ssl_cert,
key = ssl_key,
sni = "test.com",
client = {
ca = ssl_ca_cert2,
depth = 2,
}
}
local code, body = t.test('/apisix/admin/ssls/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
=== TEST 18: skip the mtls, although no client cert provided
--- exec
curl -k https://localhost:1994/hello1
--- response_body eval
qr/hello1 world/
=== TEST 19: skip the mtls, although with wrong client cert
--- exec
curl -k --cert t/certs/test2.crt --key t/certs/test2.key -k https://localhost:1994/hello1
--- response_body eval
qr/hello1 world/
=== TEST 20: mtls failed, returns 400
--- exec
curl -k https://localhost:1994/hello
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate was not present
=== TEST 21: mtls failed, wrong client cert
--- exec
curl --cert t/certs/test2.crt --key t/certs/test2.key -k https://localhost:1994/hello
--- response_body eval
qr/400 Bad Request/
--- error_log
client certificate verification is not passed: FAILED
=== TEST 22: mtls failed, at handshake phase
--- exec
curl -k -v --resolve "test.com:1994:127.0.0.1" https://test.com:1994/hello
--- error_log
peer did not return a certificate

View File

@@ -0,0 +1,312 @@
#
# 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);
log_level('warn');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->error_log && !$block->no_error_log) {
$block->set_value("no_error_log", "[error]");
}
});
run_tests();
__DATA__
=== TEST 1: consumer group usage
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/consumer_groups/bar',
ngx.HTTP_PUT,
[[{
"plugins": {
"response-rewrite": {
"body": "hello"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "foo",
"group_id": "bar",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"basic-auth": {}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.5)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local headers = {
["Authorization"] = "Basic Zm9vOmJhcg=="
}
local res, err = httpc:request_uri(uri, {headers = headers})
ngx.say(res.body)
local code, err = t('/apisix/admin/consumer_groups/bar',
ngx.HTTP_PATCH,
[[{
"plugins": {
"response-rewrite": {
"body": "world"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local res, err = httpc:request_uri(uri, {headers = headers})
ngx.say(res.body)
}
}
--- response_body
hello
world
=== TEST 2: validated plugins configuration via incremental sync (malformed data)
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local core = require("apisix.core")
assert(core.etcd.set("/consumer_groups/bar",
{id = "bar", plugins = { ["uri-blocker"] = { block_rules = 1 }}}
))
-- wait for sync
ngx.sleep(0.6)
assert(core.etcd.delete("/consumer_groups/bar"))
}
}
--- error_log
property "block_rules" validation failed
=== TEST 3: don't override the plugin in the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/consumer_groups/bar',
ngx.HTTP_PUT,
[[{
"plugins": {
"response-rewrite": {
"body": "hello"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "foo",
"group_id": "bar",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
},
"response-rewrite": {
"body": "world"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"basic-auth": {}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local headers = {
["Authorization"] = "Basic Zm9vOmJhcg=="
}
local res, err = httpc:request_uri(uri, {headers = headers})
ngx.say(res.body)
}
}
--- response_body
world
=== TEST 4: check consumer_group_id var
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/consumer_groups/bar',
ngx.HTTP_PUT,
[[{
"plugins": {
"serverless-post-function": {
"phase": "access",
"functions" : ["return function(_, ctx) ngx.say(ctx.var.consumer_group_id); ngx.exit(200); end"]
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "foo",
"group_id": "bar",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"basic-auth": {}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.5)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local headers = {
["Authorization"] = "Basic Zm9vOmJhcg=="
}
local res, err = httpc:request_uri(uri, {headers = headers})
ngx.print(res.body)
}
}
--- response_body
bar

View File

@@ -0,0 +1,464 @@
#
# 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();
run_tests;
__DATA__
=== TEST 1: add consumer with username and plugins
--- 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",
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
},
"key-auth": {
"key": "auth-one"
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: enable key auth plugin using admin api
--- 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": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: invalid consumer
--- request
GET /hello
--- more_headers
apikey: 123
--- error_code: 401
--- response_body
{"message":"Invalid API key in request"}
=== TEST 4: valid consumer
--- request
GET /hello
--- more_headers
apikey: auth-one
--- response_body
hello world
=== TEST 5: up the limit
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- more_headers
apikey: auth-one
--- error_code eval
[200, 200, 503, 503]
=== TEST 6: use the new configuration after the consumer's configuration is updated
--- config
location /t {
content_by_lua_block {
local function test()
local json_encode = require("toolkit.json").encode
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local status_count = {}
for i = 1, 5 do
local httpc = http.new()
local res, err = httpc:request_uri(uri,
{
method = "GET",
headers = {
apikey = "auth-one",
}
}
)
if not res then
ngx.say(err)
return
end
local status = tostring(res.status)
status_count[status] = (status_count[status] or 0) + 1
end
ngx.say(json_encode(status_count))
end
test()
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "jack",
"plugins": {
"limit-count": {
"count": 4,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
},
"key-auth": {
"key": "auth-one"
}
}
}]]
)
ngx.sleep(0.1)
test()
}
}
--- request
GET /t
--- response_body
{"200":2,"503":3}
{"200":4,"503":1}
=== TEST 7: consumer with multiple auth plugins
--- 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": "John_Doe",
"desc": "new consumer",
"plugins": {
"key-auth": {
"key": "consumer-plugin-John_Doe"
},
"hmac-auth": {
"key_id": "my-access-key",
"secret_key": "my-secret-key",
"clock_skew": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: bind to routes
--- 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": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.log(ngx.ERR, "failed to bind route 1")
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"plugins": {
"hmac-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/status"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: hit consumer, key-auth
--- request
GET /hello
--- more_headers
apikey: consumer-plugin-John_Doe
--- response_body
hello world
--- error_log
find consumer John_Doe
=== TEST 10: hit consumer, hmac-auth
--- config
location /t {
content_by_lua_block {
local ngx_time = ngx.time
local ngx_http_time = ngx.http_time
local core = require("apisix.core")
local t = require("lib.test_admin")
local hmac = require("resty.hmac")
local ngx_encode_base64 = ngx.encode_base64
local secret_key = "my-secret-key"
local timestamp = ngx_time()
local gmt = ngx_http_time(timestamp)
local key_id = "my-access-key"
local custom_header_a = "asld$%dfasf"
local custom_header_b = "23879fmsldfk"
local signing_string = {
key_id,
"GET /status",
"date: " .. gmt,
"x-custom-header-a: " .. custom_header_a,
"x-custom-header-b: " .. custom_header_b
}
signing_string = core.table.concat(signing_string, "\n") .. "\n"
core.log.info("signing_string:", signing_string)
local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
core.log.info("signature:", ngx_encode_base64(signature))
local headers = {}
headers["Date"] = gmt
headers["Authorization"] = "Signature keyId=\"" .. key_id .. "\",algorithm=\"hmac-sha256\"" .. ",headers=\"@request-target date x-custom-header-a x-custom-header-b\",signature=\"" .. ngx_encode_base64(signature) .. "\""
headers["x-custom-header-a"] = custom_header_a
headers["x-custom-header-b"] = custom_header_b
local code, body = t.test('/status',
ngx.HTTP_GET,
nil,
nil,
headers
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- error_log
find consumer John_Doe
=== TEST 11: the plugins bound on the service should use the latest configuration
--- 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",
"plugins": {
"key-auth": {
"key": "auth-jack"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {
"header": "Authorization"
},
"proxy-rewrite": {
"uri": "/hello1"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": [
"GET"
],
"uri": "/hello",
"service_id": "1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local headers = {
["Authorization"] = "auth-jack"
}
local res, err = httpc:request_uri(uri, {headers = headers})
assert(res.status == 200)
if not res then
ngx.log(ngx.ERR, err)
return
end
ngx.print(res.body)
local code, body = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {
"header": "Authorization"
},
"proxy-rewrite": {
"uri": "/server_port"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
local res, err = httpc:request_uri(uri, {headers = headers})
assert(res.status == 200)
if not res then
ngx.log(ngx.ERR, err)
return
end
ngx.say(res.body)
}
}
--- request
GET /t
--- response_body
hello1 world
1980

View File

@@ -0,0 +1,470 @@
#
# 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 (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->response_body) {
$block->set_value("response_body", "passed\n");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
our $debug_config = t::APISIX::read_file("conf/debug.yaml");
$debug_config =~ s/basic:\n enable: false/basic:\n enable: true/;
$debug_config =~ s/hook_conf:\n enable: false/hook_conf:\n enable: true/;
run_tests;
__DATA__
=== TEST 1: configure non-auth plugins in the consumer and run it's rewrite phase
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_PUT,
[[{
"username": "jack",
"plugins": {
"key-auth": {
"key": "auth-jack"
},
"proxy-rewrite": {
"uri": "/uri/plugin_proxy_rewrite",
"headers": {
"X-Api-Engine": "APISIX",
"X-CONSUMER-ID": "1"
}
}
}
}]]
)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: hit routes
--- request
GET /hello
--- more_headers
apikey: auth-jack
--- response_body
uri: /uri/plugin_proxy_rewrite
apikey: auth-jack
host: localhost
x-api-engine: APISIX
x-consumer-id: 1
x-consumer-username: jack
x-real-ip: 127.0.0.1
=== TEST 3: trace plugins info for debug
--- debug_config eval: $::debug_config
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local ngx_re = require("ngx.re")
local http = require "resty.http"
local httpc = http.new()
local headers = {}
headers["apikey"] = "auth-jack"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local res, err = httpc:request_uri(uri, {
method = "GET",
headers = headers,
})
local debug_header = res.headers["Apisix-Plugins"]
local arr = ngx_re.split(debug_header, ", ")
local hash = {}
for i, v in ipairs(arr) do
hash[v] = true
end
ngx.status = res.status
ngx.say(json.encode(hash))
}
}
--- response_body
{"key-auth":true,"proxy-rewrite":true}
=== TEST 4: configure non-auth plugins in the route and run it's rewrite phase
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_PUT,
[[{
"username": "jack",
"plugins": {
"key-auth": {
"key": "auth-jack"
}
}
}]]
)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {},
"proxy-rewrite": {
"uri": "/uri/plugin_proxy_rewrite",
"headers": {
"X-Api-Engine": "APISIX",
"X-CONSUMER-ID": "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 5: hit routes
--- request
GET /hello
--- more_headers
apikey: auth-jack
--- response_body
uri: /uri/plugin_proxy_rewrite
apikey: auth-jack
host: localhost
x-api-engine: APISIX
x-consumer-id: 1
x-consumer-username: jack
x-real-ip: 127.0.0.1
=== TEST 6: trace plugins info for debug
--- debug_config eval: $::debug_config
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local ngx_re = require("ngx.re")
local http = require "resty.http"
local httpc = http.new()
local headers = {}
headers["apikey"] = "auth-jack"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local res, err = httpc:request_uri(uri, {
method = "GET",
headers = headers,
})
local debug_header = res.headers["Apisix-Plugins"]
local arr = ngx_re.split(debug_header, ", ")
local hash = {}
for i, v in ipairs(arr) do
hash[v] = true
end
ngx.status = res.status
ngx.say(json.encode(hash))
}
}
--- response_body
{"key-auth":true,"proxy-rewrite":true}
=== TEST 7: configure non-auth plugins in the consumer and run it's rewrite phase
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_PUT,
[[{
"username": "jack",
"plugins": {
"key-auth": {
"key": "auth-jack"
},
"ip-restriction": {
"blacklist": [
"127.0.0.0/24"
]
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {}
},
"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 8: hit routes and ip-restriction work well
--- request
GET /hello
--- more_headers
apikey: auth-jack
--- error_code: 403
--- response_body
{"message":"Your IP address is not allowed"}
=== TEST 9: use the latest consumer modifiedIndex as lrucache key
--- 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": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"ip-restriction": {
"whitelist": ["1.1.1.1"]
},
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugin_config_id": "1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uris": ["/hello"]
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local headers = {
["Authorization"] = "Basic Zm9vOmJhcg=="
}
local res, err = httpc:request_uri(uri, {headers = headers})
ngx.print(res.body)
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"ip-restriction": {
"whitelist": ["1.1.1.1", "127.0.0.1"]
},
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5)
local res, err = httpc:request_uri(uri, {headers = headers})
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bala"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5)
local headers = {
["Authorization"] = "Basic Zm9vOmJhbGE="
}
local res, err = httpc:request_uri(uri, {headers = headers})
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
}
}
--- response_body
{"message":"Your IP address is not allowed"}
hello world
hello world
=== TEST 10: consumer should work if the etcd connection failed during starting
--- extra_init_by_lua
local etcd_apisix = require("apisix.core.etcd")
etcd_apisix.get_etcd_syncer = function ()
return nil, "", "ouch"
end
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local headers = {
["Authorization"] = "Basic Zm9vOmJhbGE="
}
local res, err = httpc:request_uri(uri, {headers = headers})
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
}
}
--- response_body
hello world
--- error_log
failed to fetch data from etcd

View File

@@ -0,0 +1,159 @@
#
# 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_shuffle();
no_root_location();
run_tests;
__DATA__
=== TEST 1: add consumer with csrf plugin (data encryption enabled)
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json = require("toolkit.json")
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "jack",
"plugins": {
"key-auth": {
"key": "key-a"
},
"csrf": {
"key": "userkey",
"expires": 1000000000
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
-- verify csrf key is decrypted in admin API
local code, message, res = t('/apisix/admin/consumers/jack',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
local consumer = json.decode(res)
ngx.say(consumer.value.plugins["csrf"].key)
-- verify csrf key is encrypted in etcd
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/jack'))
ngx.say(res.body.node.value.plugins["csrf"].key)
}
}
--- request
GET /t
--- response_body
userkey
mt39FazQccyMqt4ctoRV7w==
--- no_error_log
[error]
=== TEST 2: add 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,
[[{
"uri": "/hello",
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: invalid request - no csrf token
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
POST /hello
--- more_headers
apikey: key-a
--- error_code: 401
--- response_body
{"error_msg":"no csrf token in headers"}
=== TEST 4: valid request - with csrf token
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
POST /hello
--- more_headers
apikey: key-a
apisix-csrf-token: eyJyYW5kb20iOjAuNDI5ODYzMTk3MTYxMzksInNpZ24iOiI0ODRlMDY4NTkxMWQ5NmJhMDc5YzQ1ZGI0OTE2NmZkYjQ0ODhjODVkNWQ0NmE1Y2FhM2UwMmFhZDliNjE5OTQ2IiwiZXhwaXJlcyI6MjY0MzExOTYyNH0=
Cookie: apisix-csrf-token=eyJyYW5kb20iOjAuNDI5ODYzMTk3MTYxMzksInNpZ24iOiI0ODRlMDY4NTkxMWQ5NmJhMDc5YzQ1ZGI0OTE2NmZkYjQ0ODhjODVkNWQ0NmE1Y2FhM2UwMmFhZDliNjE5OTQ2IiwiZXhwaXJlcyI6MjY0MzExOTYyNH0=
--- response_body
hello world
--- no_error_log
[error]

View File

@@ -0,0 +1,137 @@
# 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();
run_tests;
__DATA__
=== TEST 1: enable basic-auth on the route /hello
--- 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": {
"basic-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create 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 code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: create a credential with basic-auth plugin enabled for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31',
ngx.HTTP_PUT,
[[{
"plugins": {
"basic-auth": {"username": "foo", "password": "bar"}
}
}]],
[[{
"value":{
"id":"34010989-ce4e-4d61-9493-b54cca8edb31",
"plugins":{
"basic-auth":{"username":"foo","password":"+kOEVUuRc5rC5ZwvvAMLwg=="}
}
},
"key":"/apisix/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: access with invalid basic-auth (invalid password)
--- request
GET /hello
--- more_headers
Authorization: Basic Zm9vOmZvbwo=
--- error_code: 401
--- response_body
{"message":"Invalid user authorization"}
=== TEST 5: access with valid basic-auth
--- request
GET /hello
--- more_headers
Authorization: Basic Zm9vOmJhcg==
--- response_body
hello world

View File

@@ -0,0 +1,125 @@
# 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();
run_tests;
__DATA__
=== TEST 1: test continuous watch etcd changes without APISIX reload
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- enable key-auth on /hello
t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
ngx.sleep(0.2) -- On some machines, changes may not be instantly watched, so sleep makes the test more robust.
-- request /hello without key-auth should response status 401
local code, body = t('/hello', ngx.HTTP_GET)
assert(code == 401)
-- add a consumer jack
t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username":"jack"
}]],
[[{
"key": "/apisix/consumers/jack",
"value":
{
"username":"jack"
}
}]]
)
-- create first credential for consumer jack
t('/apisix/admin/consumers/jack/credentials/the-first-one',
ngx.HTTP_PUT,
[[{
"plugins":{"key-auth":{"key":"p7a3k6r4t9"}}
}]],
[[{
"value":{
"id":"the-first-one",
"plugins":{"key-auth":{"key":"p7a3k6r4t9"}}
},
"key":"/apisix/consumers/jack/credentials/the-first-one"
}]]
)
ngx.sleep(0.2)
-- request /hello with credential a
local headers = {}
headers["apikey"] = "p7a3k6r4t9"
code, body = t('/hello', ngx.HTTP_GET, "", nil, headers)
assert(code == 200)
-- create second credential for consumer jack
t('/apisix/admin/consumers/jack/credentials/the-second-one',
ngx.HTTP_PUT,
[[{
"plugins":{"key-auth":{"key":"v8p3q6r7t9"}}
}]],
[[{
"value":{
"id":"the-second-one",
"plugins":{"key-auth":{"key":"v8p3q6r7t9"}}
},
"key":"/apisix/consumers/jack/credentials/the-second-one"
}]]
)
ngx.sleep(0.2)
-- request /hello with credential b
headers["apikey"] = "v8p3q6r7t9"
code, body = t('/hello', ngx.HTTP_GET, "", nil, headers)
assert(code == 200)
-- delete the first credential
code, body = t('/apisix/admin/consumers/jack/credentials/the-first-one', ngx.HTTP_DELETE)
assert(code == 200)
ngx.sleep(0.2)
-- request /hello with credential a
headers["apikey"] = "p7a3k6r4t9"
code, body = t('/hello', ngx.HTTP_GET, "", nil, headers)
assert(code == 401)
}
}
--- request
GET /t

View File

@@ -0,0 +1,137 @@
# 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();
run_tests;
__DATA__
=== TEST 1: enable jwt-auth on the route /hello
--- 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": {
"jwt-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create 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 code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: create a credential with jwt-auth plugin enabled for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31',
ngx.HTTP_PUT,
[[{
"plugins": {
"jwt-auth": {"key": "user-key", "secret": "my-secret-key"}
}
}]],
[[{
"value":{
"id":"34010989-ce4e-4d61-9493-b54cca8edb31",
"plugins":{
"jwt-auth": {"key": "user-key", "secret": "kK0lkbzXrE7aiTiyK/Z0Sw=="}
}
},
"key":"/apisix/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: access with invalid JWT token
--- request
GET /hello
--- more_headers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwiZXhwIjoxNjk1MTM4NjM1fQ.Au2liSZ8eQXUJR3SJESwNlIfqZdNyRyxIJK03L4dk_g
--- error_code: 401
--- response_body
{"message":"Invalid user key in JWT token"}
=== TEST 5: access with valid JWT token in header
--- request
GET /hello
--- more_headers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs
--- response_body
hello world

View File

@@ -0,0 +1,137 @@
# 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();
run_tests;
__DATA__
=== TEST 1: enable key-auth on the route /hello
--- 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": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create 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 code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: create a credential with key-auth plugin enabled for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {"key": "p7a3k6r4t9"}
}
}]],
[[{
"value":{
"id":"34010989-ce4e-4d61-9493-b54cca8edb31",
"plugins":{
"key-auth": {"key": "fsFPtg7BtXMXkvSnS9e1zw=="}
}
},
"key":"/apisix/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: request with an invalid key: should be not OK
--- request
GET /hello
--- more_headers
apikey: 123
--- error_code: 401
--- response_body
{"message":"Invalid API key in request"}
=== TEST 5: request with the valid key: should be OK
--- request
GET /hello
--- more_headers
apikey: p7a3k6r4t9
--- response_body
hello world

View File

@@ -0,0 +1,236 @@
# 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();
run_tests;
__DATA__
=== TEST 1: enable key-auth plugin on /hello
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- basic-auth on route 1
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create 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 code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: create the first credential with the key-auth plugin enabled for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/the-first-one',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {"key": "p7a3k6r4t9"}
}
}]],
[[{
"value":{
"id":"the-first-one",
"plugins":{
"key-auth": {"key": "fsFPtg7BtXMXkvSnS9e1zw=="}
}
},
"key":"/apisix/consumers/jack/credentials/the-first-one"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: create the second credential with the key-auth plugin enabled for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/the-second-one',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {"key": "v8p3q6r7t9"}
}
}]],
[[{
"value":{
"id":"the-second-one",
"plugins":{
"key-auth": {"key": "QwGua2GjZjOiq+Mj3Mef2g=="}
}
},
"key":"/apisix/consumers/jack/credentials/the-second-one"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: request /hello with the key of the first credential: should be OK
--- request
GET /hello
--- more_headers
apikey: p7a3k6r4t9
--- response_body
hello world
=== TEST 6: request /hello with the key of second credential: should be OK
--- request
GET /hello
--- more_headers
apikey: v8p3q6r7t9
--- response_body
hello world
=== TEST 7: delete the first credential
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/the-first-one', ngx.HTTP_DELETE)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: request /hello with the key of the first credential: should be not OK
--- request
GET /hello
--- more_headers
apikey: p7a3k6r4t9
--- error_code: 401
=== TEST 9: request /hello with the key of the second credential: should be OK
--- request
GET /hello
--- more_headers
apikey: v8p3q6r7t9
--- response_body
hello world
=== TEST 10: delete the second credential
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/the-second-one', ngx.HTTP_DELETE)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: request /hello with the key of the second credential: should be not OK
--- request
GET /hello
--- more_headers
apikey: v8p3q6r7t9
--- error_code: 401

View File

@@ -0,0 +1,245 @@
# 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();
run_tests;
__DATA__
=== TEST 1: enable key-auth on the route /echo
--- 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": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/echo"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create 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 code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: create a credential with key-auth plugin enabled and 'custom_id' label for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {"key": "p7a3k6r4t9"}
},
"labels": {
"custom_id": "271fc4a264bb"
}
}]],
[[{
"value":{
"id":"34010989-ce4e-4d61-9493-b54cca8edb31",
"plugins":{
"key-auth": {"key": "fsFPtg7BtXMXkvSnS9e1zw=="}
},
"labels": {
"custom_id": "271fc4a264bb"
}
},
"key":"/apisix/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: request the route: 'x-consumer-username' and 'x-credential-identifier' is in response headers and 'x-consumer-custom-id' is not
--- request
GET /echo HTTP/1.1
--- more_headers
apikey: p7a3k6r4t9
--- response_headers
x-consumer-username: jack
x-credential-identifier: 34010989-ce4e-4d61-9493-b54cca8edb31
!x-consumer-custom-id
=== TEST 5: update the consumer add label "custom_id"
--- 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",
"labels": {
"custom_id": "495aec6a"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: request the route: the value of 'x-consumer-custom-id' come from the consumer but not the credential or downstream
--- request
GET /echo HTTP/1.1
--- more_headers
apikey: p7a3k6r4t9
x-consumer-custom-id: 271fc4a264bb
--- response_headers
x-consumer-username: jack
x-credential-identifier: 34010989-ce4e-4d61-9493-b54cca8edb31
x-consumer-custom-id: 495aec6a
=== TEST 7: delete the credential
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31', ngx.HTTP_DELETE)
assert(code == 200)
ngx.status = code
}
}
--- request
GET /t
--- response_body
=== TEST 8: update the consumer to enable a key-auth plugin
--- 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",
"plugins": {
"key-auth": {
"key": "p7a3k6r4t9"
}
}
}]],
[[{
"value": {
"username": "jack",
"plugins": {
"key-auth": {
"key": "fsFPtg7BtXMXkvSnS9e1zw=="
}
}
},
"key": "/apisix/consumers/jack"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: request the route with headers x-credential-identifier and x-consumer-custom-id: these headers will be removed
--- request
GET /echo HTTP/1.1
--- more_headers
apikey: p7a3k6r4t9
x-credential-identifier: 34010989-ce4e-4d61-9493-b54cca8edb31
x-consumer-custom-id: 271fc4a264bb
--- response_headers
x-consumer-username: jack
!x-credential-identifier
!x-consumer-custom-id

View File

@@ -0,0 +1,171 @@
# 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();
run_tests;
__DATA__
=== TEST 1: enable key-auth on /hello
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- basic-auth on route 1
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create 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 code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: create a credential with the key-auth plugin enabled for the consumer
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {"key": "p7a3k6r4t9"}
}
}]],
[[{
"value":{
"id":"34010989-ce4e-4d61-9493-b54cca8edb31",
"plugins":{
"key-auth": {"key": "fsFPtg7BtXMXkvSnS9e1zw=="}
}
},
"key":"/apisix/consumers/jack/credentials/34010989-ce4e-4d61-9493-b54cca8edb31"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: request the route /hello multi times: should be OK
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- more_headers
apikey: p7a3k6r4t9
--- error_code eval
[200, 200, 200, 200]
=== TEST 5: enable plugin `limit-count` for the 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",
"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 6: request the route /hello multi times: should be not OK, exceed the limit-count
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- more_headers
apikey: p7a3k6r4t9
--- error_code eval
[200, 200, 503, 503]

View File

@@ -0,0 +1,571 @@
#
# 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: sanity
# the sensitive data is encrypted in etcd, and it is normal to read it from the admin API
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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',
ngx.HTTP_PUT,
[[{
"username": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/consumers/foo',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["basic-auth"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/foo'))
ngx.say(res.body.node.value.plugins["basic-auth"].password)
}
}
--- response_body
bar
77+NmbYqNfN+oLm0aX5akg==
=== TEST 2: enable basic auth plugin
--- 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": {
"basic-auth": {}
},
"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: verify
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
GET /hello
--- more_headers
Authorization: Basic Zm9vOmJhcg==
--- response_body
hello world
=== TEST 4: multiple auth plugins work well
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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',
ngx.HTTP_PUT,
[[{
"username": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
},
"key-auth": {
"key": "auth-one"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
local code, message, res = t('/apisix/admin/consumers/foo',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say("done")
}
}
--- response_body
done
=== TEST 5: enable multiple auth plugins on 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": {
"basic-auth": {},
"key-auth": {}
},
"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: verify
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
GET /hello
--- more_headers
apikey: auth-one
Authorization: Basic Zm9vOmJhcg==
--- response_body
hello world
=== TEST 7: disable data_encryption
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: false
keyring:
- edd1c9f0985e76a2
--- 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',
ngx.HTTP_PUT,
[[{
"username": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/foo'))
ngx.say(res.body.node.value.plugins["basic-auth"].password)
}
}
--- response_body
bar
=== TEST 8: etcd store unencrypted password, enable data_encryption, decryption fails, use original password
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local core = require("apisix.core")
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res, err = core.etcd.set("/consumers/foo2", core.json.decode([[{
"username":"foo2",
"plugins":{
"basic-auth":{
"username":"foo2",
"password":"bar"
}
}
}]]))
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/consumers/foo2',
ngx.HTTP_GET
)
res = core.json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["basic-auth"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/foo2'))
ngx.say(res.body.node.value.plugins["basic-auth"].password)
}
}
--- response_body
bar
bar
--- error_log
failed to decrypt the conf of plugin [basic-auth] key [password], err: decrypt ssl key failed
=== TEST 9: etcd stores both encrypted and unencrypted data
# enable data_encryption, decryption of encrypted data succeeds
# decryption of unencrypted data fails, make sure it works well
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local core = require("apisix.core")
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res, err = core.etcd.set("/consumers/foo2", core.json.decode([[{
"username":"foo2",
"plugins":{
"basic-auth":{
"username":"foo2",
"password":"bar"
},
"key-auth": {
"key": "vU/ZHVJw7b0XscDJ1Fhtig=="
}
}
}]]))
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/consumers/foo2',
ngx.HTTP_GET
)
res = core.json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["basic-auth"].password)
ngx.say(res.value.plugins["key-auth"].key)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/foo2'))
ngx.say(res.body.node.value.plugins["basic-auth"].password)
ngx.say(res.body.node.value.plugins["key-auth"].key)
}
}
--- response_body
bar
auth-two
bar
vU/ZHVJw7b0XscDJ1Fhtig==
--- error_log
failed to decrypt the conf of plugin [basic-auth] key [password], err: decrypt ssl key failed
=== TEST 10: verify, use the foo2 consumer
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
GET /hello
--- more_headers
apikey: auth-two
Authorization: Basic Zm9vMjpiYXI=
--- response_body
hello world
=== TEST 11: keyring rotate, encrypt with edd1c9f0985e76a2
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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',
ngx.HTTP_PUT,
[[{
"username": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"basic-auth": {}
},
"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 12: keyring rotate, decrypt with qeddd145sfvddff3 would fail, but encrypt with edd1c9f0985e76a2 would success
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- qeddd145sfvddff3
- edd1c9f0985e76a2
--- request
GET /hello
--- more_headers
Authorization: Basic Zm9vOmJhcg==
--- response_body
hello world
=== TEST 13: search consumer list
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
-- dletet exist consumers
t('/apisix/admin/consumers/foo', ngx.HTTP_DELETE)
t('/apisix/admin/consumers/foo2', ngx.HTTP_DELETE)
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
local code, body = t('/apisix/admin/consumers',
ngx.HTTP_PUT,
[[{
"username": "test",
"plugins": {
"basic-auth": {
"username": "test",
"password": "test"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/consumers',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
local pwds = {}
table.insert(pwds, res.list[1].value.plugins["basic-auth"].password)
table.insert(pwds, res.list[2].value.plugins["basic-auth"].password)
ngx.say(json.encode(pwds))
}
}
--- response_body
["bar","test"]

View File

@@ -0,0 +1,742 @@
#
# 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");
}
});
run_tests();
__DATA__
=== TEST 1: data encryption work well with plugins that not the auth plugins
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"clickhouse-logger": {
"user": "default",
"password": "abc123",
"database": "default",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server",
"batch_max_size":1,
"inactive_timeout":1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/opentracing"
}]]
)
ngx.sleep(0.5)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["clickhouse-logger"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/routes/1'))
ngx.say(res.body.node.value.plugins["clickhouse-logger"].password)
}
}
--- response_body
abc123
7ipXoKyiZZUAgf3WWNPI5A==
=== TEST 2: verify
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
GET /opentracing
--- response_body
opentracing
--- error_log
clickhouse body: INSERT INTO t FORMAT JSONEachRow
clickhouse headers: x-clickhouse-key:abc123
clickhouse headers: x-clickhouse-user:default
clickhouse headers: x-clickhouse-database:default
--- wait: 5
=== TEST 3: POST and get list
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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',
ngx.HTTP_POST,
[[{
"plugins": {
"clickhouse-logger": {
"user": "default",
"password": "abc123",
"database": "default",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server",
"batch_max_size":1,
"inactive_timeout":1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/opentracing"
}]]
)
ngx.sleep(0.1)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/routes',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.list[1].value.plugins["clickhouse-logger"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local id = res.list[1].value.id
local key = "/routes/" .. id
local res = assert(etcd.get(key))
ngx.say(res.body.node.value.plugins["clickhouse-logger"].password)
}
}
--- response_body
abc123
7ipXoKyiZZUAgf3WWNPI5A==
=== TEST 4: PATCH
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"clickhouse-logger": {
"user": "default",
"password": "abc123",
"database": "default",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server",
"batch_max_size":1,
"inactive_timeout":1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/opentracing"
}]]
)
ngx.sleep(0.1)
local code, body = t('/apisix/admin/routes/1/plugins',
ngx.HTTP_PATCH,
[[{
"clickhouse-logger": {
"user": "default",
"password": "def456",
"database": "default",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server",
"batch_max_size":1,
"inactive_timeout":1
}
}]]
)
ngx.sleep(0.1)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/routes/1',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["clickhouse-logger"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/routes/1'))
ngx.say(res.body.node.value.plugins["clickhouse-logger"].password)
}
}
--- response_body
def456
3hlZu5mwUbqROm+cy0Vi9A==
=== TEST 5: data encryption work well with services
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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,
[[{
"plugins": {
"clickhouse-logger": {
"user": "default",
"password": "abc123",
"database": "default",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server",
"batch_max_size":1,
"inactive_timeout":1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
ngx.sleep(0.1)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"service_id": "1",
"uri": "/opentracing"
}]]
)
if code >= 300 then
ngx.status = code
return
end
ngx.sleep(0.1)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/services/1',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["clickhouse-logger"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/services/1'))
ngx.say(res.body.node.value.plugins["clickhouse-logger"].password)
}
}
--- response_body
abc123
7ipXoKyiZZUAgf3WWNPI5A==
=== TEST 6: verify
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
GET /opentracing
--- response_body
opentracing
--- error_log
clickhouse body: INSERT INTO t FORMAT JSONEachRow
clickhouse headers: x-clickhouse-key:abc123
clickhouse headers: x-clickhouse-user:default
clickhouse headers: x-clickhouse-database:default
--- wait: 5
=== TEST 7: data encryption work well with plugin_configs
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"clickhouse-logger": {
"user": "default",
"password": "abc123",
"database": "default",
"logtable": "t",
"endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server",
"batch_max_size":1,
"inactive_timeout":1
}
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
ngx.sleep(0.1)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugin_config_id": 1,
"uri": "/opentracing",
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
ngx.sleep(0.1)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["clickhouse-logger"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/plugin_configs/1'))
ngx.say(res.body.node.value.plugins["clickhouse-logger"].password)
}
}
--- response_body
abc123
7ipXoKyiZZUAgf3WWNPI5A==
=== TEST 8: verify
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- request
GET /opentracing
--- response_body
opentracing
--- error_log
clickhouse body: INSERT INTO t FORMAT JSONEachRow
clickhouse headers: x-clickhouse-key:abc123
clickhouse headers: x-clickhouse-user:default
clickhouse headers: x-clickhouse-database:default
--- wait: 5
=== TEST 9: data encryption work well with global rule
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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',
ngx.HTTP_PUT,
[[{
"username": "test",
"plugins": {
"basic-auth": {
"username": "test",
"password": "test"
}
},
"desc": "test description"
}]]
)
if code >= 300 then
ngx.status = code
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
-- sleep for data sync
ngx.sleep(0.5)
-- get plugin conf from admin api, password is decrypted
local code, message, res = t('/apisix/admin/consumers/test',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["basic-auth"].password)
-- get plugin conf from etcd, password is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/test'))
ngx.say(res.body.node.value.plugins["basic-auth"].password)
-- hit the route with authorization
local code, body = t('/hello',
ngx.HTTP_PUT,
nil,
nil,
{Authorization = "Basic dGVzdDp0ZXN0"}
)
if code ~= 200 then
ngx.status = code
return
end
-- delete global rule
t('/apisix/admin/global_rules/1',
ngx.HTTP_DELETE
)
ngx.say(body)
}
}
--- request
GET /t
--- response_body
test
9QKrmTT3TkWGvjlIoe5XXw==
passed
=== TEST 10: data encryption work well with consumer groups
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- 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, 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"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.1)
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
ngx.say(body)
return
end
ngx.sleep(0.1)
-- get plugin conf from admin api, key is decrypted
local code, message, res = t('/apisix/admin/consumers/foobar',
ngx.HTTP_GET
)
res = json.decode(res)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(res.value.plugins["key-auth"].key)
-- get plugin conf from etcd, key is encrypted
local etcd = require("apisix.core.etcd")
local res = assert(etcd.get('/consumers/foobar'))
ngx.say(res.body.node.value.plugins["key-auth"].key)
}
}
--- response_body
auth-two
vU/ZHVJw7b0XscDJ1Fhtig==
=== TEST 11: verify data encryption
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: true
keyring:
- edd1c9f0985e76a2
--- config
location /t {
content_by_lua_block {
local json = require "t.toolkit.json"
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"key-auth": {}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local ress = {}
for i = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {
method = "GET",
headers = {
["apikey"] = "auth-two"
}
})
if not res then
ngx.say(err)
return
end
table.insert(ress, res.status)
end
ngx.say(json.encode(ress))
}
}
--- response_body
[200,200,503]
=== TEST 12: verify whether print warning log when disable data_encryption
--- yaml_config
apisix:
data_encryption:
enable_encrypt_fields: false
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
}
}]]
)
if code > 300 then
ngx.status = code
return
end
ngx.say(body)
}
}
--- reponse_body
passed
--- no_error_log
failed to get schema for plugin

View File

@@ -0,0 +1,360 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use t::APISIX 'no_plan';
repeat_each(1);
#no_long_string();
no_root_location();
log_level('info');
worker_connections(256);
run_tests;
__DATA__
=== TEST 1: add upstream
--- 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": 100,
"127.0.0.1:1981": 100
},
"type": "ewma"
},
"uri": "/ewma"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: about latency
--- timeout: 5
--- config
location /t {
content_by_lua_block {
--node: "127.0.0.1:1980": latency is 0.001
--node: "127.0.0.1:1981": latency is 0.005
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/ewma"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
httpc:set_timeout(1000)
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":1,"port":"1981"},{"count":11,"port":"1980"}]
--- error_code: 200
=== TEST 3: about frequency
--- timeout: 30
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/ewma"
--node: "127.0.0.1:1980": latency is 0.001
--node: "127.0.0.1:1981": latency is 0.005
local ports_count = {}
for i = 1, 2 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
end
--remove the 1981 node,
--add the 1982 node
--keep two nodes for triggering ewma logic in server_picker function of balancer phase
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 100,
"127.0.0.1:1982": 100
},
"type": "ewma"
},
"uri": "/ewma"
}]]
)
if code ~= 200 then
ngx.say("update route failed")
return
end
ngx.sleep(11)
--keep the node 1980 hot
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
end
--recover the 1981 node
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 100,
"127.0.0.1:1981": 100
},
"type": "ewma"
},
"uri": "/ewma"
}]]
)
if code ~= 200 then
ngx.say("update route failed")
return
end
--should select the 1981 node,because it is idle
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ngx.say(require("toolkit.json").encode({port = res.body, count = 1}))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
{"count":1,"port":"1981"}
--- error_code: 200
=== TEST 4: about filter tried servers
--- timeout: 10
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
--remove the 1981 node,
--add the 9527 node (invalid node)
--keep two nodes for triggering ewma logic in server_picker function of balancer phase
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:9527": 1
},
"type": "ewma",
"timeout": {
"connect": 0.1,
"send": 0.5,
"read": 0.5
}
},
"uri": "/ewma"
}]]
)
if code ~= 200 then
ngx.say("update route failed")
return
end
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/ewma"
--should always select the 1980 node, because 0 is invalid
local t = {}
local ports_count = {}
for i = 1, 12 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
httpc:set_timeout(2000)
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- error_code: 200
--- error_log
Connection refused) while connecting to upstream
=== TEST 5: about all endpoints have been retried
--- timeout: 10
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
--add the 9527 node (invalid node)
--add the 9528 node (invalid node)
--keep two nodes for triggering ewma logic in server_picker function of balancer phase
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:9527": 1,
"127.0.0.1:9528": 1
},
"type": "ewma",
"timeout": {
"connect": 0.1,
"send": 0.5,
"read": 0.5
}
},
"uri": "/ewma"
}]]
)
if code ~= 200 then
ngx.say("update route failed")
return
end
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/ewma"
--should always return 502, because both 9527 and 9528 are invalid
local t = {}
local ports_count = {}
for i = 1, 12 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
httpc:set_timeout(2000)
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.status] = (ports_count[res.status] or 0) + 1
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":502}]
--- error_code: 200
--- error_log
Connection refused) while connecting to upstream

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);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set route with filter_func
--- 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",
"filter_func": "function(vars)
return vars['arg_a1'] == 'a1' and vars['arg_a2'] == 'a2'
end",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit route
--- request
GET /hello?a1=a1&a2=a2
--- response_body
hello world
=== TEST 3: miss route
--- request
GET /hello?a1=xxxx&a2=xxxx
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}

View File

@@ -0,0 +1,419 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set 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": {
"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 2: delete 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_DELETE)
ngx.say("passed")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: /not_found
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 5: /not_found
--- request
GET /hello
--- error_code: 503
=== TEST 6: global rule for internal api (should limit)
--- yaml_config
plugins:
- limit-count
- node-status
--- request
GET /apisix/status
--- error_code: 503
=== TEST 7: update 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": {
"response-rewrite": {
"headers": {
"X-VERSION":"1.0"
}
},
"uri-blocker": {
"block_rules": ["select.+(from|limit)", "(?:(union(.*?)select))"]
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: set one more global rule
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/global_rules/2',
ngx.HTTP_PUT,
[[{
"plugins": {
"response-rewrite": {
"headers": {
"X-TEST":"test"
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: hit global rules
--- request
GET /hello?name=;union%20select%20
--- error_code: 403
--- response_headers
X-VERSION: 1.0
X-TEST: test
=== TEST 10: hit global rules by internal api (only check uri-blocker)
--- yaml_config
plugins:
- response-rewrite
- uri-blocker
- node-status
--- request
GET /apisix/status?name=;union%20select%20
--- error_code: 403
--- response_headers
X-VERSION: 1.0
X-TEST: test
=== TEST 11: delete 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_DELETE)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
local code, body = t('/apisix/admin/global_rules/2', ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
end
local code, body = t('/not_found', ngx.HTTP_GET)
ngx.say(code)
local code, body = t('/not_found', ngx.HTTP_GET)
ngx.say(code)
}
}
--- request
GET /t
--- response_body
passed
404
404
=== TEST 12: empty 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": {
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"response-rewrite": {
"body": "changed\n"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
return
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: hit global rules
--- request
GET /hello
--- response_body
changed
=== TEST 14: global rule works with the consumer, after deleting the global rule, ensure no stale plugins remaining
--- 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": {
"basic-auth": {
"username": "test",
"password": "test"
}
},
"desc": "test description"
}]]
)
if code >= 300 then
ngx.status = code
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
-- sleep for data sync
ngx.sleep(0.5)
-- hit the route without authorization, should be 401
local code, body = t('/hello',
ngx.HTTP_PUT
)
if code ~= 401 then
ngx.status = 400
return
end
-- hit the route with authorization
local code, body = t('/hello',
ngx.HTTP_PUT,
nil,
nil,
{Authorization = "Basic dGVzdDp0ZXN0"}
)
if code ~= 200 then
ngx.status = code
return
end
local code, body = t('/apisix/admin/global_rules/1',
ngx.HTTP_DELETE,
[[{
"plugins": {
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
return
end
ngx.sleep(0.5)
-- hit the route with authorization, should be 200
local code, body = t('/hello',
ngx.HTTP_PUT
)
if code ~= 200 then
ngx.status = code
return
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed

View File

@@ -0,0 +1,102 @@
#
# 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;
my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
my $version = eval { `$nginx_binary -V 2>&1` };
if ($version !~ m/\/apisix-nginx-module/) {
plan(skip_all => "apisix-nginx-module not installed");
} else {
plan('no_plan');
}
no_long_string();
no_root_location();
no_shuffle();
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: Unary API grpcs proxy test with mTLS
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpcs
tls:
client_cert: "-----BEGIN CERTIFICATE-----\nMIIDUzCCAjugAwIBAgIURw+Rc5FSNUQWdJD+quORtr9KaE8wDQYJKoZIhvcNAQEN\nBQAwWDELMAkGA1UEBhMCY24xEjAQBgNVBAgMCUd1YW5nRG9uZzEPMA0GA1UEBwwG\nWmh1SGFpMRYwFAYDVQQDDA1jYS5hcGlzaXguZGV2MQwwCgYDVQQLDANvcHMwHhcN\nMjIxMjAxMTAxOTU3WhcNNDIwODE4MTAxOTU3WjBOMQswCQYDVQQGEwJjbjESMBAG\nA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxGjAYBgNVBAMMEWNsaWVu\ndC5hcGlzaXguZGV2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzypq\nkrsJ8MaqpS0kr2SboE9aRKOJzd6mY3AZLq3tFpio5cK5oIHkQLfeaaLcd4ycFcZw\nFTpxc+Eth6I0X9on+j4tEibc5IpDnRSAQlzHZzlrOG6WxcOza4VmfcrKqj27oodr\noqXv05r/5yIoRrEN9ZXfA8n2OnjhkP+C3Q68L6dBtPpv+e6HaAuw8MvcsEo+MQwu\ncTZyWqWT2UzKVzToW29dHRW+yZGuYNWRh15X09VSvx+E0s+uYKzN0Cyef2C6VtBJ\nKmJ3NtypAiPqw7Ebfov2Ym/zzU9pyWPi3P1mYPMKQqUT/FpZSXm4iSy0a5qTYhkF\nrFdV1YuYYZL5YGl9aQIDAQABox8wHTAbBgNVHREEFDASghBhZG1pbi5hcGlzaXgu\nZGV2MA0GCSqGSIb3DQEBDQUAA4IBAQBepRpwWdckZ6QdL5EuufYwU7p5SIqkVL/+\nN4/l5YSjPoAZf/M6XkZu/PsLI9/kPZN/PX4oxjZSDH14dU9ON3JjxtSrebizcT8V\naQ13TeW9KSv/i5oT6qBmj+V+RF2YCUhyzXdYokOfsSVtSlA1qMdm+cv0vkjYcImV\nl3L9nVHRPq15dY9sbmWEtFBWvOzqNSuQYax+iYG+XEuL9SPaYlwKRC6eS/dbXa1T\nPPWDQad2X/WmhxPzEHvjSl2bsZF1u0GEdKyhXWMOLCLiYIJo15G7bMz8cTUvkDN3\n6WaWBd6bd2g13Ho/OOceARpkR/ND8PU78Y8cq+zHoOSqH+1aly5H\n-----END CERTIFICATE-----\n"
client_key: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAzypqkrsJ8MaqpS0kr2SboE9aRKOJzd6mY3AZLq3tFpio5cK5\noIHkQLfeaaLcd4ycFcZwFTpxc+Eth6I0X9on+j4tEibc5IpDnRSAQlzHZzlrOG6W\nxcOza4VmfcrKqj27oodroqXv05r/5yIoRrEN9ZXfA8n2OnjhkP+C3Q68L6dBtPpv\n+e6HaAuw8MvcsEo+MQwucTZyWqWT2UzKVzToW29dHRW+yZGuYNWRh15X09VSvx+E\n0s+uYKzN0Cyef2C6VtBJKmJ3NtypAiPqw7Ebfov2Ym/zzU9pyWPi3P1mYPMKQqUT\n/FpZSXm4iSy0a5qTYhkFrFdV1YuYYZL5YGl9aQIDAQABAoIBAD7tUG//lnZnsj/4\nJXONaORaFj5ROrOpFPuRemS+egzqFCuuaXpC2lV6RHnr+XHq6SKII1WfagTb+lt/\nvs760jfmGQSxf1mAUidtqcP+sKc/Pr1mgi/SUTawz8AYEFWD6PHmlqBSLTYml+La\nckd+0pGtk49wEnYSb9n+cv640hra9AYpm9LXUFaypiFEu+xJhtyKKWkmiVGrt/X9\n3aG6MuYeZplW8Xq1L6jcHsieTOB3T+UBfG3O0bELBgTVexOQYI9O4Ejl9/n5/8WP\nAbIw7PaAYc7fBkwOGh7/qYUdHnrm5o9MiRT6dPxrVSf0PZVACmA+JoNjCPv0Typf\n3MMkHoECgYEA9+3LYzdP8j9iv1fP5hn5K6XZAobCD1mnzv3my0KmoSMC26XuS71f\nvyBhjL7zMxGEComvVTF9SaNMfMYTU4CwOJQxLAuT69PEzW6oVEeBoscE5hwhjj6o\n/lr5jMbt807J9HnldSpwllfj7JeiTuqRcCu/cwqKQQ1aB3YBZ7h5pZkCgYEA1ejo\nKrR1hN2FMhp4pj0nZ5+Ry2lyIVbN4kIcoteaPhyQ0AQ0zNoi27EBRnleRwVDYECi\nXAFrgJU+laKsg1iPjvinHibrB9G2p1uv3BEh6lPl9wPFlENTOjPkqjR6eVVZGP8e\nVzxYxIo2x/QLDUeOpxySdG4pdhEHGfvmdGmr2FECgYBeknedzhCR4HnjcTSdmlTA\nwI+p9gt6XYG0ZIewCymSl89UR9RBUeh++HQdgw0z8r+CYYjfH3SiLUdU5R2kIZeW\nzXiAS55OO8Z7cnWFSI17sRz+RcbLAr3l4IAGoi9MO0awGftcGSc/QiFwM1s3bSSz\nPAzYbjHUpKot5Gae0PCeKQKBgQCHfkfRBQ2LY2WDHxFc+0+Ca6jF17zbMUioEIhi\n/X5N6XowyPlI6MM7tRrBsQ7unX7X8Rjmfl/ByschsTDk4avNO+NfTfeBtGymBYWX\nN6Lr8sivdkwoZZzKOSSWSzdos48ELlThnO/9Ti706Lg3aSQK5iY+aakJiC+fXdfT\n1TtsgQKBgQDRYvtK/Cpaq0W6wO3I4R75lHGa7zjEr4HA0Kk/FlwS0YveuTh5xqBj\nwQz2YyuQQfJfJs7kbWOITBT3vuBJ8F+pktL2Xq5p7/ooIXOGS8Ib4/JAS1C/wb+t\nuJHGva12bZ4uizxdL2Q0/n9ziYTiMc/MMh/56o4Je8RMdOMT5lTsRQ==\n-----END RSA PRIVATE KEY-----\n"
nodes:
"127.0.0.1:10053": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
=== TEST 2: Bidirectional API grpcs proxy test with mTLS
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHelloBidirectionalStream
methods: [
POST
]
upstream:
scheme: grpcs
tls:
client_cert: "-----BEGIN CERTIFICATE-----\nMIIDUzCCAjugAwIBAgIURw+Rc5FSNUQWdJD+quORtr9KaE8wDQYJKoZIhvcNAQEN\nBQAwWDELMAkGA1UEBhMCY24xEjAQBgNVBAgMCUd1YW5nRG9uZzEPMA0GA1UEBwwG\nWmh1SGFpMRYwFAYDVQQDDA1jYS5hcGlzaXguZGV2MQwwCgYDVQQLDANvcHMwHhcN\nMjIxMjAxMTAxOTU3WhcNNDIwODE4MTAxOTU3WjBOMQswCQYDVQQGEwJjbjESMBAG\nA1UECAwJR3VhbmdEb25nMQ8wDQYDVQQHDAZaaHVIYWkxGjAYBgNVBAMMEWNsaWVu\ndC5hcGlzaXguZGV2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzypq\nkrsJ8MaqpS0kr2SboE9aRKOJzd6mY3AZLq3tFpio5cK5oIHkQLfeaaLcd4ycFcZw\nFTpxc+Eth6I0X9on+j4tEibc5IpDnRSAQlzHZzlrOG6WxcOza4VmfcrKqj27oodr\noqXv05r/5yIoRrEN9ZXfA8n2OnjhkP+C3Q68L6dBtPpv+e6HaAuw8MvcsEo+MQwu\ncTZyWqWT2UzKVzToW29dHRW+yZGuYNWRh15X09VSvx+E0s+uYKzN0Cyef2C6VtBJ\nKmJ3NtypAiPqw7Ebfov2Ym/zzU9pyWPi3P1mYPMKQqUT/FpZSXm4iSy0a5qTYhkF\nrFdV1YuYYZL5YGl9aQIDAQABox8wHTAbBgNVHREEFDASghBhZG1pbi5hcGlzaXgu\nZGV2MA0GCSqGSIb3DQEBDQUAA4IBAQBepRpwWdckZ6QdL5EuufYwU7p5SIqkVL/+\nN4/l5YSjPoAZf/M6XkZu/PsLI9/kPZN/PX4oxjZSDH14dU9ON3JjxtSrebizcT8V\naQ13TeW9KSv/i5oT6qBmj+V+RF2YCUhyzXdYokOfsSVtSlA1qMdm+cv0vkjYcImV\nl3L9nVHRPq15dY9sbmWEtFBWvOzqNSuQYax+iYG+XEuL9SPaYlwKRC6eS/dbXa1T\nPPWDQad2X/WmhxPzEHvjSl2bsZF1u0GEdKyhXWMOLCLiYIJo15G7bMz8cTUvkDN3\n6WaWBd6bd2g13Ho/OOceARpkR/ND8PU78Y8cq+zHoOSqH+1aly5H\n-----END CERTIFICATE-----\n"
client_key: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAzypqkrsJ8MaqpS0kr2SboE9aRKOJzd6mY3AZLq3tFpio5cK5\noIHkQLfeaaLcd4ycFcZwFTpxc+Eth6I0X9on+j4tEibc5IpDnRSAQlzHZzlrOG6W\nxcOza4VmfcrKqj27oodroqXv05r/5yIoRrEN9ZXfA8n2OnjhkP+C3Q68L6dBtPpv\n+e6HaAuw8MvcsEo+MQwucTZyWqWT2UzKVzToW29dHRW+yZGuYNWRh15X09VSvx+E\n0s+uYKzN0Cyef2C6VtBJKmJ3NtypAiPqw7Ebfov2Ym/zzU9pyWPi3P1mYPMKQqUT\n/FpZSXm4iSy0a5qTYhkFrFdV1YuYYZL5YGl9aQIDAQABAoIBAD7tUG//lnZnsj/4\nJXONaORaFj5ROrOpFPuRemS+egzqFCuuaXpC2lV6RHnr+XHq6SKII1WfagTb+lt/\nvs760jfmGQSxf1mAUidtqcP+sKc/Pr1mgi/SUTawz8AYEFWD6PHmlqBSLTYml+La\nckd+0pGtk49wEnYSb9n+cv640hra9AYpm9LXUFaypiFEu+xJhtyKKWkmiVGrt/X9\n3aG6MuYeZplW8Xq1L6jcHsieTOB3T+UBfG3O0bELBgTVexOQYI9O4Ejl9/n5/8WP\nAbIw7PaAYc7fBkwOGh7/qYUdHnrm5o9MiRT6dPxrVSf0PZVACmA+JoNjCPv0Typf\n3MMkHoECgYEA9+3LYzdP8j9iv1fP5hn5K6XZAobCD1mnzv3my0KmoSMC26XuS71f\nvyBhjL7zMxGEComvVTF9SaNMfMYTU4CwOJQxLAuT69PEzW6oVEeBoscE5hwhjj6o\n/lr5jMbt807J9HnldSpwllfj7JeiTuqRcCu/cwqKQQ1aB3YBZ7h5pZkCgYEA1ejo\nKrR1hN2FMhp4pj0nZ5+Ry2lyIVbN4kIcoteaPhyQ0AQ0zNoi27EBRnleRwVDYECi\nXAFrgJU+laKsg1iPjvinHibrB9G2p1uv3BEh6lPl9wPFlENTOjPkqjR6eVVZGP8e\nVzxYxIo2x/QLDUeOpxySdG4pdhEHGfvmdGmr2FECgYBeknedzhCR4HnjcTSdmlTA\nwI+p9gt6XYG0ZIewCymSl89UR9RBUeh++HQdgw0z8r+CYYjfH3SiLUdU5R2kIZeW\nzXiAS55OO8Z7cnWFSI17sRz+RcbLAr3l4IAGoi9MO0awGftcGSc/QiFwM1s3bSSz\nPAzYbjHUpKot5Gae0PCeKQKBgQCHfkfRBQ2LY2WDHxFc+0+Ca6jF17zbMUioEIhi\n/X5N6XowyPlI6MM7tRrBsQ7unX7X8Rjmfl/ByschsTDk4avNO+NfTfeBtGymBYWX\nN6Lr8sivdkwoZZzKOSSWSzdos48ELlThnO/9Ti706Lg3aSQK5iY+aakJiC+fXdfT\n1TtsgQKBgQDRYvtK/Cpaq0W6wO3I4R75lHGa7zjEr4HA0Kk/FlwS0YveuTh5xqBj\nwQz2YyuQQfJfJs7kbWOITBT3vuBJ8F+pktL2Xq5p7/ooIXOGS8Ib4/JAS1C/wb+t\nuJHGva12bZ4uizxdL2Q0/n9ziYTiMc/MMh/56o4Je8RMdOMT5lTsRQ==\n-----END RSA PRIVATE KEY-----\n"
nodes:
"127.0.0.1:10053": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHelloBidirectionalStream
--- response_body
{
"message": "Hello apisix"
}
{
"message": "stream ended"
}

View File

@@ -0,0 +1,134 @@
#
# 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 /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: Test server side streaming method through gRPC proxy
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHelloServerStream
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHelloServerStream
--- response_body
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
=== TEST 2: Test client side streaming method through gRPC proxy
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHelloClientStream
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"} {"name":"apisix"} {"name":"apisix"} {"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHelloClientStream
--- response_body
{
"message": "Hello apisix!Hello apisix!Hello apisix!Hello apisix!"
}
=== TEST 3: Test bidirectional streaming method through gRPC proxy
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHelloBidirectionalStream
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"} {"name":"apisix"} {"name":"apisix"} {"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHelloBidirectionalStream
--- response_body
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
{
"message": "Hello apisix"
}
{
"message": "stream ended"
}

View File

@@ -0,0 +1,142 @@
#
# 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 /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests;
__DATA__
=== TEST 1: Unary API gRPC proxy
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
=== TEST 2: Unary API gRPC proxy test [the old way]
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
=== TEST 3: Unary API grpcs proxy test
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpcs
nodes:
"127.0.0.1:10052": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
=== TEST 4: Unary API gRPC proxy with tls
--- http2
--- apisix_yaml
ssls:
-
id: 1
cert: "-----BEGIN CERTIFICATE-----\nMIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV\nBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G\nA1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa\nGA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n\nRG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM\nCHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe\ncvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb\nVDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR\n2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr\nabf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2\nWjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/\nEvm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1\n/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh\n/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj\ncTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ\ntSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl\nc3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC\ntC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY\n1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl\nPYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob\nrJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy\nhme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1\n7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y\nIJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve\nU/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=\n-----END CERTIFICATE-----\n"
key: "-----BEGIN RSA PRIVATE KEY-----\nMIIG5AIBAAKCAYEAyCM0rqJecvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5\njhZB3W6BkWUWR4oNFLLSqcVbVDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfo\neLj0efMiOepOSZflj9Ob4yKR2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5s\nmPtW1Oc/BV5terhscJdOgmRrabf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt\n6iMWEGeQU6mwPENgvj1olji2WjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiy\nVt1TmtMWn1ztk6FfLRqwJWR/Evm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1o\nnpRVeXhrBajbCRDRBMwaNw/1/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2\nfzaqpIfyUbPST4GdqNG9NyIh/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI\n1cGrGwyXbrieNp63AgMBAAECggGBAJM8g0duoHmIYoAJzbmKe4ew0C5fZtFUQNmu\nO2xJITUiLT3ga4LCkRYsdBnY+nkK8PCnViAb10KtIT+bKipoLsNWI9Xcq4Cg4G3t\n11XQMgPPgxYXA6m8t+73ldhxrcKqgvI6xVZmWlKDPn+CY/Wqj5PA476B5wEmYbNC\nGIcd1FLl3E9Qm4g4b/sVXOHARF6iSvTR+6ol4nfWKlaXSlx2gNkHuG8RVpyDsp9c\nz9zUqAdZ3QyFQhKcWWEcL6u9DLBpB/gUjyB3qWhDMe7jcCBZR1ALyRyEjmDwZzv2\njlv8qlLFfn9R29UI0pbuL1eRAz97scFOFme1s9oSU9a12YHfEd2wJOM9bqiKju8y\nDZzePhEYuTZ8qxwiPJGy7XvRYTGHAs8+iDlG4vVpA0qD++1FTpv06cg/fOdnwshE\nOJlEC0ozMvnM2rZ2oYejdG3aAnUHmSNa5tkJwXnmj/EMw1TEXf+H6+xknAkw05nh\nzsxXrbuFUe7VRfgB5ElMA/V4NsScgQKBwQDmMRtnS32UZjw4A8DsHOKFzugfWzJ8\nGc+3sTgs+4dNIAvo0sjibQ3xl01h0BB2Pr1KtkgBYB8LJW/FuYdCRS/KlXH7PHgX\n84gYWImhNhcNOL3coO8NXvd6+m+a/Z7xghbQtaraui6cDWPiCNd/sdLMZQ/7LopM\nRbM32nrgBKMOJpMok1Z6zsPzT83SjkcSxjVzgULNYEp03uf1PWmHuvjO1yELwX9/\ngoACViF+jst12RUEiEQIYwr4y637GQBy+9cCgcEA3pN9W5OjSPDVsTcVERig8++O\nBFURiUa7nXRHzKp2wT6jlMVcu8Pb2fjclxRyaMGYKZBRuXDlc/RNO3uTytGYNdC2\nIptU5N4M7iZHXj190xtDxRnYQWWo/PR6EcJj3f/tc3Itm1rX0JfuI3JzJQgDb9Z2\ns/9/ub8RRvmQV9LM/utgyOwNdf5dyVoPcTY2739X4ZzXNH+CybfNa+LWpiJIVEs2\ntxXbgZrhmlaWzwA525nZ0UlKdfktdcXeqke9eBghAoHARVTHFy6CjV7ZhlmDEtqE\nU58FBOS36O7xRDdpXwsHLnCXhbFu9du41mom0W4UdzjgVI9gUqG71+SXrKr7lTc3\ndMHcSbplxXkBJawND/Q1rzLG5JvIRHO1AGJLmRgIdl8jNgtxgV2QSkoyKlNVbM2H\nWy6ZSKM03lIj74+rcKuU3N87dX4jDuwV0sPXjzJxL7NpR/fHwgndgyPcI14y2cGz\nzMC44EyQdTw+B/YfMnoZx83xaaMNMqV6GYNnTHi0TO2TAoHBAKmdrh9WkE2qsr59\nIoHHygh7Wzez+Ewr6hfgoEK4+QzlBlX+XV/9rxIaE0jS3Sk1txadk5oFDebimuSk\nlQkv1pXUOqh+xSAwk5v88dBAfh2dnnSa8HFN3oz+ZfQYtnBcc4DR1y2X+fVNgr3i\nnxruU2gsAIPFRnmvwKPc1YIH9A6kIzqaoNt1f9VM243D6fNzkO4uztWEApBkkJgR\n4s/yOjp6ovS9JG1NMXWjXQPcwTq3sQVLnAHxZRJmOvx69UmK4QKBwFYXXjeXiU3d\nbcrPfe6qNGjfzK+BkhWznuFUMbuxyZWDYQD5yb6ukUosrj7pmZv3BxKcKCvmONU+\nCHgIXB+hG+R9S2mCcH1qBQoP/RSm+TUzS/Bl2UeuhnFZh2jSZQy3OwryUi6nhF0u\nLDzMI/6aO1ggsI23Ri0Y9ZtqVKczTkxzdQKR9xvoNBUufjimRlS80sJCEB3Qm20S\nwzarryret/7GFW1/3cz+hTj9/d45i25zArr3Pocfpur5mfz3fJO8jg==\n-----END RSA PRIVATE KEY-----\n"
sni: test.com
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -insecure -d '{"name":"apisix"}' test.com:1994 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}

View File

@@ -0,0 +1,287 @@
#
# 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';
# As the test framework doesn't support sending grpc request, this
# test file is only for grpc irrelative configuration check.
# To avoid confusion, we configure a closed port so if th configuration works,
# the result will be `connect refused`.
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
my $yaml_config = $block->yaml_config // <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
if (!$block->request) {
$block->set_value("request", "POST /hello");
}
});
run_tests();
__DATA__
=== TEST 1: with upstream_id
--- apisix_yaml
upstreams:
- id: 1
type: roundrobin
scheme: grpc
nodes:
"127.0.0.1:9088": 1
routes:
- id: 1
methods:
- POST
uri: "/hello"
upstream_id: 1
#END
--- error_code: 502
--- error_log
proxy request to 127.0.0.1:9088
=== TEST 2: with consumer
--- apisix_yaml
consumers:
- username: jack
plugins:
key-auth:
key: user-key
#END
routes:
- id: 1
methods:
- POST
uri: "/hello"
plugins:
key-auth:
consumer-restriction:
whitelist:
- jack
upstream:
scheme: grpc
type: roundrobin
nodes:
"127.0.0.1:9088": 1
#END
--- more_headers
apikey: user-key
--- error_code: 502
--- error_log
Connection refused
=== TEST 3: with upstream_id (old way)
--- apisix_yaml
upstreams:
- id: 1
type: roundrobin
scheme: grpc
nodes:
"127.0.0.1:9088": 1
routes:
- id: 1
methods:
- POST
uri: "/hello"
upstream_id: 1
#END
--- error_code: 502
--- error_log
proxy request to 127.0.0.1:9088
=== TEST 4: with consumer (old way)
--- apisix_yaml
consumers:
- username: jack
plugins:
key-auth:
key: user-key
#END
routes:
- id: 1
methods:
- POST
uri: "/hello"
plugins:
key-auth:
consumer-restriction:
whitelist:
- jack
upstream:
type: roundrobin
scheme: grpc
nodes:
"127.0.0.1:9088": 1
#END
--- more_headers
apikey: user-key
--- error_code: 502
--- error_log
Connection refused
=== TEST 5: use 443 as the grpcs' default port
--- apisix_yaml
routes:
-
uri: /hello
upstream:
scheme: grpcs
nodes:
"127.0.0.1": 1
type: roundrobin
#END
--- request
GET /hello
--- error_code: 502
--- error_log
connect() failed (111: Connection refused) while connecting to upstream
=== TEST 6: use 80 as the grpc's default port
--- apisix_yaml
routes:
-
uri: /hello
upstream:
scheme: grpc
nodes:
"127.0.0.1": 1
type: roundrobin
#END
--- request
GET /hello
--- error_code: 502
--- error_log
connect() failed (111: Connection refused) while connecting to upstream
=== TEST 7: set authority header
--- log_level: debug
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
--- grep_error_log eval
qr/grpc header: "(:authority|host): [^"]+"/
--- grep_error_log_out eval
qr/grpc header: "(:authority|host): 127.0.0.1:1984"/
=== TEST 8: set authority header to node header
--- log_level: debug
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpc
pass_host: node
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
--- grep_error_log eval
qr/grpc header: "(:authority|host): [^"]+"/
--- grep_error_log_out eval
qr/grpc header: "(:authority|host): 127.0.0.1:10051"/
=== TEST 9: set authority header to specific value
--- log_level: debug
--- http2
--- apisix_yaml
routes:
-
id: 1
uris:
- /helloworld.Greeter/SayHello
methods: [
POST
]
upstream:
scheme: grpc
pass_host: rewrite
upstream_host: hello.world
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}
--- grep_error_log eval
qr/grpc header: "(:authority|host): [^"]+"/
--- grep_error_log_out eval
qr/grpc header: "(:authority|host): hello.world"/

View File

@@ -0,0 +1,201 @@
#
# 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_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->yaml_config) {
my $yaml_config = <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
}
if ($block->apisix_yaml) {
my $upstream = <<_EOC_;
upstreams:
- service_name: mock
discovery_type: mock
type: roundrobin
id: 1
checks:
active:
http_path: "/status"
host: 127.0.0.1
port: 1988
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 1
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $upstream);
}
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(1.5)
ngx.say(res.status)
}
}
--- grep_error_log eval
qr/unhealthy TCP increment \(1\/2\) for '127.0.0.1\([^)]+\)'/
--- grep_error_log_out
unhealthy TCP increment (1/2) for '127.0.0.1(127.0.0.1:1988)'
unhealthy TCP increment (1/2) for '127.0.0.1(0.0.0.0:1988)'
=== TEST 2: create new checker when nodes change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(0.5)
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "127.0.0.2", port = 1980, weight = 1},
{host = "127.0.0.3", port = 1980, weight = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
}
}
--- grep_error_log eval
qr/(create new checker|try to release checker): table/
--- grep_error_log_out
create new checker: table
try to release checker: table
create new checker: table
=== TEST 3: don't create new checker when nodes don't change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(0.5)
discovery.mock = {
nodes = function()
return {
{host = "0.0.0.0", port = 1980, weight = 1},
{host = "127.0.0.1", port = 1980, weight = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
}
}
--- grep_error_log eval
qr/(create new checker|try to release checker): table/
--- grep_error_log_out
create new checker: table

View File

@@ -0,0 +1,341 @@
#
# 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();
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->http_config) {
my $http_config = <<'_EOC_';
server {
listen 8765 ssl;
ssl_certificate ../../certs/mtls_server.crt;
ssl_certificate_key ../../certs/mtls_server.key;
ssl_client_certificate ../../certs/mtls_ca.crt;
location /ping {
return 200 '8765';
}
location /healthz {
return 200 'ok';
}
}
server {
listen 8766 ssl;
ssl_certificate ../../certs/mtls_server.crt;
ssl_certificate_key ../../certs/mtls_server.key;
ssl_client_certificate ../../certs/mtls_ca.crt;
location /ping {
return 200 '8766';
}
location /healthz {
return 500;
}
}
server {
listen 8767 ssl;
ssl_certificate ../../certs/mtls_server.crt;
ssl_certificate_key ../../certs/mtls_server.key;
ssl_client_certificate ../../certs/mtls_ca.crt;
location /ping {
return 200 '8766';
}
location /healthz {
return 200 'ok';
}
}
server {
listen 8768 ssl;
ssl_certificate ../../certs/mtls_server.crt;
ssl_certificate_key ../../certs/mtls_server.key;
ssl_client_certificate ../../certs/mtls_ca.crt;
location /ping {
return 200 '8766';
}
location /healthz {
return 500;
}
}
_EOC_
$block->set_value("http_config", $http_config);
}
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests;
__DATA__
=== TEST 1: https health check (two health nodes)
--- config
location /t {
lua_ssl_trusted_certificate ../../certs/mtls_ca.crt;
content_by_lua_block {
local t = require("lib.test_admin")
local core = require("apisix.core")
local cert = t.read_file("t/certs/mtls_client.crt")
local key = t.read_file("t/certs/mtls_client.key")
local data = {
uri = "/ping",
upstream = {
scheme = "https",
nodes = {
["127.0.0.1:8765"] = 1,
["127.0.0.1:8767"] = 1
},
tls = {
client_cert = cert,
client_key = key
},
retries = 2,
checks = {
active = {
type = "https",
http_path = "/healthz",
https_verify_certificate = false,
healthy = {
interval = 1,
successes = 1
},
unhealthy = {
interval = 1,
http_failures = 1
},
}
}
}
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT, core.json.encode(data))
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local http = require("resty.http")
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/ping"
local _, _ = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(0.5)
local healthcheck_uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/v1/healthcheck/routes/1"
local httpc = http.new()
local res, _ = httpc:request_uri(healthcheck_uri, {method = "GET", keepalive = false})
local json_data = core.json.decode(res.body)
assert(json_data.type == "https")
assert(#json_data.nodes == 2)
local function check_node_health(port, status)
for _, node in ipairs(json_data.nodes) do
if node.port == port and node.status == status then
return true
end
end
return false
end
assert(check_node_health(8765, "healthy"), "Port 8765 is not healthy")
assert(check_node_health(8767, "healthy"), "Port 8767 is not healthy")
}
}
--- request
GET /t
--- error_code: 200
=== TEST 2: https health check (one healthy node, one unhealthy node)
--- config
location /t {
lua_ssl_trusted_certificate ../../certs/mtls_ca.crt;
content_by_lua_block {
local t = require("lib.test_admin")
local core = require("apisix.core")
local cert = t.read_file("t/certs/mtls_client.crt")
local key = t.read_file("t/certs/mtls_client.key")
local data = {
uri = "/ping",
upstream = {
scheme = "https",
nodes = {
["127.0.0.1:8765"] = 1,
["127.0.0.1:8766"] = 1
},
tls = {
client_cert = cert,
client_key = key
},
retries = 2,
checks = {
active = {
type = "https",
http_path = "/healthz",
https_verify_certificate = false,
healthy = {
interval = 1,
successes = 1
},
unhealthy = {
interval = 1,
http_failures = 1
},
}
}
}
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT, core.json.encode(data))
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local http = require("resty.http")
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/ping"
local _, _ = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(1.5)
local healthcheck_uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/v1/healthcheck/routes/1"
local httpc = http.new()
local res, _ = httpc:request_uri(healthcheck_uri, {method = "GET", keepalive = false})
local json_data = core.json.decode(res.body)
assert(json_data.type == "https")
assert(#json_data.nodes == 2)
local function check_node_health(port, status)
for _, node in ipairs(json_data.nodes) do
if node.port == port and node.status == status then
return true
end
end
return false
end
assert(check_node_health(8765, "healthy"), "Port 8765 is not healthy")
assert(check_node_health(8766, "unhealthy"), "Port 8766 is not unhealthy")
}
}
--- request
GET /t
--- grep_error_log eval
qr/\([^)]+\) unhealthy .* for '.*'/
--- grep_error_log_out
(upstream#/apisix/routes/1) unhealthy HTTP increment (1/1) for '127.0.0.1(127.0.0.1:8766)'
=== TEST 3: https health check (two unhealthy nodes)
--- config
location /t {
lua_ssl_trusted_certificate ../../certs/mtls_ca.crt;
content_by_lua_block {
local t = require("lib.test_admin")
local core = require("apisix.core")
local cert = t.read_file("t/certs/mtls_client.crt")
local key = t.read_file("t/certs/mtls_client.key")
local data = {
uri = "/ping",
upstream = {
scheme = "https",
nodes = {
["127.0.0.1:8766"] = 1,
["127.0.0.1:8768"] = 1
},
tls = {
client_cert = cert,
client_key = key
},
retries = 2,
checks = {
active = {
type = "https",
http_path = "/healthz",
https_verify_certificate = false,
healthy = {
interval = 1,
successes = 1
},
unhealthy = {
interval = 1,
http_failures = 1
},
}
}
}
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT, core.json.encode(data))
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local http = require("resty.http")
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/ping"
local _, _ = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(1.5)
local healthcheck_uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/v1/healthcheck/routes/1"
local httpc = http.new()
local res, _ = httpc:request_uri(healthcheck_uri, {method = "GET", keepalive = false})
local json_data = core.json.decode(res.body)
assert(json_data.type == "https")
assert(#json_data.nodes == 2)
local function check_node_health(port, status)
for _, node in ipairs(json_data.nodes) do
if node.port == port and node.status == status then
return true
end
end
return false
end
assert(check_node_health(8766, "unhealthy"), "Port 8766 is not unhealthy")
assert(check_node_health(8768, "unhealthy"), "Port 8768 is not unhealthy")
}
}
--- request
GET /t
--- error_code: 200

View File

@@ -0,0 +1,148 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
add_block_preprocessor(sub {
my $block = shift;
$block->set_value("listen_ipv6", 1);
});
run_tests();
__DATA__
=== TEST 1: set route(two upstream node: one healthy + one unhealthy)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1970": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 2: hit routes (two upstream node: one healthy + one unhealthy)
--- config
location /t {
content_by_lua_block {
ngx.sleep(3) -- wait for new workers replacement to complete
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.log(ngx.ERR, "It works")
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
ngx.log(ngx.ERR, "req ", i)
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ngx.log(ngx.ERR, "req ", i, " ", res.body)
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/unhealthy .* for '.*'/
--- grep_error_log_out
unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
--- timeout: 10

View File

@@ -0,0 +1,112 @@
#
# 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);
log_level('warn');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: ensure the old check is cleared after configuration updated
--- extra_init_worker_by_lua
local healthcheck = require("resty.healthcheck")
local new = healthcheck.new
healthcheck.new = function(...)
local obj = new(...)
local clear = obj.delayed_clear
obj.delayed_clear = function(...)
ngx.log(ngx.WARN, "clear checker")
return clear(...)
end
return obj
end
--- extra_init_by_lua
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" then
return {address = "127.0.0." .. count}
end
if domain == "test2.com" then
return {address = "127.0.0." .. count+100}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local cfg = [[{
"upstream": {
"nodes": {
"test1.com:1980": 1,
"test2.com:1980": 1
},
"type": "roundrobin",
"checks":{
"active":{
"healthy":{
"http_statuses":[
200,
302
],
"interval":1,
"successes":2
},
"http_path":"/hello",
"timeout":1,
"type":"http",
"unhealthy":{
"http_failures":5,
"http_statuses":[
429,
404,
500,
501,
502,
503,
504,
505
],
"interval":1,
"tcp_failures":2,
"timeouts":3
}
}
}
},
"uri": "/hello"
}]]
local t = require("lib.test_admin").test
assert(t('/apisix/admin/routes/1', ngx.HTTP_PUT, cfg) < 300)
t('/hello', ngx.HTTP_GET)
assert(t('/apisix/admin/routes/1', ngx.HTTP_PUT, cfg) < 300)
ngx.sleep(1)
}
}
--- request
GET /t
--- error_log
clear checker

View File

@@ -0,0 +1,141 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
workers(2);
worker_connections(256);
run_tests();
__DATA__
=== TEST 1: set route(two upstream node: one healthy + one unhealthy)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1970": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 2: hit routes (two upstream node: one healthy + one unhealthy)
--- config
location /t {
content_by_lua_block {
ngx.sleep(3) -- wait for new workers replacement to complete
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/unhealthy TCP increment/
--- grep_error_log_out
unhealthy TCP increment
unhealthy TCP increment
--- timeout: 20

View File

@@ -0,0 +1,382 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_EVENTS_MODULE} ne "lua-resty-events") {
$SkipReason = "Only for lua-resty-events events module";
}
}
use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : ();
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
run_tests();
__DATA__
=== TEST 1: set route(passive)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 100,
"successes": 1
},
"unhealthy": {
"interval": 100,
"http_failures": 2
}
},]] .. [[
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [502],
"http_failures": 1,
"tcp_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes (two healthy nodes)
--- config
location /t {
content_by_lua_block {
ngx.sleep(3) -- wait for sync
local json_sort = require("toolkit.json")
local http = require("resty.http")
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/server_port"
local httpc = http.new()
-- Since a failed request attempt triggers a passive health check to report
-- a non-health condition, a request is first triggered manually here to
-- trigger a passive health check to refresh the monitoring state of the build
--
-- The reason for this is to avoid delays in event synchronization timing due
-- to non-deterministic asynchronous connections when using lua-resty-events
-- as an events module.
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ngx.sleep(1) -- Wait for health check unhealthy events sync
local ports_count = {}
for i = 1, 6 do
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
local status = tostring(res.status)
ports_count[status] = (ports_count[status] or 0) + 1
end
ngx.say(json_sort.encode(ports_count))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
{"200":5,"502":1}
--- error_log
(upstream#/apisix/routes/1) unhealthy HTTP increment (1/1)
--- timeout: 10
=== TEST 3: set route(only passive)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [502],
"http_failures": 1,
"tcp_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- 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 4: set route(only active + active & passive)
--- 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",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 100,
"successes": 1
},
"unhealthy": {
"interval": 100,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"uri": "/hello_",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 100,
"successes": 1
},
"unhealthy": {
"interval": 100,
"http_failures": 2
}
},]] .. [[
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [502],
"http_failures": 1,
"tcp_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: only one route should have passive healthcheck
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json_sort = require("toolkit.json")
local http = require("resty.http")
local uri = "http://127.0.0.1:" .. ngx.var.server_port
local ports_count = {}
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello_")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
-- only /hello_ has passive healthcheck
local res, err = httpc:request_uri(uri .. "/hello")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
502
502
--- grep_error_log eval
qr/enabled healthcheck passive/
--- grep_error_log_out
enabled healthcheck passive
=== TEST 6: make sure passive healthcheck works (conf is not corrupted by the default value)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json_sort = require("toolkit.json")
local http = require("resty.http")
local uri = "http://127.0.0.1:" .. ngx.var.server_port
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
-- The first time request to /hello_
-- Ensure that the event that triggers the healthchecker to perform
-- add_target has been sent and processed correctly
--
-- Due to the implementation of lua-resty-events, it relies on the kernel and
-- the Nginx event loop to process socket connections.
-- When lua-resty-healthcheck handles passive healthchecks and uses lua-resty-events
-- as the events module, the synchronization of the first event usually occurs
-- before the start of the passive healthcheck. So when the execution finishes and
-- healthchecker tries to record the healthcheck status, it will not be able to find
-- an existing target (because the synchronization event has not finished yet), which
-- will lead to some anomalies that deviate from the original test case, so compatibility
-- operations are performed here.
local res, err = httpc:request_uri(uri .. "/hello_")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
ngx.sleep(1) -- Wait for health check unhealthy events sync
-- The second time request to /hello_
local res, err = httpc:request_uri(uri .. "/hello_")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
502
502
502
--- grep_error_log eval
qr/\[healthcheck\] \([^)]+\) unhealthy HTTP increment/
--- grep_error_log_out
[healthcheck] (upstream#/apisix/routes/2) unhealthy HTTP increment

View File

@@ -0,0 +1,344 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_EVENTS_MODULE} ne "lua-resty-worker-events") {
$SkipReason = "Only for lua-resty-worker-events events module";
}
}
use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : ();
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
run_tests();
__DATA__
=== TEST 1: set route(passive)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 100,
"successes": 1
},
"unhealthy": {
"interval": 100,
"http_failures": 2
}
},]] .. [[
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [502],
"http_failures": 1,
"tcp_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes (two healthy nodes)
--- config
location /t {
content_by_lua_block {
ngx.sleep(1) -- wait for sync
local json_sort = require("toolkit.json")
local http = require("resty.http")
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/server_port"
local ports_count = {}
for i = 1, 6 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
local status = tostring(res.status)
ports_count[status] = (ports_count[status] or 0) + 1
end
ngx.say(json_sort.encode(ports_count))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
{"200":5,"502":1}
--- error_log
(upstream#/apisix/routes/1) unhealthy HTTP increment (1/1)
=== TEST 3: set route(only passive)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [502],
"http_failures": 1,
"tcp_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- 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 4: set route(only active + active & passive)
--- 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",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 100,
"successes": 1
},
"unhealthy": {
"interval": 100,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"uri": "/hello_",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 0,
"127.0.0.1:1": 1
},
"retries": 0,
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 100,
"successes": 1
},
"unhealthy": {
"interval": 100,
"http_failures": 2
}
},]] .. [[
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [502],
"http_failures": 1,
"tcp_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: only one route should have passive healthcheck
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json_sort = require("toolkit.json")
local http = require("resty.http")
local uri = "http://127.0.0.1:" .. ngx.var.server_port
local ports_count = {}
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello_")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
-- only /hello_ has passive healthcheck
local res, err = httpc:request_uri(uri .. "/hello")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
502
502
--- grep_error_log eval
qr/enabled healthcheck passive/
--- grep_error_log_out
enabled healthcheck passive
=== TEST 6: make sure passive healthcheck works (conf is not corrupted by the default value)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local json_sort = require("toolkit.json")
local http = require("resty.http")
local uri = "http://127.0.0.1:" .. ngx.var.server_port
local ports_count = {}
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
local res, err = httpc:request_uri(uri .. "/hello_")
if not res then
ngx.say(err)
return
end
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
502
502
--- grep_error_log eval
qr/\[healthcheck\] \([^)]+\) unhealthy HTTP increment/
--- grep_error_log_out
[healthcheck] (upstream#/apisix/routes/2) unhealthy HTTP increment

View File

@@ -0,0 +1,253 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
# the healthcheck stop test requires exiting worker to keep watching etcd for a while,
# which is not the case when using gRPC.
my $yaml_config = <<_EOC_;
deployment:
role: traditional
role_traditional:
config_provider: etcd
etcd:
prefix: "/apisix"
host:
- "http://127.0.0.1:2379"
use_grpc: false
admin:
admin_key: null
_EOC_
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->yaml_config) {
$block->set_value("yaml_config", $yaml_config);
}
});
run_tests();
__DATA__
=== TEST 1: set route(two healthy upstream nodes)
--- request
PUT /apisix/admin/routes/1
{"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","host":"foo.com","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}}
--- error_code_like: ^20\d$
=== TEST 2: update + delete
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, status, body = t('/apisix/admin/routes/1',
"PUT",
[[{"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}}]]
)
if code < 300 then
code = 200
end
ngx.say("1 code: ", code)
ngx.sleep(0.2)
local code, body = t('/server_port', "GET")
ngx.say("2 code: ", code)
ngx.sleep(0.2)
code = t('/apisix/admin/routes/1', "DELETE")
ngx.say("3 code: ", code)
ngx.sleep(0.2)
local code, body = t('/server_port', "GET")
ngx.say("4 code: ", code)
}
}
--- request
GET /t
--- response_body
1 code: 200
2 code: 200
3 code: 200
4 code: 404
--- grep_error_log eval
qr/create new checker: table: 0x|try to release checker: table: 0x/
--- grep_error_log_out
create new checker: table: 0x
try to release checker: table: 0x
=== TEST 3: set route(two healthy upstream nodes)
--- request
PUT /apisix/admin/routes/1
{"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","host":"foo.com","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}}
--- error_code: 201
=== TEST 4: update
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/server_port', "GET")
ngx.say("1 code: ", code)
local code, status, body = t('/apisix/admin/routes/1',
"PUT",
[[{"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}}]]
)
if code < 300 then
code = 200
end
ngx.say("2 code: ", code)
ngx.sleep(0.2)
local code, body = t('/server_port', "GET")
ngx.say("3 code: ", code)
}
}
--- request
GET /t
--- response_body
1 code: 200
2 code: 200
3 code: 200
--- grep_error_log eval
qr/create new checker: table: 0x|try to release checker: table: 0x/
--- grep_error_log_out
create new checker: table: 0x
try to release checker: table: 0x
create new checker: table: 0x
=== TEST 5: update + delete for /upstreams
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, _, body = t('/apisix/admin/upstreams/stopchecker',
"PUT",
[[{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}]]
)
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
local code, _, body = t('/apisix/admin/routes/1',
"PUT",
[[{"uri":"/server_port","upstream_id":"stopchecker"}]]
)
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.2)
code, _, body = t('/server_port', "GET")
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5)
-- update
code, _, body = t('/apisix/admin/upstreams/stopchecker',
"PUT",
[[{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/void","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":1}}}}]]
)
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.2)
code, _, body = t('/server_port', "GET")
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
-- delete
code, _, body = t('/apisix/admin/routes/1', "DELETE")
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5) -- wait for routes delete event synced
code, _, body = t('/apisix/admin/upstreams/stopchecker', "DELETE")
if code > 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.say("ok")
}
}
--- request
GET /t
--- response_body
ok
--- grep_error_log eval
qr/create new checker: table: 0x|try to release checker: table: 0x/
--- grep_error_log_out
create new checker: table: 0x
try to release checker: table: 0x
create new checker: table: 0x
try to release checker: table: 0x

View File

@@ -0,0 +1,916 @@
#
# 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);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
run_tests();
__DATA__
=== TEST 1: set route(two healthy upstream nodes)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 2: hit routes (two healthy nodes)
--- config
location /t {
content_by_lua_block {
ngx.sleep(3) -- wait for sync
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
-- hit route before start test loop
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
local ports_count = {}
for i = 1, 12 do
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":6,"port":"1981"},{"count":6,"port":"1980"}]
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
--- timeout: 10
=== TEST 3: set route(two upstream node: one healthy + one unhealthy)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1970": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 4: hit routes (two upstream node: one healthy + one unhealthy)
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/\([^)]+\) unhealthy .* for '.*'/
--- grep_error_log_out
(upstream#/apisix/routes/1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
(upstream#/apisix/routes/1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
--- timeout: 10
=== TEST 5: chash route (two healthy nodes)
--- 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": "/server_port",
"upstream": {
"type": "chash",
"nodes": {
"127.0.0.1:1981": 1,
"127.0.0.1:1980": 1
},
"key": "remote_addr",
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 6: hit routes (two healthy nodes)
--- config
location /t {
content_by_lua_block {
ngx.sleep(2) -- wait for sync
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
--- timeout: 6
=== TEST 7: chash route (upstream nodes: 1 healthy + 8 unhealthy)
--- 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": "/server_port",
"upstream": {
"type": "chash",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1970": 1,
"127.0.0.1:1971": 1,
"127.0.0.1:1972": 1,
"127.0.0.1:1973": 1,
"127.0.0.1:1974": 1,
"127.0.0.1:1975": 1,
"127.0.0.1:1976": 1,
"127.0.0.1:1977": 1
},
"key": "remote_addr",
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 8: hit routes (upstream nodes: 1 healthy + 8 unhealthy)
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out eval
qr/Connection refused\) while connecting to upstream/
--- timeout: 10
=== TEST 9: chash route (upstream nodes: 2 unhealthy)
--- 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":"/server_port","upstream":{"type":"chash","nodes":{"127.0.0.1:1960":1,"127.0.0.1:1961":1},"key":"remote_addr","retries":3,"checks":{"active":{"http_path":"/status","host":"foo.com","healthy":{"interval":999,"successes":3},"unhealthy":{"interval":999,"http_failures":3}},"passive":{"healthy":{"http_statuses":[200,201],"successes":3},"unhealthy":{"http_statuses":[500],"http_failures":3,"tcp_failures":3}}}}}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 10: hit routes (passive + retries)
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 2 do
local httpc = http.new()
local res, err = httpc:request_uri(uri,
{method = "GET", keepalive = false}
)
ngx.say("res: ", res.status, " err: ", err)
end
}
}
--- request
GET /t
--- response_body
res: 502 err: nil
res: 502 err: nil
--- grep_error_log eval
qr{\[error\].*while connecting to upstream.*}
--- grep_error_log_out eval
qr{.*http://127.0.0.1:1960/server_port.*
.*http://127.0.0.1:1961/server_port.*
.*http://127.0.0.1:1961/server_port.*
.*http://127.0.0.1:1960/server_port.*
.*http://127.0.0.1:1961/server_port.*
.*http://127.0.0.1:1961/server_port.*}
--- timeout: 10
=== TEST 11: add new routh with healthcheck attribute
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
for i = 1, 3 do
t('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"uri": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
ngx.sleep(0.1)
local code, body = t('/server_port', ngx.HTTP_GET)
ngx.say("code: ", code, " body: ", body)
code, body = t('/apisix/admin/routes/' .. i, ngx.HTTP_DELETE)
ngx.say("delete code: ", code)
ngx.sleep(0.1)
end
}
}
--- request
GET /t
--- response_body
code: 200 body: passed
delete code: 200
code: 200 body: passed
delete code: 200
code: 200 body: passed
delete code: 200
=== TEST 12: add route (test health check config `host` valid)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1988": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: test health check config `host` valid
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(2)
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
200
--- grep_error_log eval
qr/^.*?\[warn\].*/
--- grep_error_log_out eval
qr/unhealthy TCP increment.*foo.com/
=== TEST 14: add route (test health check customized `port`)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"checks": {
"active": {
"http_path": "/status",
"port": 1988,
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 15: test health check customized `port`
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.sleep(2)
ngx.say(res.status)
}
}
--- request
GET /t
--- response_body
200
--- grep_error_log eval
qr/^.*?\[warn\].*/
--- grep_error_log_out eval
qr/unhealthy TCP increment.*foo.com.*127.0.0.1:1988/
--- timeout: 5
=== TEST 16: add route (test health check customized `port` out of minimum range)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"checks": {
"active": {
"http_path": "/status",
"port": 0,
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body_like eval
qr/expected 0 to be at least 1/
--- error_code chomp
400
=== TEST 17: add route (test health check customized `port` out of maximum range)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"checks": {
"active": {
"http_path": "/status",
"port": 65536,
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body_like eval
qr/expected 65536 to be at most 65535/
--- error_code chomp
400
=== TEST 18: set route + upstream (two upstream node: one healthy + one unhealthy)
--- 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,
[[{
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1970": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/server_port",
"upstream_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 19: hit routes, ensure the checker is bound to the upstream
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/\([^)]+\) unhealthy .* for '.*'/
--- grep_error_log_out
(upstream#/apisix/upstreams/1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
(upstream#/apisix/upstreams/1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
--- timeout: 10

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);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->yaml_config) {
my $yaml_config = <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
}
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: can't use service_name with nodes
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
upstreams:
- service_name: abaaba
discovery_type: eureka
nodes:
"127.0.0.1:80": 1
type: roundrobin
id: 1
#END
--- error_log
value should match only one schema, but matches both schemas 1 and 2
--- request
GET /hello
--- error_code: 502
=== TEST 2: route + service
--- apisix_yaml
services:
- id: 1
upstream:
type: roundrobin
nodes:
"127.0.0.1:1980": 1
"127.0.0.1:1970": 1
checks:
active:
http_path: /status
host: foo.com
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 2
routes:
- service_id: 1
uri: /server_port
#END
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/\([^)]+\) unhealthy .* for '.*'/
--- grep_error_log_out
(upstream#/services/1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
(upstream#/services/1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
--- timeout: 10
=== TEST 3: route override service
--- apisix_yaml
services:
- id: 1
upstream:
type: roundrobin
nodes:
"127.0.0.2:1980": 1
"127.0.0.2:1970": 1
checks:
active:
http_path: /status
host: foo.com
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 2
routes:
- service_id: 1
uri: /server_port
upstream:
type: roundrobin
nodes:
"127.0.0.1:1980": 1
"127.0.0.1:1970": 1
checks:
active:
http_path: /status
host: foo.com
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 2
#END
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(2.5)
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- response_body
[{"count":12,"port":"1980"}]
--- grep_error_log eval
qr/\([^)]+\) unhealthy .* for '.*'/
--- grep_error_log_out
(upstream#/routes/arr_1) unhealthy TCP increment (1/2) for 'foo.com(127.0.0.1:1970)'
(upstream#/routes/arr_1) unhealthy TCP increment (2/2) for 'foo.com(127.0.0.1:1970)'
--- timeout: 10
=== TEST 4: pass the configured host (pass_host == "pass")
--- apisix_yaml
routes:
- id: 1
uri: /server_port
upstream:
type: roundrobin
nodes:
"localhost:1980": 1
"127.0.0.1:1981": 1
checks:
active:
http_path: /status
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 2
#END
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(1)
}
}
--- no_error_log
client request host: localhost
--- error_log
client request host: 127.0.0.1
=== TEST 5: pass the configured host (pass_host == "node")
--- apisix_yaml
routes:
- id: 1
uri: /server_port
upstream:
type: roundrobin
pass_host: node
nodes:
"localhost:1980": 1
"127.0.0.1:1981": 1
checks:
active:
http_path: /status
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 2
#END
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(1)
}
}
--- error_log
client request host: localhost
client request host: 127.0.0.1
=== TEST 6: pass the configured host (pass_host == "rewrite")
--- apisix_yaml
routes:
- id: 1
uri: /server_port
upstream:
type: roundrobin
pass_host: rewrite
upstream_host: foo.com
nodes:
"localhost:1980": 1
"127.0.0.1:1981": 1
checks:
active:
http_path: /status
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 2
#END
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
end
ngx.sleep(1)
}
}
--- no_error_log
client request host: localhost
client request host: 127.0.0.1
--- error_log
client request host: foo.com

View File

@@ -0,0 +1,122 @@
#
# 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);
log_level('info');
no_root_location();
no_shuffle();
worker_connections(256);
run_tests();
__DATA__
=== TEST 1: set route(two healthy upstream nodes)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
},
"checks": {
"active": {
"http_path": "/status",
"host": "foo.com",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/^.*?\[error\](?!.*process exiting).*/
--- grep_error_log_out
=== TEST 2: In case of concurrency only one request can create a checker
--- config
location /t {
content_by_lua_block {
local healthcheck = require("resty.healthcheck")
local test = healthcheck.new
healthcheck.new = function(...)
ngx.sleep(1)
return test(...)
end
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local send_request = function()
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
if not res then
ngx.log(ngx.ERR, err)
return
end
end
local t = {}
for i = 1, 10 do
local th = assert(ngx.thread.spawn(send_request))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
ngx.exit(200)
}
}
--- request
GET /t
--- grep_error_log eval
qr/create new checker/
--- grep_error_log_out
create new checker

View File

@@ -0,0 +1,97 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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,
[[{
"uri": "/hello",
"hosts": ["foo.com", "*.bar.com"],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: /not_found
--- request
GET /hello
--- more_headers
Host: not_found.com
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: hit routes
--- request
GET /hello
--- more_headers
Host: foo.com
--- response_body
hello world
=== TEST 5: hit routes
--- request
GET /hello
--- more_headers
Host: www.bar.com
--- response_body
hello world

View File

@@ -0,0 +1,68 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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,
[[{
"uri": "/uri",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes
--- request
GET /uri
--- more_headers
Host: foo.com:1984
--- response_body
uri: /uri
host: foo.com:1984
x-real-ip: 127.0.0.1

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();
log_level("info");
add_block_preprocessor(sub {
my ($block) = @_;
$block;
});
run_tests;
__DATA__
=== TEST 1: add route to HTTPS upstream
--- 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": {
"scheme": "https",
"type": "roundrobin",
"nodes": {
"127.0.0.1:1983": 1
}
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit the upstream
--- request
GET /hello
--- more_headers
host: www.sni.com
--- error_log
Receive SNI: www.sni.com
=== TEST 3: use 443 as the default port
--- apisix_yaml
routes:
-
uri: /hello
upstream:
scheme: https
nodes:
"127.0.0.1": 1
type: roundrobin
#END
--- request
GET /hello
--- error_code: 502
--- error_log
upstream: "https://127.0.0.1:443/hello"
=== TEST 4: use 80 as the http's default port
--- apisix_yaml
routes:
-
uri: /hello
upstream:
nodes:
"127.0.0.1": 1
type: roundrobin
#END
--- request
GET /hello
--- error_code: 502
--- error_log
upstream: "http://127.0.0.1:80/hello"
=== TEST 5: rewrite SNI
--- log_level: debug
--- apisix_yaml
routes:
-
uri: /uri
upstream:
scheme: https
nodes:
"127.0.0.1:1983": 1
type: roundrobin
pass_host: "rewrite"
upstream_host: "www.test.com"
#END
--- request
GET /uri
--- more_headers
host: www.sni.com
--- error_log
Receive SNI: www.test.com
--- response_body
uri: /uri
host: www.test.com
x-real-ip: 127.0.0.1
=== TEST 6: node's SNI
--- log_level: debug
--- apisix_yaml
routes:
-
uri: /uri
upstream:
scheme: https
nodes:
"localhost:1983": 1
type: roundrobin
pass_host: "node"
#END
--- request
GET /uri
--- more_headers
host: www.sni.com
--- error_log
Receive SNI: localhost
--- response_body
uri: /uri
host: localhost:1983
x-real-ip: 127.0.0.1

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';
no_root_location();
run_tests();
__DATA__
=== TEST 1: set upstream with a invalid node port
--- 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": [{
"port": 65536,
"host": "127.0.0.1",
"weight": 1
}],
"type": "roundrobin"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like
{"error_msg":"invalid configuration: property \\\"nodes\\\" validation failed: object matches none of the required"}
=== TEST 2: set upstream with a node port greater than 65535
--- 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:65536": 1
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like
{"error_msg":"invalid port 65536"}
=== TEST 3: set upstream with a node port less than 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:0": 1
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body_like
{"error_msg":"invalid port 0"}

View File

@@ -0,0 +1,160 @@
#
# 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);
log_level('info');
no_long_string();
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set invalid route(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/routes/1", [[mexxxxxxxxxxxxxxx]])
if res.status >= 300 then
res.status = code
end
ngx.print(require("toolkit.json").encode(res.body))
ngx.sleep(1)
}
}
--- request
GET /t
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/routes/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
--- response_body_like eval
qr/"value":"mexxxxxxxxxxxxxxx"/
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/routes/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
=== TEST 3: set valid 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/routes/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
=== TEST 4: no error log
--- config
location /t {
content_by_lua_block {
ngx.sleep(1)
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
=== TEST 5: set route(with invalid 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,
[[{
"uri": "/server_port",
"upstream": {
"key": "remote_addr",
"type": "chash",
"nodes": {
"xxxx.invalid:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit route
--- request
GET /server_port
--- error_code: 503
--- error_log
failed to parse domain: xxxx.invalid
--- timeout: 10

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);
log_level('info');
no_long_string();
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set invalid service(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/services/1", [[mexxxxxxxxxxxxxxx]])
if res.status >= 300 then
ngx.status = code
return ngx.say(res.body)
end
ngx.print(require("toolkit.json").encode(res.body))
ngx.sleep(1)
}
}
--- request
GET /t
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/services/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
--- response_body_like eval
qr/"value":"mexxxxxxxxxxxxxxx"/
=== TEST 2: try /not_found, got error log
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/services/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
=== TEST 3: set valid service(id: 1), cover the old one
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/services/1", core.json.decode([[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]))
if res.status >= 300 then
ngx.status = code
end
ngx.print(require("toolkit.json").encode(res.body))
}
}
--- request
GET /t
--- ret_code: 200
--- response_body_like eval
qr/"nodes":\{"127.0.0.1:1980":1\}/
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/services/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
=== TEST 4: no error log
--- config
location /t {
content_by_lua_block {
ngx.sleep(1)
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done

View File

@@ -0,0 +1,132 @@
#
# 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);
log_level('info');
no_long_string();
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set invalid upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/upstreams/1", [[mexxxxxxxxxxxxxxx]])
if res.status >= 300 then
res.status = code
end
ngx.print(require("toolkit.json").encode(res.body))
ngx.sleep(1)
}
}
--- request
GET /t
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/upstreams/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
--- response_body_like eval
qr/"value":"mexxxxxxxxxxxxxxx"/
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- wait: 1
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/upstreams/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
=== TEST 3: delete invalid upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.delete("/upstreams/1")
if res.status >= 300 then
res.status = code
end
ngx.say("passed")
ngx.sleep(1)
}
}
--- request
GET /t
--- response_body
passed
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr{invalid item data of \[/apisix/upstreams/1\], val: mexxxxxxxxxxxxxxx, it should be an object}
=== TEST 4: set valid upstream(id: 1)
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/upstreams/1", core.json.decode([[{
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}]]))
if res.status >= 300 then
res.status = code
end
ngx.print(require("toolkit.json").encode(res.body))
ngx.sleep(1)
}
}
--- request
GET /t
--- response_body_like eval
qr/"nodes":\{"127.0.0.1:1980":1\}/
=== TEST 5: no error log
--- config
location /t {
content_by_lua_block {
ngx.sleep(1)
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done

View File

@@ -0,0 +1,151 @@
#
# 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);
log_level('info');
no_root_location();
worker_connections(1024);
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->yaml_config) {
my $yaml_config = <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
}
my $route = <<_EOC_;
routes:
- upstream_id: 1
uris:
- /mysleep
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $route);
if (!$block->request) {
$block->set_value("request", "GET /mysleep?seconds=0.1");
}
});
run_tests();
__DATA__
=== TEST 1: select highest weight
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
"127.0.0.1:1980": 2
"127.0.0.1:1981": 1
--- grep_error_log eval
qr/proxy request to \S+ while connecting to upstream/
--- grep_error_log_out
proxy request to 127.0.0.1:1980 while connecting to upstream
=== TEST 2: select least conn
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
"127.0.0.1:1980": 3
"0.0.0.0:1980": 2
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/mysleep?seconds=0.1"
local t = {}
for i = 1, 3 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
local res, err = httpc:request_uri(uri..i, {method = "GET"})
if not res then
ngx.log(ngx.ERR, err)
return
end
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
}
}
--- request
GET /t
--- grep_error_log eval
qr/proxy request to \S+ while connecting to upstream/
--- grep_error_log_out
proxy request to 127.0.0.1:1980 while connecting to upstream
proxy request to 0.0.0.0:1980 while connecting to upstream
proxy request to 127.0.0.1:1980 while connecting to upstream
=== TEST 3: retry
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
"127.0.0.1:1999": 2
"127.0.0.1:1980": 1
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+ while connecting to upstream/
--- grep_error_log_out
proxy request to 127.0.0.1:1999 while connecting to upstream
proxy request to 127.0.0.1:1980 while connecting to upstream
=== TEST 4: retry all nodes, failed
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
"127.0.0.1:1999": 2
"0.0.0.0:1999": 1
--- error_log
connect() failed
--- error_code: 502
--- grep_error_log eval
qr/proxy request to \S+ while connecting to upstream/
--- grep_error_log_out
proxy request to 127.0.0.1:1999 while connecting to upstream
proxy request to 0.0.0.0:1999 while connecting to upstream

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(2);
log_level('info');
no_root_location();
worker_connections(1024);
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: upstream across multiple routes should not share the same version
--- 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,
[[{
"type": "least_conn",
"nodes": {
"127.0.0.1:1980": 3,
"0.0.0.0:1980": 2
}
}]]
)
assert(code < 300, body)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"host": "1.com",
"uri": "/mysleep",
"upstream_id": "1"
}]]
)
assert(code < 300, body)
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"host": "2.com",
"uri": "/mysleep",
"upstream_id": "1"
}]]
)
assert(code < 300, body)
}
}
=== TEST 2: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/mysleep?seconds=0.1"
local t = {}
for i = 1, 2 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
local res, err = httpc:request_uri(uri, {headers = {Host = i..".com"}})
if not res then
ngx.log(ngx.ERR, err)
return
end
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
}
}
--- grep_error_log eval
qr/proxy request to \S+ while connecting to upstream/
--- grep_error_log_out
proxy request to 127.0.0.1:1980 while connecting to upstream
proxy request to 0.0.0.0:1980 while connecting to upstream

View File

@@ -0,0 +1,511 @@
#
# 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';
worker_connections(256);
no_root_location();
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,
[[{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: set route (different upstream)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1981": 1
},
"type": "roundrobin"
},
"uri": "/server_port",
"service_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: hit routes
--- request
GET /server_port
--- response_headers
X-RateLimit-Limit: 2
X-RateLimit-Remaining: 1
--- response_body eval
qr/1981/
=== TEST 5: set route with empty plugins, should do nothing
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {},
"uri": "/server_port",
"service_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit routes
--- request
GET /server_port
--- response_headers
X-RateLimit-Limit: 2
X-RateLimit-Remaining: 1
--- response_body eval
qr/1980/
=== TEST 7: disable plugin `limit-count`
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test
local code, body = 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": "/server_port",
"service_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes
--- request
GET /server_port
--- raw_response_headers_unlike eval
qr/X-RateLimit-Limit/
--- response_body eval
qr/1980/
=== TEST 9: hit routes two times, checker service configuration
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.5)
local t = require("lib.test_admin").test
local code, body = t('/server_port',
ngx.HTTP_GET
)
ngx.say(body)
code, body = t('/server_port',
ngx.HTTP_GET
)
ngx.say(body)
}
}
--- request
GET /t
--- error_log eval
[qr/merge_service_route.*"time_window":60/,
qr/merge_service_route.*"time_window":60/]
=== TEST 10: set service(only upstream with host)
--- 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": {
"scheme": "http",
"type": "roundrobin",
"nodes": {
"test.com:1980": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: set route(bind service 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,
[[{
"uri": "/fake",
"host": "test.com",
"plugins": {
"proxy-rewrite": {
"uri": "/echo"
}
},
"service_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 12: hit route
--- request
GET /fake
--- more_headers
host: test.com
--- response_headers
host: test.com
=== TEST 13: not hit route
--- request
GET /fake
--- more_headers
host: test.comxxx
--- error_code: 404
=== TEST 14: enabled websocket in 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,
[[{
"enable_websocket": true,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 15: set route(bind service 1)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/33',
ngx.HTTP_PUT,
[[{
"uri": "/uri",
"service_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 16: hit route
--- request
GET /uri
--- response_body
uri: /uri
connection: close
host: localhost
x-real-ip: 127.0.0.1
--- error_log
enabled websocket for route: 33
=== TEST 17: delete rout
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/33',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 18: labels exist if only route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions" : ["return function(conf, ctx)
local core = require(\"apisix.core\");
ngx.say(core.json.encode(ctx.matched_route.value.labels));
end"]
}
},
"labels": {
"version": "v2"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 19: hit routes
--- request
GET /hello
--- response_body
{"version":"v2"}
=== TEST 20: labels exist if merge route and 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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.sleep(0.6) -- wait for sync
code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions" : ["return function(conf, ctx)
local core = require(\"apisix.core\");
ngx.say(core.json.encode(ctx.matched_route.value.labels));
end"]
}
},
"labels": {
"version": "v2"
},
"uri": "/hello",
"service_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 21: hit routes
--- request
GET /hello
--- response_body
{"version":"v2"}

View File

@@ -0,0 +1,103 @@
#
# 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);
log_level('info');
no_long_string();
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: invalid service id
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/routes/1", {
service_id = "999999999",
uri = "/hello"
})
if res.status >= 300 then
ngx.status = res.status
return ngx.exit(res.status)
end
ngx.say("passed")
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes
--- request
GET /hello
--- error_code: 404
--- response_body eval
qr/404 Not Found/
--- wait_etcd_sync: 0.3
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr/failed to fetch service configuration by id/
=== TEST 3: set valid 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": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: hit routes
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,82 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";
} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
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,
[[{
"plugins": {},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: hit routes
--- request
GET /hello
--- error_code_like: ^(?:50\d)$
--- response_body eval
qr/502 Bad Gateway|503 Service Temporarily Unavailable/
--- grep_error_log eval
qr/\[error\].*/
--- grep_error_log_out eval
qr/missing upstream configuration in Route or Service/

View File

@@ -0,0 +1,410 @@
#
# 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);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: change plugin config will cause the conf_version change
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"response-rewrite": {
"body": "hello"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugin_config_id": 1,
"plugins": {
"example-plugin": {
"i": 1
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local code, err, org_body = t('/hello')
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.say(org_body)
local code, err = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PATCH,
[[{
"plugins": {
"response-rewrite": {
"body": "world"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local code, err, org_body = t('/hello')
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.say(org_body)
}
}
--- response_body
hello
world
--- grep_error_log eval
qr/conf_version: \d+#\d+/
--- grep_error_log_out eval
qr/conf_version: \d+#\d+
conf_version: \d+#\d+
/
=== TEST 2: validated plugins configuration via incremental sync
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local core = require("apisix.core")
assert(core.etcd.set("/plugin_configs/1",
{id = 1, plugins = { ["uri-blocker"] = { block_rules = {"root.exe","root.m+"} }}}
))
-- wait for sync
ngx.sleep(0.6)
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello?x=root.exe"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ngx.status = res.status
ngx.say(uri)
ngx.say(res.body)
}
}
--- error_code: 403
=== TEST 3: validated plugins configuration via incremental sync (malformed data)
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local core = require("apisix.core")
assert(core.etcd.set("/plugin_configs/1",
{id = 1, plugins = { ["uri-blocker"] = { block_rules = 1 }}}
))
-- wait for sync
ngx.sleep(0.6)
assert(core.etcd.delete("/plugin_configs/1"))
}
}
--- error_log
property "block_rules" validation failed
=== TEST 4: recover plugin when plugin_config changed
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"response-rewrite": {
"body": "hello"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugin_config_id": 1
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local code, err, org_body = t('/hello')
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.say(org_body)
local code, err = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, err, org_body = t('/hello')
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.print(org_body)
}
}
--- response_body
hello
hello world
=== TEST 5: don't override the plugin in the route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, err = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-rewrite": {
"uri": "/hello"
},
"response-rewrite": {
"body": "hello"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
local code, err = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/helloaa",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"plugin_config_id": 1,
"plugins": {
"response-rewrite": {
"body": "world"
}
}
}]]
)
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.sleep(0.1)
local code, err, org_body = t('/helloaa')
if code > 300 then
ngx.log(ngx.ERR, err)
return
end
ngx.say(org_body)
}
}
--- response_body
world
=== TEST 6: use the latest plugin_consigs after merge the plugins from consumer and route
--- 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": "foo",
"plugins": {
"basic-auth": {
"username": "foo",
"password": "bar"
}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"ip-restriction": {
"whitelist": ["1.1.1.1"]
},
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugin_config_id": "1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uris": ["/hello"]
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local headers = {
["Authorization"] = "Basic Zm9vOmJhcg=="
}
local res, err = httpc:request_uri(uri, {headers = headers})
ngx.print(res.body)
local code, body = t('/apisix/admin/plugin_configs/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"ip-restriction": {
"whitelist": ["1.1.1.1", "127.0.0.1"]
},
"basic-auth": {}
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.sleep(0.5)
local res, err = httpc:request_uri(uri, {headers = headers})
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
}
}
--- response_body
{"message":"Your IP address is not allowed"}
hello world

View File

@@ -0,0 +1,44 @@
#
# 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';
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
$block;
});
run_tests;
__DATA__
=== TEST 1: set custom log format
--- extra_init_by_lua
local exp = require("apisix.plugins.example-plugin")
exp.destroy = function()
ngx.log(ngx.WARN, "destroy method called")
end
--- config
location /t {
return 200 "dummy";
}
--- shutdown_error_log
destroy method called

View File

@@ -0,0 +1,104 @@
#
# 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 strict;
use warnings FATAL => 'all';
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: set up configuration
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/consumers/jack',
ngx.HTTP_PUT,
[[{
"username": "jack",
"plugins": {
"key-auth": {
"key": "auth-jack"
}
}
}]]
)
if code >= 300 then
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"key-auth": {},
"proxy-rewrite": {
"headers": {
"add": {
"xtest": "123"
}
}
},
"serverless-post-function": {
"functions": [
"return function(conf, ctx) \n ngx.say(ngx.req.get_headers().xtest); \n end"
]
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
ngx.say(body)
}
}
--- request
GET /t
--- timeout: 15
--- response_body
passed
=== TEST 2: the proxy-rewrite runs at 'rewrite' phase and should get executed only once, hence the response body is expected '123' not '123123'
--- request
GET /hello
--- more_headers
apikey: auth-jack
--- timeout: 15
--- response_body
123

View File

@@ -0,0 +1,184 @@
#
# 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);
log_level('info');
no_root_location();
worker_connections(1024);
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if ($block->apisix_yaml) {
if (!$block->yaml_config) {
my $yaml_config = <<_EOC_;
apisix:
node_listen: 1984
enable_admin: false
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
}
my $route = <<_EOC_;
routes:
- upstream_id: 1
uris:
- /hello
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $route);
}
if (!$block->request) {
$block->set_value("request", "GET /hello");
}
});
run_tests();
__DATA__
=== TEST 1: all are down detected by health checker
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 123
- host: 127.0.0.2
port: 1979
weight: 3
priority: -1
checks:
active:
http_path: "/status"
healthy:
interval: 1
successes: 1
unhealthy:
interval: 1
http_failures: 1
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local httpc = http.new()
httpc:request_uri(uri, {method = "GET"})
ngx.sleep(2.5)
-- still use all nodes
httpc:request_uri(uri, {method = "GET"})
}
}
--- request
GET /t
--- error_log
connect() failed
unhealthy TCP increment (2/2) for '127.0.0.1(127.0.0.1:1979)
unhealthy TCP increment (2/2) for '127.0.0.2(127.0.0.2:1979)
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
=== TEST 2: use priority as backup (setup rule)
--- 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",
"upstream": {
"type": "roundrobin",
"nodes": [
{"host": "127.0.0.1", "port": 1979, "weight": 2000},
{"host": "127.0.0.1", "port": 1980,
"weight": 1, "priority": -1}
],
"checks": {
"active": {
"http_path": "/status",
"healthy": {
"interval": 1,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 1
}
}
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: use priority as backup
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
local httpc = http.new()
httpc:request_uri(uri, {method = "GET"})
ngx.sleep(2.5)
httpc:request_uri(uri, {method = "GET"})
}
}
--- request
GET /t
--- error_log
connect() failed
unhealthy TCP increment (2/2) for '127.0.0.1(127.0.0.1:1979)
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.1:1980
proxy request to 127.0.0.1:1980

View File

@@ -0,0 +1,322 @@
#
# 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); # repeat each test to ensure after_balance is called correctly
log_level('info');
no_root_location();
worker_connections(1024);
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if ($block->apisix_yaml) {
if (!$block->yaml_config) {
my $yaml_config = <<_EOC_;
apisix:
node_listen: 1984
enable_admin: false
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
}
my $route = <<_EOC_;
routes:
- upstream_id: 1
uris:
- /hello
- /mysleep
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $route);
}
if (!$block->request) {
$block->set_value("request", "GET /hello");
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 1
- host: 127.0.0.2
port: 1979
weight: 1
priority: 1
- host: 127.0.0.3
port: 1979
weight: 2
priority: 0
- host: 127.0.0.4
port: 1979
weight: 1
priority: 0
- host: 127.0.0.1
port: 1980
weight: 2
priority: -1
--- response_body
hello world
--- error_log
connect() failed
failed to get server from current priority 1, try next one
failed to get server from current priority 0, try next one
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.3:1979
proxy request to 127.0.0.4:1979
proxy request to 127.0.0.1:1980
=== TEST 2: all failed
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 1
- host: 127.0.0.2
port: 1979
weight: 1
priority: 0
- host: 127.0.0.1
port: 1979
weight: 2
priority: -1
--- error_code: 502
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.1:1979
=== TEST 3: default priority is zero
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 1
- host: 127.0.0.2
port: 1979
weight: 1
- host: 127.0.0.1
port: 1980
weight: 2
priority: -1
--- response_body
hello world
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.1:1980
=== TEST 4: least_conn
--- apisix_yaml
upstreams:
- id: 1
type: least_conn
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 1
- host: 127.0.0.1
port: 1980
weight: 3
priority: -1
- host: 0.0.0.0
port: 1980
weight: 2
priority: -1
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/mysleep?seconds=0.1"
local t = {}
for i = 1, 3 do
local th = assert(ngx.thread.spawn(function(i)
local httpc = http.new()
-- the retry can be happened before starting the new request
-- so we exclude all the first tries from the expected log
local res, err = httpc:request_uri(uri..i, {method = "GET"})
if not res then
ngx.log(ngx.ERR, err)
return
end
end, i))
table.insert(t, th)
end
for i, th in ipairs(t) do
ngx.thread.wait(th)
end
}
}
--- request
GET /t
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+:1980 while connecting to upstream/
--- grep_error_log_out
proxy request to 127.0.0.1:1980 while connecting to upstream
proxy request to 0.0.0.0:1980 while connecting to upstream
proxy request to 127.0.0.1:1980 while connecting to upstream
=== TEST 5: roundrobin
--- apisix_yaml
upstreams:
- id: 1
type: roundrobin
nodes:
- host: 127.0.0.1
port: 1979
weight: 1000
priority: 1
- host: 127.0.0.2
port: 1979
weight: 1
priority: 1
- host: 127.0.0.3
port: 1979
weight: 1000
priority: -1
- host: 127.0.0.4
port: 1979
weight: 1
priority: -1
--- error_code: 502
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.3:1979
proxy request to 127.0.0.4:1979
=== TEST 6: ewma
--- apisix_yaml
upstreams:
- id: 1
type: ewma
key: remote_addr
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 1
- host: 127.0.0.2
port: 1979
weight: 1
priority: 0
- host: 127.0.0.3
port: 1979
weight: 2
priority: -1
--- error_code: 502
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.3:1979
=== TEST 7: chash
--- apisix_yaml
upstreams:
- id: 1
type: chash
key: remote_addr
nodes:
- host: 127.0.0.1
port: 1979
weight: 2
priority: 1
- host: 127.0.0.2
port: 1979
weight: 1
priority: 1
- host: 127.0.0.3
port: 1979
weight: 2
priority: -1
- host: 127.0.0.4
port: 1979
weight: 1
priority: -1
--- error_code: 502
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 127.0.0.2:1979
proxy request to 127.0.0.4:1979
proxy request to 127.0.0.3:1979

View File

@@ -0,0 +1,118 @@
#
# 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 route: remote addr = ::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": "::1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: IPv6 /not_found
--- listen_ipv6
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test_ipv6
t('/not_found')
}
}
--- request
GET /t
--- response_body eval
qr/"error_msg":"404 Route Not Found"/
=== TEST 3: IPv4 /not_found
--- listen_ipv6
--- request
GET /not_found
--- error_code: 404
--- response_body eval
qr/"error_msg":"404 Route Not Found"/
=== TEST 4: IPv6 /hello
--- listen_ipv6
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test_ipv6
t('/hello')
}
}
--- request
GET /t
--- response_body eval
qr{connected: 1
request sent: 59
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:
received: hello world
failed to receive a line: closed \[\]
close: 1 nil}
=== TEST 5: IPv4 /hello
--- listen_ipv6
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}

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';
no_root_location();
run_tests();
__DATA__
=== TEST 1: set route: 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: hit route
--- request
GET /hello
--- response_body
hello world
=== TEST 4: set route: remote addr = 127.0.0.2
--- 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.2",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: not hit route: 127.0.0.2 =~ 127.0.0.1
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 6: remote addr: 127.0.0.3/24 =~ 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.3/24",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: hit route
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,111 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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,
[[{
"uri": "/hello",
"remote_addrs": ["192.0.0.0/8", "127.0.0.3"],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- http_config
real_ip_header X-Real-IP;
set_real_ip_from 127.0.0.1;
set_real_ip_from unix:;
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: /not_found
--- http_config
real_ip_header X-Real-IP;
set_real_ip_from 127.0.0.1;
set_real_ip_from unix:;
--- request
GET /hello
--- more_headers
Host: not_found.com
--- error_code: 404
=== TEST 4: hit routes
--- http_config
real_ip_header X-Real-IP;
set_real_ip_from 127.0.0.1;
set_real_ip_from unix:;
--- request
GET /hello
--- more_headers
X-Real-IP: 192.168.1.100
--- response_body
hello world
=== TEST 5: hit routes
--- http_config
real_ip_header X-Real-IP;
set_real_ip_from 127.0.0.1;
set_real_ip_from unix:;
--- request
GET /hello
--- more_headers
X-Real-IP: 127.0.0.3
--- response_body
hello world

View File

@@ -0,0 +1,142 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: clear all routes
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
for i = 1, 200 do
t('/apisix/admin/routes/' .. i, ngx.HTTP_DELETE)
end
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
--- timeout: 5
=== TEST 2: create 106 routes + delete them
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
for i = 1, 106 do
local code, body = t('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello]] .. i .. [["
}]]
)
end
ngx.sleep(0.5)
for i = 1, 106 do
local code, body = t('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello]] .. i .. [["
}]]
)
end
ngx.sleep(0.5)
for i = 1, 106 do
local code, body = t('/apisix/admin/routes/' .. i,
ngx.HTTP_DELETE
)
end
ngx.sleep(0.5)
for i = 1, 106 do
local code, body = t('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello]] .. i .. [["
}]]
)
end
ngx.sleep(0.5)
for i = 1, 106 do
local code, body = t('/apisix/admin/routes/' .. i,
ngx.HTTP_DELETE
)
end
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
--- wait: 1
--- grep_error_log eval
qr/\w+ (data by key: 103)/
--- grep_error_log_out
insert data by key: 103
insert data by key: 103
update data by key: 103
update data by key: 103
delete data by key: 103
delete data by key: 103
insert data by key: 103
insert data by key: 103
delete data by key: 103
delete data by key: 103
--- timeout: 30

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.
#
BEGIN {
# for test
$ENV{ENABLE_LOCAL_DNS} = "true";
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1,
"www.apiseven.com:80": 0
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- error_log eval
qr/.*init_resolver\(\): dns resolver \[.+\]/
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
--- error_log eval
qr/.*init_resolver\(\): dns resolver \[.+\]/
=== TEST 3: hit route
--- request
GET /hello
--- response_body
hello world
--- error_log eval
qr/dns resolver domain: www.apiseven.com to \d+.\d+.\d+.\d+/

View File

@@ -0,0 +1,212 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1,
"www.apiseven.com:80": 0
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: hit route
--- request
GET /hello
--- response_body
hello world
--- error_log eval
qr/dns resolver domain: www.apiseven.com to \d+.\d+.\d+.\d+/
--- timeout: 10
=== TEST 4: set route(id: 1, using `rewrite` mode to pass upstream 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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"pass_host": "rewrite",
"upstream_host": "test.com"
},
"uri": "/echo"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: hit route
--- request
GET /echo
--- response_headers
host: test.com
=== TEST 6: set route(id: 1, using `node` mode to pass upstream 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,
[[{
"upstream": {
"nodes": {
"test.com:1980": 1
},
"type": "roundrobin",
"desc": "new upstream",
"pass_host": "node"
},
"uri": "/echo"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: hit route
--- request
GET /echo
--- response_headers
host: test.com:1980
=== TEST 8: test domain with roundrobin
--- 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": {
"localhost:1981": 2,
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/server_port"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: hit
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local bodys = {}
for i = 1, 3 do
local _, _, body = t('/server_port', ngx.HTTP_GET)
bodys[i] = body
end
table.sort(bodys)
ngx.say(table.concat(bodys, ", "))
}
}
--- request
GET /t
--- response_body
1980, 1981, 1981

View File

@@ -0,0 +1,74 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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,
[[{
"uri": "/hello",
"filter_func": "function(vars) return vars.arg_name == 'json' end",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: not hit: name=unknown
--- request
GET /hello?name=unknown
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: hit routes
--- request
GET /hello?name=json
--- response_body
hello world

View File

@@ -0,0 +1,160 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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:1980": 1
},
"type": "roundrobin"
},
"host": "foo.com",
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: /not_found
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: /not_found
--- request
GET /hello
--- more_headers
Host: not_found.com
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 5: hit routes
--- request
GET /hello
--- more_headers
Host: foo.com
--- response_body
hello world
=== TEST 6: hit routes, uppercase
--- request
GET /hello
--- more_headers
Host: FOO.com
--- response_body
hello world
=== TEST 7: set route(host is uppercase)
--- 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:1980": 1
},
"type": "roundrobin"
},
"host": "FOO.com",
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes
--- request
GET /hello
--- more_headers
Host: foo.com
--- response_body
hello world
=== TEST 9: hit routes, uppercase
--- request
GET /hello
--- more_headers
Host: FOO.com
--- response_body
hello world

View File

@@ -0,0 +1,252 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: default enable route(id: 1) with uri match
--- 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",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit route
--- request
GET /hello
--- response_body
hello world
=== TEST 3: disable route
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local data = {status = 0}
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
core.json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: route not found, failed by disable
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 5: default enable route(id: 1) with host_uri match
--- 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",
"host": "foo.com",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit route
--- request
GET /hello
--- more_headers
Host: foo.com
--- response_body
hello world
=== TEST 7: disable route
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin").test
local data = {status = 0}
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PATCH,
core.json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: route not found, failed by disable
--- request
GET /hello
--- more_headers
Host: foo.com
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 9: specify an invalid status value
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"status": 100,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/\{"error_msg":"invalid configuration: property \\"status\\" validation failed: matches none of the enum values"\}/
=== TEST 10: compatible with old route data in etcd which not has status
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local res, err = core.etcd.set("/routes/1", core.json.decode([[{
"uri": "/hello",
"priority": 0,
"id": "1",
"upstream": {
"hash_on": "vars",
"pass_host": "pass",
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]])) ---mock old route data in etcd
if res.status >= 300 then
res.status = code
end
ngx.print(require("toolkit.json").encode(res.body))
ngx.sleep(1)
}
}
--- request
GET /t
--- response_body_unlike eval
qr/status/
=== TEST 11: hit route(old route data in etcd)
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,80 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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:1980": 1
},
"type": "roundrobin"
},
"uris": ["/hello","/hello1"]
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
=== TEST 3: hit routes1
--- request
GET /hello
--- response_body
hello world
=== TEST 4: hit routes2
--- request
GET /hello1
--- response_body
hello1 world

View File

@@ -0,0 +1,316 @@
#
# 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);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set route(two upstream node)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":6,"port":"1981"},{"count":6,"port":"1980"}]
=== TEST 3: set route(three upstream node)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.1:1981": 1,
"127.0.0.1:1982": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":4,"port":"1982"},{"count":4,"port":"1981"},{"count":4,"port":"1980"}]
=== TEST 5: set route(three upstream node and different weight)
--- 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": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 3,
"127.0.0.1:1981": 2,
"127.0.0.1:1982": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":2,"port":"1982"},{"count":4,"port":"1981"},{"count":6,"port":"1980"}]
=== TEST 7: set route(weight is 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,
[[{
"uri": "/server_port",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 3,
"127.0.0.1:1981": 0,
"127.0.0.1:1982": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 12 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
ngx.exit(200)
}
}
--- request
GET /t
--- response_body
[{"count":3,"port":"1982"},{"count":9,"port":"1980"}]

View File

@@ -0,0 +1,139 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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"],
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 4: 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": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello*"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: hit routes/hello
--- request
GET /hello
--- response_body
hello world
=== TEST 6: hit routes: /hello1
--- request
GET /hello1
--- response_body
hello1 world
=== TEST 7: hit routes: /hello2
--- request
GET /hello2
--- error_code: 404
--- response_body eval
qr/404 Not Found/
=== TEST 8: hit routes: /hel
--- request
GET /hel
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}

View File

@@ -0,0 +1,89 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set empty service. (id: 1)allow empty `service` object
--- 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,
'{}'
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: route binding empty service
--- 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:1980": 1
},
"type": "roundrobin"
},
"service_id": "1",
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: /hello
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,298 @@
#
# 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;
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
my $openssl_bin = $ENV{OPENSSL_BIN};
if (! -x $openssl_bin) {
$ENV{OPENSSL_BIN} = '/usr/local/openresty/openssl3/bin/openssl';
if (! -x $ENV{OPENSSL_BIN}) {
plan(skip_all => "openssl3 not installed");
}
}
plan('no_plan');
add_block_preprocessor(sub {
my ($block) = @_;
my $yaml_config = $block->yaml_config // <<_EOC_;
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
admin_key: null
apisix:
node_listen: 1984
proxy_mode: http&stream
stream_proxy:
tcp:
- 9100
enable_resolv_search_opt: false
ssl:
ssl_protocols: TLSv1.1 TLSv1.2 TLSv1.3
ssl_ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA
_EOC_
$block->set_value("yaml_config", $yaml_config);
});
run_tests();
__DATA__
=== TEST 1: 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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uris": ["/hello", "/world"]
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(message)
return
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: create ssl for test.com (unset 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"}
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
=== TEST 3: Successfully, access test.com with TLSv1.3
--- exec
echo -n "Q" | $OPENSSL_BIN s_client -connect 127.0.0.1:1994 -servername test.com -tls1_3 2>&1 | cat
--- response_body eval
qr/Server certificate/
=== TEST 4: Successfully, access test.com with TLSv1.2
--- exec
curl -k -v --tls-max 1.2 --tlsv1.2 --resolve "test.com:1994:127.0.0.1" https://test.com:1994/hello 2>&1 | cat
--- response_body eval
qr/TLSv1\.2 \(IN\), TLS handshake, Server hello(?s).*hello world/
=== TEST 5: Successfully, access test.com with TLSv1.1
--- exec
echo -n "Q" | $OPENSSL_BIN s_client -connect 127.0.0.1:1994 -servername test.com -tls1_1 2>&1 | cat
--- response_body eval
qr/Server certificate/
=== TEST 6: set TLSv1.2 and TLSv1.3 for test.com
--- 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.2", "TLSv1.3"}}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"ssl_protocols": ["TLSv1.2", "TLSv1.3"],
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: Set TLSv1.3 for the test2.com
--- 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", ssl_protocols = {"TLSv1.3"}}
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
--- request
GET /t
=== TEST 8: Successfully, access test.com with TLSv1.3
--- exec
echo -n "Q" | $OPENSSL_BIN s_client -connect 127.0.0.1:1994 -servername test.com -tls1_3 2>&1 | cat
--- response_body eval
qr/Server certificate/
=== TEST 9: Successfully, access test.com with TLSv1.2
--- exec
curl -k -v --tls-max 1.2 --tlsv1.2 --resolve "test.com:1994:127.0.0.1" https://test.com:1994/hello 2>&1 | cat
--- response_body eval
qr/TLSv1\.2 \(IN\), TLS handshake, Server hello(?s).*hello world/
=== TEST 10: Successfully, access test2.com with TLSv1.3
--- exec
echo -n "Q" | $OPENSSL_BIN s_client -connect 127.0.0.1:1994 -servername test2.com -tls1_3 2>&1 | cat
--- response_body eval
qr/Server certificate/
=== TEST 11: Failed, access test2.com with TLSv1.2
--- exec
curl -k -v --tls-max 1.2 --tlsv1.2 --resolve "test2.com:1994:127.0.0.1" https://test2.com:1994/hello 2>&1 | cat
--- response_body eval
qr/TLSv1\.2 \(IN\), TLS alert/
=== TEST 12: set TLSv1.1 for test.com
--- 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.1"}}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"sni": "test.com",
"ssl_protocols": ["TLSv1.1"],
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: Successfully, access test.com with TLSv1.1
--- exec
echo -n "Q" | $OPENSSL_BIN s_client -connect 127.0.0.1:1994 -servername test.com -tls1_1 2>&1 | cat
--- response_body eval
qr/Server certificate/
=== TEST 14: Failed, access test.com with TLSv1.3
--- exec
echo -n "Q" | $OPENSSL_BIN s_client -connect 127.0.0.1:1994 -servername test.com -tls1_3 2>&1 | cat
--- response_body eval
qr/tlsv1 alert/

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.
#
BEGIN {
sub set_env_from_file {
my ($env_name, $file_path) = @_;
open my $fh, '<', $file_path or die $!;
my $content = do { local $/; <$fh> };
close $fh;
$ENV{$env_name} = $content;
}
# set env
set_env_from_file('TEST_CERT', 't/certs/apisix.crt');
set_env_from_file('TEST_KEY', 't/certs/apisix.key');
set_env_from_file('TEST2_CERT', 't/certs/test2.crt');
set_env_from_file('TEST2_KEY', 't/certs/test2.key');
}
use t::APISIX 'no_plan';
log_level('info');
no_root_location();
sub set_env_from_file {
my ($env_name, $file_path) = @_;
open my $fh, '<', $file_path or die $!;
my $content = do { local $/; <$fh> };
close $fh;
$ENV{$env_name} = $content;
}
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests;
__DATA__
=== TEST 1: store two certs and keys in vault
--- exec
VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/ssl \
test.com.crt=@t/certs/apisix.crt \
test.com.key=@t/certs/apisix.key \
test.com.2.crt=@t/certs/test2.crt \
test.com.2.key=@t/certs/test2.key
--- response_body
Success! Data written to: kv/apisix/ssl
=== TEST 2: set secret
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/secrets/vault/test',
ngx.HTTP_PUT,
[[{
"uri": "http://0.0.0.0:8200",
"prefix": "kv/apisix",
"token": "root"
}]],
[[{
"key": "/apisix/secrets/vault/test",
"value": {
"uri": "http://0.0.0.0:8200",
"prefix": "kv/apisix",
"token": "root"
}
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: set ssl with two certs and keys in vault
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local data = {
snis = {"test.com"},
key = "$secret://vault/test/ssl/test.com.key",
cert = "$secret://vault/test/ssl/test.com.crt",
keys = {"$secret://vault/test/ssl/test.com.2.key"},
certs = {"$secret://vault/test/ssl/test.com.2.crt"}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"snis": ["test.com"],
"key": "$secret://vault/test/ssl/test.com.key",
"cert": "$secret://vault/test/ssl/test.com.crt",
"keys": ["$secret://vault/test/ssl/test.com.2.key"],
"certs": ["$secret://vault/test/ssl/test.com.2.crt"]
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: set route
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/2',
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)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: access to https with test.com
--- exec
curl -s -k https://test.com:1994/hello
--- response_body
hello world
--- error_log
fetching data from secret uri
fetching data from secret uri
fetching data from secret uri
fetching data from secret uri
=== TEST 6: set ssl with two certs and keys in env
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local data = {
snis = {"test.com"},
key = "$env://TEST_KEY",
cert = "$env://TEST_CERT",
keys = {"$env://TEST2_KEY"},
certs = {"$env://TEST2_CERT"}
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data),
[[{
"value": {
"snis": ["test.com"],
"key": "$env://TEST_KEY",
"cert": "$env://TEST_CERT",
"keys": ["$env://TEST2_KEY"],
"certs": ["$env://TEST2_CERT"]
},
"key": "/apisix/ssls/1"
}]]
)
ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: access to https with test.com
--- exec
curl -s -k https://test.com:1994/hello
--- response_body
hello world
--- error_log
fetching data from env uri
fetching data from env uri
fetching data from env uri
fetching data from env uri

View File

@@ -0,0 +1,191 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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:1980": 1
},
"type": "roundrobin",
"timeout": {
"connect": 0.5,
"send": 0.5,
"read": 0.5
}
},
"uri": "/mysleep"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit routes (timeout)
--- request
GET /mysleep?seconds=1
--- error_code: 504
--- response_body eval
qr/504 Gateway Time-out/
--- error_log
timed out) while reading response header from upstream
=== TEST 3: set custom timeout for route(overwrite upstream 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"],
"timeout": {
"connect": 0.5,
"send": 0.5,
"read": 0.5
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"timeout": {
"connect": 2,
"send": 2,
"read": 2
}
},
"uri": "/mysleep"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: hit routes (timeout)
--- request
GET /mysleep?seconds=1
--- error_code: 504
--- response_body eval
qr/504 Gateway Time-out/
--- error_log
timed out) while reading response header from upstream
=== TEST 5: set route inherit hosts from service
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local scode, sbody = t('/apisix/admin/services/1',
ngx.HTTP_PUT,
[[{
"desc":"test-service",
"hosts": ["foo.com"]
}]]
)
if scode >= 300 then
ngx.status = scode
end
ngx.say(sbody)
local rcode, rbody = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"service_id": "1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"timeout": {
"connect": 0.5,
"send": 0.5,
"read": 0.5
}
},
"uri": "/mysleep"
}]]
)
if rcode >= 300 then
ngx.status = rcode
end
ngx.say(rbody)
}
}
--- request
GET /t
--- response_body
passed
passed
=== TEST 6: hit service route (timeout)
--- request
GET /mysleep?seconds=1
--- more_headers
Host: foo.com
--- error_code: 504
--- response_body eval
qr/504 Gateway Time-out/
--- error_log
timed out) while reading response header from upstream

View File

@@ -0,0 +1,199 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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": 1980,
"weight": 1
}],
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 4: 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,
[[{
"uri": "/hello",
"upstream": {
"nodes": [{
"host": "127.0.0.1",
"port": 1980,
"weight": 1
}],
"type": "roundrobin",
"desc": "new upstream"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 6: set services(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": 1980,
"weight": 1
}],
"type": "roundrobin",
"desc": "new upstream"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- 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,
[[{
"uri": "/hello",
"service_id": 1
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,133 @@
#
# 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);
log_level('warn');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: dynamic host based discovery
--- extra_yaml_config
nginx_config:
worker_processes: 1
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local discovery = require("apisix.discovery.init").discovery
local core = require("apisix.core")
discovery.demo_discover = {
nodes = function()
local demo_nodes_tab = {
a = { host = "127.0.0.1", port = 1111 },
b = { host = "127.0.0.1", port = 2222 }
}
local host = ngx.var.host
local service_id = host:match("([^.]+).myhost.com")
local demo_node = demo_nodes_tab[service_id]
local node_list = core.table.new(1, 0)
core.table.insert(node_list, {
host = demo_node.host,
port = tonumber(demo_node.port),
weight = 100,
})
return node_list
end
}
local code, body = t('/apisix/admin/services/',
ngx.HTTP_PUT,
[[{
"id": "demo_service",
"name": "demo_service",
"upstream": {
"discovery_type": "demo_discover",
"service_name": "demo_service",
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.sleep(0.5)
local code, body = t('/apisix/admin/routes/',
ngx.HTTP_PUT,
[[{
"id": "demo_route",
"name": "demo_route",
"uri": "/*",
"hosts":[
"*.myhost.com"
],
"service_id": "demo_service"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.sleep(0.5)
local hosts = {
"a.myhost.com",
"a.myhost.com",
"b.myhost.com",
"b.myhost.com",
"a.myhost.com",
"b.myhost.com",
"b.myhost.com",
"a.myhost.com",
"b.myhost.com",
"a.myhost.com",
}
for i, url_host in ipairs(hosts) do
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false, headers = {
["Host"] = url_host
}})
end
}
}
--- request
GET /t
--- grep_error_log eval
qr/upstream: \S+, host: \S+/
--- grep_error_log_out
upstream: "http://127.0.0.1:1111/", host: "a.myhost.com"
upstream: "http://127.0.0.1:1111/", host: "a.myhost.com"
upstream: "http://127.0.0.1:2222/", host: "b.myhost.com"
upstream: "http://127.0.0.1:2222/", host: "b.myhost.com"
upstream: "http://127.0.0.1:1111/", host: "a.myhost.com"
upstream: "http://127.0.0.1:2222/", host: "b.myhost.com"
upstream: "http://127.0.0.1:2222/", host: "b.myhost.com"
upstream: "http://127.0.0.1:1111/", host: "a.myhost.com"
upstream: "http://127.0.0.1:2222/", host: "b.myhost.com"
upstream: "http://127.0.0.1:1111/", host: "a.myhost.com"

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';
repeat_each(1);
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->yaml_config) {
my $yaml_config = <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
}
if ($block->apisix_yaml) {
my $upstream = <<_EOC_;
upstreams:
- service_name: mock
discovery_type: mock
type: roundrobin
id: 1
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $upstream);
}
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: create new server picker when nodes change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.2", port = 1980, weight = 1},
{host = "127.0.0.3", port = 1980, weight = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
create_obj_fun(): upstream nodes:
=== TEST 2: don't create new server picker if nodes don't change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "0.0.0.0", port = 1980, weight = 1},
{host = "127.0.0.1", port = 1980, weight = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
=== TEST 3: create new server picker when nodes change, up_conf doesn't come from upstream
--- apisix_yaml
routes:
- uris:
- /hello
service_id: 1
services:
- id: 1
upstream:
service_name: mock
discovery_type: mock
type: roundrobin
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.2", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
create_obj_fun(): upstream nodes:
=== TEST 4: don't create new server picker if nodes don't change (port missing)
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", weight = 1},
{host = "0.0.0.0", weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "0.0.0.0", weight = 1},
{host = "127.0.0.1", weight = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
--- error_log
connect() failed
=== TEST 5: create new server picker when priority change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1},
{host = "0.0.0.0", port = 1980, weight = 1, priority = 1},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
create_obj_fun(): upstream nodes:
=== TEST 6: default priority of discovered node is 0
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1979, weight = 1, priority = 1},
{host = "0.0.0.0", port = 1980, weight = 1},
{host = "127.0.0.2", port = 1979, weight = 1, priority = -1},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
}
}
--- error_log
connect() failed
--- grep_error_log eval
qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 0.0.0.0:1980
=== TEST 7: create new server picker when metadata change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = {a = 1}},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = {}},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = {a = 1}},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = {b = 1}},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
create_obj_fun(): upstream nodes:
=== TEST 8: don't create new server picker when metadata doesn't change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
local meta1 = {a = 1}
local meta2 = {b = 2}
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = meta1},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = meta2},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = meta1},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = meta2},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
=== TEST 9: bad nodes return by the discovery
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = "0"},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)
}
}
--- response_body
503
--- error_log
invalid nodes format: failed to validate item 1: property "weight" validation failed: wrong type: expected integer, got string
=== TEST 10: compare nodes by value only once when nodes's address be changed but values are same
--- log_level: debug
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local old_nodes = {{host = "127.0.0.1", port = 1980, weight = 1}, {host = "127.0.0.2", port = 1980, weight = 1}}
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return old_nodes
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
for i = 1, 10 do
local res = httpc:request_uri(uri, {method = "GET", keepalive = false})
if res.status ~= 200 then
ngx.say("request failed: ", res.status)
return
end
end
local new_nodes = {{host = "127.0.0.2", port = 1980, weight = 1}, {host = "127.0.0.1", port = 1980, weight = 1}}
discovery.mock = {
nodes = function()
return new_nodes
end
}
for i = 1, 10 do
local res = httpc:request_uri(uri, {method = "GET", keepalive = false})
if res.status ~= 200 then
ngx.say("request failed: ", res.status)
return
end
end
ngx.say("pass")
}
}
--- response_body
pass
--- grep_error_log eval
qr/compare upstream nodes by value|fill node info for upstream/
--- grep_error_log_out
fill node info for upstream
compare upstream nodes by value
fill node info for upstream

View File

@@ -0,0 +1,230 @@
#
# 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 {
$ENV{CUSTOM_DNS_SERVER} = "127.0.0.1:1053";
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
my $yaml_config = $block->yaml_config // <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
my $routes = <<_EOC_;
routes:
-
uri: /hello
upstream_id: 1
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $routes);
});
run_tests();
__DATA__
=== TEST 1: AAAA
--- listen_ipv6
--- apisix_yaml
upstreams:
- id: 1
nodes:
ipv6.test.local:1980: 1
type: roundrobin
--- request
GET /hello
--- response_body
hello world
=== TEST 2: default ttl
--- log_level: debug
--- apisix_yaml
upstreams:
- id: 1
nodes:
ttl.test.local:1980: 1
type: roundrobin
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
for i = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res or res.body ~= "hello world\n" then
ngx.say(err)
return
end
end
}
}
--- request
GET /t
--- error_log
"ttl":300
--- grep_error_log eval
qr/connect to 127.0.0.1:1053/
--- grep_error_log_out
connect to 127.0.0.1:1053
=== TEST 3: override ttl
--- log_level: debug
--- yaml_config
apisix:
node_listen: 1984
dns_resolver_valid: 900
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
--- apisix_yaml
upstreams:
- id: 1
nodes:
ttl.test.local:1980: 1
type: roundrobin
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
for i = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res or res.body ~= "hello world\n" then
ngx.say(err)
return
end
end
}
}
--- request
GET /t
--- grep_error_log eval
qr/connect to 127.0.0.1:1053/
--- grep_error_log_out
connect to 127.0.0.1:1053
--- error_log
"ttl":900
=== TEST 4: cache expire
--- log_level: debug
--- apisix_yaml
upstreams:
- id: 1
nodes:
ttl.1s.test.local:1980: 1
type: roundrobin
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
for i = 1, 2 do
for j = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res or res.body ~= "hello world\n" then
ngx.say(err)
return
end
end
if i < 2 then
ngx.sleep(1.1)
end
end
}
}
--- request
GET /t
--- grep_error_log eval
qr/connect to 127.0.0.1:1053/
--- grep_error_log_out
connect to 127.0.0.1:1053
connect to 127.0.0.1:1053
=== TEST 5: cache expire (override ttl)
--- log_level: debug
--- yaml_config
apisix:
node_listen: 1984
dns_resolver_valid: 1
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
--- apisix_yaml
upstreams:
- id: 1
nodes:
ttl.test.local:1980: 1
type: roundrobin
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
for i = 1, 2 do
for j = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET"})
if not res or res.body ~= "hello world\n" then
ngx.say(err)
return
end
end
if i < 2 then
ngx.sleep(1.1)
end
end
}
}
--- request
GET /t
--- grep_error_log eval
qr/connect to 127.0.0.1:1053/
--- grep_error_log_out
connect to 127.0.0.1:1053
connect to 127.0.0.1:1053

View File

@@ -0,0 +1,70 @@
#
# 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 {
$ENV{CUSTOM_DNS_SERVER} = "[::1]:1053";
}
use t::APISIX 'no_plan';
repeat_each(1);
log_level('debug');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
my $yaml_config = $block->yaml_config // <<_EOC_;
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
_EOC_
$block->set_value("yaml_config", $yaml_config);
my $routes = <<_EOC_;
routes:
-
uri: /hello
upstream_id: 1
#END
_EOC_
$block->set_value("apisix_yaml", $block->apisix_yaml . $routes);
});
run_tests();
__DATA__
=== TEST 1: AAAA
--- listen_ipv6
--- apisix_yaml
upstreams:
- id: 1
nodes:
ipv6.test.local:1980: 1
type: roundrobin
--- request
GET /hello
--- error_log
connect to [::1]:1053
--- response_body
hello world

View File

@@ -0,0 +1,415 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
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": {
"foo.com:80": 0,
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: hit routes
--- request
GET /hello
--- response_body
hello world
--- error_log eval
qr/dns resolver domain: foo.com to \d+.\d+.\d+.\d+/
=== TEST 5: set upstream(invalid node host)
--- 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": {
"test.comx:80": 0
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6:
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local function test()
local code, body = t('/hello', ngx.HTTP_GET)
ngx.say("status: ", code)
end
test()
test()
}
}
--- request
GET /t
--- response_body
status: 503
status: 503
--- error_log
failed to parse domain: test.comx
failed to parse domain: test.comx
--- timeout: 10
=== TEST 7: delete route
--- 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
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: delete upstream
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
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)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: set upstream(with domain)
--- 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": {
"foo.com:80": 0,
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: set empty 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,
[[{
"desc": "new service",
"plugins": {
"prometheus": {}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: set route(with upstream)
--- 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",
"upstream": {
"nodes": {
"foo.com": 0,
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
},
"service_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 12: hit routes, parse the domain of upstream node
--- request
GET /hello
--- response_body
hello world
--- error_log eval
qr/dns resolver domain: foo.com to \d+.\d+.\d+.\d+/
=== TEST 13: set route(with 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": {
"localhost:1981": 2,
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/server_port",
"service_id": "1",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: roundrobin
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local bodys = {}
for i = 1, 3 do
local _, _, body = t('/server_port', ngx.HTTP_GET)
bodys[i] = body
end
table.sort(bodys)
ngx.say(table.concat(bodys, ", "))
}
}
--- request
GET /t
--- response_body
1980, 1981, 1981
=== TEST 15: set route(with upstream)
--- 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",
"upstream": {
"nodes": {
"foo.com.": 0,
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
},
"service_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 16: hit routes, parse the domain of upstream node
--- request
GET /hello
--- response_body
hello world
--- error_log eval
qr/dns resolver domain: foo.com. to \d+.\d+.\d+.\d+/

View File

@@ -0,0 +1,272 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my $block = shift;
$block->set_value("listen_ipv6", 1);
});
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": {
"[::1]:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 5: 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": [
{
"weight": 100,
"priority": 0,
"host": "::1",
"port": 1980
}
],
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 7: set upstream, one array item to specify node
--- 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": [
{
"weight": 100,
"priority": 0,
"host": "[::1]",
"port": 1980
}
],
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 9: set upstream, one hash key to specify node, in wrong format
--- 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": {
"::1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: hit routes
--- request
GET /hello
--- error_code: 502
--- error_log
connect() to [::0.1.25.128]:80 failed
=== TEST 11: set upstream, two array items to specify 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_PUT,
[[{
"nodes": [
{
"weight": 100,
"priority": 0,
"host": "::1",
"port": 1980
},
{
"weight": 100,
"priority": 0,
"host": "::1",
"port": 1980
}
],
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 12: hit routes
--- request
GET /hello
--- response_body
hello world

View File

@@ -0,0 +1,807 @@
#
# 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;
my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
my $version = eval { `$nginx_binary -V 2>&1` };
if ($version !~ m/\/apisix-nginx-module/) {
plan(skip_all => "apisix-nginx-module not installed");
} else {
plan('no_plan');
}
repeat_each(1);
log_level('debug');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!defined $block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: bad pool size
--- 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,
[[{
"type": "roundrobin",
"nodes": {
"127.0.0.1:1983": 1
},
"keepalive_pool": {
"size": 0
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"keepalive_pool\" validation failed: property \"size\" validation failed: expected 0 to be at least 1"}
=== TEST 2: set route/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,
[[{
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
},
"keepalive_pool": {
"size": 4,
"idle_timeout": 8,
"requests": 16
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri":"/hello",
"upstream_id": 1
}]])
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
=== TEST 3: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
for i = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
end
}
}
--- response_body
hello world
hello world
hello world
--- grep_error_log eval
qr/lua balancer: keepalive .*/
--- grep_error_log_out eval
qr/^lua balancer: keepalive create pool, crc32: \S+, size: 4
lua balancer: keepalive no free connection, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
lua balancer: keepalive reusing connection \S+, requests: 1, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
lua balancer: keepalive reusing connection \S+, requests: 2, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
$/
=== TEST 4: only reuse one time
--- 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,
[[{
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
},
"keepalive_pool": {
"size": 1,
"idle_timeout": 8,
"requests": 2
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
=== TEST 5: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
for i = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
end
}
}
--- response_body
hello world
hello world
hello world
--- grep_error_log eval
qr/lua balancer: keepalive .*/
--- grep_error_log_out eval
qr/^lua balancer: keepalive create pool, crc32: \S+, size: 1
lua balancer: keepalive no free connection, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
lua balancer: keepalive reusing connection \S+, requests: 1, cpool: \S+
lua balancer: keepalive not saving connection \S+, cpool: \S+, connections: 0
lua balancer: keepalive free pool \S+, crc32: \S+
lua balancer: keepalive create pool, crc32: \S+, size: 1
lua balancer: keepalive no free connection, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
$/
=== TEST 6: set upstream without keepalive_pool
--- 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,
[[{
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
}
}
=== TEST 7: should not override default value
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/hello"
for i = 1, 3 do
local httpc = http.new()
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
end
}
}
--- response_body
hello world
hello world
hello world
--- grep_error_log eval
qr/lua balancer: keepalive .*/
--- grep_error_log_out eval
qr/^lua balancer: keepalive create pool, crc32: \S+, size: 320
lua balancer: keepalive no free connection, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
lua balancer: keepalive reusing connection \S+, requests: 1, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
lua balancer: keepalive reusing connection \S+, requests: 2, cpool: \S+
lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
$/
=== TEST 8: upstreams with different client cert
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local test = require("lib.test_admin").test
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 ssl_cert2 = t.read_file("t/certs/apisix.crt")
local ssl_key2 = t.read_file("t/certs/apisix.key")
local code, body = test('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"scheme": "https",
"type": "roundrobin",
"nodes": {
"127.0.0.1:1983": 1
},
"keepalive_pool": {
"size": 4
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
},
keepalive_pool = {
size = 8
}
}
local code, body = test('/apisix/admin/upstreams/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert2,
client_key = ssl_key2,
},
keepalive_pool = {
size = 16
}
}
local code, body = test('/apisix/admin/upstreams/3',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
for i = 1, 3 do
local code, body = test('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"uri":"/hello/]] .. i .. [[",
"plugins": {
"proxy-rewrite": {
"uri": "/hello"
}
},
"upstream_id": ]] .. i .. [[
}]])
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
end
}
}
--- response_body
=== TEST 9: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
for i = 1, 12 do
local idx = (i % 3) + 1
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
if not res then
ngx.say(err)
return
end
if idx == 2 then
assert(res.status == 200)
else
assert(res.status == 400)
end
end
}
}
=== TEST 10: upstreams with different client cert (without pool)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local test = require("lib.test_admin").test
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 ssl_cert2 = t.read_file("t/certs/apisix.crt")
local ssl_key2 = t.read_file("t/certs/apisix.key")
local code, body = test('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"scheme": "https",
"type": "roundrobin",
"nodes": {
"127.0.0.1:1983": 1
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
}
local code, body = test('/apisix/admin/upstreams/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert2,
client_key = ssl_key2,
}
}
local code, body = test('/apisix/admin/upstreams/3',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
for i = 1, 3 do
local code, body = test('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"uri":"/hello/]] .. i .. [[",
"plugins": {
"proxy-rewrite": {
"uri": "/hello"
}
},
"upstream_id": ]] .. i .. [[
}]])
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
end
}
}
--- response_body
=== TEST 11: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
for i = 1, 12 do
local idx = (i % 3) + 1
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
if not res then
ngx.say(err)
return
end
if idx == 2 then
assert(res.status == 200)
else
assert(res.status == 400)
end
end
}
}
=== TEST 12: upstreams with different SNI
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local test = require("lib.test_admin").test
local json = require("toolkit.json")
local code, body = test('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"scheme": "https",
"type": "roundrobin",
"nodes": {
"127.0.0.1:1983": 1
},
"pass_host": "rewrite",
"upstream_host": "a.com",
"keepalive_pool": {
"size": 4
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
pass_host = "rewrite",
upstream_host = "b.com",
keepalive_pool = {
size = 8
}
}
local code, body = test('/apisix/admin/upstreams/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
for i = 1, 2 do
local code, body = test('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"uri":"/hello/]] .. i .. [[",
"plugins": {
"proxy-rewrite": {
"uri": "/hello"
}
},
"upstream_id": ]] .. i .. [[
}]])
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
end
}
}
--- response_body
=== TEST 13: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
for i = 1, 4 do
local idx = i % 2 + 1
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
end
}
}
--- grep_error_log eval
qr/lua balancer: keepalive create pool, .*/
--- grep_error_log_out eval
qr/^lua balancer: keepalive create pool, crc32: \S+, size: 8
lua balancer: keepalive create pool, crc32: \S+, size: 4
$/
=== TEST 14: upstreams with SNI, then without SNI
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local test = require("lib.test_admin").test
local json = require("toolkit.json")
local code, body = test('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"scheme": "https",
"type": "roundrobin",
"nodes": {
"127.0.0.1:1983": 1
},
"pass_host": "rewrite",
"upstream_host": "a.com",
"keepalive_pool": {
"size": 4
}
}]]
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
local data = {
scheme = "http",
type = "roundrobin",
nodes = {
["127.0.0.1:1980"] = 1,
},
pass_host = "rewrite",
upstream_host = "b.com",
keepalive_pool = {
size = 8
}
}
local code, body = test('/apisix/admin/upstreams/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
for i = 1, 2 do
local code, body = test('/apisix/admin/routes/' .. i,
ngx.HTTP_PUT,
[[{
"uri":"/hello/]] .. i .. [[",
"plugins": {
"proxy-rewrite": {
"uri": "/hello"
}
},
"upstream_id": ]] .. i .. [[
}]])
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
end
}
}
--- response_body
=== TEST 15: hit
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
for i = 0, 1 do
local idx = i % 2 + 1
local httpc = http.new()
local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
end
}
}
--- grep_error_log eval
qr/lua balancer: keepalive create pool, .*/
--- grep_error_log_out eval
qr/^lua balancer: keepalive create pool, crc32: \S+, size: 4
lua balancer: keepalive create pool, crc32: \S+, size: 8
$/
=== TEST 16: backend serve http and grpc with the same port
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local test = require("lib.test_admin").test
local json = require("toolkit.json")
local data = {
uri = "",
upstream = {
scheme = "",
type = "roundrobin",
nodes = {
["127.0.0.1:10054"] = 1,
},
keepalive_pool = {
size = 4
}
}
}
data.uri = "/helloworld.Greeter/SayHello"
data.upstream.scheme = "grpc"
local code, body = test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
data.uri = "/hello"
data.upstream.scheme = "http"
local code, body = test('/apisix/admin/routes/2',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.print(body)
return
end
}
}
--- response_body
=== TEST 17: hit http
--- request
GET /hello
--- response_body chomp
hello http
=== TEST 18: hit grpc
--- http2
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body
{
"message": "Hello apisix"
}

View File

@@ -0,0 +1,684 @@
#
# 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;
my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
my $version = eval { `$nginx_binary -V 2>&1` };
if ($version !~ m/\/apisix-nginx-module/) {
plan(skip_all => "apisix-nginx-module not installed");
} else {
plan('no_plan');
}
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
});
run_tests();
__DATA__
=== TEST 1: tls without key
--- 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 data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
}
},
uri = "/hello"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"tls\" validation failed: failed to validate dependent schema for \"client_cert\": property \"client_key\" is required"}
=== TEST 2: tls with bad key
--- 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 data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ("AAA"):rep(128),
}
},
uri = "/hello"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"failed to decrypt previous encrypted key"}
--- error_log
decrypt ssl key failed
=== TEST 3: encrypt key by default
--- 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 = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
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.say(body)
return
end
local code, body, res = t.test('/apisix/admin/routes/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
res = json.decode(res)
ngx.say(res.value.upstream.tls.client_key == ssl_key)
-- upstream
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
}
local code, body = t.test('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body, res = t.test('/apisix/admin/upstreams/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
res = json.decode(res)
ngx.say(res.value.tls.client_key == ssl_key)
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
}
local code, body = t.test('/apisix/admin/services/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body, res = t.test('/apisix/admin/services/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
res = json.decode(res)
ngx.say(res.value.upstream.tls.client_key == ssl_key)
}
}
--- request
GET /t
--- response_body
false
false
false
=== TEST 4: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /hello
--- response_body
hello world
=== TEST 5: wrong cert
--- 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/apisix.crt")
local ssl_key = t.read_file("t/certs/apisix.key")
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
uri = "/hello"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /hello
--- error_code: 400
--- error_log
client SSL certificate verify error
=== TEST 7: clean old data
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
assert(t.test('/apisix/admin/routes/1',
ngx.HTTP_DELETE
))
assert(t.test('/apisix/admin/services/1',
ngx.HTTP_DELETE
))
assert(t.test('/apisix/admin/upstreams/1',
ngx.HTTP_DELETE
))
}
}
--- request
GET /t
=== TEST 8: don't encrypt key
--- yaml_config
apisix:
node_listen: 1984
data_encryption:
keyring: null
--- 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 = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
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.say(body)
return
end
local code, body, res = t.test('/apisix/admin/routes/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
res = json.decode(res)
ngx.say(res.value.upstream.tls.client_key == ssl_key)
-- upstream
local data = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
}
local code, body = t.test('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body, res = t.test('/apisix/admin/upstreams/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
res = json.decode(res)
ngx.say(res.value.tls.client_key == ssl_key)
local data = {
upstream = {
scheme = "https",
type = "roundrobin",
nodes = {
["127.0.0.1:1983"] = 1,
},
tls = {
client_cert = ssl_cert,
client_key = ssl_key,
}
},
}
local code, body = t.test('/apisix/admin/services/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body, res = t.test('/apisix/admin/services/1',
ngx.HTTP_GET
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
res = json.decode(res)
ngx.say(res.value.upstream.tls.client_key == ssl_key)
}
}
--- request
GET /t
--- response_body
true
true
true
=== TEST 9: bind upstream
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local data = {
upstream_id = 1,
uri = "/server_port"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- request
GET /t
=== TEST 10: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /server_port
--- response_body chomp
1983
=== TEST 11: bind service
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local data = {
service_id = 1,
uri = "/hello_chunked"
}
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- request
GET /t
=== TEST 12: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /hello_chunked
--- response_body
hello world
=== TEST 13: get cert by tls.client_cert_id
--- 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 = {
type = "client",
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.say(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.say(body)
return
end
}
}
--- request
GET /t
=== TEST 14: hit
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /hello
--- response_body
hello world
=== TEST 15: change ssl object 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 = {
type = "server",
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.say(body)
return
end
}
}
--- request
GET /t
=== TEST 16: hit, ssl object type mismatch
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /hello
--- error_code: 502
--- error_log
failed to get ssl cert: ssl type should be 'client'
=== TEST 17: delete ssl object
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin")
local json = require("toolkit.json")
local code, body = t.test('/apisix/admin/ssls/1', ngx.HTTP_DELETE)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
}
}
--- request
GET /t
=== TEST 18: hit, ssl object not exits
--- upstream_server_config
ssl_client_certificate ../../certs/mtls_ca.crt;
ssl_verify_client on;
--- request
GET /hello
--- error_code: 502
--- error_log
failed to get ssl cert: ssl id [1] not exits

View File

@@ -0,0 +1,558 @@
#
# 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);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: route with one upstream node
--- 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": {
"test1.com:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit route, resolve upstream node to "127.0.0.2" always
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
utils.dns_parse = function (domain) -- mock: DNS parser
if domain == "test1.com" then
return {address = "127.0.0.2"}
end
error("unknown domain: " .. domain)
end
--- request
GET /hello
--- response_body
hello world
=== TEST 3: hit route, resolve upstream node to different values
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" then
return {address = "127.0.0." .. count}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
core.log.info("call /hello")
local code, body = t('/hello', ngx.HTTP_GET)
}
}
--- request
GET /t
--- grep_error_log eval
qr/dns resolver domain: test1.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
--- grep_error_log_out
call /hello
dns resolver domain: test1.com to 127.0.0.1
proxy request to 127.0.0.1:1980
=== TEST 4: set route with two upstream nodes
--- 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": {
"test1.com:1980": 1,
"test2.com:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: hit route, resolve the upstream node to "127.0.0.2"
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
utils.dns_parse = function (domain) -- mock: DNS parser
if domain == "test1.com" or domain == "test2.com" then
return {address = "127.0.0.2"}
end
error("unknown domain: " .. domain)
end
--- request
GET /hello
--- response_body
hello world
=== TEST 6: hit route, resolve upstream node to different values
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" or domain == "test2.com" then
return {address = "127.0.0." .. count}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
core.log.info("call /hello")
local code, body = t('/hello', ngx.HTTP_GET)
core.log.warn("code: ", code)
}
}
--- request
GET /t
--- grep_error_log eval
qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
--- grep_error_log_out eval
qr/call \/hello(
dns resolver domain: test1.com to 127.0.0.1
dns resolver domain: test2.com to 127.0.0.2|
dns resolver domain: test2.com to 127.0.0.1
dns resolver domain: test1.com to 127.0.0.2)
proxy request to 127.0.0.[12]:1980
/
=== TEST 7: upstream with one upstream node
--- 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": {
"test1.com:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: set route with upstream_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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: hit route, resolve upstream node to different values
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" then
return {address = "127.0.0." .. count}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
core.log.info("call /hello")
local code, body = t('/hello', ngx.HTTP_GET)
}
}
--- request
GET /t
--- grep_error_log eval
qr/dns resolver domain: test1.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
--- grep_error_log_out
call /hello
dns resolver domain: test1.com to 127.0.0.1
proxy request to 127.0.0.1:1980
=== TEST 10: two upstream nodes in upstream object
--- 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": {
"test1.com:1980": 1,
"test2.com:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: hit route, resolve upstream node to different values
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" or domain == "test2.com" then
return {address = "127.0.0." .. count}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
core.log.info("call /hello")
local code, body = t('/hello', ngx.HTTP_GET)
}
}
--- request
GET /t
--- grep_error_log eval
qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
--- grep_error_log_out eval
qr/call \/hello(
dns resolver domain: test1.com to 127.0.0.1
dns resolver domain: test2.com to 127.0.0.2|
dns resolver domain: test2.com to 127.0.0.1
dns resolver domain: test1.com to 127.0.0.2)
proxy request to 127.0.0.[12]:1980
/
=== TEST 12: dns cached expired, resolve the domain always with same value
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 1
utils.dns_parse = function (domain) -- mock: DNS parser
if domain == "test1.com" or domain == "test2.com" then
return {address = "127.0.0.1"}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
core.log.info("call /hello")
local code, body = t('/hello', ngx.HTTP_GET)
}
}
--- request
GET /t
--- grep_error_log eval
qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:1980/
--- grep_error_log_out eval
qr/call \/hello(
dns resolver domain: test1.com to 127.0.0.1
dns resolver domain: test2.com to 127.0.0.1|
dns resolver domain: test2.com to 127.0.0.1
dns resolver domain: test1.com to 127.0.0.1)
proxy request to 127.0.0.1:1980
/
=== TEST 13: two upstream nodes in upstream object (one host + one IP)
--- 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": {
"test1.com:1980": 1,
"127.0.0.5:1981": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: dns cached expired, resolve the domain with different values
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" or domain == "test2.com" then
return {address = "127.0.0." .. count}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
core.log.info("call /hello")
local code, body = t('/hello', ngx.HTTP_GET)
}
}
--- request
GET /t
--- grep_error_log eval
qr/dns resolver domain: \w+.com to 127.0.0.\d|call \/hello|proxy request to 127.0.0.\d:198\d/
--- grep_error_log_out eval
qr/call \/hello
dns resolver domain: test1.com to 127.0.0.1
proxy request to 127.0.0.(1:1980|5:1981)
/
=== TEST 15: route with upstream node, the domain's IP is changed
--- 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": {
"test1.com:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 16: hit
--- init_by_lua_block
require "resty.core"
apisix = require("apisix")
core = require("apisix.core")
apisix.http_init()
local utils = require("apisix.core.utils")
local count = 0
utils.dns_parse = function (domain) -- mock: DNS parser
count = count + 1
if domain == "test1.com" then
return {address = "127.0.0." .. count}
end
error("unknown domain: " .. domain)
end
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
t('/hello', ngx.HTTP_GET)
-- avoid adding more "dns_value" into the route
t('/hello', ngx.HTTP_GET)
}
}
--- request
GET /t
--- grep_error_log eval
qr/parse route which contain domain: .+("dns_value":.+){3}/
--- grep_error_log_out

View File

@@ -0,0 +1,304 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set upstream(id: 1), by default retries count = number of 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_PUT,
[[{
"nodes": {
"127.0.0.1:1": 1,
"127.0.0.2:1": 1,
"127.0.0.3:1": 1,
"127.0.0.4:1": 1
},
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: hit routes
--- request
GET /hello
--- error_code: 502
--- grep_error_log eval
qr/\[error\]/
--- grep_error_log_out
[error]
[error]
[error]
[error]
=== TEST 5: hit routes
--- request
GET /hello
--- error_code: 502
--- error_log
connect() failed
=== TEST 6: set upstream(id: 1), retries = 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:1": 1,
"127.0.0.2:1": 1,
"127.0.0.3:1": 1,
"127.0.0.4:1": 1
},
"retries": 1,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: hit routes
--- request
GET /hello
--- error_code: 502
--- grep_error_log eval
qr/\[error\]/
--- grep_error_log_out
[error]
[error]
=== TEST 8: set upstream(id: 1), retries = 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_PUT,
[[{
"nodes": {
"127.0.0.1:1": 1,
"127.0.0.2:1": 1,
"127.0.0.3:1": 1,
"127.0.0.4:1": 1
},
"retries": 0,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: hit routes
--- request
GET /hello
--- error_code: 502
--- grep_error_log eval
qr/\[error\]/
--- grep_error_log_out
[error]
=== TEST 10: set upstream, retries > number of nodes, only try number of nodes time
--- 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:1": 1,
"127.0.0.2:1": 1
},
"retries": 3,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: hit routes
--- request
GET /hello
--- error_code: 502
--- error_log
all upstream servers tried
--- grep_error_log eval
qr/connect\(\) failed/
--- grep_error_log_out
connect() failed
connect() failed
=== TEST 12: don't retry the same node twice
--- request
GET /hello
--- error_code: 502
--- error_log
Connection refused
failed to find valid upstream server
proxy request to 127.0.0.1:1
proxy request to 127.0.0.2:1
=== TEST 13: stop proxy to next upstream by retry_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,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 100,
"127.0.0.1:1981": 100,
"127.0.0.1:1982": 100
},
"retries": 10,
"retry_timeout": 0.15,
"type": "roundrobin"
},
"uri": "/mysleep"
}]]
)
if code ~= 200 then
ngx.say(body)
return
end
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/mysleep?abort=true&seconds=0.1"
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ngx.status = res.status
ngx.say(res.status)
}
}
--- request
GET /t
--- error_code: 502
--- error_log
proxy retry timeout, retry count: 1

View File

@@ -0,0 +1,407 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set route(id: 1) and available upstream
--- 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: hit the route and $upstream_status is 200
--- request
GET /hello
--- response_body
hello world
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 200/
--- grep_error_log_out
=== TEST 3: set route(id: 1) and set the timeout field
--- 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:1980": 1
},
"type": "roundrobin",
"timeout": {
"connect": 0.5,
"send": 0.5,
"read": 0.5
}
},
"uri": "/mysleep"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: hit routes (timeout) and $upstream_status is 504
--- request
GET /mysleep?seconds=1
--- error_code: 504
--- response_body eval
qr/504 Gateway Time-out/
--- response_headers
X-APISIX-Upstream-Status: 504
--- error_log
Connection timed out
=== TEST 5: set route(id: 1), upstream service is not available
--- 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:1": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: hit routes and $upstream_status is 502
--- request
GET /hello
--- error_code: 502
--- response_body eval
qr/502 Bad Gateway/
--- response_headers
X-APISIX-Upstream-Status: 502
--- error_log
Connection refused
=== TEST 7: set route(id: 1) and uri is `/server_error`
--- 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/server_error"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 8: hit routes and $upstream_status is 500
--- request
GET /server_error
--- error_code: 500
--- response_body eval
qr/500 Internal Server Error/
--- response_headers
X-APISIX-Upstream-Status: 500
--- error_log
500 Internal Server Error
=== TEST 9: set upstream(id: 1, retries = 2), has available 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.2:1": 1,
"127.0.0.1:1980": 1
},
"retries": 2,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: set route(id: 1) and bind the 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: hit routes and $upstream_status is `502, 200`
--- request
GET /hello
--- response_body
hello world
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 502, 200/
--- grep_error_log_out
=== TEST 12: set upstream(id: 1, retries = 2), all upstream nodes are unavailable
--- 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.3:1": 1,
"127.0.0.2:1": 1,
"127.0.0.1:1": 1
},
"retries": 2,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 13: hit routes, retry between upstream failed, $upstream_status is `502, 502, 502`
--- request
GET /hello
--- error_code: 502
--- response_headers_raw_like eval
qr/X-APISIX-Upstream-Status: 502, 502, 502/
--- error_log
Connection refused
=== TEST 14: return 500 status code from APISIX
--- 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": {
"fault-injection": {
"abort": {
"http_status": 500,
"body": "Fault Injection!\n"
}
}
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 15: hit routes, status code is 500
--- request
GET /hello
--- error_code: 500
--- response_body
Fault Injection!
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 500/
--- grep_error_log_out
=== TEST 16: return 200 status code from APISIX
--- 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": {
"fault-injection": {
"abort": {
"http_status": 200,
"body": "Fault Injection!\n"
}
}
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 17: hit routes, status code is 200
--- request
GET /hello
--- response_body
Fault Injection!
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 200/
--- grep_error_log_out

View File

@@ -0,0 +1,465 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});
run_tests();
__DATA__
=== TEST 1: set route(id: 1) and available upstream and show_upstream_status_in_response_header: true
--- 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 2: hit the route and $upstream_status is 200
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /hello
--- response_body
hello world
--- response_headers
X-APISIX-Upstream-Status: 200
=== TEST 3: set route(id: 1) and set the timeout field
--- 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:1980": 1
},
"type": "roundrobin",
"timeout": {
"connect": 0.5,
"send": 0.5,
"read": 0.5
}
},
"uri": "/mysleep"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 4: hit routes (timeout) and $upstream_status is 504
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /mysleep?seconds=1
--- error_code: 504
--- response_body eval
qr/504 Gateway Time-out/
--- response_headers
X-APISIX-Upstream-Status: 504
--- error_log
Connection timed out
=== TEST 5: set route(id: 1), upstream service is not available
--- 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:1": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 6: hit routes and $upstream_status is 502
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /hello
--- error_code: 502
--- response_body eval
qr/502 Bad Gateway/
--- response_headers
X-APISIX-Upstream-Status: 502
--- error_log
Connection refused
=== TEST 7: set route(id: 1) and uri is `/server_error`
--- 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/server_error"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 8: hit routes and $upstream_status is 500
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /server_error
--- error_code: 500
--- response_body eval
qr/500 Internal Server Error/
--- response_headers
X-APISIX-Upstream-Status: 500
--- error_log
500 Internal Server Error
=== TEST 9: set upstream(id: 1, retries = 2), has available 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.1.0.2:1": 1,
"127.0.0.1:1980": 1
},
"retries": 2,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 10: set route(id: 1) and bind the 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 11: hit routes and $upstream_status is `502, 200`
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /hello
--- response_body
hello world
--- response_headers_raw_like eval
qr/X-APISIX-Upstream-Status: 502, 200|X-APISIX-Upstream-Status: 200/
--- error_log
=== TEST 12: set upstream(id: 1, retries = 2), all upstream nodes are unavailable
--- 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.3:1": 1,
"127.0.0.2:1": 1,
"127.0.0.1:1": 1
},
"retries": 2,
"type": "roundrobin"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 13: hit routes, retry between upstream failed, $upstream_status is `502, 502, 502`
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /hello
--- error_code: 502
--- response_headers_raw_like eval
qr/X-APISIX-Upstream-Status: 502, 502, 502/
--- error_log
Connection refused
=== TEST 14: return 500 status code from APISIX
--- 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": {
"fault-injection": {
"abort": {
"http_status": 500,
"body": "Fault Injection!\n"
}
}
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 15: hit routes, status code is 500
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /hello
--- error_code: 500
--- response_body
Fault Injection!
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 500/
--- grep_error_log_out
=== TEST 16: return 200 status code from APISIX
--- 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": {
"fault-injection": {
"abort": {
"http_status": 200,
"body": "Fault Injection!\n"
}
}
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 17: hit routes, status code is 200
--- yaml_config
apisix:
show_upstream_status_in_response_header: true
--- request
GET /hello
--- response_body
Fault Injection!
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 200/
--- grep_error_log_out
=== TEST 18: return 200 status code from APISIX (with show_upstream_status_in_response_header:false)
--- 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": {
"fault-injection": {
"abort": {
"http_status": 200,
"body": "Fault Injection!\n"
}
}
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 19: hit routes, status code is 200
--- yaml_config
apisix:
show_upstream_status_in_response_header: false
--- request
GET /hello
--- response_body
Fault Injection!
--- grep_error_log eval
qr/X-APISIX-Upstream-Status: 200/
--- grep_error_log_out

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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set upstream with websocket (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:1980": 1
},
"type": "roundrobin"
},
"enable_websocket": true,
"uri": "/websocket_handshake"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: send websocket
--- raw_request eval
"GET /websocket_handshake HTTP/1.1\r
Host: server.example.com\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r
Sec-WebSocket-Protocol: chat\r
Sec-WebSocket-Version: 13\r
Origin: http://example.com\r
\r
"
--- response_headers
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
!Content-Type
--- raw_response_headers_like: ^HTTP/1.1 101 Switching Protocols\r\n
--- response_body_like eval
qr/hello/
--- error_code: 101
=== TEST 3: set upstream(id: 6)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/6',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:1981": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: set route with upstream websocket enabled(id: 6)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/6',
ngx.HTTP_PUT,
[[{
"uri": "/websocket_handshake/route",
"enable_websocket": true,
"upstream_id": "6"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 5: send success websocket to upstream
--- raw_request eval
"GET /websocket_handshake/route HTTP/1.1\r
Host: server.example.com\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r
Sec-WebSocket-Protocol: chat\r
Sec-WebSocket-Version: 13\r
Origin: http://example.com\r
\r
"
--- response_headers
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
!Content-Type
--- raw_response_headers_like: ^HTTP/1.1 101 Switching Protocols\r\n
--- response_body_like eval
qr/hello/
--- error_code: 101
=== TEST 6: disable websocket(id: 6)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/6',
ngx.HTTP_PUT,
[[{
"uri": "/websocket_handshake/route",
"enable_websocket": false,
"upstream_id": "6"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: send websocket to upstream without header support
--- raw_request eval
"GET /websocket_handshake/route HTTP/1.1\r
Host: server.example.com\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r
Sec-WebSocket-Protocol: chat\r
Sec-WebSocket-Version: 13\r
Origin: http://example.com\r
\r
"
[error]
--- error_code: 400
--- grep_error_log eval
qr/failed to new websocket: bad "upgrade" request header: nil/
--- grep_error_log_out
=== TEST 8: set wss
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"scheme": "https",
"nodes": {
"127.0.0.1:1983": 1
},
"type": "roundrobin"
},
"enable_websocket": true,
"uri": "/websocket_handshake"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
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 = "127.0.0.1"}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 9: send websocket
--- config
location /t {
content_by_lua_block {
local client = require "resty.websocket.client"
local wb = client:new()
local uri = "wss://127.0.0.1:1994/websocket_handshake"
local opts = {
server_name = "127.0.0.1"
}
local ok, err = wb:connect(uri, opts)
if not ok then
ngx.say("failed to connect: " .. err)
return
end
local typ
data, typ, err = wb:recv_frame()
if not data then
ngx.say("failed to receive 2nd frame: ", err)
return
end
ngx.say("received: ", data, " (", typ, ")")
}
}
--- request
GET /t
--- response_body
received: hello (text)

View File

@@ -0,0 +1,630 @@
#
# 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);
log_level('info');
worker_connections(256);
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set upstream(id: 1) invalid parameters
--- 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,
[[{
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
=== TEST 2: set upstream(id: 1) 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_PUT,
[[{
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"desc": "new upstream"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 3: 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,
[[{
"uri": "/hello",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 4: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 5: hit routes
--- request
GET /hello
--- response_body
hello world
=== TEST 6: delete upstream(id: 1)
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.5)
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)
}
}
--- request
GET /t
--- response_body
[delete] code: 400 message: {"error_msg":"can not delete this upstream, route [1] is still using it now"}
=== 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/routes/1',
ngx.HTTP_DELETE
)
ngx.say("[delete] code: ", code, " message: ", message)
}
}
--- request
GET /t
--- response_body
[delete] code: 200 message: passed
=== TEST 8: 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 9: delete upstream again(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)
}
}
--- request
GET /t
--- response_body
[delete] code: 404
=== TEST 10: set upstream(id: 1, using `node` mode to pass upstream host)
--- 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": {
"test.com:1980": 1
},
"type": "roundrobin",
"desc": "new upstream",
"pass_host": "node"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 11: set route(id: 1, using `node` mode to pass upstream 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,
[[{
"uri": "/echo",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 12: hit route
--- request
GET /echo
--- response_headers
host: test.com:1980
=== TEST 13: set upstream(using `rewrite` mode to pass upstream host)
--- 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",
"desc": "new upstream",
"pass_host": "rewrite",
"upstream_host": "test.com"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: set route(using `rewrite` mode to pass upstream 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,
[[{
"uri": "/echo",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 15: hit route
--- request
GET /echo
--- response_headers
host: test.com
=== TEST 16: delete upstream in used
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
ngx.sleep(0.5) -- wait for data synced
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_DELETE
)
if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"can not delete this upstream, route [1] is still using it now"}
=== TEST 17: 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/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"localhost:1979": 1000,
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"pass_host": "node"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/uri",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 18: hit route
--- request
GET /uri
--- response_body eval
qr/host: 127.0.0.1/
--- error_log
proxy request to 127.0.0.1:1980
=== TEST 19: multi nodes with `node` mode to pass host, the second node has domain
--- 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:1979": 1000,
"localhost:1980": 1
},
"type": "roundrobin",
"pass_host": "node"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/uri",
"upstream_id": "1"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 20: hit route
--- request
GET /uri
--- response_body eval
qr/host: localhost/
--- error_log
proxy request to 127.0.0.1:1980
=== TEST 21: check that including port in host header is supported when pass_host = node and port is not standard
--- 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": {
"localhost:1980": 1000
},
"type": "roundrobin",
"pass_host": "node"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream_id": "1",
"uri": "/uri"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 22: hit route
--- request
GET /uri
--- response_body eval
qr/host: localhost:1980/
=== TEST 23: check that including port in host header is supported when retrying and pass_host = node and port is not standard
--- 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:1979": 1000,
"localhost:1980": 1
},
"type": "roundrobin",
"pass_host": "node"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream_id": "1",
"uri": "/uri"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 24: hit route
--- log_level: debug
--- request
GET /uri
--- error_log
Host: 127.0.0.1:1979
=== TEST 25: distinguish different upstreams even they have the same addr
--- 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 = {["localhost:1980"] = 1},
type = "roundrobin"
}
)
assert(code < 300)
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream_id": "1",
"uri": "/server_port"
}]]
)
assert(code < 300)
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
.. "/server_port"
local ports_count = {}
for i = 1, 24 do
local httpc = http.new()
local res, err = httpc:request_uri(uri)
if not res then
ngx.say(err)
return
end
ports_count[res.body] = (ports_count[res.body] or 0) + 1
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
{
nodes = {["localhost:" .. (1980 + i % 3)] = 1},
type = "roundrobin"
}
)
assert(code < 300)
end
local ports_arr = {}
for port, count in pairs(ports_count) do
table.insert(ports_arr, {port = port, count = count})
end
local function cmd(a, b)
return a.port > b.port
end
table.sort(ports_arr, cmd)
ngx.say(require("toolkit.json").encode(ports_arr))
}
}
--- request
GET /t
--- timeout: 5
--- response_body
[{"count":8,"port":"1982"},{"count":8,"port":"1981"},{"count":8,"port":"1980"}]

View File

@@ -0,0 +1,343 @@
#
# 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);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: set route(only arg_k)
--- 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": [ ["arg_k", "==", "v"] ],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: /not_found
--- request
GET /hello?k=not-hit
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: hit routes
--- request
GET /hello?k=v
--- response_body
hello world
=== TEST 5: set route(cookie)
--- 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": [["cookie_k", "==", "v"]],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]=]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 6: /not_found
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 7: /not_found
--- more_headers
Cookie: k=not-hit; kkk=vvv;
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 8: hit routes
--- more_headers
Cookie: k=v; kkk=vvv;
--- request
GET /hello
--- response_body
hello world
=== TEST 9: set route(header)
--- 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": [["http_k", "==", "v"]],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]=]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 10: /not_found
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 11: /not_found
--- more_headers
k: not-hit
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 12: hit routes
--- more_headers
k: v
--- request
GET /hello
--- response_body
hello world
=== TEST 13: set route(uri arg + header + cookie)
--- 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": [["http_k", "==", "header"], ["cookie_k", "==", "cookie"], ["arg_k", "==", "uri_arg"]],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]=]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 14: /not_found
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 15: /not_found
--- more_headers
k: header
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 16: hit routes
--- more_headers
Cookie: k=cookie
k: header
--- request
GET /hello?k=uri_arg
--- response_body
hello world
=== TEST 17: set route(only post arg)
--- 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_k", "==", "post_form"]],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]=]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 18: not_found (GET request)
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 19: not_found (wrong request body)
--- request
POST /hello
123
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 20: not_found (wrong content type)
--- request
POST /hello
k=post_form
--- more_headers
Content-Type: multipart/form-data
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 21: hit routes
--- request
POST /hello
k=post_form
--- more_headers
Content-Type: application/x-www-form-urlencoded
--- response_body
hello world

View File

@@ -0,0 +1,102 @@
#
# 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: 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:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 2: /not_found
--- request
GET /not_found
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 3: not found, missing host
--- request
GET /hello
--- error_code: 404
--- response_body
{"error_msg":"404 Route Not Found"}
=== TEST 4: host: a.foo.com
--- request
GET /hello
--- more_headers
Host: a.foo.com
--- response_body
hello world
=== TEST 5: host: a.b.foo.com
--- request
GET /hello
--- more_headers
Host: a.b.foo.com
--- response_body
hello world
=== TEST 6: host: .foo.com
--- request
GET /hello
--- more_headers
Host: .foo.com
--- response_body
hello world