chash-hashon.t 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  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. BEGIN {
  18. if ($ENV{TEST_NGINX_CHECK_LEAK}) {
  19. $SkipReason = "unavailable for the hup tests";
  20. } else {
  21. $ENV{TEST_NGINX_USE_HUP} = 1;
  22. undef $ENV{TEST_NGINX_USE_STAP};
  23. }
  24. }
  25. use t::APISIX 'no_plan';
  26. repeat_each(1);
  27. log_level('info');
  28. no_root_location();
  29. no_shuffle();
  30. run_tests();
  31. __DATA__
  32. === TEST 1: add two consumer with username and plugins
  33. --- config
  34. location /t {
  35. content_by_lua_block {
  36. local t = require("lib.test_admin").test
  37. local code, body = t('/apisix/admin/consumers',
  38. ngx.HTTP_PUT,
  39. [[{
  40. "username": "jack",
  41. "plugins": {
  42. "key-auth": {
  43. "key": "auth-jack"
  44. }
  45. }
  46. }]],
  47. [[{
  48. "value": {
  49. "username": "jack",
  50. "plugins": {
  51. "key-auth": {
  52. "key": "re62sf0vRJqOBjvJJ6RUcA=="
  53. }
  54. }
  55. }
  56. }]]
  57. )
  58. if code ~= 200 then
  59. ngx.say("create consumer jack failed")
  60. return
  61. end
  62. ngx.say(code .. " " ..body)
  63. code, body = t('/apisix/admin/consumers',
  64. ngx.HTTP_PUT,
  65. [[{
  66. "username": "tom",
  67. "plugins": {
  68. "key-auth": {
  69. "key": "auth-tom"
  70. }
  71. }
  72. }]],
  73. [[{
  74. "value": {
  75. "username": "tom",
  76. "plugins": {
  77. "key-auth": {
  78. "key": "RAL/niDfEUpx+ynsoqWDuA=="
  79. }
  80. }
  81. }
  82. }]]
  83. )
  84. ngx.say(code .. " " ..body)
  85. }
  86. }
  87. --- request
  88. GET /t
  89. --- response_body
  90. 200 passed
  91. 200 passed
  92. === TEST 2: add key auth plugin, chash hash_on consumer
  93. --- config
  94. location /t {
  95. content_by_lua_block {
  96. local t = require("lib.test_admin").test
  97. local code, body = t('/apisix/admin/routes/1',
  98. ngx.HTTP_PUT,
  99. [[{
  100. "plugins": {
  101. "key-auth": {}
  102. },
  103. "upstream": {
  104. "nodes": {
  105. "127.0.0.1:1980": 1,
  106. "127.0.0.1:1981": 1
  107. },
  108. "type": "chash",
  109. "hash_on": "consumer"
  110. },
  111. "uri": "/server_port"
  112. }]]
  113. )
  114. if code >= 300 then
  115. ngx.status = code
  116. end
  117. ngx.say(body)
  118. }
  119. }
  120. --- request
  121. GET /t
  122. --- response_body
  123. passed
  124. === TEST 3: hit routes, hash_on one consumer
  125. --- config
  126. location /t {
  127. content_by_lua_block {
  128. local http = require "resty.http"
  129. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  130. .. "/server_port"
  131. local request_headers = {}
  132. request_headers["apikey"] = "auth-jack"
  133. local ports_count = {}
  134. for i = 1, 4 do
  135. local httpc = http.new()
  136. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  137. if not res then
  138. ngx.say(err)
  139. return
  140. end
  141. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  142. end
  143. local ports_arr = {}
  144. for port, count in pairs(ports_count) do
  145. table.insert(ports_arr, {port = port, count = count})
  146. end
  147. local function cmd(a, b)
  148. return a.port > b.port
  149. end
  150. table.sort(ports_arr, cmd)
  151. ngx.say(require("toolkit.json").encode(ports_arr))
  152. ngx.exit(200)
  153. }
  154. }
  155. --- request
  156. GET /t
  157. --- response_body
  158. [{"count":4,"port":"1981"}]
  159. --- grep_error_log eval
  160. qr/hash_on: consumer|chash_key: "jack"|chash_key: "tom"/
  161. --- grep_error_log_out
  162. hash_on: consumer
  163. chash_key: "jack"
  164. hash_on: consumer
  165. chash_key: "jack"
  166. hash_on: consumer
  167. chash_key: "jack"
  168. hash_on: consumer
  169. chash_key: "jack"
  170. === TEST 4: hit routes, hash_on two consumer
  171. --- config
  172. location /t {
  173. content_by_lua_block {
  174. local http = require "resty.http"
  175. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  176. .. "/server_port"
  177. local request_headers = {}
  178. local ports_count = {}
  179. for i = 1, 4 do
  180. if i%2 == 0 then
  181. request_headers["apikey"] = "auth-tom"
  182. else
  183. request_headers["apikey"] = "auth-jack"
  184. end
  185. local httpc = http.new()
  186. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  187. if not res then
  188. ngx.say(err)
  189. return
  190. end
  191. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  192. end
  193. local ports_arr = {}
  194. for port, count in pairs(ports_count) do
  195. table.insert(ports_arr, {port = port, count = count})
  196. end
  197. local function cmd(a, b)
  198. return a.port > b.port
  199. end
  200. table.sort(ports_arr, cmd)
  201. ngx.say(require("toolkit.json").encode(ports_arr))
  202. ngx.exit(200)
  203. }
  204. }
  205. --- request
  206. GET /t
  207. --- response_body
  208. [{"count":2,"port":"1981"},{"count":2,"port":"1980"}]
  209. --- grep_error_log eval
  210. qr/hash_on: consumer|chash_key: "jack"|chash_key: "tom"/
  211. --- grep_error_log_out
  212. hash_on: consumer
  213. chash_key: "jack"
  214. hash_on: consumer
  215. chash_key: "tom"
  216. hash_on: consumer
  217. chash_key: "jack"
  218. hash_on: consumer
  219. chash_key: "tom"
  220. === TEST 5: set route(two upstream node, type chash), hash_on header
  221. --- config
  222. location /t {
  223. content_by_lua_block {
  224. local t = require("lib.test_admin").test
  225. local code, body = t('/apisix/admin/routes/1',
  226. ngx.HTTP_PUT,
  227. [[{
  228. "uri": "/server_port",
  229. "upstream": {
  230. "key": "custom_header",
  231. "type": "chash",
  232. "hash_on": "header",
  233. "nodes": {
  234. "127.0.0.1:1980": 1,
  235. "127.0.0.1:1981": 1
  236. }
  237. }
  238. }]]
  239. )
  240. if code >= 300 then
  241. ngx.status = code
  242. end
  243. ngx.say(body)
  244. }
  245. }
  246. --- request
  247. GET /t
  248. --- response_body
  249. passed
  250. === TEST 6: hit routes, hash_on custom header
  251. --- config
  252. location /t {
  253. content_by_lua_block {
  254. local http = require "resty.http"
  255. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  256. .. "/server_port"
  257. local request_headers = {}
  258. request_headers["custom_header"] = "custom-one"
  259. local ports_count = {}
  260. for i = 1, 4 do
  261. local httpc = http.new()
  262. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  263. if not res then
  264. ngx.say(err)
  265. return
  266. end
  267. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  268. end
  269. local ports_arr = {}
  270. for port, count in pairs(ports_count) do
  271. table.insert(ports_arr, {port = port, count = count})
  272. end
  273. local function cmd(a, b)
  274. return a.port > b.port
  275. end
  276. table.sort(ports_arr, cmd)
  277. ngx.say(require("toolkit.json").encode(ports_arr))
  278. ngx.exit(200)
  279. }
  280. }
  281. --- request
  282. GET /t
  283. --- response_body
  284. [{"count":4,"port":"1980"}]
  285. --- grep_error_log eval
  286. qr/hash_on: header|chash_key: "custom-one"/
  287. --- grep_error_log_out
  288. hash_on: header
  289. chash_key: "custom-one"
  290. hash_on: header
  291. chash_key: "custom-one"
  292. hash_on: header
  293. chash_key: "custom-one"
  294. hash_on: header
  295. chash_key: "custom-one"
  296. === TEST 7: hit routes, hash_on custom header miss, use default
  297. --- config
  298. location /t {
  299. content_by_lua_block {
  300. local http = require "resty.http"
  301. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  302. .. "/server_port"
  303. local request_headers = {}
  304. request_headers["miss-custom-header"] = "custom-one"
  305. local ports_count = {}
  306. for i = 1, 4 do
  307. local httpc = http.new()
  308. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  309. if not res then
  310. ngx.say(err)
  311. return
  312. end
  313. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  314. end
  315. local ports_arr = {}
  316. for port, count in pairs(ports_count) do
  317. table.insert(ports_arr, {port = port, count = count})
  318. end
  319. local function cmd(a, b)
  320. return a.port > b.port
  321. end
  322. table.sort(ports_arr, cmd)
  323. ngx.say(require("toolkit.json").encode(ports_arr))
  324. ngx.exit(200)
  325. }
  326. }
  327. --- request
  328. GET /t
  329. --- response_body
  330. [{"count":4,"port":"1980"}]
  331. --- grep_error_log eval
  332. qr/chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1/
  333. --- grep_error_log_out
  334. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  335. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  336. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  337. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  338. === TEST 8: set route(two upstream node, type chash), hash_on cookie
  339. --- config
  340. location /t {
  341. content_by_lua_block {
  342. local t = require("lib.test_admin").test
  343. local code, body = t('/apisix/admin/routes/1',
  344. ngx.HTTP_PUT,
  345. [[{
  346. "uri": "/server_port",
  347. "upstream": {
  348. "key": "custom-cookie",
  349. "type": "chash",
  350. "hash_on": "cookie",
  351. "nodes": {
  352. "127.0.0.1:1980": 1,
  353. "127.0.0.1:1981": 1
  354. }
  355. }
  356. }]]
  357. )
  358. if code >= 300 then
  359. ngx.status = code
  360. end
  361. ngx.say(body)
  362. }
  363. }
  364. --- request
  365. GET /t
  366. --- response_body
  367. passed
  368. === TEST 9: hit routes, hash_on custom cookie
  369. --- config
  370. location /t {
  371. content_by_lua_block {
  372. local http = require "resty.http"
  373. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  374. .. "/server_port"
  375. local request_headers = {}
  376. request_headers["Cookie"] = "custom-cookie=cuscookie"
  377. local ports_count = {}
  378. for i = 1, 4 do
  379. local httpc = http.new()
  380. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  381. if not res then
  382. ngx.say(err)
  383. return
  384. end
  385. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  386. end
  387. local ports_arr = {}
  388. for port, count in pairs(ports_count) do
  389. table.insert(ports_arr, {port = port, count = count})
  390. end
  391. local function cmd(a, b)
  392. return a.port > b.port
  393. end
  394. table.sort(ports_arr, cmd)
  395. ngx.say(require("toolkit.json").encode(ports_arr))
  396. ngx.exit(200)
  397. }
  398. }
  399. --- request
  400. GET /t
  401. --- response_body
  402. [{"count":4,"port":"1981"}]
  403. --- grep_error_log eval
  404. qr/hash_on: cookie|chash_key: "cuscookie"/
  405. --- grep_error_log_out
  406. hash_on: cookie
  407. chash_key: "cuscookie"
  408. hash_on: cookie
  409. chash_key: "cuscookie"
  410. hash_on: cookie
  411. chash_key: "cuscookie"
  412. hash_on: cookie
  413. chash_key: "cuscookie"
  414. === TEST 10: hit routes, hash_on custom cookie miss, use default
  415. --- config
  416. location /t {
  417. content_by_lua_block {
  418. local http = require "resty.http"
  419. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  420. .. "/server_port"
  421. local request_headers = {}
  422. request_headers["Cookie"] = "miss-custom-cookie=cuscookie"
  423. local ports_count = {}
  424. for i = 1, 4 do
  425. local httpc = http.new()
  426. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  427. if not res then
  428. ngx.say(err)
  429. return
  430. end
  431. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  432. end
  433. local ports_arr = {}
  434. for port, count in pairs(ports_count) do
  435. table.insert(ports_arr, {port = port, count = count})
  436. end
  437. local function cmd(a, b)
  438. return a.port > b.port
  439. end
  440. table.sort(ports_arr, cmd)
  441. ngx.say(require("toolkit.json").encode(ports_arr))
  442. ngx.exit(200)
  443. }
  444. }
  445. --- request
  446. GET /t
  447. --- response_body
  448. [{"count":4,"port":"1980"}]
  449. --- grep_error_log eval
  450. qr/chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1/
  451. --- grep_error_log_out
  452. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  453. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  454. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  455. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  456. === TEST 11: set route(key contains uppercase letters and hyphen)
  457. --- config
  458. location /t {
  459. content_by_lua_block {
  460. local t = require("lib.test_admin").test
  461. local code, body = t('/apisix/admin/routes/1',
  462. ngx.HTTP_PUT,
  463. [[{
  464. "uri": "/server_port",
  465. "upstream": {
  466. "key": "X-Sessionid",
  467. "type": "chash",
  468. "hash_on": "header",
  469. "nodes": {
  470. "127.0.0.1:1980": 1,
  471. "127.0.0.1:1981": 1
  472. }
  473. }
  474. }]]
  475. )
  476. if code >= 300 then
  477. ngx.status = code
  478. end
  479. ngx.say(body)
  480. }
  481. }
  482. --- request
  483. GET /t
  484. --- response_body
  485. passed
  486. === TEST 12: hit routes with header
  487. --- config
  488. location /t {
  489. content_by_lua_block {
  490. local http = require "resty.http"
  491. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  492. .. "/server_port"
  493. local ports_count = {}
  494. for i = 1, 6 do
  495. local httpc = http.new()
  496. local res, err = httpc:request_uri(uri, {
  497. method = "GET",
  498. headers = {
  499. ["X-Sessionid"] = "chash_val_" .. i
  500. }
  501. })
  502. if not res then
  503. ngx.say(err)
  504. return
  505. end
  506. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  507. end
  508. local ports_arr = {}
  509. for port, count in pairs(ports_count) do
  510. table.insert(ports_arr, {port = port, count = count})
  511. end
  512. local function cmd(a, b)
  513. return a.port > b.port
  514. end
  515. table.sort(ports_arr, cmd)
  516. ngx.say(require("toolkit.json").encode(ports_arr))
  517. ngx.exit(200)
  518. }
  519. }
  520. --- request
  521. GET /t
  522. --- response_body
  523. [{"count":3,"port":"1981"},{"count":3,"port":"1980"}]
  524. --- error_log
  525. chash_key: "chash_val_1"
  526. chash_key: "chash_val_2"
  527. chash_key: "chash_val_3"
  528. chash_key: "chash_val_4"
  529. chash_key: "chash_val_5"
  530. chash_key: "chash_val_6"
  531. === TEST 13: set route(two upstream nodes, type chash), hash_on vars_combinations
  532. --- config
  533. location /t {
  534. content_by_lua_block {
  535. local t = require("lib.test_admin").test
  536. local code, body = t('/apisix/admin/routes/1',
  537. ngx.HTTP_PUT,
  538. [[{
  539. "uri": "/server_port",
  540. "upstream": {
  541. "key": "$http_custom_header-$http_custom_header_second",
  542. "type": "chash",
  543. "hash_on": "vars_combinations",
  544. "nodes": {
  545. "127.0.0.1:1980": 1,
  546. "127.0.0.1:1981": 1
  547. }
  548. }
  549. }]]
  550. )
  551. if code >= 300 then
  552. ngx.status = code
  553. end
  554. ngx.say(body)
  555. }
  556. }
  557. --- request
  558. GET /t
  559. --- response_body
  560. passed
  561. === TEST 14: hit routes, hash_on custom header combinations
  562. --- config
  563. location /t {
  564. content_by_lua_block {
  565. local http = require "resty.http"
  566. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  567. .. "/server_port"
  568. local request_headers = {}
  569. request_headers["custom_header"] = "custom-one"
  570. request_headers["custom_header_second"] = "custom-two"
  571. local ports_count = {}
  572. for i = 1, 4 do
  573. local httpc = http.new()
  574. local res, err = httpc:request_uri(uri, {method = "GET", headers = request_headers})
  575. if not res then
  576. ngx.say(err)
  577. return
  578. end
  579. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  580. end
  581. local ports_arr = {}
  582. for port, count in pairs(ports_count) do
  583. table.insert(ports_arr, {port = port, count = count})
  584. end
  585. local function cmd(a, b)
  586. return a.port > b.port
  587. end
  588. table.sort(ports_arr, cmd)
  589. ngx.say(require("toolkit.json").encode(ports_arr))
  590. ngx.exit(200)
  591. }
  592. }
  593. --- request
  594. GET /t
  595. --- response_body
  596. [{"count":4,"port":"1980"}]
  597. --- grep_error_log eval
  598. qr/hash_on: vars_combinations|chash_key: "custom-one-custom-two"/
  599. --- grep_error_log_out
  600. hash_on: vars_combinations
  601. chash_key: "custom-one-custom-two"
  602. hash_on: vars_combinations
  603. chash_key: "custom-one-custom-two"
  604. hash_on: vars_combinations
  605. chash_key: "custom-one-custom-two"
  606. hash_on: vars_combinations
  607. chash_key: "custom-one-custom-two"
  608. === TEST 15: hit routes, hash_on custom header combinations
  609. --- config
  610. location /t {
  611. content_by_lua_block {
  612. local http = require "resty.http"
  613. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  614. .. "/server_port"
  615. local ports_count = {}
  616. for i = 1, 2 do
  617. local httpc = http.new()
  618. local res, err = httpc:request_uri(uri)
  619. if not res then
  620. ngx.say(err)
  621. return
  622. end
  623. ports_count[res.body] = (ports_count[res.body] or 0) + 1
  624. end
  625. local ports_arr = {}
  626. for port, count in pairs(ports_count) do
  627. table.insert(ports_arr, {port = port, count = count})
  628. end
  629. local function cmd(a, b)
  630. return a.port > b.port
  631. end
  632. table.sort(ports_arr, cmd)
  633. ngx.say(require("toolkit.json").encode(ports_arr))
  634. }
  635. }
  636. --- request
  637. GET /t
  638. --- response_body
  639. [{"count":2,"port":"1980"}]
  640. --- grep_error_log eval
  641. qr/chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1/
  642. --- grep_error_log_out
  643. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1
  644. chash_key fetch is nil, use default chash_key remote_addr: 127.0.0.1