unicorn-maintained 6.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.CHANGELOG.old +25 -0
- data/.document +28 -0
- data/.gitattributes +5 -0
- data/.gitignore +25 -0
- data/.mailmap +26 -0
- data/.manifest +149 -0
- data/.olddoc.yml +25 -0
- data/Application_Timeouts +77 -0
- data/CONTRIBUTORS +39 -0
- data/COPYING +674 -0
- data/DESIGN +99 -0
- data/Documentation/.gitignore +3 -0
- data/Documentation/unicorn.1 +222 -0
- data/Documentation/unicorn_rails.1 +207 -0
- data/FAQ +70 -0
- data/GIT-VERSION-FILE +1 -0
- data/GIT-VERSION-GEN +39 -0
- data/GNUmakefile +317 -0
- data/HACKING +112 -0
- data/ISSUES +102 -0
- data/KNOWN_ISSUES +79 -0
- data/LATEST +1 -0
- data/LICENSE +67 -0
- data/Links +58 -0
- data/NEWS +1 -0
- data/PHILOSOPHY +139 -0
- data/README +156 -0
- data/Rakefile +16 -0
- data/SIGNALS +123 -0
- data/Sandbox +104 -0
- data/TODO +3 -0
- data/TUNING +119 -0
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/bin/unicorn +128 -0
- data/bin/unicorn_rails +209 -0
- data/examples/big_app_gc.rb +2 -0
- data/examples/echo.ru +26 -0
- data/examples/init.sh +102 -0
- data/examples/logger_mp_safe.rb +25 -0
- data/examples/logrotate.conf +44 -0
- data/examples/nginx.conf +156 -0
- data/examples/unicorn.conf.minimal.rb +13 -0
- data/examples/unicorn.conf.rb +110 -0
- data/examples/unicorn.socket +11 -0
- data/examples/unicorn@.service +40 -0
- data/ext/unicorn_http/CFLAGS +13 -0
- data/ext/unicorn_http/c_util.h +116 -0
- data/ext/unicorn_http/common_field_optimization.h +128 -0
- data/ext/unicorn_http/epollexclusive.h +128 -0
- data/ext/unicorn_http/ext_help.h +38 -0
- data/ext/unicorn_http/extconf.rb +39 -0
- data/ext/unicorn_http/global_variables.h +97 -0
- data/ext/unicorn_http/httpdate.c +91 -0
- data/ext/unicorn_http/unicorn_http.c +4334 -0
- data/ext/unicorn_http/unicorn_http.rl +1040 -0
- data/ext/unicorn_http/unicorn_http_common.rl +76 -0
- data/lib/unicorn/app/old_rails/static.rb +59 -0
- data/lib/unicorn/app/old_rails.rb +35 -0
- data/lib/unicorn/cgi_wrapper.rb +147 -0
- data/lib/unicorn/configurator.rb +748 -0
- data/lib/unicorn/const.rb +21 -0
- data/lib/unicorn/http_request.rb +201 -0
- data/lib/unicorn/http_response.rb +93 -0
- data/lib/unicorn/http_server.rb +859 -0
- data/lib/unicorn/launcher.rb +62 -0
- data/lib/unicorn/oob_gc.rb +81 -0
- data/lib/unicorn/preread_input.rb +33 -0
- data/lib/unicorn/select_waiter.rb +6 -0
- data/lib/unicorn/socket_helper.rb +185 -0
- data/lib/unicorn/stream_input.rb +151 -0
- data/lib/unicorn/tee_input.rb +131 -0
- data/lib/unicorn/tmpio.rb +33 -0
- data/lib/unicorn/util.rb +90 -0
- data/lib/unicorn/version.rb +1 -0
- data/lib/unicorn/worker.rb +165 -0
- data/lib/unicorn.rb +136 -0
- data/man/man1/unicorn.1 +222 -0
- data/man/man1/unicorn_rails.1 +207 -0
- data/setup.rb +1586 -0
- data/t/.gitignore +4 -0
- data/t/GNUmakefile +5 -0
- data/t/README +49 -0
- data/t/active-unix-socket.t +117 -0
- data/t/bin/unused_listen +40 -0
- data/t/broken-app.ru +12 -0
- data/t/client_body_buffer_size.ru +14 -0
- data/t/client_body_buffer_size.t +80 -0
- data/t/detach.ru +11 -0
- data/t/env.ru +3 -0
- data/t/fails-rack-lint.ru +5 -0
- data/t/heartbeat-timeout.ru +12 -0
- data/t/heartbeat-timeout.t +62 -0
- data/t/integration.ru +115 -0
- data/t/integration.t +356 -0
- data/t/lib.perl +258 -0
- data/t/listener_names.ru +4 -0
- data/t/my-tap-lib.sh +201 -0
- data/t/oob_gc.ru +17 -0
- data/t/oob_gc_path.ru +17 -0
- data/t/pid.ru +3 -0
- data/t/preread_input.ru +22 -0
- data/t/reload-bad-config.t +54 -0
- data/t/reopen-logs.ru +13 -0
- data/t/reopen-logs.t +39 -0
- data/t/t0008-back_out_of_upgrade.sh +110 -0
- data/t/t0009-broken-app.sh +56 -0
- data/t/t0010-reap-logging.sh +55 -0
- data/t/t0012-reload-empty-config.sh +86 -0
- data/t/t0013-rewindable-input-false.sh +24 -0
- data/t/t0013.ru +12 -0
- data/t/t0014-rewindable-input-true.sh +24 -0
- data/t/t0014.ru +12 -0
- data/t/t0015-configurator-internals.sh +25 -0
- data/t/t0020-at_exit-handler.sh +49 -0
- data/t/t0021-process_detach.sh +29 -0
- data/t/t0022-listener_names-preload_app.sh +32 -0
- data/t/t0300-no-default-middleware.sh +20 -0
- data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
- data/t/t0301.ru +13 -0
- data/t/t9001-oob_gc.sh +47 -0
- data/t/t9002-oob_gc-path.sh +75 -0
- data/t/test-lib.sh +125 -0
- data/t/winch_ttin.t +67 -0
- data/t/working_directory.t +94 -0
- data/test/aggregate.rb +15 -0
- data/test/benchmark/README +60 -0
- data/test/benchmark/dd.ru +18 -0
- data/test/benchmark/ddstream.ru +50 -0
- data/test/benchmark/readinput.ru +40 -0
- data/test/benchmark/stack.ru +8 -0
- data/test/benchmark/uconnect.perl +66 -0
- data/test/exec/README +5 -0
- data/test/exec/test_exec.rb +1029 -0
- data/test/test_helper.rb +306 -0
- data/test/unit/test_ccc.rb +91 -0
- data/test/unit/test_configurator.rb +175 -0
- data/test/unit/test_droplet.rb +28 -0
- data/test/unit/test_http_parser.rb +884 -0
- data/test/unit/test_http_parser_ng.rb +714 -0
- data/test/unit/test_request.rb +169 -0
- data/test/unit/test_server.rb +244 -0
- data/test/unit/test_signals.rb +188 -0
- data/test/unit/test_socket_helper.rb +159 -0
- data/test/unit/test_stream_input.rb +210 -0
- data/test/unit/test_tee_input.rb +303 -0
- data/test/unit/test_util.rb +131 -0
- data/test/unit/test_waiter.rb +34 -0
- data/unicorn.gemspec +48 -0
- metadata +275 -0
data/t/t0013.ru
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 4 "rewindable_input toggled to true"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
echo rewindable_input true >> $unicorn_config
|
8
|
+
unicorn -D -c $unicorn_config t0014.ru
|
9
|
+
unicorn_wait_start
|
10
|
+
}
|
11
|
+
|
12
|
+
t_begin "ensure worker is started" && {
|
13
|
+
test xOK = x$(curl -T t0014.ru -sSf http://$listen/)
|
14
|
+
}
|
15
|
+
|
16
|
+
t_begin "killing succeeds" && {
|
17
|
+
kill $unicorn_pid
|
18
|
+
}
|
19
|
+
|
20
|
+
t_begin "check stderr" && {
|
21
|
+
check_stderr
|
22
|
+
}
|
23
|
+
|
24
|
+
t_done
|
data/t/t0014.ru
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 4 "configurator internals tests (from FAQ)"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
cat >> $unicorn_config <<EOF
|
8
|
+
HttpRequest::DEFAULTS["rack.url_scheme"] = "https"
|
9
|
+
Configurator::DEFAULTS[:logger].formatter = Logger::Formatter.new
|
10
|
+
EOF
|
11
|
+
unicorn -D -c $unicorn_config env.ru
|
12
|
+
unicorn_wait_start
|
13
|
+
}
|
14
|
+
|
15
|
+
t_begin "single request" && {
|
16
|
+
curl -sSfv http://$listen/ | grep '"rack.url_scheme"=>"https"'
|
17
|
+
}
|
18
|
+
|
19
|
+
t_begin "killing succeeds" && {
|
20
|
+
kill $unicorn_pid
|
21
|
+
}
|
22
|
+
|
23
|
+
t_begin "no errors" && check_stderr
|
24
|
+
|
25
|
+
t_done
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
|
4
|
+
t_plan 5 "at_exit/END handlers work as expected"
|
5
|
+
|
6
|
+
t_begin "setup and startup" && {
|
7
|
+
unicorn_setup
|
8
|
+
cat >> $unicorn_config <<EOF
|
9
|
+
at_exit { \$stdout.syswrite("#{Process.pid} BOTH\\n") }
|
10
|
+
END { \$stdout.syswrite("#{Process.pid} END BOTH\\n") }
|
11
|
+
after_fork do |_,_|
|
12
|
+
at_exit { \$stdout.syswrite("#{Process.pid} WORKER ONLY\\n") }
|
13
|
+
END { \$stdout.syswrite("#{Process.pid} END WORKER ONLY\\n") }
|
14
|
+
end
|
15
|
+
EOF
|
16
|
+
|
17
|
+
unicorn -D pid.ru -c $unicorn_config
|
18
|
+
unicorn_wait_start
|
19
|
+
}
|
20
|
+
|
21
|
+
t_begin "read worker PID" && {
|
22
|
+
worker_pid=$(curl -sSf http://$listen/)
|
23
|
+
t_info "worker_pid=$worker_pid"
|
24
|
+
}
|
25
|
+
|
26
|
+
t_begin "issue graceful shutdown (SIGQUIT) and wait for termination" && {
|
27
|
+
kill -QUIT $unicorn_pid
|
28
|
+
|
29
|
+
while kill -0 $unicorn_pid >/dev/null 2>&1
|
30
|
+
do
|
31
|
+
sleep 1
|
32
|
+
done
|
33
|
+
}
|
34
|
+
|
35
|
+
t_begin "check stderr" && check_stderr
|
36
|
+
|
37
|
+
dbgcat r_err
|
38
|
+
dbgcat r_out
|
39
|
+
|
40
|
+
t_begin "all at_exit handlers ran" && {
|
41
|
+
grep "$worker_pid BOTH" $r_out
|
42
|
+
grep "$unicorn_pid BOTH" $r_out
|
43
|
+
grep "$worker_pid END BOTH" $r_out
|
44
|
+
grep "$unicorn_pid END BOTH" $r_out
|
45
|
+
grep "$worker_pid WORKER ONLY" $r_out
|
46
|
+
grep "$worker_pid END WORKER ONLY" $r_out
|
47
|
+
}
|
48
|
+
|
49
|
+
t_done
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
|
4
|
+
t_plan 5 "Process.detach on forked background process works"
|
5
|
+
|
6
|
+
t_begin "setup and startup" && {
|
7
|
+
t_fifos process_detach
|
8
|
+
unicorn_setup
|
9
|
+
TEST_FIFO=$process_detach \
|
10
|
+
unicorn -E none -D detach.ru -c $unicorn_config
|
11
|
+
unicorn_wait_start
|
12
|
+
}
|
13
|
+
|
14
|
+
t_begin "read detached PID with HTTP/1.0" && {
|
15
|
+
detached_pid=$(curl -0 -sSf http://$listen/)
|
16
|
+
t_info "detached_pid=$detached_pid"
|
17
|
+
}
|
18
|
+
|
19
|
+
t_begin "read background FIFO" && {
|
20
|
+
test xHIHI = x"$(cat $process_detach)"
|
21
|
+
}
|
22
|
+
|
23
|
+
t_begin "killing succeeds" && {
|
24
|
+
kill $unicorn_pid
|
25
|
+
}
|
26
|
+
|
27
|
+
t_begin "check stderr" && check_stderr
|
28
|
+
|
29
|
+
t_done
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
|
4
|
+
# Raindrops::Middleware depends on Unicorn.listener_names,
|
5
|
+
# ensure we don't break Raindrops::Middleware when preload_app is true
|
6
|
+
|
7
|
+
t_plan 4 "Unicorn.listener_names available with preload_app=true"
|
8
|
+
|
9
|
+
t_begin "setup and startup" && {
|
10
|
+
unicorn_setup
|
11
|
+
echo preload_app true >> $unicorn_config
|
12
|
+
unicorn -E none -D listener_names.ru -c $unicorn_config
|
13
|
+
unicorn_wait_start
|
14
|
+
}
|
15
|
+
|
16
|
+
t_begin "read listener names includes listener" && {
|
17
|
+
resp=$(curl -sSf http://$listen/)
|
18
|
+
ok=false
|
19
|
+
t_info "resp=$resp"
|
20
|
+
case $resp in
|
21
|
+
*\"$listen\"*) ok=true ;;
|
22
|
+
esac
|
23
|
+
$ok
|
24
|
+
}
|
25
|
+
|
26
|
+
t_begin "killing succeeds" && {
|
27
|
+
kill $unicorn_pid
|
28
|
+
}
|
29
|
+
|
30
|
+
t_begin "check stderr" && check_stderr
|
31
|
+
|
32
|
+
t_done
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 3 "test the -N / --no-default-middleware option"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
unicorn -N -D -c $unicorn_config fails-rack-lint.ru
|
8
|
+
unicorn_wait_start
|
9
|
+
}
|
10
|
+
|
11
|
+
t_begin "check exit status with Rack::Lint not present" && {
|
12
|
+
test 500 -ne "$(curl -sf -o/dev/null -w'%{http_code}' http://$listen/)"
|
13
|
+
}
|
14
|
+
|
15
|
+
t_begin "killing succeeds" && {
|
16
|
+
kill $unicorn_pid
|
17
|
+
check_stderr
|
18
|
+
}
|
19
|
+
|
20
|
+
t_done
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 3 "-N / --no-default-middleware option not supported in config.ru"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
RACK_ENV=development unicorn -D -c $unicorn_config t0301.ru
|
8
|
+
unicorn_wait_start
|
9
|
+
}
|
10
|
+
|
11
|
+
t_begin "check switches parsed as expected and -N ignored for Rack::Lint" && {
|
12
|
+
debug=false
|
13
|
+
lint=
|
14
|
+
eval "$(curl -sf http://$listen/vars)"
|
15
|
+
test x"$debug" = xtrue
|
16
|
+
test x"$lint" != x
|
17
|
+
test -f "$lint"
|
18
|
+
}
|
19
|
+
|
20
|
+
t_begin "killing succeeds" && {
|
21
|
+
kill $unicorn_pid
|
22
|
+
check_stderr
|
23
|
+
}
|
24
|
+
|
25
|
+
t_done
|
data/t/t0301.ru
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#\-N --debug
|
2
|
+
run(lambda do |env|
|
3
|
+
case env['PATH_INFO']
|
4
|
+
when '/vars'
|
5
|
+
b = "debug=#{$DEBUG.inspect}\n" \
|
6
|
+
"lint=#{caller.grep(%r{rack/lint\.rb})[0].split(':')[0]}\n"
|
7
|
+
end
|
8
|
+
h = {
|
9
|
+
'content-length' => b.size.to_s,
|
10
|
+
'content-type' => 'text/plain',
|
11
|
+
}
|
12
|
+
[ 200, h, [ b ] ]
|
13
|
+
end)
|
data/t/t9001-oob_gc.sh
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 9 "OobGC test"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
unicorn -D -c $unicorn_config oob_gc.ru
|
8
|
+
unicorn_wait_start
|
9
|
+
}
|
10
|
+
|
11
|
+
t_begin "test default interval (4 requests)" && {
|
12
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
13
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
14
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
15
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
16
|
+
}
|
17
|
+
|
18
|
+
t_begin "GC starting-request returns immediately" && {
|
19
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
20
|
+
}
|
21
|
+
|
22
|
+
t_begin "GC is started after 5 requests" && {
|
23
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
24
|
+
}
|
25
|
+
|
26
|
+
t_begin "reset GC" && {
|
27
|
+
test xfalse = x$(curl -vsSf -X POST http://$listen/gc_reset 2>> $tmp)
|
28
|
+
}
|
29
|
+
|
30
|
+
t_begin "test default interval again (3 requests)" && {
|
31
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
32
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
33
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
34
|
+
}
|
35
|
+
|
36
|
+
t_begin "GC is started after 5 requests" && {
|
37
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
38
|
+
}
|
39
|
+
|
40
|
+
t_begin "killing succeeds" && {
|
41
|
+
kill -QUIT $unicorn_pid
|
42
|
+
}
|
43
|
+
|
44
|
+
t_begin "check_stderr" && check_stderr
|
45
|
+
dbgcat r_err
|
46
|
+
|
47
|
+
t_done
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 12 "OobGC test with limited path"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
unicorn -D -c $unicorn_config oob_gc_path.ru
|
8
|
+
unicorn_wait_start
|
9
|
+
}
|
10
|
+
|
11
|
+
t_begin "test default is noop" && {
|
12
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
13
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
14
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
15
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
16
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
17
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
18
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
19
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
20
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
21
|
+
}
|
22
|
+
|
23
|
+
t_begin "4 bad requests to bump counter" && {
|
24
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
25
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
26
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
27
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
28
|
+
}
|
29
|
+
|
30
|
+
t_begin "GC-starting request returns immediately" && {
|
31
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
32
|
+
}
|
33
|
+
|
34
|
+
t_begin "GC was started after 5 requests" && {
|
35
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
36
|
+
}
|
37
|
+
|
38
|
+
t_begin "reset GC" && {
|
39
|
+
test xfalse = x$(curl -vsSf -X POST http://$listen/gc_reset 2>> $tmp)
|
40
|
+
}
|
41
|
+
|
42
|
+
t_begin "test default is noop" && {
|
43
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
44
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
45
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
46
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
47
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
48
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
49
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
50
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
51
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
52
|
+
}
|
53
|
+
|
54
|
+
t_begin "4 bad requests to bump counter" && {
|
55
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
56
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
57
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
58
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
59
|
+
}
|
60
|
+
|
61
|
+
t_begin "GC-starting request returns immediately" && {
|
62
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
63
|
+
}
|
64
|
+
|
65
|
+
t_begin "GC was started after 5 requests" && {
|
66
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
67
|
+
}
|
68
|
+
|
69
|
+
t_begin "killing succeeds" && {
|
70
|
+
kill -QUIT $unicorn_pid
|
71
|
+
}
|
72
|
+
|
73
|
+
t_begin "check_stderr" && check_stderr
|
74
|
+
|
75
|
+
t_done
|
data/t/test-lib.sh
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# Copyright (c) 2009 Rainbows! hackers
|
3
|
+
# Copyright (c) 2010 Unicorn hackers
|
4
|
+
. ./my-tap-lib.sh
|
5
|
+
|
6
|
+
set +u
|
7
|
+
|
8
|
+
# sometimes we rely on http_proxy to avoid wasting bandwidth with Isolate
|
9
|
+
# and multiple Ruby versions
|
10
|
+
NO_PROXY=${UNICORN_TEST_ADDR-127.0.0.1}
|
11
|
+
export NO_PROXY
|
12
|
+
|
13
|
+
set -e
|
14
|
+
RUBY="${RUBY-ruby}"
|
15
|
+
RUBY_VERSION=${RUBY_VERSION-$($RUBY -e 'puts RUBY_VERSION')}
|
16
|
+
RUBY_ENGINE=${RUBY_ENGINE-$($RUBY -e 'puts((RUBY_ENGINE rescue "ruby"))')}
|
17
|
+
t_pfx=$PWD/trash/$T-$RUBY_ENGINE-$RUBY_VERSION
|
18
|
+
set -u
|
19
|
+
|
20
|
+
PATH=$PWD/bin:$PATH
|
21
|
+
export PATH
|
22
|
+
|
23
|
+
test -x $PWD/bin/unused_listen || die "must be run in 't' directory"
|
24
|
+
|
25
|
+
wait_for_pid () {
|
26
|
+
path="$1"
|
27
|
+
nr=30
|
28
|
+
while ! test -s "$path" && test $nr -gt 0
|
29
|
+
do
|
30
|
+
nr=$(($nr - 1))
|
31
|
+
sleep 1
|
32
|
+
done
|
33
|
+
}
|
34
|
+
|
35
|
+
# "unix_time" is not in POSIX, but in GNU, and FreeBSD 9.0 (possibly earlier)
|
36
|
+
unix_time () {
|
37
|
+
$RUBY -e 'puts Time.now.to_i'
|
38
|
+
}
|
39
|
+
|
40
|
+
# "wc -l" outputs leading whitespace on *BSDs, filter it out for portability
|
41
|
+
count_lines () {
|
42
|
+
wc -l | tr -d '[:space:]'
|
43
|
+
}
|
44
|
+
|
45
|
+
# "wc -c" outputs leading whitespace on *BSDs, filter it out for portability
|
46
|
+
count_bytes () {
|
47
|
+
wc -c | tr -d '[:space:]'
|
48
|
+
}
|
49
|
+
|
50
|
+
# given a list of variable names, create temporary files and assign
|
51
|
+
# the pathnames to those variables
|
52
|
+
rtmpfiles () {
|
53
|
+
for id in "$@"
|
54
|
+
do
|
55
|
+
name=$id
|
56
|
+
|
57
|
+
case $name in
|
58
|
+
*fifo)
|
59
|
+
_tmp=$t_pfx.$id
|
60
|
+
eval "$id=$_tmp"
|
61
|
+
rm -f $_tmp
|
62
|
+
mkfifo $_tmp
|
63
|
+
T_RM_LIST="$T_RM_LIST $_tmp"
|
64
|
+
;;
|
65
|
+
*socket)
|
66
|
+
_tmp="$(mktemp -t $id.$$.XXXXXXXX)"
|
67
|
+
if test $(printf "$_tmp" |count_bytes) -gt 108
|
68
|
+
then
|
69
|
+
echo >&2 "$_tmp too long, tests may fail"
|
70
|
+
echo >&2 "Try to set TMPDIR to a shorter path"
|
71
|
+
fi
|
72
|
+
eval "$id=$_tmp"
|
73
|
+
rm -f $_tmp
|
74
|
+
T_RM_LIST="$T_RM_LIST $_tmp"
|
75
|
+
;;
|
76
|
+
*)
|
77
|
+
_tmp=$t_pfx.$id
|
78
|
+
eval "$id=$_tmp"
|
79
|
+
> $_tmp
|
80
|
+
T_OK_RM_LIST="$T_OK_RM_LIST $_tmp"
|
81
|
+
;;
|
82
|
+
esac
|
83
|
+
done
|
84
|
+
}
|
85
|
+
|
86
|
+
dbgcat () {
|
87
|
+
id=$1
|
88
|
+
eval '_file=$'$id
|
89
|
+
echo "==> $id <=="
|
90
|
+
sed -e "s/^/$id:/" < $_file
|
91
|
+
}
|
92
|
+
|
93
|
+
check_stderr () {
|
94
|
+
set +u
|
95
|
+
_r_err=${1-${r_err}}
|
96
|
+
set -u
|
97
|
+
if grep -v $T $_r_err | grep -i Error | \
|
98
|
+
grep -v NameError.*Unicorn::Waiter
|
99
|
+
then
|
100
|
+
die "Errors found in $_r_err"
|
101
|
+
elif grep SIGKILL $_r_err
|
102
|
+
then
|
103
|
+
die "SIGKILL found in $_r_err"
|
104
|
+
fi
|
105
|
+
}
|
106
|
+
|
107
|
+
# unicorn_setup
|
108
|
+
unicorn_setup () {
|
109
|
+
eval $(unused_listen)
|
110
|
+
port=$(expr $listen : '[^:]*:\([0-9]*\)')
|
111
|
+
host=$(expr $listen : '\([^:][^:]*\):[0-9][0-9]*')
|
112
|
+
|
113
|
+
rtmpfiles unicorn_config pid r_err r_out fifo tmp ok
|
114
|
+
cat > $unicorn_config <<EOF
|
115
|
+
listen "$listen"
|
116
|
+
pid "$pid"
|
117
|
+
stderr_path "$r_err"
|
118
|
+
stdout_path "$r_out"
|
119
|
+
EOF
|
120
|
+
}
|
121
|
+
|
122
|
+
unicorn_wait_start () {
|
123
|
+
# no need to play tricks with FIFOs since we got "ready_pipe" now
|
124
|
+
unicorn_pid=$(cat $pid)
|
125
|
+
}
|
data/t/winch_ttin.t
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#!perl -w
|
2
|
+
# Copyright (C) unicorn hackers <unicorn-public@yhbt.net>
|
3
|
+
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
|
+
use v5.14; BEGIN { require './t/lib.perl' };
|
5
|
+
use autodie;
|
6
|
+
use POSIX qw(mkfifo);
|
7
|
+
my $u_conf = "$tmpdir/u.conf.rb";
|
8
|
+
my $u_sock = "$tmpdir/u.sock";
|
9
|
+
my $fifo = "$tmpdir/fifo";
|
10
|
+
mkfifo($fifo, 0666) or die "mkfifo($fifo): $!";
|
11
|
+
|
12
|
+
open my $fh, '>', $u_conf;
|
13
|
+
print $fh <<EOM;
|
14
|
+
pid "$tmpdir/pid"
|
15
|
+
listen "$u_sock"
|
16
|
+
stderr_path "$err_log"
|
17
|
+
after_fork do |server, worker|
|
18
|
+
# test script will block while reading from $fifo,
|
19
|
+
File.open("$fifo", "wb") { |fp| fp.syswrite worker.nr.to_s }
|
20
|
+
end
|
21
|
+
EOM
|
22
|
+
close $fh;
|
23
|
+
|
24
|
+
unicorn('-D', '-c', $u_conf, 't/integration.ru')->join;
|
25
|
+
is($?, 0, 'daemonized properly');
|
26
|
+
open $fh, '<', "$tmpdir/pid";
|
27
|
+
chomp(my $pid = <$fh>);
|
28
|
+
ok(kill(0, $pid), 'daemonized PID works');
|
29
|
+
my $quit = sub { kill('QUIT', $pid) if $pid; $pid = undef };
|
30
|
+
END { $quit->() };
|
31
|
+
|
32
|
+
open $fh, '<', $fifo;
|
33
|
+
my $worker_nr = <$fh>;
|
34
|
+
close $fh;
|
35
|
+
is($worker_nr, '0', 'initial worker spawned');
|
36
|
+
|
37
|
+
my ($status, $hdr, $worker_pid) = do_req($u_sock, 'GET /pid HTTP/1.0');
|
38
|
+
like($status, qr/ 200\b/, 'got 200 response');
|
39
|
+
like($worker_pid, qr/\A[0-9]+\n\z/s, 'PID in response');
|
40
|
+
chomp $worker_pid;
|
41
|
+
ok(kill(0, $worker_pid), 'worker_pid is valid');
|
42
|
+
|
43
|
+
ok(kill('WINCH', $pid), 'SIGWINCH can be sent');
|
44
|
+
|
45
|
+
my $tries = 1000;
|
46
|
+
while (CORE::kill(0, $worker_pid) && --$tries) { sleep 0.01 }
|
47
|
+
ok(!CORE::kill(0, $worker_pid), 'worker not running');
|
48
|
+
|
49
|
+
ok(kill('TTIN', $pid), 'SIGTTIN to restart worker');
|
50
|
+
|
51
|
+
open $fh, '<', $fifo;
|
52
|
+
$worker_nr = <$fh>;
|
53
|
+
close $fh;
|
54
|
+
is($worker_nr, '0', 'worker restarted');
|
55
|
+
|
56
|
+
($status, $hdr, my $new_worker_pid) = do_req($u_sock, 'GET /pid HTTP/1.0');
|
57
|
+
like($status, qr/ 200\b/, 'got 200 response');
|
58
|
+
like($new_worker_pid, qr/\A[0-9]+\n\z/, 'got new worker PID');
|
59
|
+
chomp $new_worker_pid;
|
60
|
+
ok(kill(0, $new_worker_pid), 'got a valid worker PID');
|
61
|
+
isnt($worker_pid, $new_worker_pid, 'worker PID changed');
|
62
|
+
|
63
|
+
$quit->();
|
64
|
+
|
65
|
+
check_stderr;
|
66
|
+
undef $tmpdir;
|
67
|
+
done_testing;
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#!perl -w
|
2
|
+
# Copyright (C) unicorn hackers <unicorn-public@yhbt.net>
|
3
|
+
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
4
|
+
use v5.14; BEGIN { require './t/lib.perl' };
|
5
|
+
use autodie;
|
6
|
+
mkdir "$tmpdir/alt";
|
7
|
+
my $ru = "$tmpdir/alt/config.ru";
|
8
|
+
open my $fh, '>', $u_conf;
|
9
|
+
print $fh <<EOM;
|
10
|
+
pid "$pid_file"
|
11
|
+
preload_app true
|
12
|
+
stderr_path "$err_log"
|
13
|
+
working_directory "$tmpdir/alt" # the whole point of this test
|
14
|
+
before_fork { |_,_| \$master_ppid = Process.ppid }
|
15
|
+
EOM
|
16
|
+
close $fh;
|
17
|
+
|
18
|
+
my $common_ru = <<'EOM';
|
19
|
+
use Rack::ContentLength
|
20
|
+
use Rack::ContentType, 'text/plain'
|
21
|
+
run lambda { |env| [ 200, {}, [ "#{$master_ppid}\n" ] ] }
|
22
|
+
EOM
|
23
|
+
|
24
|
+
open $fh, '>', $ru;
|
25
|
+
print $fh <<EOM;
|
26
|
+
#\\--daemonize --listen $u_sock
|
27
|
+
$common_ru
|
28
|
+
EOM
|
29
|
+
close $fh;
|
30
|
+
|
31
|
+
unicorn('-c', $u_conf)->join; # will daemonize
|
32
|
+
chomp($daemon_pid = slurp($pid_file));
|
33
|
+
|
34
|
+
my ($status, $hdr, $bdy) = do_req($u_sock, 'GET / HTTP/1.0');
|
35
|
+
is($bdy, "1\n", 'got expected $master_ppid');
|
36
|
+
|
37
|
+
stop_daemon;
|
38
|
+
check_stderr;
|
39
|
+
|
40
|
+
if ('test without CLI switches in config.ru') {
|
41
|
+
truncate $err_log, 0;
|
42
|
+
open $fh, '>', $ru;
|
43
|
+
print $fh $common_ru;
|
44
|
+
close $fh;
|
45
|
+
|
46
|
+
unicorn('-D', '-l', $u_sock, '-c', $u_conf)->join; # will daemonize
|
47
|
+
chomp($daemon_pid = slurp($pid_file));
|
48
|
+
|
49
|
+
($status, $hdr, $bdy) = do_req($u_sock, 'GET / HTTP/1.0');
|
50
|
+
is($bdy, "1\n", 'got expected $master_ppid');
|
51
|
+
|
52
|
+
stop_daemon;
|
53
|
+
check_stderr;
|
54
|
+
}
|
55
|
+
|
56
|
+
if ('ensures broken working_directory (missing config.ru) is OK') {
|
57
|
+
truncate $err_log, 0;
|
58
|
+
unlink $ru;
|
59
|
+
|
60
|
+
my $auto_reap = unicorn('-c', $u_conf);
|
61
|
+
$auto_reap->join;
|
62
|
+
isnt($?, 0, 'exited with error due to missing config.ru');
|
63
|
+
|
64
|
+
like(slurp($err_log), qr/rackup file \Q(config.ru)\E not readable/,
|
65
|
+
'noted unreadability of config.ru in stderr');
|
66
|
+
}
|
67
|
+
|
68
|
+
if ('fooapp.rb (not config.ru) works with working_directory') {
|
69
|
+
truncate $err_log, 0;
|
70
|
+
my $fooapp = "$tmpdir/alt/fooapp.rb";
|
71
|
+
open $fh, '>', $fooapp;
|
72
|
+
print $fh <<EOM;
|
73
|
+
class Fooapp
|
74
|
+
def self.call(env)
|
75
|
+
b = "dir=#{Dir.pwd}"
|
76
|
+
h = { 'content-type' => 'text/plain', 'content-length' => b.bytesize.to_s }
|
77
|
+
[ 200, h, [ b ] ]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
EOM
|
81
|
+
close $fh;
|
82
|
+
my $srv = tcp_server;
|
83
|
+
my $auto_reap = unicorn(qw(-c), $u_conf, qw(-I. fooapp.rb),
|
84
|
+
{ -C => '/', 3 => $srv });
|
85
|
+
($status, $hdr, $bdy) = do_req($srv, 'GET / HTTP/1.0');
|
86
|
+
is($bdy, "dir=$tmpdir/alt",
|
87
|
+
'fooapp.rb (w/o config.ru) w/ working_directory');
|
88
|
+
$auto_reap->join('TERM');
|
89
|
+
is($?, 0, 'fooapp.rb process exited');
|
90
|
+
check_stderr;
|
91
|
+
}
|
92
|
+
|
93
|
+
undef $tmpdir;
|
94
|
+
done_testing;
|
data/test/aggregate.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/ruby -n
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
|
4
|
+
BEGIN { $tests = $assertions = $failures = $errors = 0 }
|
5
|
+
|
6
|
+
$_ =~ /(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/ or next
|
7
|
+
$tests += $1.to_i
|
8
|
+
$assertions += $2.to_i
|
9
|
+
$failures += $3.to_i
|
10
|
+
$errors += $4.to_i
|
11
|
+
|
12
|
+
END {
|
13
|
+
printf("\n%d tests, %d assertions, %d failures, %d errors\n",
|
14
|
+
$tests, $assertions, $failures, $errors)
|
15
|
+
}
|