| # vim:set ft= ts=4 sw=4 et fdm=marker: |
| |
| use lib 'lib'; |
| use Test::Nginx::Socket::Lua; |
| use t::StapThread; |
| |
| our $GCScript = $t::StapThread::GCScript; |
| our $StapScript = $t::StapThread::StapScript; |
| |
| repeat_each(2); |
| |
| plan tests => repeat_each() * (blocks() * 4); |
| |
| $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; |
| $ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211'; |
| |
| #no_shuffle(); |
| worker_connections(256); |
| no_long_string(); |
| run_tests(); |
| |
| __DATA__ |
| |
| === TEST 1: simple user thread without I/O |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("hello in thread") |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| |
| --- response_body |
| before |
| hello in thread |
| after |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 2: two simple user threads without I/O |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("in thread 1") |
| end |
| |
| function g() |
| ngx.say("in thread 2") |
| end |
| |
| ngx.say("before 1") |
| ngx.thread.spawn(f) |
| ngx.say("after 1") |
| |
| ngx.say("before 2") |
| ngx.thread.spawn(g) |
| ngx.say("after 2") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 3: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 3 |
| delete thread 1 |
| |
| --- response_body |
| before 1 |
| in thread 1 |
| after 1 |
| before 2 |
| in thread 2 |
| after 2 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 3: simple user thread with sleep |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before sleep") |
| ngx.sleep(0.1) |
| ngx.say("after sleep") |
| end |
| |
| ngx.say("before thread create") |
| ngx.thread.spawn(f) |
| ngx.say("after thread create") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| before thread create |
| before sleep |
| after thread create |
| after sleep |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 4: two simple user threads with sleep |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("1: before sleep") |
| ngx.sleep(0.2) |
| ngx.say("1: after sleep") |
| end |
| |
| function g() |
| ngx.say("2: before sleep") |
| ngx.sleep(0.1) |
| ngx.say("2: after sleep") |
| end |
| |
| ngx.say("1: before thread create") |
| ngx.thread.spawn(f) |
| ngx.say("1: after thread create") |
| |
| ngx.say("2: before thread create") |
| ngx.thread.spawn(g) |
| ngx.say("2: after thread create") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 3: ok |
| delete thread 3 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- wait: 0.1 |
| --- response_body |
| 1: before thread create |
| 1: before sleep |
| 1: after thread create |
| 2: before thread create |
| 2: before sleep |
| 2: after thread create |
| 2: after sleep |
| 1: after sleep |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 5: error in user thread |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.blah() |
| end |
| |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: fail |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| |
| --- response_body |
| after |
| --- error_log |
| lua user thread aborted: runtime error: [string "content_by_lua"]:3: attempt to call field 'blah' (a nil value) |
| |
| |
| |
| === TEST 6: simple user threads doing a single subrequest (entry quits early) |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before capture") |
| res = ngx.location.capture("/proxy") |
| ngx.say("after capture: ", res.body) |
| end |
| |
| ngx.say("before thread create") |
| ngx.thread.spawn(f) |
| ngx.say("after thread create") |
| '; |
| } |
| |
| location /proxy { |
| proxy_pass http://127.0.0.1:$server_port/foo; |
| } |
| |
| location /foo { |
| echo_sleep 0.1; |
| echo -n hello world; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| before thread create |
| before capture |
| after thread create |
| after capture: hello world |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 7: simple user threads doing a single subrequest (entry also does a subrequest and quits early) |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before capture") |
| local res = ngx.location.capture("/proxy?foo") |
| ngx.say("after capture: ", res.body) |
| end |
| |
| ngx.say("before thread create") |
| ngx.thread.spawn(f) |
| ngx.say("after thread create") |
| local res = ngx.location.capture("/proxy?bar") |
| ngx.say("capture: ", res.body) |
| '; |
| } |
| |
| location /proxy { |
| proxy_pass http://127.0.0.1:$server_port/$args; |
| } |
| |
| location /foo { |
| echo_sleep 0.1; |
| echo -n hello foo; |
| } |
| |
| location /bar { |
| echo -n hello bar; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| before thread create |
| before capture |
| after thread create |
| capture: hello bar |
| after capture: hello foo |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 8: simple user threads doing a single subrequest (entry also does a subrequest and quits late) |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before capture") |
| local res = ngx.location.capture("/proxy?foo") |
| ngx.say("after capture: ", res.body) |
| end |
| |
| ngx.say("before thread create") |
| ngx.thread.spawn(f) |
| ngx.say("after thread create") |
| local res = ngx.location.capture("/proxy?bar") |
| ngx.say("capture: ", res.body) |
| '; |
| } |
| |
| location /proxy { |
| proxy_pass http://127.0.0.1:$server_port/$args; |
| } |
| |
| location /foo { |
| echo_sleep 0.1; |
| echo -n hello foo; |
| } |
| |
| location /bar { |
| echo_sleep 0.2; |
| echo -n hello bar; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| |
| --- response_body |
| before thread create |
| before capture |
| after thread create |
| after capture: hello foo |
| capture: hello bar |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 9: two simple user threads doing single subrequests (entry also does a subrequest and quits between) |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("f: before capture") |
| local res = ngx.location.capture("/proxy?foo") |
| ngx.say("f: after capture: ", res.body) |
| end |
| |
| function g() |
| ngx.say("g: before capture") |
| local res = ngx.location.capture("/proxy?bah") |
| ngx.say("g: after capture: ", res.body) |
| end |
| |
| ngx.say("before thread 1 create") |
| ngx.thread.spawn(f) |
| ngx.say("after thread 1 create") |
| |
| ngx.say("before thread 2 create") |
| ngx.thread.spawn(g) |
| ngx.say("after thread 2 create") |
| |
| local res = ngx.location.capture("/proxy?bar") |
| ngx.say("capture: ", res.body) |
| '; |
| } |
| |
| location /proxy { |
| proxy_pass http://127.0.0.1:$server_port/$args; |
| } |
| |
| location /foo { |
| echo_sleep 0.1; |
| echo -n hello foo; |
| } |
| |
| location /bar { |
| echo_sleep 0.2; |
| echo -n hello bar; |
| } |
| |
| location /bah { |
| echo_sleep 0.3; |
| echo -n hello bah; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| terminate 3: ok |
| delete thread 3 |
| |
| --- response_body |
| before thread 1 create |
| f: before capture |
| after thread 1 create |
| before thread 2 create |
| g: before capture |
| after thread 2 create |
| f: after capture: hello foo |
| capture: hello bar |
| g: after capture: hello bah |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 10: nested user threads |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before g") |
| ngx.thread.spawn(g) |
| ngx.say("after g") |
| end |
| |
| function g() |
| ngx.say("hello in g()") |
| end |
| |
| ngx.say("before f") |
| ngx.thread.spawn(f) |
| ngx.say("after f") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 2 |
| spawn user thread 3 in 2 |
| terminate 3: ok |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 3 |
| delete thread 2 |
| |
| --- response_body |
| before f |
| before g |
| hello in g() |
| after f |
| after g |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 11: nested user threads (with I/O) |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before g") |
| ngx.thread.spawn(g) |
| ngx.say("after g") |
| end |
| |
| function g() |
| ngx.sleep(0.1) |
| ngx.say("hello in g()") |
| end |
| |
| ngx.say("before f") |
| ngx.thread.spawn(f) |
| ngx.say("after f") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 2 |
| spawn user thread 3 in 2 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| terminate 3: ok |
| delete thread 3 |
| |
| --- response_body |
| before f |
| before g |
| after f |
| after g |
| hello in g() |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 12: coroutine status of a running user thread |
| --- config |
| location /lua { |
| content_by_lua ' |
| local co |
| function f() |
| co = coroutine.running() |
| ngx.sleep(0.1) |
| end |
| |
| ngx.thread.spawn(f) |
| ngx.say("status: ", coroutine.status(co)) |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| status: running |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 13: coroutine status of a dead user thread |
| --- config |
| location /lua { |
| content_by_lua ' |
| local co |
| function f() |
| co = coroutine.running() |
| end |
| |
| ngx.thread.spawn(f) |
| ngx.say("status: ", coroutine.status(co)) |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| |
| --- response_body |
| status: zombie |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 14: coroutine status of a "normal" user thread |
| --- config |
| location /lua { |
| content_by_lua ' |
| local co |
| function f() |
| co = coroutine.running() |
| local co2 = coroutine.create(g) |
| coroutine.resume(co2) |
| end |
| |
| function g() |
| ngx.sleep(0.1) |
| end |
| |
| ngx.thread.spawn(f) |
| ngx.say("status: ", coroutine.status(co)) |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 2 |
| terminate 1: ok |
| delete thread 1 |
| terminate 3: ok |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| status: normal |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 15: creating user threads in a user coroutine |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("before g") |
| ngx.thread.spawn(g) |
| ngx.say("after g") |
| end |
| |
| function g() |
| ngx.say("hello in g()") |
| end |
| |
| ngx.say("before f") |
| local co = coroutine.create(f) |
| coroutine.resume(co) |
| ngx.say("after f") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| create 3 in 2 |
| spawn user thread 3 in 2 |
| terminate 3: ok |
| terminate 2: ok |
| delete thread 3 |
| terminate 1: ok |
| delete thread 1 |
| |
| --- response_body |
| before f |
| before g |
| hello in g() |
| after g |
| after f |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 16: manual time slicing between a user thread and the entry thread |
| --- config |
| location /lua { |
| content_by_lua ' |
| local yield = coroutine.yield |
| |
| function f() |
| local self = coroutine.running() |
| ngx.say("f 1") |
| yield(self) |
| ngx.say("f 2") |
| yield(self) |
| ngx.say("f 3") |
| end |
| |
| local self = coroutine.running() |
| ngx.say("0") |
| yield(self) |
| ngx.say("1") |
| ngx.thread.spawn(f) |
| ngx.say("2") |
| yield(self) |
| ngx.say("3") |
| yield(self) |
| ngx.say("4") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| |
| --- response_body |
| 0 |
| 1 |
| f 1 |
| 2 |
| f 2 |
| 3 |
| f 3 |
| 4 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 17: manual time slicing between two user threads |
| --- config |
| location /lua { |
| content_by_lua ' |
| local yield = coroutine.yield |
| |
| function f() |
| local self = coroutine.running() |
| ngx.say("f 1") |
| yield(self) |
| ngx.say("f 2") |
| yield(self) |
| ngx.say("f 3") |
| end |
| |
| function g() |
| local self = coroutine.running() |
| ngx.say("g 1") |
| yield(self) |
| ngx.say("g 2") |
| yield(self) |
| ngx.say("g 3") |
| end |
| |
| ngx.thread.spawn(f) |
| ngx.thread.spawn(g) |
| ngx.say("done") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| terminate 3: ok |
| delete thread 3 |
| |
| --- response_body |
| f 1 |
| g 1 |
| f 2 |
| done |
| g 2 |
| f 3 |
| g 3 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 18: entry thread and a user thread flushing at the same time |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("hello in thread") |
| coroutine.yield(coroutine.running) |
| ngx.flush(true) |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| ngx.flush(true) |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| before |
| hello in thread |
| after |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 19: two user threads flushing at the same time |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.say("hello from f") |
| ngx.flush(true) |
| end |
| |
| function g() |
| ngx.say("hello from g") |
| ngx.flush(true) |
| end |
| |
| ngx.thread.spawn(f) |
| ngx.thread.spawn(g) |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out_like |
| ^(?:create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| terminate 3: ok |
| delete thread 3|create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 3: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 3 |
| delete thread 1)$ |
| |
| --- response_body |
| hello from f |
| hello from g |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 20: user threads + ngx.socket.tcp |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| local sock = ngx.socket.tcp() |
| local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) |
| if not ok then |
| ngx.say("failed to connect: ", err) |
| return |
| end |
| local bytes, err = sock:send("flush_all\\r\\n") |
| if not bytes then |
| ngx.say("failed to send query: ", err) |
| return |
| end |
| |
| local line, err = sock:receive() |
| if not line then |
| ngx.say("failed to receive: ", err) |
| return |
| end |
| |
| ngx.say("received: ", line) |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| before |
| after |
| received: OK |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 21: user threads + ngx.socket.udp |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| local sock = ngx.socket.udp() |
| local ok, err = sock:setpeername("127.0.0.1", 12345) |
| local bytes, err = sock:send("blah") |
| if not bytes then |
| ngx.say("failed to send query: ", err) |
| return |
| end |
| |
| local line, err = sock:receive() |
| if not line then |
| ngx.say("failed to receive: ", err) |
| return |
| end |
| |
| ngx.say("received: ", line) |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out_like chop |
| ^(?:create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| )$ |
| |
| --- udp_listen: 12345 |
| --- udp_query: blah |
| --- udp_reply: hello udp |
| --- response_body_like chop |
| ^(?:before |
| after |
| received: hello udp |
| |before |
| received: hello udp |
| after)$ |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 22: simple user thread with ngx.req.read_body() |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.req.read_body() |
| local body = ngx.req.get_body_data() |
| ngx.say("body: ", body) |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| POST /lua |
| hello world |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out_like chop |
| ^(?:create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1|create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2)$ |
| |
| --- response_body_like chop |
| ^(?:before |
| body: hello world |
| after|before |
| after |
| body: hello world)$ |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 23: simple user thread with ngx.req.socket() |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| local sock = ngx.req.socket() |
| local body, err = sock:receive(11) |
| if not body then |
| ngx.say("failed to read body: ", err) |
| return |
| end |
| |
| ngx.say("body: ", body) |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| POST /lua |
| hello world |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out_like chop |
| ^(?:create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1|create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2)$ |
| |
| --- response_body_like chop |
| ^(?:before |
| body: hello world |
| after|before |
| after |
| body: hello world)$ |
| |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 24: simple user thread with args |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f(a, b) |
| ngx.say("hello ", a, " and ", b) |
| end |
| |
| ngx.say("before") |
| ngx.thread.spawn(f, "foo", 3.14) |
| ngx.say("after") |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 2: ok |
| terminate 1: ok |
| delete thread 2 |
| delete thread 1 |
| |
| --- response_body |
| before |
| hello foo and 3.14 |
| after |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 25: multiple user threads + subrequests returning 404 immediately |
| --- config |
| location /t { |
| content_by_lua ' |
| local capture = ngx.location.capture |
| local insert = table.insert |
| |
| local function f(i) |
| local res = capture("/proxy/" .. i) |
| ngx.say("status: ", res.status) |
| end |
| |
| local threads = {} |
| for i = 1, 2 do |
| local co = ngx.thread.spawn(f, i) |
| insert(threads, co) |
| end |
| |
| ngx.say("ok") |
| '; |
| } |
| |
| location ~ ^/proxy/(\d+) { |
| return 404; |
| } |
| --- request |
| GET /t |
| --- stap2 eval: $::StapScript |
| --- stap eval |
| "$::GCScript" |
| . |
| ' |
| F(ngx_http_finalize_request) { |
| printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); |
| #if ($rc == -1) { |
| #print_ubacktrace() |
| #} |
| } |
| |
| M(http-subrequest-done) { |
| printf("subrequest %s done\n", ngx_http_req_uri($r)) |
| } |
| |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, |
| $r->headers_out->status, $r == $r->main) |
| #print_ubacktrace() |
| } |
| ' |
| --- stap_out_like chop |
| ^create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 1: ok |
| delete thread 1 |
| finalize request /t: rc:-4 c:4 a:1 |
| finalize request /proxy/1: rc:404 c:3 a:0 |
| post subreq: /proxy/1 rc=404, status=0 a=0 |
| subrequest /proxy/1 done |
| terminate 2: ok |
| delete thread 2 |
| finalize request /proxy/2: rc:404 c:2 a:0 |
| post subreq: /proxy/2 rc=404, status=0 a=0 |
| subrequest /proxy/2 done |
| terminate 3: ok |
| delete thread 3 |
| finalize request /t: rc:0 c:1 a:1 |
| (?:finalize request /t: rc:0 c:1 a:1)?$ |
| |
| --- response_body |
| ok |
| status: 404 |
| status: 404 |
| --- no_error_log |
| [error] |
| --- timeout: 3 |
| |
| |
| |
| === TEST 26: multiple user threads + subrequests returning 404 remotely (no wait) |
| --- config |
| location /t { |
| content_by_lua ' |
| local capture = ngx.location.capture |
| local insert = table.insert |
| |
| local function f(i) |
| local res = capture("/proxy/" .. i) |
| ngx.say("status: ", res.status) |
| end |
| |
| local threads = {} |
| for i = 1, 5 do |
| local co = ngx.thread.spawn(f, i) |
| insert(threads, co) |
| end |
| |
| ngx.say("ok") |
| '; |
| } |
| |
| location ~ ^/proxy/(\d+) { |
| proxy_pass http://127.0.0.1:$server_port/d/$1; |
| } |
| |
| location /d { |
| return 404; |
| #echo $uri; |
| } |
| --- request |
| GET /t |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out_like chop |
| ^create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| create 4 in 1 |
| spawn user thread 4 in 1 |
| create 5 in 1 |
| spawn user thread 5 in 1 |
| create 6 in 1 |
| spawn user thread 6 in 1 |
| terminate 1: ok |
| delete thread 1 |
| (?:terminate 2: ok |
| delete thread 2 |
| terminate 3: ok |
| delete thread 3 |
| terminate 4: ok |
| delete thread 4 |
| terminate 5: ok |
| delete thread 5 |
| terminate 6: ok |
| delete thread 6 |
| |terminate 6: ok |
| delete thread 6 |
| terminate 5: ok |
| delete thread 5 |
| terminate 4: ok |
| delete thread 4 |
| terminate 3: ok |
| delete thread 3 |
| terminate 2: ok |
| delete thread 2)$ |
| |
| --- response_body |
| ok |
| status: 404 |
| status: 404 |
| status: 404 |
| status: 404 |
| status: 404 |
| --- no_error_log |
| [error] |
| --- timeout: 6 |
| |
| |
| |
| === TEST 27: multiple user threads + subrequests returning 201 immediately |
| --- config |
| location /t { |
| content_by_lua ' |
| local capture = ngx.location.capture |
| local insert = table.insert |
| |
| local function f(i) |
| local res = capture("/proxy/" .. i) |
| ngx.say("status: ", res.status) |
| end |
| |
| local threads = {} |
| for i = 1, 2 do |
| local co = ngx.thread.spawn(f, i) |
| insert(threads, co) |
| end |
| |
| ngx.say("ok") |
| '; |
| } |
| |
| location ~ ^/proxy/(\d+) { |
| content_by_lua 'ngx.exit(201)'; |
| } |
| --- request |
| GET /t |
| --- stap2 eval: $::StapScript |
| --- stap eval |
| "$::GCScript" |
| . |
| ' |
| F(ngx_http_finalize_request) { |
| printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); |
| #if ($rc == -1) { |
| #print_ubacktrace() |
| #} |
| } |
| |
| M(http-subrequest-done) { |
| printf("subrequest %s done\n", ngx_http_req_uri($r)) |
| } |
| |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, |
| $r->headers_out->status, $r == $r->main) |
| #print_ubacktrace() |
| } |
| ' |
| |
| --- stap_out_like chop |
| ^create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 1: ok |
| delete thread 1 |
| finalize request /t: rc:-4 c:4 a:1 |
| terminate 4: ok |
| delete thread 4 |
| finalize request /proxy/1: rc:0 c:3 a:0 |
| post subreq: /proxy/1 rc=0, status=201 a=0 |
| subrequest /proxy/1 done |
| terminate 2: ok |
| delete thread 2 |
| terminate 5: ok |
| delete thread 5 |
| finalize request /proxy/2: rc:0 c:2 a:0 |
| post subreq: /proxy/2 rc=0, status=201 a=0 |
| subrequest /proxy/2 done |
| terminate 3: ok |
| delete thread 3 |
| finalize request /t: rc:0 c:1 a:1 |
| (?:finalize request /t: rc:0 c:1 a:1)?$ |
| |
| --- response_body |
| ok |
| status: 201 |
| status: 201 |
| --- no_error_log |
| [error] |
| --- timeout: 3 |
| |
| |
| |
| === TEST 28: multiple user threads + subrequests returning 204 immediately |
| --- config |
| location /t { |
| content_by_lua ' |
| local capture = ngx.location.capture |
| local insert = table.insert |
| |
| local function f(i) |
| local res = capture("/proxy/" .. i) |
| ngx.say("status: ", res.status) |
| end |
| |
| local threads = {} |
| for i = 1, 2 do |
| local co = ngx.thread.spawn(f, i) |
| insert(threads, co) |
| end |
| |
| ngx.say("ok") |
| '; |
| } |
| |
| location ~ ^/proxy/(\d+) { |
| content_by_lua 'ngx.exit(204)'; |
| } |
| --- request |
| GET /t |
| --- stap2 eval: $::StapScript |
| --- stap eval |
| "$::GCScript" |
| . |
| ' |
| F(ngx_http_finalize_request) { |
| printf("finalize request %s: rc:%d c:%d a:%d\n", ngx_http_req_uri($r), $rc, $r->main->count, $r == $r->main); |
| #if ($rc == -1) { |
| #print_ubacktrace() |
| #} |
| } |
| |
| M(http-subrequest-done) { |
| printf("subrequest %s done\n", ngx_http_req_uri($r)) |
| } |
| |
| F(ngx_http_lua_post_subrequest) { |
| printf("post subreq: %s rc=%d, status=%d a=%d\n", ngx_http_req_uri($r), $rc, |
| $r->headers_out->status, $r == $r->main) |
| #print_ubacktrace() |
| } |
| ' |
| --- stap_out_like chop |
| ^create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| terminate 1: ok |
| delete thread 1 |
| finalize request /t: rc:-4 c:4 a:1 |
| terminate 4: ok |
| delete thread 4 |
| finalize request /proxy/1: rc:204 c:3 a:0 |
| post subreq: /proxy/1 rc=204, status=204 a=0 |
| subrequest /proxy/1 done |
| terminate 2: ok |
| delete thread 2 |
| terminate 5: ok |
| delete thread 5 |
| finalize request /proxy/2: rc:204 c:2 a:0 |
| post subreq: /proxy/2 rc=204, status=204 a=0 |
| subrequest /proxy/2 done |
| terminate 3: ok |
| delete thread 3 |
| finalize request /t: rc:0 c:1 a:1 |
| (?:finalize request /t: rc:0 c:1 a:1)?$ |
| |
| --- response_body |
| ok |
| status: 204 |
| status: 204 |
| --- no_error_log |
| [error] |
| --- timeout: 3 |
| |
| |
| |
| === TEST 29: multiple user threads + subrequests returning 404 remotely (wait) |
| --- config |
| location /t { |
| content_by_lua ' |
| local n = 5 |
| local capture = ngx.location.capture |
| local insert = table.insert |
| |
| local function f(i) |
| local res = capture("/proxy/" .. i) |
| return res.status |
| end |
| |
| local threads = {} |
| for i = 1, n do |
| local co = ngx.thread.spawn(f, i) |
| insert(threads, co) |
| end |
| |
| for i = 1, n do |
| local ok, res = ngx.thread.wait(threads[i]) |
| ngx.say(i, ": ", res) |
| end |
| |
| ngx.say("ok") |
| '; |
| } |
| |
| location ~ ^/proxy/(\d+) { |
| proxy_pass http://127.0.0.1:$server_port/d/$1; |
| } |
| |
| location /d { |
| return 404; |
| #echo $uri; |
| } |
| --- request |
| GET /t |
| --- stap2 eval: $::StapScript |
| --- stap3 eval: $::GCScript |
| --- stap_out3 |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| create 4 in 1 |
| spawn user thread 4 in 1 |
| create 5 in 1 |
| spawn user thread 5 in 1 |
| create 6 in 1 |
| spawn user thread 6 in 1 |
| terminate 2: ok |
| delete thread 2 |
| terminate 3: ok |
| delete thread 3 |
| terminate 4: ok |
| delete thread 4 |
| terminate 5: ok |
| delete thread 5 |
| terminate 6: ok |
| delete thread 6 |
| terminate 1: ok |
| delete thread 1 |
| |
| --- response_body |
| 1: 404 |
| 2: 404 |
| 3: 404 |
| 4: 404 |
| 5: 404 |
| ok |
| --- no_error_log |
| [error] |
| --- timeout: 6 |
| |
| |
| |
| === TEST 30: multiple user threads + subrequests remotely (wait) |
| --- config |
| location /t { |
| content_by_lua ' |
| local n = 20 |
| local capture = ngx.location.capture |
| local insert = table.insert |
| |
| local function f(i) |
| local res = capture("/proxy/" .. i) |
| return res.status |
| end |
| |
| local threads = {} |
| for i = 1, n do |
| local co = ngx.thread.spawn(f, i) |
| insert(threads, co) |
| end |
| |
| for i = 1, n do |
| local ok, res = ngx.thread.wait(threads[i]) |
| ngx.say(i, ": ", res) |
| end |
| |
| ngx.say("ok") |
| '; |
| } |
| |
| location ~ ^/proxy/(\d+) { |
| proxy_pass http://127.0.0.1:$server_port/d/$1; |
| } |
| |
| location /d { |
| echo_sleep 0.001; |
| echo $uri; |
| } |
| --- request |
| GET /t |
| --- stap2 eval: $::StapScript |
| --- stap3 eval: $::GCScript |
| --- stap_out3 |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| create 3 in 1 |
| spawn user thread 3 in 1 |
| create 4 in 1 |
| spawn user thread 4 in 1 |
| create 5 in 1 |
| spawn user thread 5 in 1 |
| create 6 in 1 |
| spawn user thread 6 in 1 |
| terminate 2: ok |
| delete thread 2 |
| terminate 3: ok |
| delete thread 3 |
| terminate 4: ok |
| delete thread 4 |
| terminate 5: ok |
| delete thread 5 |
| terminate 6: ok |
| delete thread 6 |
| terminate 1: ok |
| delete thread 1 |
| |
| --- response_body |
| 1: 200 |
| 2: 200 |
| 3: 200 |
| 4: 200 |
| 5: 200 |
| 6: 200 |
| 7: 200 |
| 8: 200 |
| 9: 200 |
| 10: 200 |
| 11: 200 |
| 12: 200 |
| 13: 200 |
| 14: 200 |
| 15: 200 |
| 16: 200 |
| 17: 200 |
| 18: 200 |
| 19: 200 |
| 20: 200 |
| ok |
| --- no_error_log |
| [error] |
| [alert] |
| --- timeout: 10 |
| |
| |
| |
| === TEST 31: simple user thread without I/O |
| --- config |
| location /lua { |
| content_by_lua ' |
| function f() |
| ngx.sleep(0.1) |
| ngx.say("f") |
| end |
| |
| ngx.thread.spawn(f) |
| collectgarbage() |
| '; |
| } |
| --- request |
| GET /lua |
| --- stap2 eval: $::StapScript |
| --- stap eval: $::GCScript |
| --- stap_out |
| create 2 in 1 |
| spawn user thread 2 in 1 |
| terminate 1: ok |
| delete thread 1 |
| terminate 2: ok |
| delete thread 2 |
| |
| --- response_body |
| f |
| --- no_error_log |
| [error] |
| |