1# vim:set ft= ts=4 sw=4 et fdm=marker: 2 3our $SkipReason; 4 5BEGIN { 6 if ($ENV{TEST_NGINX_CHECK_LEAK}) { 7 $SkipReason = "unavailable for the hup tests"; 8 9 } else { 10 $ENV{TEST_NGINX_USE_HUP} = 1; 11 undef $ENV{TEST_NGINX_USE_STAP}; 12 } 13} 14 15use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); 16 17 18use t::StapThread; 19 20our $GCScript = $t::StapThread::GCScript; 21our $StapScript = $t::StapThread::StapScript; 22 23#worker_connections(1014); 24#master_on(); 25#workers(2); 26#log_level('warn'); 27 28repeat_each(2); 29 30plan tests => repeat_each() * 81; 31 32#no_diff(); 33no_long_string(); 34 35our $HtmlDir = html_dir; 36 37$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; 38$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; 39 40worker_connections(1024); 41run_tests(); 42 43__DATA__ 44 45=== TEST 1: single timer 46--- config 47 location /t { 48 content_by_lua ' 49 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 50 if not f then 51 ngx.say("failed to open nginx.pid: ", err) 52 return 53 end 54 55 local pid = f:read() 56 -- ngx.say("master pid: [", pid, "]") 57 58 f:close() 59 60 local i = 0 61 local function f(premature) 62 i = i + 1 63 print("timer prematurely expired: ", premature) 64 print("in callback: hello, ", i) 65 end 66 local ok, err = ngx.timer.at(3, f) 67 if not ok then 68 ngx.say("failed to set timer: ", err) 69 return 70 end 71 ngx.say("registered timer") 72 os.execute("kill -HUP " .. pid) 73 '; 74 } 75--- request 76GET /t 77 78--- response_body 79registered timer 80 81--- wait: 0.3 82--- no_error_log 83[error] 84[alert] 85[crit] 86in callback: hello, 2 87timer prematurely expired: false 88 89--- error_log 90lua abort pending timers 91lua ngx.timer expired 92http lua close fake http connection 93in callback: hello, 1 94timer prematurely expired: true 95 96 97 98=== TEST 2: multiple timers 99--- config 100 location /t { 101 content_by_lua ' 102 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 103 if not f then 104 ngx.say("failed to open nginx.pid: ", err) 105 return 106 end 107 108 local pid = f:read() 109 -- ngx.say("master pid: [", pid, "]") 110 111 f:close() 112 113 local i = 0 114 local function f(premature) 115 i = i + 1 116 print("timer prematurely expired: ", premature) 117 print("in callback: hello, ", i, "!") 118 end 119 for i = 1, 10 do 120 local ok, err = ngx.timer.at(3, f) 121 if not ok then 122 ngx.say("failed to set timer: ", err) 123 return 124 end 125 end 126 ngx.say("registered timers") 127 os.execute("kill -HUP " .. pid) 128 '; 129 } 130--- request 131GET /t 132 133--- response_body 134registered timers 135 136--- wait: 0.3 137--- no_error_log 138[error] 139[alert] 140[crit] 141in callback: hello, 11! 142timer prematurely expired: false 143 144--- error_log 145lua abort pending timers 146lua ngx.timer expired 147http lua close fake http connection 148in callback: hello, 1! 149in callback: hello, 2! 150in callback: hello, 3! 151in callback: hello, 4! 152in callback: hello, 5! 153in callback: hello, 6! 154in callback: hello, 7! 155in callback: hello, 8! 156in callback: hello, 9! 157in callback: hello, 10! 158timer prematurely expired: true 159 160 161 162=== TEST 3: trying to add new timer after HUP reload 163--- config 164 location /t { 165 content_by_lua ' 166 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 167 if not f then 168 ngx.say("failed to open nginx.pid: ", err) 169 return 170 end 171 172 local pid = f:read() 173 -- ngx.say("master pid: [", pid, "]") 174 175 f:close() 176 177 local function f(premature) 178 print("timer prematurely expired: ", premature) 179 local ok, err = ngx.timer.at(3, f) 180 if not ok then 181 print("failed to register a new timer after reload: ", err) 182 else 183 print("registered a new timer after reload") 184 end 185 end 186 local ok, err = ngx.timer.at(3, f) 187 if not ok then 188 ngx.say("failed to set timer: ", err) 189 return 190 end 191 ngx.say("registered timer") 192 os.execute("kill -HUP " .. pid) 193 '; 194 } 195--- request 196GET /t 197 198--- response_body 199registered timer 200 201--- wait: 0.2 202--- no_error_log 203[error] 204[alert] 205[crit] 206in callback: hello, 2 207timer prematurely expired: false 208 209--- error_log 210lua abort pending timers 211lua ngx.timer expired 212http lua close fake http connection 213timer prematurely expired: true 214failed to register a new timer after reload: process exiting, context: ngx.timer 215 216 217 218=== TEST 4: trying to add new timer after HUP reload 219--- config 220 location /t { 221 content_by_lua ' 222 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 223 if not f then 224 ngx.say("failed to open nginx.pid: ", err) 225 return 226 end 227 228 local pid = f:read() 229 -- ngx.say("master pid: [", pid, "]") 230 231 f:close() 232 233 local function g(premature) 234 print("g: timer prematurely expired: ", premature) 235 print("g: exiting=", ngx.worker.exiting()) 236 end 237 238 local function f(premature) 239 print("f: timer prematurely expired: ", premature) 240 print("f: exiting=", ngx.worker.exiting()) 241 local ok, err = ngx.timer.at(0, g) 242 if not ok then 243 print("f: failed to register a new timer after reload: ", err) 244 else 245 print("f: registered a new timer after reload") 246 end 247 end 248 local ok, err = ngx.timer.at(3, f) 249 if not ok then 250 ngx.say("failed to set timer: ", err) 251 return 252 end 253 ngx.say("registered timer") 254 os.execute("kill -HUP " .. pid) 255 '; 256 } 257--- request 258GET /t 259 260--- response_body 261registered timer 262 263--- wait: 0.2 264--- no_error_log 265[error] 266[alert] 267[crit] 268in callback: hello, 2 269failed to register a new timer after reload 270 271--- error_log 272lua abort pending timers 273lua ngx.timer expired 274http lua close fake http connection 275f: timer prematurely expired: true 276f: registered a new timer after reload 277f: exiting=true 278g: timer prematurely expired: false 279g: exiting=true 280 281 282 283=== TEST 5: HUP reload should abort pending timers 284--- config 285 location /t { 286 content_by_lua ' 287 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 288 if not f then 289 ngx.say("failed to open nginx.pid: ", err) 290 return 291 end 292 293 local pid = f:read() 294 -- ngx.say("master pid: [", pid, "]") 295 296 f:close() 297 298 local function f(premature) 299 print("f: timer prematurely expired: ", premature) 300 print("f: exiting=", ngx.worker.exiting()) 301 end 302 303 for i = 1, 100 do 304 local ok, err = ngx.timer.at(3 + i, f) 305 if not ok then 306 ngx.say("failed to set timer: ", err) 307 return 308 end 309 end 310 ngx.say("ok") 311 os.execute("kill -HUP " .. pid) 312 '; 313 } 314--- request 315GET /t 316 317--- response_body 318ok 319 320--- wait: 0.5 321--- no_error_log 322[error] 323[alert] 324[crit] 325in callback: hello, 2 326failed to register a new timer after reload 327 328--- grep_error_log eval: qr/lua found \d+ pending timers/ 329--- grep_error_log_out 330lua found 100 pending timers 331 332 333 334=== TEST 6: HUP reload should abort pending timers (coroutine + cosocket) 335--- http_config 336 lua_shared_dict test_dict 1m; 337 338 server { 339 listen 12355; 340 location = /foo { 341 echo 'foo'; 342 } 343 } 344 345--- config 346 location /t { 347 content_by_lua ' 348 local http_req = {"GET /foo HTTP/1.1", "Host: localhost:1234", "", ""} 349 http_req = table.concat(http_req, "\\r\\n") 350 351 -- Connect the socket 352 local sock = ngx.socket.tcp() 353 local ok,err = sock:connect("127.0.0.1", 12355) 354 if not ok then 355 ngx.log(ngx.ERR, err) 356 end 357 358 -- Send the request 359 local ok,err = sock:send(http_req) 360 361 -- Get Headers 362 repeat 363 local line, err = sock:receive("*l") 364 until not line or string.find(line, "^%s*$") 365 366 local function foo() 367 repeat 368 -- Get and read chunk 369 local line, err = sock:receive("*l") 370 local len = tonumber(line) 371 if len > 0 then 372 local chunk, err = sock:receive(len) 373 coroutine.yield(chunk) 374 sock:receive(2) 375 else 376 -- Read last newline 377 sock:receive(2) 378 end 379 until len == 0 380 end 381 382 local co = coroutine.create(foo) 383 repeat 384 local chunk = select(2,coroutine.resume(co)) 385 until chunk == nil 386 387 -- Breaks the timer 388 sock:setkeepalive() 389 ngx.say("ok") 390 '; 391 392 log_by_lua ' 393 local background_thread 394 background_thread = function(premature) 395 ngx.log(ngx.DEBUG, premature) 396 if premature then 397 ngx.shared["test_dict"]:delete("background_flag") 398 return 399 end 400 local ok, err = ngx.timer.at(1, background_thread) 401 402 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 403 if not f then 404 ngx.say("failed to open nginx.pid: ", err) 405 return 406 end 407 local pid = f:read() 408 -- ngx.say("master pid: [", pid, "]") 409 f:close() 410 411 os.execute("kill -HUP " .. pid) 412 end 413 local dict = ngx.shared["test_dict"] 414 415 if dict:get("background_flag") == nil then 416 local ok, err = ngx.timer.at(0, background_thread) 417 if ok then 418 dict:set("test_dict", 1) 419 end 420 end 421 '; 422 } 423--- request 424GET /t 425 426--- response_body 427ok 428 429--- wait: 0.3 430--- no_error_log 431[error] 432[alert] 433[crit] 434in callback: hello, 2 435failed to register a new timer after reload 436 437--- grep_error_log eval: qr/lua found \d+ pending timers/ 438--- grep_error_log_out 439lua found 1 pending timers 440 441 442 443=== TEST 7: HUP reload should abort pending timers (fuzz test) 444--- http_config 445 lua_max_pending_timers 8192; 446 447--- config 448 location /t { 449 content_by_lua ' 450 local job = function(premature, kill) 451 if premature then 452 return 453 end 454 455 if kill then 456 local f, err = io.open("$TEST_NGINX_SERVER_ROOT/logs/nginx.pid", "r") 457 if not f then 458 ngx.log(ngx.ERR, "failed to open nginx.pid: ", err) 459 return 460 end 461 local pid = f:read() 462 -- ngx.say("master pid: [", pid, "]") 463 f:close() 464 465 os.execute("kill -HUP " .. pid) 466 end 467 end 468 469 math.randomseed(ngx.time()) 470 local rand = math.random 471 local newtimer = ngx.timer.at 472 for i = 1, 8191 do 473 local delay = rand(4096) 474 local ok, err = newtimer(delay, job, false) 475 if not ok then 476 ngx.say("failed to create timer at ", delay, ": ", err) 477 return 478 end 479 end 480 local ok, err = newtimer(0, job, true) 481 if not ok then 482 ngx.say("failed to create the killer timer: ", err) 483 return 484 end 485 ngx.say("ok") 486 '; 487 } 488--- request 489GET /t 490 491--- response_body 492ok 493 494--- wait: 0.3 495--- no_error_log 496[error] 497[alert] 498 499--- grep_error_log eval: qr/lua found \d+ pending timers/ 500--- grep_error_log_out 501lua found 8191 pending timers 502--- timeout: 20 503