|  | # | 
|  | # 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. | 
|  | # | 
|  | BEGIN { | 
|  | if ($ENV{TEST_NGINX_CHECK_LEAK}) { | 
|  | $SkipReason = "unavailable for the hup tests"; | 
|  |  | 
|  | } else { | 
|  | $ENV{TEST_NGINX_USE_HUP} = 1; | 
|  | undef $ENV{TEST_NGINX_USE_STAP}; | 
|  | } | 
|  | } | 
|  |  | 
|  | use t::APISIX 'no_plan'; | 
|  |  | 
|  | repeat_each(1); | 
|  | log_level('info'); | 
|  | no_root_location(); | 
|  | no_shuffle(); | 
|  | worker_connections(256); | 
|  |  | 
|  | # the healthcheck stop test requires exiting worker to keep watching etcd for a while, | 
|  | # which is not the case when using gRPC. | 
|  | my $yaml_config = <<_EOC_; | 
|  | deployment: | 
|  | role: traditional | 
|  | role_traditional: | 
|  | config_provider: etcd | 
|  | etcd: | 
|  | prefix: "/apisix" | 
|  | host: | 
|  | - "http://127.0.0.1:2379" | 
|  | use_grpc: false | 
|  | admin: | 
|  | admin_key: null | 
|  | _EOC_ | 
|  |  | 
|  | add_block_preprocessor(sub { | 
|  | my ($block) = @_; | 
|  |  | 
|  | if (!$block->yaml_config) { | 
|  | $block->set_value("yaml_config", $yaml_config); | 
|  | } | 
|  | }); | 
|  |  | 
|  | run_tests(); | 
|  |  | 
|  | __DATA__ | 
|  |  | 
|  | === TEST 1: set route(two healthy upstream nodes) | 
|  | --- request | 
|  | PUT /apisix/admin/routes/1 | 
|  | {"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","host":"foo.com","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}} | 
|  | --- error_code_like: ^20\d$ | 
|  |  | 
|  |  | 
|  |  | 
|  | === TEST 2: update + delete | 
|  | --- config | 
|  | location /t { | 
|  | content_by_lua_block { | 
|  | local t = require("lib.test_admin").test | 
|  |  | 
|  | local code, status, body = t('/apisix/admin/routes/1', | 
|  | "PUT", | 
|  | [[{"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}}]] | 
|  | ) | 
|  |  | 
|  | if code < 300 then | 
|  | code = 200 | 
|  | end | 
|  | ngx.say("1 code: ", code) | 
|  |  | 
|  | ngx.sleep(0.2) | 
|  | local code, body = t('/server_port', "GET") | 
|  | ngx.say("2 code: ", code) | 
|  |  | 
|  | ngx.sleep(0.2) | 
|  | code = t('/apisix/admin/routes/1', "DELETE") | 
|  | ngx.say("3 code: ", code) | 
|  |  | 
|  | ngx.sleep(0.2) | 
|  | local code, body = t('/server_port', "GET") | 
|  | ngx.say("4 code: ", code) | 
|  | } | 
|  | } | 
|  | --- request | 
|  | GET /t | 
|  | --- response_body | 
|  | 1 code: 200 | 
|  | 2 code: 200 | 
|  | 3 code: 200 | 
|  | 4 code: 404 | 
|  | --- grep_error_log eval | 
|  | qr/create new checker: table: 0x|try to release checker: table: 0x/ | 
|  | --- grep_error_log_out | 
|  | create new checker: table: 0x | 
|  | try to release checker: table: 0x | 
|  |  | 
|  |  | 
|  |  | 
|  | === TEST 3: set route(two healthy upstream nodes) | 
|  | --- request | 
|  | PUT /apisix/admin/routes/1 | 
|  | {"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","host":"foo.com","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}} | 
|  | --- error_code: 201 | 
|  |  | 
|  |  | 
|  |  | 
|  | === TEST 4: update | 
|  | --- config | 
|  | location /t { | 
|  | content_by_lua_block { | 
|  | local t = require("lib.test_admin").test | 
|  |  | 
|  | local code, body = t('/server_port', "GET") | 
|  | ngx.say("1 code: ", code) | 
|  |  | 
|  | local code, status, body = t('/apisix/admin/routes/1', | 
|  | "PUT", | 
|  | [[{"uri":"/server_port","upstream":{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}}]] | 
|  | ) | 
|  |  | 
|  | if code < 300 then | 
|  | code = 200 | 
|  | end | 
|  | ngx.say("2 code: ", code) | 
|  |  | 
|  | ngx.sleep(0.2) | 
|  | local code, body = t('/server_port', "GET") | 
|  | ngx.say("3 code: ", code) | 
|  | } | 
|  | } | 
|  | --- request | 
|  | GET /t | 
|  | --- response_body | 
|  | 1 code: 200 | 
|  | 2 code: 200 | 
|  | 3 code: 200 | 
|  | --- grep_error_log eval | 
|  | qr/create new checker: table: 0x|try to release checker: table: 0x/ | 
|  | --- grep_error_log_out | 
|  | create new checker: table: 0x | 
|  | try to release checker: table: 0x | 
|  | create new checker: table: 0x | 
|  |  | 
|  |  | 
|  |  | 
|  | === TEST 5: update + delete for /upstreams | 
|  | --- config | 
|  | location /t { | 
|  | content_by_lua_block { | 
|  | local t = require("lib.test_admin").test | 
|  |  | 
|  | local code, _, body = t('/apisix/admin/upstreams/stopchecker', | 
|  | "PUT", | 
|  | [[{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/status","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":2}}}}]] | 
|  | ) | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  |  | 
|  | local code, _, body = t('/apisix/admin/routes/1', | 
|  | "PUT", | 
|  | [[{"uri":"/server_port","upstream_id":"stopchecker"}]] | 
|  | ) | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  |  | 
|  | ngx.sleep(0.2) | 
|  | code, _, body = t('/server_port', "GET") | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  |  | 
|  | ngx.sleep(0.5) | 
|  |  | 
|  | -- update | 
|  | code, _, body = t('/apisix/admin/upstreams/stopchecker', | 
|  | "PUT", | 
|  | [[{"type":"roundrobin","nodes":{"127.0.0.1:1980":1,"127.0.0.1:1981":1},"checks":{"active":{"http_path":"/void","healthy":{"interval":1,"successes":1},"unhealthy":{"interval":1,"http_failures":1}}}}]] | 
|  | ) | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  |  | 
|  | ngx.sleep(0.2) | 
|  | code, _, body = t('/server_port', "GET") | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  |  | 
|  | -- delete | 
|  | code, _, body = t('/apisix/admin/routes/1', "DELETE") | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  | ngx.sleep(0.5) -- wait for routes delete event synced | 
|  |  | 
|  | code, _, body = t('/apisix/admin/upstreams/stopchecker', "DELETE") | 
|  |  | 
|  | if code > 300 then | 
|  | ngx.status = code | 
|  | ngx.say(body) | 
|  | return | 
|  | end | 
|  |  | 
|  | ngx.say("ok") | 
|  | } | 
|  | } | 
|  | --- request | 
|  | GET /t | 
|  | --- response_body | 
|  | ok | 
|  | --- grep_error_log eval | 
|  | qr/create new checker: table: 0x|try to release checker: table: 0x/ | 
|  | --- grep_error_log_out | 
|  | create new checker: table: 0x | 
|  | try to release checker: table: 0x | 
|  | create new checker: table: 0x | 
|  | try to release checker: table: 0x |