You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ch...@apache.org on 2021/02/26 07:15:44 UTC

[apisix-dashboard] branch master updated: feat: rewrite e2e test(upstream_test) with ginkgo (#1502)

This is an automated email from the ASF dual-hosted git repository.

chenjunxu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 10f6044  feat: rewrite e2e test(upstream_test) with ginkgo (#1502)
10f6044 is described below

commit 10f60447bb99a08a8ba1aa11ef684472176f80a0
Author: JinChen <36...@users.noreply.github.com>
AuthorDate: Fri Feb 26 15:14:46 2021 +0800

    feat: rewrite e2e test(upstream_test) with ginkgo (#1502)
---
 api/test/e2e/upstream_test.go                   | 607 ---------------------
 api/test/e2enew/upstream/upstream_suite_test.go |  36 ++
 api/test/e2enew/upstream/upstream_test.go       | 680 ++++++++++++++++++++++++
 3 files changed, 716 insertions(+), 607 deletions(-)

diff --git a/api/test/e2e/upstream_test.go b/api/test/e2e/upstream_test.go
deleted file mode 100644
index be2dd6f..0000000
--- a/api/test/e2e/upstream_test.go
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * 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.
- */
-package e2e
-
-import (
-	"io/ioutil"
-	"net/http"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-// todo: the code to access the route should be encapsulated as a function, like line 245-263, 316-327
-func TestUpstream_Create(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:   "use upstream that not exist",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/r1",
-			Body: `{
-				"uri": "/hello",
-				"upstream_id": "not-exists"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusBadRequest,
-		},
-		{
-			Desc:   "create upstream",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"name": "upstream1",
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 1
-				}],
-				"type": "roundrobin"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "check upstream exists by name",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/apisix/admin/notexist/upstreams",
-			Query:        "name=upstream1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusBadRequest,
-			ExpectBody:   "Upstream name is reduplicate",
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:         "upstream name list",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/apisix/admin/names/upstreams",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   `"name":"upstream1"`,
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:         "check upstream exists by name (exclude it self)",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/apisix/admin/notexist/upstreams",
-			Query:        "name=upstream1&exclude=1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:   "create route using the upstream just created",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/1",
-			Body: `{
-				"uri": "/hello",
-				"upstream_id": "1"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:         "hit the route just created",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/hello",
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "hello world",
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-}
-
-func TestUpstream_Update(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:   "update upstream with domain",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1981,
-					"weight": 1
-				}],
-				"type": "roundrobin"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "hit the route using upstream 1",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/hello",
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "hello world",
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-}
-
-func TestRoute_Node_Host(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:   "update upstream - pass host: node",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"nodes": [{
-					"host": "httpbin.org",
-					"port": 80,
-					"weight": 1
-				}],
-				"type": "roundrobin",
-				"pass_host": "node"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:   "update path for route",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/1",
-			Body: `{
-					"uri": "/*",
-					"upstream_id": "1"
-				}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "hit the route ",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/get",
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "\"Host\": \"httpbin.org\"",
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:   "update upstream - pass host: rewrite",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 1
-				}],
-				"type": "roundrobin",
-				"pass_host": "rewrite",
-				"upstream_host": "httpbin.org"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "hit the route ",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/uri",
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "x-forwarded-host: 127.0.0.1",
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-}
-
-func TestUpstream_chash_remote_addr(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:   "create chash upstream with key (remote_addr)",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 1
-				},
-				{
-					"host": "172.16.238.20",
-					"port": 1981,
-					"weight": 1
-				},
-				{
-					"host": "172.16.238.20",
-					"port": 1982,
-					"weight": 1
-				}],
-				"type": "chash",
-				"hash_on":"header",
-				"key": "remote_addr"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:   "create route using the upstream just created",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/1",
-			Body: `{
-				"uri": "/server_port",
-				"upstream_id": "1"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-
-	//hit routes
-	basepath := "http://127.0.0.1:9080/"
-	request, err := http.NewRequest("GET", basepath+"/server_port", nil)
-	request.Header.Add("Authorization", token)
-	var resp *http.Response
-	var respBody []byte
-	var count int
-	res := map[string]int{}
-	for i := 0; i < 18; i++ {
-		resp, err = http.DefaultClient.Do(request)
-		assert.Nil(t, err)
-		respBody, err = ioutil.ReadAll(resp.Body)
-		body := string(respBody)
-		if _, ok := res[body]; !ok {
-			res[body] = 1
-		} else {
-			res[body] += 1
-		}
-		resp.Body.Close()
-	}
-	assert.Equal(t, 18, res["1982"])
-
-	tests = []HttpTestCase{
-		{
-			Desc:   "create chash upstream with key (remote_addr, weight equal 0 or 1)",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"nodes": [
-				{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 1
-				},
-				{
-					"host": "172.16.238.20",
-					"port": 1981,
-					"weight": 0
-				},
-				{
-					"host": "172.16.238.20",
-					"port": 1982,
-					"weight": 0
-				}],
-				"type": "chash",
-				"hash_on":"header",
-				"key": "remote_addr"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:   "create route using the upstream just created",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/1",
-			Body: `{
-				"uri": "/server_port",
-				"upstream_id": "1"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-
-	//hit routes
-	basepath = "http://127.0.0.1:9080/"
-	request, err = http.NewRequest("GET", basepath+"/server_port", nil)
-	request.Header.Add("Authorization", token)
-	count = 0
-	for i := 0; i <= 17; i++ {
-		resp, err = http.DefaultClient.Do(request)
-		assert.Nil(t, err)
-		respBody, err = ioutil.ReadAll(resp.Body)
-		if string(respBody) == "1980" {
-			count++
-		}
-	}
-	assert.Equal(t, 18, count)
-	defer resp.Body.Close()
-
-	tests = []HttpTestCase{
-		{
-			Desc:   "create chash upstream with key (remote_addr, all weight equal 0)",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/upstreams/1",
-			Body: `{
-				"nodes": [
-				{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 0
-				},
-				{
-					"host": "172.16.238.20",
-					"port": 1981,
-					"weight": 0
-				}],
-				"type": "chash",
-				"hash_on":"header",
-				"key": "remote_addr"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:   "create route using the upstream just created",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/1",
-			Body: `{
-				"uri": "/server_port",
-				"upstream_id": "1"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:         "hit the route ",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/server_port",
-			ExpectStatus: http.StatusBadGateway,
-			ExpectBody:   "<head><title>502 Bad Gateway</title></head>",
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-
-}
-
-func TestUpstream_Delete(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:         "delete not exist upstream",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodDelete,
-			Path:         "/apisix/admin/upstreams/not-exist",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusNotFound,
-		},
-		{
-			Desc:         "delete route",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodDelete,
-			Path:         "/apisix/admin/routes/1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "delete upstream",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodDelete,
-			Path:         "/apisix/admin/upstreams/1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "hit the route just deleted",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/hello1",
-			ExpectStatus: http.StatusNotFound,
-			ExpectBody:   "{\"error_msg\":\"404 Route Not Found\"}\n",
-			Sleep:        sleepTime,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-}
-
-func TestUpstream_Create_via_Post(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:   "create upstream via POST",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPost,
-			Path:   "/apisix/admin/upstreams",
-			Body: `{
-				"id": "u1",
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 1
-				}],
-				"type": "roundrobin"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			// should return id and other request body content
-			ExpectBody: []string{"\"id\":\"u1\"", "\"type\":\"roundrobin\""},
-		},
-		{
-			Desc:   "create route using the upstream just created",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPut,
-			Path:   "/apisix/admin/routes/1",
-			Body: `{
-				"uri": "/hello",
-				"upstream_id": "u1"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			Sleep:        sleepTime,
-		},
-		{
-			Desc:         "hit the route just created",
-			Object:       APISIXExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/hello",
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "hello world",
-			Sleep:        sleepTime,
-		},
-		//
-		{
-			Desc:         "delete route",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodDelete,
-			Path:         "/apisix/admin/routes/1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "delete upstream",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodDelete,
-			Path:         "/apisix/admin/upstreams/u1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-}
-
-func TestUpstream_Update_Use_Patch_Method(t *testing.T) {
-	tests := []HttpTestCase{
-		{
-			Desc:   "create upstream via POST",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPost,
-			Path:   "/apisix/admin/upstreams",
-			Body: `{
-				"id": "u1",
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1980,
-					"weight": 1
-				}],
-				"type": "roundrobin"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   []string{"\"id\":\"u1\"", "\"type\":\"roundrobin\""},
-		},
-		{
-			Desc:   "update upstream use patch method",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPatch,
-			Path:   "/apisix/admin/upstreams/u1",
-			Body: `{
-				"nodes": [{
-					"host": "172.16.238.20",
-					"port": 1981,
-					"weight": 1
-				}],
-				"type": "roundrobin"
-			}`,
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "get upstream data",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/apisix/admin/upstreams/u1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "nodes\":[{\"host\":\"172.16.238.20\",\"port\":1981,\"weight\":1}],\"type\":\"roundrobin\"}",
-		},
-		{
-			Desc:   "Update upstream using path parameter patch method",
-			Object: ManagerApiExpect(t),
-			Method: http.MethodPatch,
-			Path:   "/apisix/admin/upstreams/u1/nodes",
-			Body:   `[{"host":"172.16.238.20","port": 1980,"weight":1}]`,
-			Headers: map[string]string{
-				"Authorization": token,
-				"Content-Type":  "text/plain",
-			},
-			ExpectStatus: http.StatusOK,
-		},
-		{
-			Desc:         "get upstream data",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodGet,
-			Path:         "/apisix/admin/upstreams/u1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-			ExpectBody:   "nodes\":[{\"host\":\"172.16.238.20\",\"port\":1980,\"weight\":1}],\"type\":\"roundrobin\"}",
-		},
-		{
-			Desc:         "delete upstream",
-			Object:       ManagerApiExpect(t),
-			Method:       http.MethodDelete,
-			Path:         "/apisix/admin/upstreams/u1",
-			Headers:      map[string]string{"Authorization": token},
-			ExpectStatus: http.StatusOK,
-		},
-	}
-
-	for _, tc := range tests {
-		testCaseCheck(tc, t)
-	}
-}
-
diff --git a/api/test/e2enew/upstream/upstream_suite_test.go b/api/test/e2enew/upstream/upstream_suite_test.go
new file mode 100644
index 0000000..ca965e7
--- /dev/null
+++ b/api/test/e2enew/upstream/upstream_suite_test.go
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package upstream
+
+import (
+	"testing"
+	"time"
+
+	"github.com/onsi/ginkgo"
+
+	"e2enew/base"
+)
+
+func TestRoute(t *testing.T) {
+	ginkgo.RunSpecs(t, "upstream suite")
+}
+
+var _ = ginkgo.AfterSuite(func() {
+	base.CleanResource("routes")
+	base.CleanResource("upstreams")
+	time.Sleep(base.SleepTime)
+})
diff --git a/api/test/e2enew/upstream/upstream_test.go b/api/test/e2enew/upstream/upstream_test.go
new file mode 100644
index 0000000..c0776a0
--- /dev/null
+++ b/api/test/e2enew/upstream/upstream_test.go
@@ -0,0 +1,680 @@
+/*
+ * 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.
+ */
+package upstream
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"net/http"
+	"time"
+
+	"github.com/onsi/ginkgo"
+	"github.com/stretchr/testify/assert"
+
+	"e2enew/base"
+)
+
+var _ = ginkgo.Describe("Upstream", func() {
+	ginkgo.It("test upstream create failed", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/r1",
+			Body: `{
+				 "uri": "/hello",
+				 "upstream_id": "not-exists"
+			 }`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusBadRequest,
+		})
+	})
+
+	ginkgo.It("create upstream success", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["name"] = "upstream1"
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1980,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "roundrobin"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPut,
+			Path:         "/apisix/admin/upstreams/1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("check upstream exists by name", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodGet,
+			Path:         "/apisix/admin/notexist/upstreams",
+			Query:        "name=upstream1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusBadRequest,
+			ExpectBody:   "Upstream name is reduplicate",
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("upstream name list", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodGet,
+			Path:         "/apisix/admin/names/upstreams",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			ExpectBody:   `"name":"upstream1"`,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("check upstream exists by name (exclude it self)", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodGet,
+			Path:         "/apisix/admin/notexist/upstreams",
+			Query:        "name=upstream1&exclude=1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("create route using the upstream just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/1",
+			Body: `{
+				 "uri": "/hello",
+				 "upstream_id": "1"
+			 }`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("hit the route just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/hello",
+			ExpectStatus: http.StatusOK,
+			ExpectBody:   "hello world",
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("delete not exist upstream", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/upstreams/not-exist",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusNotFound,
+		})
+	})
+	ginkgo.It("delete route", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("delete upstream", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/upstreams/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("hit the route just deleted", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/hello",
+			ExpectStatus: http.StatusNotFound,
+			ExpectBody:   "{\"error_msg\":\"404 Route Not Found\"}\n",
+			Sleep:        base.SleepTime,
+		})
+	})
+})
+
+var _ = ginkgo.Describe("Upstream update with domain", func() {
+	ginkgo.It("create upstream success", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["name"] = "upstream1"
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1980,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "roundrobin"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPut,
+			Path:         "/apisix/admin/upstreams/1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("create route using the upstream(use proxy rewriteproxy rewrite plugin)", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/1",
+			Body: `{
+				 "uri": "/get",
+				 "upstream_id": "1",
+				 "plugins": {
+					"proxy-rewrite": {
+						"uri": "/get",
+						"scheme": "https"
+					}
+				}
+			 }`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("update upstream with domain", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   "httpbin.org",
+				"port":   443,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "roundrobin"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPut,
+			Path:         "/apisix/admin/upstreams/1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("hit the route using upstream 1", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/get",
+			ExpectStatus: http.StatusOK,
+			ExpectBody:   "\n  \"url\": \"https://127.0.0.1/get\"\n}\n",
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("delete route", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("delete upstream", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/upstreams/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("hit the route just deleted", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/get",
+			ExpectStatus: http.StatusNotFound,
+			ExpectBody:   "{\"error_msg\":\"404 Route Not Found\"}\n",
+			Sleep:        base.SleepTime,
+		})
+	})
+})
+
+var _ = ginkgo.Describe("Upstream chash remote addr", func() {
+	ginkgo.It("create chash upstream with key (remote_addr)", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1980,
+				"weight": 1,
+			},
+			{
+				"host":   base.UpstreamIp,
+				"port":   1981,
+				"weight": 1,
+			},
+			{
+				"host":   base.UpstreamIp,
+				"port":   1982,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "chash"
+		createUpstreamBody["hash_on"] = "header"
+		createUpstreamBody["key"] = "remote_addr"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPut,
+			Path:         "/apisix/admin/upstreams/1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+
+	ginkgo.It("create route using the upstream just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/1",
+			Body: `{
+				 "uri": "/server_port",
+				 "upstream_id": "1"
+			 }`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+
+	ginkgo.It("hit routes(upstream weight 1)", func() {
+		t := ginkgo.GinkgoT()
+		time.Sleep(time.Duration(500) * time.Millisecond)
+		basepath := base.APISIXHost
+		request, err := http.NewRequest("GET", basepath+"/server_port", nil)
+		assert.Nil(t, err)
+		request.Header.Add("Authorization", base.GetToken())
+		res := map[string]int{}
+		for i := 0; i < 18; i++ {
+			resp, err := http.DefaultClient.Do(request)
+			assert.Nil(t, err)
+			respBody, err := ioutil.ReadAll(resp.Body)
+			assert.Nil(t, err)
+			body := string(respBody)
+			if _, ok := res[body]; !ok {
+				res[body] = 1
+			} else {
+				res[body]++
+			}
+			resp.Body.Close()
+		}
+		assert.Equal(t, 18, res["1982"])
+	})
+
+	ginkgo.It("create chash upstream with key (remote_addr, weight equal 0 or 1)", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1980,
+				"weight": 1,
+			},
+			{
+				"host":   base.UpstreamIp,
+				"port":   1981,
+				"weight": 0,
+			},
+			{
+				"host":   base.UpstreamIp,
+				"port":   1982,
+				"weight": 0,
+			},
+		}
+		createUpstreamBody["type"] = "chash"
+		createUpstreamBody["hash_on"] = "header"
+		createUpstreamBody["key"] = "remote_addr"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPut,
+			Path:         "/apisix/admin/upstreams/1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("create route using the upstream just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/1",
+			Body: `{
+				"uri": "/server_port",
+				"upstream_id": "1"
+			}`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("hit routes(remote_addr, weight equal 0 or 1)", func() {
+		t := ginkgo.GinkgoT()
+		time.Sleep(time.Duration(500) * time.Millisecond)
+		basepath := base.APISIXHost
+		request, err := http.NewRequest("GET", basepath+"/server_port", nil)
+		assert.Nil(t, err)
+		request.Header.Add("Authorization", base.GetToken())
+		count := 0
+		for i := 0; i <= 17; i++ {
+			resp, err := http.DefaultClient.Do(request)
+			assert.Nil(t, err)
+			respBody, err := ioutil.ReadAll(resp.Body)
+			if string(respBody) == "1980" {
+				count++
+			}
+			resp.Body.Close()
+		}
+		assert.Equal(t, 18, count)
+	})
+	ginkgo.It("create chash upstream with key (remote_addr, all weight equal 0)", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1980,
+				"weight": 0,
+			},
+			{
+				"host":   base.UpstreamIp,
+				"port":   1982,
+				"weight": 0,
+			},
+		}
+		createUpstreamBody["type"] = "chash"
+		createUpstreamBody["hash_on"] = "header"
+		createUpstreamBody["key"] = "remote_addr"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPut,
+			Path:         "/apisix/admin/upstreams/1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("create route using the upstream just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/1",
+			Body: `{
+				 "uri": "/server_port",
+				 "upstream_id": "1"
+			 }`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("hit the route(remote_addr, all weight equal 0)", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/server_port",
+			ExpectStatus: http.StatusBadGateway,
+			ExpectBody:   "<head><title>502 Bad Gateway</title></head>",
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("delete route", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("delete upstream", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/upstreams/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("hit the route just deleted", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/server_port",
+			ExpectStatus: http.StatusNotFound,
+			ExpectBody:   "{\"error_msg\":\"404 Route Not Found\"}\n",
+			Sleep:        base.SleepTime,
+		})
+	})
+})
+
+var _ = ginkgo.Describe("Upstream create via post", func() {
+	ginkgo.It("create upstream via POST", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["id"] = "u1"
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1981,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "roundrobin"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPost,
+			Path:         "/apisix/admin/upstreams",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			// should return id and other request body content
+			ExpectBody: []string{"\"id\":\"u1\"", "\"type\":\"roundrobin\""},
+		})
+	})
+	ginkgo.It("create route using the upstream just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPut,
+			Path:   "/apisix/admin/routes/1",
+			Body: `{
+				 "uri": "/hello",
+				 "upstream_id": "u1"
+			 }`,
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("hit the route just created", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/hello",
+			ExpectStatus: http.StatusOK,
+			ExpectBody:   "hello world",
+			Sleep:        base.SleepTime,
+		})
+	})
+	ginkgo.It("delete route", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/routes/1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("delete upstream", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/upstreams/u1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("hit the route just deleted", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.APISIXExpect(),
+			Method:       http.MethodGet,
+			Path:         "/hello",
+			ExpectStatus: http.StatusNotFound,
+			ExpectBody:   "{\"error_msg\":\"404 Route Not Found\"}\n",
+			Sleep:        base.SleepTime,
+		})
+	})
+})
+
+var _ = ginkgo.Describe("Upstream update use patch method", func() {
+	ginkgo.It("create upstream via POST", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["id"] = "u1"
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1981,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "roundrobin"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPost,
+			Path:         "/apisix/admin/upstreams",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			// should return id and other request body content
+			ExpectBody: []string{"\"id\":\"u1\"", "\"type\":\"roundrobin\""},
+		})
+	})
+	ginkgo.It("update upstream use patch method", func() {
+		t := ginkgo.GinkgoT()
+		createUpstreamBody := make(map[string]interface{})
+		createUpstreamBody["nodes"] = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1981,
+				"weight": 1,
+			},
+		}
+		createUpstreamBody["type"] = "roundrobin"
+		_createUpstreamBody, err := json.Marshal(createUpstreamBody)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodPatch,
+			Path:         "/apisix/admin/upstreams/u1",
+			Body:         string(_createUpstreamBody),
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("get upstream data", func() {
+
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodGet,
+			Path:         "/apisix/admin/upstreams/u1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			ExpectBody:   "nodes\":[{\"host\":\"" + base.UpstreamIp + "\",\"port\":1981,\"weight\":1}],\"type\":\"roundrobin\"}",
+		})
+	})
+	ginkgo.It("Upstream update use patch method", func() {
+		t := ginkgo.GinkgoT()
+		var nodes []map[string]interface{} = []map[string]interface{}{
+			{
+				"host":   base.UpstreamIp,
+				"port":   1980,
+				"weight": 1,
+			},
+		}
+		_nodes, err := json.Marshal(nodes)
+		assert.Nil(t, err)
+		base.RunTestCase(base.HttpTestCase{
+			Object: base.ManagerApiExpect(),
+			Method: http.MethodPatch,
+			Path:   "/apisix/admin/upstreams/u1/nodes",
+			Body:   string(_nodes),
+			Headers: map[string]string{
+				"Authorization": base.GetToken(),
+				"Content-Type":  "text/plain",
+			},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+	ginkgo.It("get upstream data", func() {
+
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodGet,
+			Path:         "/apisix/admin/upstreams/u1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+			ExpectBody:   "nodes\":[{\"host\":\"" + base.UpstreamIp + "\",\"port\":1980,\"weight\":1}],\"type\":\"roundrobin\"}",
+		})
+	})
+	ginkgo.It("delete upstream", func() {
+		base.RunTestCase(base.HttpTestCase{
+			Object:       base.ManagerApiExpect(),
+			Method:       http.MethodDelete,
+			Path:         "/apisix/admin/upstreams/u1",
+			Headers:      map[string]string{"Authorization": base.GetToken()},
+			ExpectStatus: http.StatusOK,
+		})
+	})
+})