| # vim:set ft= ts=4 sw=4 et fdm=marker: |
| |
| BEGIN { |
| $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; |
| } |
| |
| use lib 'lib'; |
| use Test::Nginx::Socket::Lua; |
| |
| #worker_connections(1014); |
| #master_on(); |
| #workers(2); |
| #log_level('warn'); |
| |
| repeat_each(2); |
| |
| plan tests => repeat_each() * 55; |
| |
| #no_diff(); |
| no_long_string(); |
| run_tests(); |
| |
| __DATA__ |
| |
| === TEST 1: flush wait - content |
| --- config |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| local ok, err = ngx.flush(true) |
| if not ok then |
| ngx.log(ngx.ERR, "flush failed: ", err) |
| return |
| end |
| ngx.say("hiya") |
| '; |
| } |
| --- request |
| GET /test |
| --- response_body |
| hello, world |
| hiya |
| --- no_error_log |
| [error] |
| --- error_log |
| lua reuse free buf memory 13 >= 5 |
| |
| |
| |
| === TEST 2: flush no wait - content |
| --- config |
| send_timeout 500ms; |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| local ok, err = ngx.flush(false) |
| if not ok then |
| ngx.log(ngx.ERR, "flush failed: ", err) |
| return |
| end |
| ngx.say("hiya") |
| '; |
| } |
| --- request |
| GET /test |
| --- response_body |
| hello, world |
| hiya |
| |
| |
| |
| === TEST 3: flush wait - rewrite |
| --- config |
| location /test { |
| rewrite_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(true) |
| ngx.say("hiya") |
| '; |
| content_by_lua return; |
| } |
| --- request |
| GET /test |
| --- response_body |
| hello, world |
| hiya |
| |
| |
| |
| === TEST 4: flush no wait - rewrite |
| --- config |
| location /test { |
| rewrite_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(false) |
| ngx.say("hiya") |
| '; |
| content_by_lua return; |
| } |
| --- request |
| GET /test |
| --- response_body |
| hello, world |
| hiya |
| |
| |
| |
| === TEST 5: http 1.0 (sync) |
| --- config |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(true) |
| ngx.say("hiya") |
| ngx.flush(true) |
| ngx.say("blah") |
| '; |
| } |
| --- request |
| GET /test HTTP/1.0 |
| --- response_body |
| hello, world |
| hiya |
| blah |
| --- response_headers |
| Content-Length: 23 |
| --- timeout: 5 |
| --- error_log |
| lua buffering output bufs for the HTTP 1.0 request |
| lua http 1.0 buffering makes ngx.flush() a no-op |
| |
| |
| |
| === TEST 6: http 1.0 (async) |
| --- config |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| local ok, err = ngx.flush(false) |
| if not ok then |
| ngx.log(ngx.WARN, "1: failed to flush: ", err) |
| end |
| ngx.say("hiya") |
| local ok, err = ngx.flush(false) |
| if not ok then |
| ngx.log(ngx.WARN, "2: failed to flush: ", err) |
| end |
| ngx.say("blah") |
| '; |
| } |
| --- request |
| GET /test HTTP/1.0 |
| --- response_body |
| hello, world |
| hiya |
| blah |
| --- response_headers |
| Content-Length: 23 |
| --- error_log |
| lua buffering output bufs for the HTTP 1.0 request |
| lua http 1.0 buffering makes ngx.flush() a no-op |
| 1: failed to flush: buffering |
| 2: failed to flush: buffering |
| --- timeout: 5 |
| |
| |
| |
| === TEST 7: flush wait - big data |
| --- config |
| location /test { |
| content_by_lua ' |
| ngx.say(string.rep("a", 1024 * 64)) |
| ngx.flush(true) |
| ngx.say("hiya") |
| '; |
| } |
| --- request |
| GET /test |
| --- response_body |
| hello, world |
| hiya |
| --- SKIP |
| |
| |
| |
| === TEST 8: flush wait - content |
| --- config |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(true) |
| local res = ngx.location.capture("/sub") |
| ngx.print(res.body) |
| ngx.flush(true) |
| '; |
| } |
| location /sub { |
| echo sub; |
| } |
| --- request |
| GET /test |
| --- response_body |
| hello, world |
| sub |
| |
| |
| |
| === TEST 9: http 1.0 (sync + buffering off) |
| --- config |
| lua_http10_buffering off; |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(true) |
| ngx.say("hiya") |
| ngx.flush(true) |
| ngx.say("blah") |
| '; |
| } |
| --- request |
| GET /test HTTP/1.0 |
| --- response_body |
| hello, world |
| hiya |
| blah |
| --- response_headers |
| !Content-Length |
| --- timeout: 5 |
| --- no_error_log |
| lua buffering output bufs for the HTTP 1.0 request |
| lua http 1.0 buffering makes ngx.flush() a no-op |
| |
| |
| |
| === TEST 10: http 1.0 (async) |
| --- config |
| lua_http10_buffering on; |
| location /test { |
| lua_http10_buffering off; |
| content_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(false) |
| ngx.say("hiya") |
| ngx.flush(false) |
| ngx.say("blah") |
| '; |
| } |
| --- request |
| GET /test HTTP/1.0 |
| --- response_body |
| hello, world |
| hiya |
| blah |
| --- response_headers |
| !Content-Length |
| --- no_error_log |
| lua buffering output bufs for the HTTP 1.0 request |
| lua http 1.0 buffering makes ngx.flush() a no-op |
| --- timeout: 5 |
| |
| |
| |
| === TEST 11: http 1.0 (sync) - buffering explicitly off |
| --- config |
| location /test { |
| lua_http10_buffering on; |
| content_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(true) |
| ngx.say("hiya") |
| ngx.flush(true) |
| ngx.say("blah") |
| '; |
| } |
| --- request |
| GET /test HTTP/1.0 |
| --- response_body |
| hello, world |
| hiya |
| blah |
| --- response_headers |
| Content-Length: 23 |
| --- timeout: 5 |
| --- error_log |
| lua buffering output bufs for the HTTP 1.0 request |
| lua http 1.0 buffering makes ngx.flush() a no-op |
| |
| |
| |
| === TEST 12: http 1.0 (async) - buffering explicitly off |
| --- config |
| location /test { |
| lua_http10_buffering on; |
| content_by_lua ' |
| ngx.say("hello, world") |
| ngx.flush(false) |
| ngx.say("hiya") |
| ngx.flush(false) |
| ngx.say("blah") |
| '; |
| } |
| --- request |
| GET /test HTTP/1.0 |
| --- response_body |
| hello, world |
| hiya |
| blah |
| --- response_headers |
| Content-Length: 23 |
| --- error_log |
| lua buffering output bufs for the HTTP 1.0 request |
| lua http 1.0 buffering makes ngx.flush() a no-op |
| --- timeout: 5 |
| |
| |
| |
| === TEST 13: flush wait in a user coroutine |
| --- config |
| location /test { |
| content_by_lua ' |
| function f() |
| ngx.say("hello, world") |
| ngx.flush(true) |
| coroutine.yield() |
| ngx.say("hiya") |
| end |
| local c = coroutine.create(f) |
| ngx.say(coroutine.resume(c)) |
| ngx.say(coroutine.resume(c)) |
| '; |
| } |
| --- request |
| GET /test |
| --- stap2 |
| F(ngx_http_lua_wev_handler) { |
| printf("wev handler: wev:%d\n", $r->connection->write->ready) |
| } |
| |
| global ids, cur |
| |
| function gen_id(k) { |
| if (ids[k]) return ids[k] |
| ids[k] = ++cur |
| return cur |
| } |
| |
| F(ngx_http_handler) { |
| delete ids |
| cur = 0 |
| } |
| |
| /* |
| F(ngx_http_lua_run_thread) { |
| id = gen_id($ctx->cur_co) |
| printf("run thread %d\n", id) |
| } |
| |
| probe process("/usr/local/openresty-debug/luajit/lib/libluajit-5.1.so.2").function("lua_resume") { |
| id = gen_id($L) |
| printf("lua resume %d\n", id) |
| } |
| */ |
| |
| M(http-lua-user-coroutine-resume) { |
| p = gen_id($arg2) |
| c = gen_id($arg3) |
| printf("resume %x in %x\n", c, p) |
| } |
| |
| M(http-lua-entry-coroutine-yield) { |
| println("entry coroutine yield") |
| } |
| |
| /* |
| F(ngx_http_lua_coroutine_yield) { |
| printf("yield %x\n", gen_id($L)) |
| } |
| */ |
| |
| M(http-lua-user-coroutine-yield) { |
| p = gen_id($arg2) |
| c = gen_id($arg3) |
| printf("yield %x in %x\n", c, p) |
| } |
| |
| F(ngx_http_lua_atpanic) { |
| printf("lua atpanic(%d):", gen_id($L)) |
| print_ubacktrace(); |
| } |
| |
| M(http-lua-user-coroutine-create) { |
| p = gen_id($arg2) |
| c = gen_id($arg3) |
| printf("create %x in %x\n", c, p) |
| } |
| |
| F(ngx_http_lua_ngx_exec) { println("exec") } |
| |
| F(ngx_http_lua_ngx_exit) { println("exit") } |
| |
| F(ngx_http_writer) { println("http writer") } |
| |
| --- response_body |
| hello, world |
| true |
| hiya |
| true |
| --- error_log |
| lua reuse free buf memory 13 >= 5 |
| |
| |
| |
| === TEST 14: flush before sending out the header |
| --- config |
| location /test { |
| content_by_lua ' |
| ngx.flush() |
| ngx.status = 404 |
| ngx.say("not found") |
| '; |
| } |
| --- request |
| GET /test |
| --- response_body |
| not found |
| --- error_code: 404 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 15: flush wait - gzip |
| --- config |
| gzip on; |
| gzip_min_length 1; |
| gzip_types text/plain; |
| |
| location /test { |
| content_by_lua ' |
| ngx.say("hello, world") |
| local ok, err = ngx.flush(true) |
| if not ok then |
| ngx.log(ngx.ERR, "flush failed: ", err) |
| return |
| end |
| ngx.say("hiya") |
| '; |
| } |
| --- request |
| GET /test |
| --- more_headers |
| Accept-Encoding: gzip |
| --- response_body_like: .{15} |
| --- response_headers |
| Content-Encoding: gzip |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 16: flush wait - gunzip |
| --- config |
| location /test { |
| gunzip on; |
| content_by_lua ' |
| local f, err = io.open(ngx.var.document_root .. "/gzip.bin", "r") |
| if not f then |
| ngx.say("failed to open file: ", err) |
| return |
| end |
| local data = f:read(100) |
| ngx.header.content_encoding = "gzip" |
| ngx.print(data) |
| local ok, err = ngx.flush(true) |
| if not ok then |
| ngx.log(ngx.ERR, "flush failed: ", err) |
| return |
| end |
| data = f:read("*a") |
| ngx.print(data) |
| '; |
| } |
| --- user_files eval |
| ">>> gzip.bin |
| \x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x62\x64\x62\x62\x61\x62\x64\x63\x61\xe4\xe0\xe2\xe6\xe4\x61\xe4\xe4\xe7\x63\x12\xe4\xe1\xe0\x60\x14\x12\xe3\x91\xe4\xe4\xe4\x13\x60\xe3\x95\x12\x90\x15\xe0\x11\x50\x92\xd1\x16\x17\xe2\xd3\x17\x14\x11\x95\x95\x57\x96\x63\x37\xd2\x36\xd6\x51\x34\xb1\xe6\x62\x17\x95\xb0\x77\x60\xe3\x96\x33\x95\xb6\x91\x75\x97\x30\xe4\x66\x0c\xd0\xe3\xe0\xb5\xd3\x33\xf6\x90\x16\xb2\x90\x77\x56\x31\xe7\x55\x32\x11\x74\xe0\x02\x00\x00\x00\xff\xff\xcb\xc8\xac\x4c\xe4\x02\x00\x19\x15\xa9\x77\x6a\x00\x00\x00" |
| --- request |
| GET /test |
| --- ignore_response |
| --- no_error_log |
| [error] |
| |