healthcheck-passive.t 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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_EVENTS_MODULE} ne "lua-resty-worker-events") {
  19. $SkipReason = "Only for lua-resty-worker-events events module";
  20. }
  21. }
  22. use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : ();
  23. use t::APISIX 'no_plan';
  24. repeat_each(1);
  25. log_level('info');
  26. no_root_location();
  27. no_shuffle();
  28. worker_connections(256);
  29. run_tests();
  30. __DATA__
  31. === TEST 1: set route(passive)
  32. --- config
  33. location /t {
  34. content_by_lua_block {
  35. local t = require("lib.test_admin").test
  36. local code, body = t('/apisix/admin/routes/1',
  37. ngx.HTTP_PUT,
  38. [[{
  39. "uri": "/server_port",
  40. "upstream": {
  41. "type": "roundrobin",
  42. "nodes": {
  43. "127.0.0.1:1980": 0,
  44. "127.0.0.1:1": 1
  45. },
  46. "retries": 0,
  47. "checks": {
  48. "active": {
  49. "http_path": "/status",
  50. "host": "foo.com",
  51. "healthy": {
  52. "interval": 100,
  53. "successes": 1
  54. },
  55. "unhealthy": {
  56. "interval": 100,
  57. "http_failures": 2
  58. }
  59. },]] .. [[
  60. "passive": {
  61. "healthy": {
  62. "http_statuses": [200, 201],
  63. "successes": 3
  64. },
  65. "unhealthy": {
  66. "http_statuses": [502],
  67. "http_failures": 1,
  68. "tcp_failures": 1
  69. }
  70. }
  71. }
  72. }
  73. }]]
  74. )
  75. if code >= 300 then
  76. ngx.status = code
  77. end
  78. ngx.say(body)
  79. }
  80. }
  81. --- request
  82. GET /t
  83. --- response_body
  84. passed
  85. === TEST 2: hit routes (two healthy nodes)
  86. --- config
  87. location /t {
  88. content_by_lua_block {
  89. ngx.sleep(1) -- wait for sync
  90. local json_sort = require("toolkit.json")
  91. local http = require("resty.http")
  92. local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/server_port"
  93. local ports_count = {}
  94. for i = 1, 6 do
  95. local httpc = http.new()
  96. local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
  97. if not res then
  98. ngx.say(err)
  99. return
  100. end
  101. local status = tostring(res.status)
  102. ports_count[status] = (ports_count[status] or 0) + 1
  103. end
  104. ngx.say(json_sort.encode(ports_count))
  105. ngx.exit(200)
  106. }
  107. }
  108. --- request
  109. GET /t
  110. --- response_body
  111. {"200":5,"502":1}
  112. --- error_log
  113. (upstream#/apisix/routes/1) unhealthy HTTP increment (1/1)
  114. === TEST 3: set route(only passive)
  115. --- config
  116. location /t {
  117. content_by_lua_block {
  118. local t = require("lib.test_admin").test
  119. local code, body = t('/apisix/admin/routes/1',
  120. ngx.HTTP_PUT,
  121. [[{
  122. "uri": "/server_port",
  123. "upstream": {
  124. "type": "roundrobin",
  125. "nodes": {
  126. "127.0.0.1:1980": 0,
  127. "127.0.0.1:1": 1
  128. },
  129. "retries": 0,
  130. "checks": {
  131. "passive": {
  132. "healthy": {
  133. "http_statuses": [200, 201],
  134. "successes": 3
  135. },
  136. "unhealthy": {
  137. "http_statuses": [502],
  138. "http_failures": 1,
  139. "tcp_failures": 1
  140. }
  141. }
  142. }
  143. }
  144. }]]
  145. )
  146. if code >= 300 then
  147. ngx.status = code
  148. end
  149. ngx.print(body)
  150. }
  151. }
  152. --- request
  153. GET /t
  154. --- error_code: 400
  155. --- response_body
  156. {"error_msg":"invalid configuration: property \"upstream\" validation failed: property \"checks\" validation failed: object matches none of the required: [\"active\"] or [\"active\",\"passive\"]"}
  157. === TEST 4: set route(only active + active & passive)
  158. --- config
  159. location /t {
  160. content_by_lua_block {
  161. local t = require("lib.test_admin").test
  162. local code, body = t('/apisix/admin/routes/1',
  163. ngx.HTTP_PUT,
  164. [[{
  165. "uri": "/hello",
  166. "upstream": {
  167. "type": "roundrobin",
  168. "nodes": {
  169. "127.0.0.1:1980": 0,
  170. "127.0.0.1:1": 1
  171. },
  172. "retries": 0,
  173. "checks": {
  174. "active": {
  175. "http_path": "/status",
  176. "host": "foo.com",
  177. "healthy": {
  178. "interval": 100,
  179. "successes": 1
  180. },
  181. "unhealthy": {
  182. "interval": 100,
  183. "http_failures": 2
  184. }
  185. }
  186. }
  187. }
  188. }]]
  189. )
  190. if code >= 300 then
  191. ngx.status = code
  192. ngx.say(body)
  193. return
  194. end
  195. local code, body = t('/apisix/admin/routes/2',
  196. ngx.HTTP_PUT,
  197. [[{
  198. "uri": "/hello_",
  199. "upstream": {
  200. "type": "roundrobin",
  201. "nodes": {
  202. "127.0.0.1:1980": 0,
  203. "127.0.0.1:1": 1
  204. },
  205. "retries": 0,
  206. "checks": {
  207. "active": {
  208. "http_path": "/status",
  209. "host": "foo.com",
  210. "healthy": {
  211. "interval": 100,
  212. "successes": 1
  213. },
  214. "unhealthy": {
  215. "interval": 100,
  216. "http_failures": 2
  217. }
  218. },]] .. [[
  219. "passive": {
  220. "healthy": {
  221. "http_statuses": [200, 201],
  222. "successes": 3
  223. },
  224. "unhealthy": {
  225. "http_statuses": [502],
  226. "http_failures": 1,
  227. "tcp_failures": 1
  228. }
  229. }
  230. }
  231. }
  232. }]]
  233. )
  234. if code >= 300 then
  235. ngx.status = code
  236. end
  237. ngx.say(body)
  238. }
  239. }
  240. --- request
  241. GET /t
  242. --- response_body
  243. passed
  244. === TEST 5: only one route should have passive healthcheck
  245. --- config
  246. location /t {
  247. content_by_lua_block {
  248. local t = require("lib.test_admin").test
  249. local json_sort = require("toolkit.json")
  250. local http = require("resty.http")
  251. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  252. local ports_count = {}
  253. local httpc = http.new()
  254. local res, err = httpc:request_uri(uri .. "/hello_")
  255. if not res then
  256. ngx.say(err)
  257. return
  258. end
  259. ngx.say(res.status)
  260. -- only /hello_ has passive healthcheck
  261. local res, err = httpc:request_uri(uri .. "/hello")
  262. if not res then
  263. ngx.say(err)
  264. return
  265. end
  266. ngx.say(res.status)
  267. }
  268. }
  269. --- request
  270. GET /t
  271. --- response_body
  272. 502
  273. 502
  274. --- grep_error_log eval
  275. qr/enabled healthcheck passive/
  276. --- grep_error_log_out
  277. enabled healthcheck passive
  278. === TEST 6: make sure passive healthcheck works (conf is not corrupted by the default value)
  279. --- config
  280. location /t {
  281. content_by_lua_block {
  282. local t = require("lib.test_admin").test
  283. local json_sort = require("toolkit.json")
  284. local http = require("resty.http")
  285. local uri = "http://127.0.0.1:" .. ngx.var.server_port
  286. local ports_count = {}
  287. local httpc = http.new()
  288. local res, err = httpc:request_uri(uri .. "/hello")
  289. if not res then
  290. ngx.say(err)
  291. return
  292. end
  293. ngx.say(res.status)
  294. local res, err = httpc:request_uri(uri .. "/hello_")
  295. if not res then
  296. ngx.say(err)
  297. return
  298. end
  299. ngx.say(res.status)
  300. }
  301. }
  302. --- request
  303. GET /t
  304. --- response_body
  305. 502
  306. 502
  307. --- grep_error_log eval
  308. qr/\[healthcheck\] \([^)]+\) unhealthy HTTP increment/
  309. --- grep_error_log_out
  310. [healthcheck] (upstream#/apisix/routes/2) unhealthy HTTP increment