| # |
| # 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. |
| # |
| use t::APISIX 'no_plan'; |
| |
| log_level('warn'); |
| repeat_each(1); |
| no_long_string(); |
| no_root_location(); |
| no_shuffle(); |
| |
| add_block_preprocessor(sub { |
| my ($block) = @_; |
| |
| if (!defined $block->request) { |
| $block->set_value("request", "GET /t"); |
| } |
| |
| my $user_yaml_config = <<_EOC_; |
| plugin_attr: |
| inspect: |
| delay: 1 |
| hooks_file: "/tmp/apisix_inspect_hooks.lua" |
| _EOC_ |
| $block->set_value("yaml_config", $user_yaml_config); |
| |
| my $extra_init_worker_by_lua = $block->extra_init_worker_by_lua // ""; |
| $extra_init_worker_by_lua .= <<_EOC_; |
| local function gen_funcs_invoke(...) |
| local code = "" |
| for _, func in ipairs({...}) do |
| code = code .. "test." .. func .. "();" |
| end |
| return code |
| end |
| function set_test_route(...) |
| func = func or 'run1' |
| local t = require("lib.test_admin").test |
| local code = [[{ |
| "methods": ["GET"], |
| "uri": "/inspect", |
| "plugins": { |
| "serverless-pre-function": { |
| "phase": "rewrite", |
| "functions" : ["return function() local test = require(\\"lib.test_inspect\\");]] |
| .. gen_funcs_invoke(...) |
| .. [[ngx.say(\\"ok\\"); end"] |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1980": 1 |
| } |
| } |
| }]] |
| return t('/apisix/admin/routes/inspect', ngx.HTTP_PUT, code) |
| end |
| |
| function do_request() |
| local http = require "resty.http" |
| local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/inspect" |
| |
| local httpc = http.new() |
| local res = httpc:request_uri(uri, {method = "GET"}) |
| assert(res.body == "ok\\n") |
| end |
| |
| function write_hooks(code, file) |
| local file = io.open(file or "/tmp/apisix_inspect_hooks.lua", "w") |
| file:write(code) |
| file:close() |
| end |
| _EOC_ |
| $block->set_value("extra_init_worker_by_lua", $extra_init_worker_by_lua); |
| |
| # note that it's different from APISIX.pm, |
| # here we enable no_error_log ignoreless of error_log. |
| if (!$block->no_error_log) { |
| $block->set_value("no_error_log", "[error]"); |
| } |
| |
| if (!$block->timeout) { |
| $block->set_value("timeout", "10"); |
| } |
| }); |
| |
| add_cleanup_handler(sub { |
| unlink("/tmp/apisix_inspect_hooks.lua"); |
| }); |
| |
| run_tests; |
| |
| __DATA__ |
| |
| === TEST 1: simple hook |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 27, nil, function(info) |
| ngx.log(ngx.WARN, "var1=", info.vals.var1) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| var1=hello |
| |
| |
| |
| === TEST 2: filename only |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("test_inspect.lua", 27, nil, function(info) |
| ngx.log(ngx.WARN, "var1=", info.vals.var1) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| var1=hello |
| |
| |
| |
| === TEST 3: hook lifetime |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| local hook1_times = 2 |
| dbg.set_hook("test_inspect.lua", 27, nil, function(info) |
| ngx.log(ngx.WARN, "var1=", info.vals.var1) |
| hook1_times = hook1_times - 1 |
| return hook1_times == 0 |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| -- request 3 times, but hook triggered 2 times |
| for _ = 1,3 do |
| do_request() |
| end |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| var1=hello |
| var1=hello |
| |
| |
| |
| === TEST 4: multiple hooks |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("test_inspect.lua", 26, nil, function(info) |
| ngx.log(ngx.WARN, "var1=", info.vals.var1) |
| return true |
| end) |
| |
| dbg.set_hook("test_inspect.lua", 27, nil, function(info) |
| ngx.log(ngx.WARN, "var2=", info.vals.var2) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| -- note that we don't remove the hook file, |
| -- used for next test case |
| } |
| } |
| --- error_log |
| var1=hello |
| var2=world |
| |
| |
| |
| === TEST 5: hook file not removed, re-enabled by next startup |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| var1=hello |
| |
| |
| |
| === TEST 6: soft link |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 27, nil, function(info) |
| ngx.log(ngx.WARN, "var1=", info.vals.var1) |
| return true |
| end) |
| ]], "/tmp/test_real_tmp_file.lua") |
| |
| os.execute("ln -sf /tmp/test_real_tmp_file.lua /tmp/apisix_inspect_hooks.lua") |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| os.remove("/tmp/test_real_tmp_file.lua") |
| } |
| } |
| --- error_log |
| var1=hello |
| |
| |
| |
| === TEST 7: remove soft link would disable hooks |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 27, nil, function(info) |
| ngx.log(ngx.WARN, "var1=", info.vals.var1) |
| return true |
| end) |
| ]], "/tmp/test_real_tmp_file.lua") |
| |
| os.execute("ln -sf /tmp/test_real_tmp_file.lua /tmp/apisix_inspect_hooks.lua") |
| |
| ngx.sleep(1.5) |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/test_real_tmp_file.lua") |
| } |
| } |
| --- no_error_log |
| var1=hello |
| |
| |
| |
| === TEST 8: ensure we see all local variables till the hook line |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 27, nil, function(info) |
| local count = 0 |
| for k,v in pairs(info.vals) do |
| count = count + 1 |
| end |
| ngx.log(ngx.WARN, "count=", count) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| count=2 |
| |
| |
| |
| === TEST 9: check upvalue of run2(), only upvalue used in function code are visible |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run2") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 33, nil, function(info) |
| ngx.log(ngx.WARN, "upvar1=", info.uv.upvar1) |
| ngx.log(ngx.WARN, "upvar2=", info.uv.upvar2) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| upvar1=2 |
| upvar2=nil |
| |
| |
| |
| === TEST 10: check upvalue of run3(), now both upvar1 and upvar2 are visible |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run3") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 37, nil, function(info) |
| ngx.log(ngx.WARN, "upvar1=", info.uv.upvar1) |
| ngx.log(ngx.WARN, "upvar2=", info.uv.upvar2) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| upvar1=2 |
| upvar2=yes |
| |
| |
| |
| === TEST 11: flush specific JIT cache |
| --- config |
| location /t { |
| content_by_lua_block { |
| local test = require("lib.test_inspect") |
| |
| local t1 = test.hot1() |
| local t8 = test.hot2() |
| |
| write_hooks([[ |
| local test = require("lib.test_inspect") |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 47, test.hot1, function(info) |
| return false |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| local t2 = test.hot1() |
| local t9 = test.hot2() |
| |
| assert(t2-t1 > t1, "hot1 consumes at least double times than before") |
| assert(t9-t8 < t8*0.8, "hot2 not affected") |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| |
| ngx.sleep(1.5) |
| |
| local t3 = test.hot1() |
| local t4 = test.hot2() |
| assert(t3-t1 < t1*0.8, "hot1 jit recover") |
| assert(t4-t8 < t4*0.8, "hot2 jit recover") |
| } |
| } |
| |
| |
| |
| === TEST 12: flush the whole JIT cache |
| --- config |
| location /t { |
| content_by_lua_block { |
| local test = require("lib.test_inspect") |
| |
| local t1 = test.hot1() |
| local t8 = test.hot2() |
| |
| write_hooks([[ |
| local test = require("lib.test_inspect") |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 47, nil, function(info) |
| return false |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| local t2 = test.hot1() |
| local t9 = test.hot2() |
| |
| assert(t2-t1 > t1, "hot1 consumes at least double times than before") |
| assert(t9-t8 > t8, "hot2 consumes at least double times than before") |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| |
| ngx.sleep(1.5) |
| |
| local t3 = test.hot1() |
| local t4 = test.hot2() |
| assert(t3-t1 < t1*0.8, "hot1 jit recover") |
| assert(t4-t8 < t4*0.8, "hot2 jit recover") |
| } |
| } |
| |
| |
| |
| === TEST 13: remove hook log |
| --- config |
| location /t { |
| content_by_lua_block { |
| local code = set_test_route("run1") |
| if code >= 300 then |
| ngx.status = code |
| return |
| end |
| |
| write_hooks([[ |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 27, nil, function(info) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| do_request() |
| |
| os.remove("/tmp/apisix_inspect_hooks.lua") |
| } |
| } |
| --- error_log |
| inspect: remove hook: t/lib/test_inspect.lua#27 |
| inspect: all hooks removed |
| |
| |
| |
| === TEST 14: jit should be recovered after all hooks are done |
| --- config |
| location /t { |
| content_by_lua_block { |
| local test = require("lib.test_inspect") |
| |
| local t1 = test.hot1() |
| |
| write_hooks([[ |
| local test = require("lib.test_inspect") |
| local dbg = require "apisix.inspect.dbg" |
| dbg.set_hook("t/lib/test_inspect.lua", 47, test.hot1, function(info) |
| return true |
| end) |
| ]]) |
| |
| ngx.sleep(1.5) |
| |
| local t2 = test.hot1() |
| assert(t2-t1 < t1*0.8, "hot1 consumes at least double times than before") |
| } |
| } |
| --- error_log |
| inspect: remove hook: t/lib/test_inspect.lua#47 |
| inspect: all hooks removed |