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")
+            }
+        }
+    }
+}

Reply via email to