Skip to content

Commit b4ad55d

Browse files
authored
test: e2e test chash upstream hash on (consumer, header, cookie) (#936)
related #908
1 parent 0aca093 commit b4ad55d

File tree

1 file changed

+361
-0
lines changed

1 file changed

+361
-0
lines changed
Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package e2e
18+
19+
import (
20+
"io/ioutil"
21+
"net/http"
22+
"strconv"
23+
"testing"
24+
"time"
25+
26+
"github.com/stretchr/testify/assert"
27+
)
28+
29+
// todo: the code to access the route should be encapsulated as a function, like line 75-96, 134-154, 160-174, 212-233, 294-314
30+
func TestUpstream_chash_hash_on_custom_header(t *testing.T) {
31+
tests := []HttpTestCase{
32+
{
33+
caseDesc: "create chash upstream with hash_on (custom_header)",
34+
Object: ManagerApiExpect(t),
35+
Method: http.MethodPut,
36+
Path: "/apisix/admin/upstreams/1",
37+
Body: `{
38+
"nodes": [{
39+
"host": "172.16.238.20",
40+
"port": 1980,
41+
"weight": 1
42+
},
43+
{
44+
"host": "172.16.238.20",
45+
"port": 1981,
46+
"weight": 1
47+
}],
48+
"type": "chash",
49+
"key": "custom_header",
50+
"hash_on": "header"
51+
}`,
52+
Headers: map[string]string{"Authorization": token},
53+
ExpectStatus: http.StatusOK,
54+
},
55+
{
56+
caseDesc: "create route using the upstream just created",
57+
Object: ManagerApiExpect(t),
58+
Method: http.MethodPut,
59+
Path: "/apisix/admin/routes/1",
60+
Body: `{
61+
"uri": "/server_port",
62+
"upstream_id": "1"
63+
}`,
64+
Headers: map[string]string{"Authorization": token},
65+
ExpectStatus: http.StatusOK,
66+
Sleep: sleepTime,
67+
},
68+
}
69+
70+
for _, tc := range tests {
71+
testCaseCheck(tc)
72+
}
73+
74+
// hit routes
75+
time.Sleep(time.Duration(100) * time.Millisecond)
76+
basepath := "http://127.0.0.1:9080"
77+
var req *http.Request
78+
var err error
79+
var url string
80+
var resp *http.Response
81+
var respBody []byte
82+
res := map[string]int{}
83+
for i := 0; i <= 3; i++ {
84+
url = basepath + "/server_port?var=2&var2=" + strconv.Itoa(i)
85+
req, err = http.NewRequest("GET", url, nil)
86+
req.Header.Add("custom_header", `custom-one`)
87+
resp, err = http.DefaultClient.Do(req)
88+
assert.Nil(t, err)
89+
respBody, err = ioutil.ReadAll(resp.Body)
90+
body := string(respBody)
91+
if _, ok := res[body]; !ok {
92+
res[body] = 1
93+
} else {
94+
res[body] += 1
95+
}
96+
}
97+
// it is possible to hit any one of upstreams, and only one will be hit
98+
assert.Equal(t, true, res["1980"] == 4 || res["1981"] == 4)
99+
resp.Body.Close()
100+
}
101+
102+
func TestUpstream_chash_hash_on_cookie(t *testing.T) {
103+
tests := []HttpTestCase{
104+
{
105+
caseDesc: "create chash upstream with hash_on (cookie)",
106+
Object: ManagerApiExpect(t),
107+
Method: http.MethodPut,
108+
Path: "/apisix/admin/upstreams/1",
109+
Body: `{
110+
"nodes": [{
111+
"host": "172.16.238.20",
112+
"port": 1980,
113+
"weight": 1
114+
},
115+
{
116+
"host": "172.16.238.20",
117+
"port": 1981,
118+
"weight": 1
119+
}],
120+
"type": "chash",
121+
"key": "custom-cookie",
122+
"hash_on": "cookie"
123+
}`,
124+
Headers: map[string]string{"Authorization": token},
125+
ExpectStatus: http.StatusOK,
126+
},
127+
}
128+
129+
for _, tc := range tests {
130+
testCaseCheck(tc)
131+
}
132+
133+
// hit routes
134+
time.Sleep(time.Duration(100) * time.Millisecond)
135+
basepath := "http://127.0.0.1:9080"
136+
var req *http.Request
137+
var err error
138+
var url string
139+
var resp *http.Response
140+
var respBody []byte
141+
res := map[string]int{}
142+
for i := 0; i <= 3; i++ {
143+
url = basepath + "/server_port"
144+
req, err = http.NewRequest("GET", url, nil)
145+
req.Header.Add("Cookie", `custom-cookie=cuscookie`)
146+
resp, err = http.DefaultClient.Do(req)
147+
assert.Nil(t, err)
148+
respBody, err = ioutil.ReadAll(resp.Body)
149+
body := string(respBody)
150+
if _, ok := res[body]; !ok {
151+
res[body] = 1
152+
} else {
153+
res[body] += 1
154+
}
155+
}
156+
// it is possible to hit any one of upstreams, and only one will be hit
157+
assert.Equal(t, true, res["1980"] == 4 || res["1981"] == 4)
158+
resp.Body.Close()
159+
160+
// hit routes with miss cookie
161+
res = map[string]int{}
162+
for i := 0; i <= 3; i++ {
163+
url = basepath + "/server_port"
164+
req, err = http.NewRequest("GET", url, nil)
165+
req.Header.Add("Cookie", `miss-custom-cookie=cuscookie`)
166+
resp, err = http.DefaultClient.Do(req)
167+
assert.Nil(t, err)
168+
respBody, err = ioutil.ReadAll(resp.Body)
169+
body := string(respBody)
170+
if _, ok := res[body]; !ok {
171+
res[body] = 1
172+
} else {
173+
res[body] += 1
174+
}
175+
}
176+
// it is possible to hit any one of upstreams, and only one will be hit
177+
assert.Equal(t, true, res["1980"] == 4 || res["1981"] == 4)
178+
resp.Body.Close()
179+
}
180+
181+
func TestUpstream_key_contains_uppercase_letters_and_hyphen(t *testing.T) {
182+
tests := []HttpTestCase{
183+
{
184+
caseDesc: "create chash upstream with key contains uppercase letters and hyphen",
185+
Object: ManagerApiExpect(t),
186+
Method: http.MethodPut,
187+
Path: "/apisix/admin/upstreams/1",
188+
Body: `{
189+
"nodes": [{
190+
"host": "172.16.238.20",
191+
"port": 1980,
192+
"weight": 1
193+
},
194+
{
195+
"host": "172.16.238.20",
196+
"port": 1981,
197+
"weight": 1
198+
}],
199+
"type": "chash",
200+
"key": "X-Sessionid",
201+
"hash_on": "header"
202+
}`,
203+
Headers: map[string]string{"Authorization": token},
204+
ExpectStatus: http.StatusOK,
205+
},
206+
}
207+
208+
for _, tc := range tests {
209+
testCaseCheck(tc)
210+
}
211+
212+
// hit routes
213+
time.Sleep(time.Duration(100) * time.Millisecond)
214+
basepath := "http://127.0.0.1:9080"
215+
var req *http.Request
216+
var err error
217+
var url string
218+
var resp *http.Response
219+
var respBody []byte
220+
res := map[string]int{}
221+
for i := 0; i <= 15; i++ {
222+
url = basepath + "/server_port"
223+
req, err = http.NewRequest("GET", url, nil)
224+
req.Header.Add("X-Sessionid", `chash_val_`+strconv.Itoa(i))
225+
resp, err = http.DefaultClient.Do(req)
226+
assert.Nil(t, err)
227+
respBody, err = ioutil.ReadAll(resp.Body)
228+
body := string(respBody)
229+
if _, ok := res[body]; !ok {
230+
res[body] = 1
231+
} else {
232+
res[body] += 1
233+
}
234+
}
235+
// the X-Sessionid of each request is different, the weight of upstreams are the same, so these requests will be sent to each upstream equally
236+
assert.Equal(t, true, res["1980"] == 8 && res["1981"] == 8)
237+
resp.Body.Close()
238+
}
239+
240+
func TestUpstream_chash_hash_on_consumer(t *testing.T) {
241+
tests := []HttpTestCase{
242+
{
243+
caseDesc: "create consumer with key-auth",
244+
Object: ManagerApiExpect(t),
245+
Method: http.MethodPut,
246+
Path: "/apisix/admin/consumers",
247+
Body: `{
248+
"username": "jack",
249+
"plugins": {
250+
"key-auth": {
251+
"key": "auth-jack"
252+
}
253+
}
254+
}`,
255+
Headers: map[string]string{"Authorization": token},
256+
ExpectStatus: http.StatusOK,
257+
},
258+
{
259+
caseDesc: "create route with key-auth",
260+
Object: ManagerApiExpect(t),
261+
Method: http.MethodPut,
262+
Path: "/apisix/admin/routes/1",
263+
Body: `{
264+
"uri": "/server_port",
265+
"plugins": {
266+
"key-auth": {}
267+
},
268+
"upstream": {
269+
"nodes": [{
270+
"host": "172.16.238.20",
271+
"port": 1980,
272+
"weight": 1
273+
},
274+
{
275+
"host": "172.16.238.20",
276+
"port": 1981,
277+
"weight": 1
278+
}],
279+
"type": "chash",
280+
"hash_on": "consumer"
281+
}
282+
}`,
283+
Headers: map[string]string{"Authorization": token},
284+
ExpectStatus: http.StatusOK,
285+
Sleep: sleepTime,
286+
},
287+
}
288+
289+
for _, tc := range tests {
290+
testCaseCheck(tc)
291+
}
292+
293+
// hit routes
294+
time.Sleep(time.Duration(100) * time.Millisecond)
295+
basepath := "http://127.0.0.1:9080"
296+
var req *http.Request
297+
var err error
298+
var url string
299+
var resp *http.Response
300+
var respBody []byte
301+
res := map[string]int{}
302+
for i := 0; i <= 3; i++ {
303+
url = basepath + "/server_port"
304+
req, err = http.NewRequest("GET", url, nil)
305+
req.Header.Add("apikey", `auth-jack`)
306+
resp, err = http.DefaultClient.Do(req)
307+
assert.Nil(t, err)
308+
respBody, err = ioutil.ReadAll(resp.Body)
309+
body := string(respBody)
310+
if _, ok := res[body]; !ok {
311+
res[body] = 1
312+
} else {
313+
res[body] += 1
314+
}
315+
}
316+
// it is possible to hit any one of upstreams, and only one will be hit
317+
assert.Equal(t, true, res["1980"] == 4 || res["1981"] == 4)
318+
resp.Body.Close()
319+
}
320+
321+
func TestUpstream_Delete_hash_on(t *testing.T) {
322+
tests := []HttpTestCase{
323+
{
324+
caseDesc: "delete consumer",
325+
Object: ManagerApiExpect(t),
326+
Method: http.MethodDelete,
327+
Path: "/apisix/admin/consumers/jack",
328+
Headers: map[string]string{"Authorization": token},
329+
ExpectStatus: http.StatusOK,
330+
},
331+
{
332+
caseDesc: "delete route",
333+
Object: ManagerApiExpect(t),
334+
Method: http.MethodDelete,
335+
Path: "/apisix/admin/routes/1",
336+
Headers: map[string]string{"Authorization": token},
337+
ExpectStatus: http.StatusOK,
338+
},
339+
{
340+
caseDesc: "delete upstream",
341+
Object: ManagerApiExpect(t),
342+
Method: http.MethodDelete,
343+
Path: "/apisix/admin/upstreams/1",
344+
Headers: map[string]string{"Authorization": token},
345+
ExpectStatus: http.StatusOK,
346+
},
347+
{
348+
caseDesc: "hit the route just deleted",
349+
Object: APISIXExpect(t),
350+
Method: http.MethodGet,
351+
Path: "/hello1",
352+
ExpectStatus: http.StatusNotFound,
353+
ExpectBody: "{\"error_msg\":\"404 Route Not Found\"}\n",
354+
Sleep: sleepTime,
355+
},
356+
}
357+
358+
for _, tc := range tests {
359+
testCaseCheck(tc)
360+
}
361+
}

0 commit comments

Comments
 (0)