2013-04-12 10:59:10 +04:00
|
|
|
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
|
|
|
|
|
|
|
our $SkipReason;
|
|
|
|
|
|
|
|
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};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-06 02:46:51 +04:00
|
|
|
use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : ();
|
2013-04-12 10:59:10 +04:00
|
|
|
|
|
|
|
|
|
|
|
use t::StapThread;
|
|
|
|
|
|
|
|
our $GCScript = $t::StapThread::GCScript;
|
|
|
|
our $StapScript = $t::StapThread::StapScript;
|
|
|
|
|
|
|
|
#worker_connections(1014);
|
|
|
|
#master_on();
|
|
|
|
#workers(2);
|
|
|
|
#log_level('warn');
|
|
|
|
|
|
|
|
repeat_each(2);
|
|
|
|
|
2014-05-10 22:02:37 +04:00
|
|
|
plan tests => repeat_each() * 81;
|
2013-04-12 10:59:10 +04:00
|
|
|
|
|
|
|
#no_diff();
|
|
|
|
no_long_string();
|
|
|
|
|
|
|
|
our $HtmlDir = html_dir;
|
|
|
|
|
|
|
|
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
|
|
|
|
$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir;
|
|
|
|
|
|
|
|
worker_connections(1024);
|
|
|
|
run_tests();
|
|
|
|
|
|
|
|
__DATA__
|
|
|
|
|
|
|
|
=== TEST 1: single timer
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.say("failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
local i = 0
|
|
|
|
local function f(premature)
|
|
|
|
i = i + 1
|
|
|
|
print("timer prematurely expired: ", premature)
|
|
|
|
print("in callback: hello, ", i)
|
|
|
|
end
|
|
|
|
local ok, err = ngx.timer.at(3, f)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to set timer: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
ngx.say("registered timer")
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
registered timer
|
|
|
|
|
|
|
|
--- wait: 0.3
|
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
[crit]
|
|
|
|
in callback: hello, 2
|
|
|
|
timer prematurely expired: false
|
|
|
|
|
|
|
|
--- error_log
|
|
|
|
lua abort pending timers
|
|
|
|
lua ngx.timer expired
|
|
|
|
http lua close fake http connection
|
|
|
|
in callback: hello, 1
|
|
|
|
timer prematurely expired: true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== TEST 2: multiple timers
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.say("failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
local i = 0
|
|
|
|
local function f(premature)
|
|
|
|
i = i + 1
|
|
|
|
print("timer prematurely expired: ", premature)
|
|
|
|
print("in callback: hello, ", i, "!")
|
|
|
|
end
|
|
|
|
for i = 1, 10 do
|
|
|
|
local ok, err = ngx.timer.at(3, f)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to set timer: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
ngx.say("registered timers")
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
registered timers
|
|
|
|
|
|
|
|
--- wait: 0.3
|
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
[crit]
|
|
|
|
in callback: hello, 11!
|
|
|
|
timer prematurely expired: false
|
|
|
|
|
|
|
|
--- error_log
|
|
|
|
lua abort pending timers
|
|
|
|
lua ngx.timer expired
|
|
|
|
http lua close fake http connection
|
|
|
|
in callback: hello, 1!
|
|
|
|
in callback: hello, 2!
|
|
|
|
in callback: hello, 3!
|
|
|
|
in callback: hello, 4!
|
|
|
|
in callback: hello, 5!
|
|
|
|
in callback: hello, 6!
|
|
|
|
in callback: hello, 7!
|
|
|
|
in callback: hello, 8!
|
|
|
|
in callback: hello, 9!
|
|
|
|
in callback: hello, 10!
|
|
|
|
timer prematurely expired: true
|
|
|
|
|
2013-04-12 23:29:20 +04:00
|
|
|
|
|
|
|
|
|
|
|
=== TEST 3: trying to add new timer after HUP reload
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.say("failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
local function f(premature)
|
|
|
|
print("timer prematurely expired: ", premature)
|
2013-11-24 06:59:37 +04:00
|
|
|
local ok, err = ngx.timer.at(3, f)
|
2013-04-12 23:29:20 +04:00
|
|
|
if not ok then
|
|
|
|
print("failed to register a new timer after reload: ", err)
|
|
|
|
else
|
|
|
|
print("registered a new timer after reload")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local ok, err = ngx.timer.at(3, f)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to set timer: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
ngx.say("registered timer")
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
registered timer
|
|
|
|
|
|
|
|
--- wait: 0.2
|
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
[crit]
|
|
|
|
in callback: hello, 2
|
|
|
|
timer prematurely expired: false
|
|
|
|
|
|
|
|
--- error_log
|
|
|
|
lua abort pending timers
|
|
|
|
lua ngx.timer expired
|
|
|
|
http lua close fake http connection
|
|
|
|
timer prematurely expired: true
|
|
|
|
failed to register a new timer after reload: process exiting, context: ngx.timer
|
|
|
|
|
2013-11-24 06:59:37 +04:00
|
|
|
|
|
|
|
|
|
|
|
=== TEST 4: trying to add new timer after HUP reload
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.say("failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
local function g(premature)
|
|
|
|
print("g: timer prematurely expired: ", premature)
|
2013-11-24 08:32:43 +04:00
|
|
|
print("g: exiting=", ngx.worker.exiting())
|
2013-11-24 06:59:37 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
local function f(premature)
|
|
|
|
print("f: timer prematurely expired: ", premature)
|
2013-11-24 08:32:43 +04:00
|
|
|
print("f: exiting=", ngx.worker.exiting())
|
2013-11-24 06:59:37 +04:00
|
|
|
local ok, err = ngx.timer.at(0, g)
|
|
|
|
if not ok then
|
|
|
|
print("f: failed to register a new timer after reload: ", err)
|
|
|
|
else
|
|
|
|
print("f: registered a new timer after reload")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local ok, err = ngx.timer.at(3, f)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to set timer: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
ngx.say("registered timer")
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
registered timer
|
|
|
|
|
|
|
|
--- wait: 0.2
|
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
[crit]
|
|
|
|
in callback: hello, 2
|
|
|
|
failed to register a new timer after reload
|
|
|
|
|
|
|
|
--- error_log
|
|
|
|
lua abort pending timers
|
|
|
|
lua ngx.timer expired
|
|
|
|
http lua close fake http connection
|
|
|
|
f: timer prematurely expired: true
|
|
|
|
f: registered a new timer after reload
|
2013-11-24 08:32:43 +04:00
|
|
|
f: exiting=true
|
2013-11-24 08:50:48 +04:00
|
|
|
g: timer prematurely expired: false
|
2013-11-24 08:32:43 +04:00
|
|
|
g: exiting=true
|
2013-11-24 06:59:37 +04:00
|
|
|
|
2014-01-26 01:54:24 +04:00
|
|
|
|
|
|
|
|
|
|
|
=== TEST 5: HUP reload should abort pending timers
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.say("failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
local function f(premature)
|
|
|
|
print("f: timer prematurely expired: ", premature)
|
|
|
|
print("f: exiting=", ngx.worker.exiting())
|
|
|
|
end
|
|
|
|
|
|
|
|
for i = 1, 100 do
|
|
|
|
local ok, err = ngx.timer.at(3 + i, f)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to set timer: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
ngx.say("ok")
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
ok
|
|
|
|
|
2014-03-31 07:45:49 +04:00
|
|
|
--- wait: 0.5
|
2014-01-26 01:54:24 +04:00
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
[crit]
|
|
|
|
in callback: hello, 2
|
|
|
|
failed to register a new timer after reload
|
|
|
|
|
|
|
|
--- grep_error_log eval: qr/lua found \d+ pending timers/
|
|
|
|
--- grep_error_log_out
|
|
|
|
lua found 100 pending timers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== TEST 6: HUP reload should abort pending timers (coroutine + cosocket)
|
|
|
|
--- http_config
|
|
|
|
lua_shared_dict test_dict 1m;
|
|
|
|
|
|
|
|
server {
|
2014-01-27 02:06:06 +04:00
|
|
|
listen 12355;
|
2014-01-26 01:54:24 +04:00
|
|
|
location = /foo {
|
|
|
|
echo 'foo';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local http_req = {"GET /foo HTTP/1.1", "Host: localhost:1234", "", ""}
|
|
|
|
http_req = table.concat(http_req, "\\r\\n")
|
|
|
|
|
|
|
|
-- Connect the socket
|
|
|
|
local sock = ngx.socket.tcp()
|
2014-01-27 02:06:06 +04:00
|
|
|
local ok,err = sock:connect("127.0.0.1", 12355)
|
2014-01-26 01:54:24 +04:00
|
|
|
if not ok then
|
|
|
|
ngx.log(ngx.ERR, err)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Send the request
|
|
|
|
local ok,err = sock:send(http_req)
|
|
|
|
|
|
|
|
-- Get Headers
|
|
|
|
repeat
|
|
|
|
local line, err = sock:receive("*l")
|
2014-08-30 03:22:36 +04:00
|
|
|
until not line or string.find(line, "^%s*$")
|
2014-01-26 01:54:24 +04:00
|
|
|
|
|
|
|
function foo()
|
|
|
|
repeat
|
|
|
|
-- Get and read chunk
|
|
|
|
local line, err = sock:receive("*l")
|
|
|
|
local len = tonumber(line)
|
|
|
|
if len > 0 then
|
|
|
|
local chunk, err = sock:receive(len)
|
|
|
|
coroutine.yield(chunk)
|
|
|
|
sock:receive(2)
|
|
|
|
else
|
|
|
|
-- Read last newline
|
|
|
|
sock:receive(2)
|
|
|
|
end
|
|
|
|
until len == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
co = coroutine.create(foo)
|
|
|
|
repeat
|
|
|
|
local chunk = select(2,coroutine.resume(co))
|
|
|
|
until chunk == nil
|
|
|
|
|
|
|
|
-- Breaks the timer
|
|
|
|
sock:setkeepalive()
|
|
|
|
ngx.say("ok")
|
|
|
|
';
|
|
|
|
|
|
|
|
log_by_lua '
|
|
|
|
local background_thread
|
|
|
|
background_thread = function(premature)
|
|
|
|
ngx.log(ngx.DEBUG, premature)
|
|
|
|
if premature then
|
|
|
|
ngx.shared["test_dict"]:delete("background_flag")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local ok, err = ngx.timer.at(1, background_thread)
|
|
|
|
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.say("failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
end
|
|
|
|
local dict = ngx.shared["test_dict"]
|
|
|
|
|
|
|
|
if dict:get("background_flag") == nil then
|
|
|
|
local ok, err = ngx.timer.at(0, background_thread)
|
|
|
|
if ok then
|
|
|
|
dict:set("test_dict", 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
ok
|
|
|
|
|
|
|
|
--- wait: 0.3
|
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
[crit]
|
|
|
|
in callback: hello, 2
|
|
|
|
failed to register a new timer after reload
|
|
|
|
|
|
|
|
--- grep_error_log eval: qr/lua found \d+ pending timers/
|
|
|
|
--- grep_error_log_out
|
|
|
|
lua found 1 pending timers
|
|
|
|
|
2014-05-10 22:02:37 +04:00
|
|
|
|
|
|
|
|
2014-05-12 23:54:40 +04:00
|
|
|
=== TEST 7: HUP reload should abort pending timers (fuzz test)
|
2014-05-10 22:02:37 +04:00
|
|
|
--- http_config
|
|
|
|
lua_max_pending_timers 8192;
|
|
|
|
|
|
|
|
--- config
|
|
|
|
location /t {
|
|
|
|
content_by_lua '
|
|
|
|
local job = function(premature, kill)
|
|
|
|
if premature then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if kill then
|
|
|
|
local f, err = io.open("t/servroot/logs/nginx.pid", "r")
|
|
|
|
if not f then
|
|
|
|
ngx.log(ngx.ERR, "failed to open nginx.pid: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local pid = f:read()
|
|
|
|
-- ngx.say("master pid: [", pid, "]")
|
|
|
|
f:close()
|
|
|
|
|
|
|
|
os.execute("kill -HUP " .. pid)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
math.randomseed(ngx.time())
|
|
|
|
local rand = math.random
|
|
|
|
local newtimer = ngx.timer.at
|
|
|
|
for i = 1, 8191 do
|
|
|
|
local delay = rand(4096)
|
|
|
|
local ok, err = newtimer(delay, job, false)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to create timer at ", delay, ": ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local ok, err = newtimer(0, job, true)
|
|
|
|
if not ok then
|
|
|
|
ngx.say("failed to create the killer timer: ", err)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
ngx.say("ok")
|
|
|
|
';
|
|
|
|
}
|
|
|
|
--- request
|
|
|
|
GET /t
|
|
|
|
|
|
|
|
--- response_body
|
|
|
|
ok
|
|
|
|
|
|
|
|
--- wait: 0.3
|
|
|
|
--- no_error_log
|
|
|
|
[error]
|
|
|
|
[alert]
|
|
|
|
|
|
|
|
--- grep_error_log eval: qr/lua found \d+ pending timers/
|
|
|
|
--- grep_error_log_out
|
|
|
|
lua found 8191 pending timers
|
|
|
|
--- timeout: 20
|
|
|
|
|