This is an automated email from the ASF dual-hosted git repository.
xiaoyu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu-nginx.git
The following commit(s) were added to refs/heads/main by this push:
new 199c6e2 add integration test (#5)
199c6e2 is described below
commit 199c6e27e25e45afb7e5328c60273ca0bf580db9
Author: zhc <[email protected]>
AuthorDate: Fri May 20 09:39:10 2022 +0800
add integration test (#5)
---
.github/workflows/it.yaml | 46 +++++++++++++
lib/shenyu/register/etcd.lua | 19 ++++--
test/it/consumer/Dockerfile | 26 ++++++++
test/it/consumer/bin/entrypoint.sh | 93 +++++++++++++++++++++++++++
test/it/docker-compose.yml | 125 ++++++++++++++++++++++++++++++++++++
test/it/gateway/Dockerfile | 27 ++++++++
test/it/gateway/conf/nginx.conf | 51 +++++++++++++++
test/it/mock-shenyu/Dockerfile | 22 +++++++
test/it/mock-shenyu/conf/nginx.conf | 74 +++++++++++++++++++++
9 files changed, 476 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/it.yaml b/.github/workflows/it.yaml
new file mode 100644
index 0000000..e769f3b
--- /dev/null
+++ b/.github/workflows/it.yaml
@@ -0,0 +1,46 @@
+# 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.
+
+name: IT
+
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+ tags:
+ - 'v*'
+
+jobs:
+ etcd:
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: true
+ - uses: actions/setup-java@v1
+ with:
+ java-version: 8
+ - run: |
+ docker-compose -f ./test/it/docker-compose.yml run -d consumer
+ docker wait $(docker ps -qa --filter Name=it_consumer)
+ status="$?"
+ docker-compose -f ./test/it/docker-compose.yml logs
+ if [ $status -eq 0 ]; then
+ docker-compose -f test/it/docker-compose.yml logs consumer
+ fi
+ docker-compose -f ./test/it/docker-compose.yml kill
diff --git a/lib/shenyu/register/etcd.lua b/lib/shenyu/register/etcd.lua
index 27a020d..6f3ee21 100644
--- a/lib/shenyu/register/etcd.lua
+++ b/lib/shenyu/register/etcd.lua
@@ -117,9 +117,12 @@ local function fetch_shenyu_instances(conf)
local _revision = _M.revision
local shenyu_instances = _M.shenyu_instances
- local server_list = {}
local kvs = json.decode(res.body).kvs
+ if not kvs then
+ return false
+ end
+ local server_list = {}
for _, kv in pairs(kvs) do
local ver = tonumber(kv.mod_revision)
if _revision < ver then
@@ -205,20 +208,22 @@ local function watch(premature, watching)
end
if not watching then
- local conf, err = parse_base_url(_M.etcd_base_url)
- if not conf then
- log(ERR, err)
- return err
+ if not _M.etcd_conf then
+ local conf, err = parse_base_url(_M.etcd_base_url)
+ if not conf then
+ log(ERR, err)
+ return err
+ end
+ _M.etcd_conf = conf
end
- local ok, err = fetch_shenyu_instances(conf)
+ local ok, err = fetch_shenyu_instances(_M.etcd_conf)
if not ok then
log(ERR, err)
_M.time_at = 3
else
watching = true
end
- _M.etcd_conf = conf
else
local conf = _M.etcd_conf
local httpc = http.new()
diff --git a/test/it/consumer/Dockerfile b/test/it/consumer/Dockerfile
new file mode 100644
index 0000000..2952ded
--- /dev/null
+++ b/test/it/consumer/Dockerfile
@@ -0,0 +1,26 @@
+# 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.
+
+FROM alpine
+
+WORKDIR /consumer
+
+RUN apk add --no-cache curl
+
+COPY ./test/it/consumer/bin/entrypoint.sh entrypoint.sh
+RUN chmod +x /consumer/entrypoint.sh
+
+ENTRYPOINT /bin/sh -c /consumer/entrypoint.sh
diff --git a/test/it/consumer/bin/entrypoint.sh
b/test/it/consumer/bin/entrypoint.sh
new file mode 100644
index 0000000..a78b8e3
--- /dev/null
+++ b/test/it/consumer/bin/entrypoint.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env sh
+
+# 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
+
+
+inst_addr_1=$(curl -s http://instance1:9090/get)
+if [[ -z "$inst_addr_1" ]]; then
+ echo "failed to start instance 1."
+ exit 129
+fi
+
+inst_addr_2=$(curl -s http://instance2:9090/get)
+if [[ -z "$inst_addr_2" ]]; then
+ echo "failed to start instance 2."
+ exit 129
+fi
+
+rst=$(curl -Is http://gateway:8080/get | grep "HTTP/1.1 500")
+if [[ -z "$rst" ]]; then
+ echo "failed to set new environment for testing."
+ exit 128
+fi
+
+rst=$(curl -Is http://instance1:9090/register | grep "HTTP/1.1 200")
+echo $rst
+if [[ -z "$rst" ]]; then
+ echo "failed to register instance1 to etcd."
+ exit 128
+fi
+
+rst=$(curl -Is http://instance2:9090/register | grep "HTTP/1.1 200")
+echo $rst
+if [[ -z "$rst" ]]; then
+ echo "failed to register instance2 to etcd."
+ exit 128
+fi
+
+sleep 5
+
+curl -s http://gateway:8080/get
+
+rst=$(curl -Is http://gateway:8080/get | grep "HTTP/1.1 200")
+if [[ -z "$rst" ]]; then
+ echo "shenyu nginx module did not work."
+ exit 128
+fi
+
+inst1=$(curl -s http://gateway:8080/get)
+inst2=$(curl -s http://gateway:8080/get)
+
+[[ "$inst1" == "$inst2" ]] || (echo "validation failed" && exit 128)
+
+# remove instance 1
+rst=$(curl -Is http://instance1:9090/unregister | grep "HTTP/1.1 200")
+if [[ -z "$rst" ]]; then
+ echo "failed to unregister instance1 to etcd."
+ exit 128
+fi
+
+sleep 5
+
+rst=$(curl -Is http://gateway:8080/get | grep "HTTP/1.1 200")
+if [[ -z "$rst" ]]; then
+ echo "shenyu nginx module did not work right"
+ exit 128
+fi
+
+rst=$(curl -s http://gateway:8080/get)
+if [[ "$rst" == "$inst_addr_1" ]]; then
+ echo "nginx module did remove unregister instance 1."
+ exit 128
+fi
+rst=$(curl -s http://gateway:8080/get)
+if [[ "$rst" == "$inst_addr_1" ]]; then
+ echo "nginx module did remove unregister instance 1."
+ exit 128
+fi
+
+echo "validation successful"
diff --git a/test/it/docker-compose.yml b/test/it/docker-compose.yml
new file mode 100644
index 0000000..ae4944e
--- /dev/null
+++ b/test/it/docker-compose.yml
@@ -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.
+
+version: "2.3"
+
+services:
+ etcd:
+ image: bitnami/etcd:3.4
+ expose:
+ - 2379
+ environment:
+ - ALLOW_NONE_AUTHENTICATION=yes
+ - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/2379"
]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+ networks:
+ shenyu:
+ ipv4_address: 172.16.238.10
+
+ instance1:
+ build:
+ context: ./mock-shenyu
+ expose:
+ - 9090
+ environment:
+ - APP_NAME=mock-shenyu-instance-1
+ - ETCD_SERVER_URL=http://172.16.238.10:2379
+ ports:
+ - 9090:9090
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9090"
]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+ depends_on:
+ etcd:
+ condition: service_healthy
+ networks:
+ shenyu:
+ ipv4_address: 172.16.238.11
+
+ instance2:
+ build:
+ context: ./mock-shenyu
+ expose:
+ - 9090
+ environment:
+ - APP_NAME=mock-shenyu-instance-2
+ - ETCD_SERVER_URL=http://172.16.238.10:2379
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9090"
]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+ depends_on:
+ etcd:
+ condition: service_healthy
+ networks:
+ shenyu:
+ ipv4_address: 172.16.238.12
+
+ gateway:
+ build:
+ context: ../..
+ dockerfile: ./test/it/gateway/Dockerfile
+ ports:
+ - 8080:8080
+ volumes:
+ - ./gateway/conf:/conf
+ environment:
+ - ETCD_SERVER_URL=http://172.16.238.10:2379
+ restart: on-failure
+ healthcheck:
+ test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/8080"
]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+ depends_on:
+ etcd:
+ condition: service_healthy
+ networks:
+ shenyu:
+ ipv4_address: 172.16.238.13
+
+ consumer:
+ build:
+ context: ../..
+ dockerfile: ./test/it/consumer/Dockerfile
+ depends_on:
+ gateway:
+ condition: service_healthy
+ instance1:
+ condition: service_healthy
+ instance2:
+ condition: service_healthy
+ networks:
+ shenyu:
+ ipv4_address: 172.16.238.20
+
+networks:
+ shenyu:
+ driver: bridge
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.16.238.0/24
+ gateway: 172.16.238.1
diff --git a/test/it/gateway/Dockerfile b/test/it/gateway/Dockerfile
new file mode 100644
index 0000000..8942dd2
--- /dev/null
+++ b/test/it/gateway/Dockerfile
@@ -0,0 +1,27 @@
+# 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.
+
+FROM openresty/openresty:1.17.8.2-5-alpine-fat
+
+WORKDIR /shenyu-nginx
+
+COPY ./lib lib
+COPY ./rockspec rockspec
+COPY ./test/it/gateway/conf/nginx.conf conf/nginx.conf
+
+RUN luarocks make ./rockspec/shenyu-nginx-main-0.rockspec
+
+ENTRYPOINT openresty -c /shenyu-nginx/conf/nginx.conf
diff --git a/test/it/gateway/conf/nginx.conf b/test/it/gateway/conf/nginx.conf
new file mode 100644
index 0000000..fac4fc9
--- /dev/null
+++ b/test/it/gateway/conf/nginx.conf
@@ -0,0 +1,51 @@
+# 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.
+
+worker_processes 1;
+daemon off;
+error_log /dev/stdout debug;
+
+events {
+ worker_connections 1024;
+}
+
+env ETCD_SERVER_URL;
+
+http {
+ init_worker_by_lua_block {
+ local register = require("shenyu.register.etcd")
+ register.init({
+ balancer_type = "chash",
+ etcd_base_url = os.getenv("ETCD_SERVER_URL"),
+ })
+ }
+
+ upstream shenyu {
+ server 0.0.0.1;
+ balancer_by_lua_block {
+ require("shenyu.register.etcd").pick_and_set_peer()
+ }
+ }
+
+ server {
+ listen 8080;
+
+ location ~ /* {
+ proxy_pass http://shenyu;
+ }
+ }
+}
diff --git a/test/it/mock-shenyu/Dockerfile b/test/it/mock-shenyu/Dockerfile
new file mode 100644
index 0000000..46ca147
--- /dev/null
+++ b/test/it/mock-shenyu/Dockerfile
@@ -0,0 +1,22 @@
+# 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.
+
+FROM openresty/openresty:1.17.8.2-5-alpine-fat
+
+RUN luarocks install lua-resty-http
+COPY ./conf/nginx.conf /conf/nginx.conf
+
+ENTRYPOINT openresty -c /conf/nginx.conf
diff --git a/test/it/mock-shenyu/conf/nginx.conf
b/test/it/mock-shenyu/conf/nginx.conf
new file mode 100644
index 0000000..e3e9f5d
--- /dev/null
+++ b/test/it/mock-shenyu/conf/nginx.conf
@@ -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.
+
+worker_processes 1;
+daemon off;
+error_log /dev/stdout debug;
+
+events {
+ worker_connections 1024;
+}
+
+env APP_NAME;
+env ETCD_SERVER_URL;
+
+http {
+ server {
+ listen 9090;
+ location ~ /get {
+ content_by_lua_block {
+ ngx.say(ngx.var.server_addr)
+ }
+ }
+
+ location = /register {
+ content_by_lua_block {
+ local json = require("cjson.safe")
+ local httpc = require("resty.http").new()
+ local encode = ngx.encode_base64
+ httpc:request_uri(os.getenv("ETCD_SERVER_URL") ..
"/v3/kv/put", {
+ method = "POST",
+ body = json.encode({
+ key = encode("/shenyu/register/instance/" ..
ngx.var.server_addr .. ":9090"),
+ value = encode(json.encode({
+ host = ngx.var.server_addr,
+ port = 9090,
+ appName = os.getenv("APP_NAME"),
+ })),
+ }),
+ })
+ ngx.say("register successful")
+ }
+ }
+
+ location = /unregister {
+ content_by_lua_block {
+ local json = require("cjson.safe")
+ local httpc = require("resty.http").new()
+ local encode = ngx.encode_base64
+ httpc:request_uri(os.getenv("ETCD_SERVER_URL") ..
"/v3/kv/deleterange", {
+ method = "POST",
+ body = json.encode({
+ key = encode("/shenyu/register/instance/" ..
ngx.var.server_addr .. ":9090"),
+ range_end = encode("/shenyu/register/instance/" ..
ngx.var.server_addr .. ":9090a"),
+ }),
+ })
+ ngx.say("unregister successful")
+ }
+ }
+ }
+}