unicorn-simon 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/.CHANGELOG.old +25 -0
  3. data/.document +28 -0
  4. data/.gitattributes +5 -0
  5. data/.gitignore +25 -0
  6. data/.mailmap +26 -0
  7. data/.manifest +156 -0
  8. data/.olddoc.yml +18 -0
  9. data/Application_Timeouts +77 -0
  10. data/CONTRIBUTORS +35 -0
  11. data/COPYING +674 -0
  12. data/DESIGN +95 -0
  13. data/Documentation/.gitignore +5 -0
  14. data/Documentation/GNUmakefile +30 -0
  15. data/Documentation/unicorn.1.txt +187 -0
  16. data/Documentation/unicorn_rails.1.txt +175 -0
  17. data/FAQ +70 -0
  18. data/GIT-VERSION-FILE +1 -0
  19. data/GIT-VERSION-GEN +39 -0
  20. data/GNUmakefile +253 -0
  21. data/HACKING +120 -0
  22. data/ISSUES +90 -0
  23. data/KNOWN_ISSUES +79 -0
  24. data/LATEST +30 -0
  25. data/LICENSE +67 -0
  26. data/Links +56 -0
  27. data/NEWS +2465 -0
  28. data/PHILOSOPHY +139 -0
  29. data/README +138 -0
  30. data/Rakefile +16 -0
  31. data/SIGNALS +123 -0
  32. data/Sandbox +104 -0
  33. data/TODO +3 -0
  34. data/TUNING +119 -0
  35. data/archive/.gitignore +3 -0
  36. data/archive/slrnpull.conf +4 -0
  37. data/bin/unicorn +126 -0
  38. data/bin/unicorn_rails +209 -0
  39. data/examples/big_app_gc.rb +2 -0
  40. data/examples/echo.ru +27 -0
  41. data/examples/init.sh +102 -0
  42. data/examples/logger_mp_safe.rb +25 -0
  43. data/examples/logrotate.conf +44 -0
  44. data/examples/nginx.conf +155 -0
  45. data/examples/unicorn.conf.minimal.rb +13 -0
  46. data/examples/unicorn.conf.rb +110 -0
  47. data/examples/unicorn.socket +11 -0
  48. data/examples/unicorn@.service +33 -0
  49. data/ext/unicorn_http/CFLAGS +13 -0
  50. data/ext/unicorn_http/c_util.h +124 -0
  51. data/ext/unicorn_http/common_field_optimization.h +111 -0
  52. data/ext/unicorn_http/ext_help.h +62 -0
  53. data/ext/unicorn_http/extconf.rb +11 -0
  54. data/ext/unicorn_http/global_variables.h +97 -0
  55. data/ext/unicorn_http/httpdate.c +78 -0
  56. data/ext/unicorn_http/unicorn_http.c +4274 -0
  57. data/ext/unicorn_http/unicorn_http.rl +980 -0
  58. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  59. data/lib/unicorn/app/old_rails/static.rb +59 -0
  60. data/lib/unicorn/app/old_rails.rb +35 -0
  61. data/lib/unicorn/cgi_wrapper.rb +147 -0
  62. data/lib/unicorn/configurator.rb +664 -0
  63. data/lib/unicorn/const.rb +21 -0
  64. data/lib/unicorn/http_request.rb +122 -0
  65. data/lib/unicorn/http_response.rb +60 -0
  66. data/lib/unicorn/http_server.rb +824 -0
  67. data/lib/unicorn/launcher.rb +62 -0
  68. data/lib/unicorn/oob_gc.rb +82 -0
  69. data/lib/unicorn/preread_input.rb +33 -0
  70. data/lib/unicorn/socket_helper.rb +195 -0
  71. data/lib/unicorn/stream_input.rb +146 -0
  72. data/lib/unicorn/tee_input.rb +133 -0
  73. data/lib/unicorn/tmpio.rb +27 -0
  74. data/lib/unicorn/util.rb +90 -0
  75. data/lib/unicorn/version.rb +1 -0
  76. data/lib/unicorn/worker.rb +140 -0
  77. data/lib/unicorn.rb +123 -0
  78. data/man/man1/unicorn.1 +221 -0
  79. data/man/man1/unicorn_rails.1 +212 -0
  80. data/setup.rb +1586 -0
  81. data/t/.gitignore +4 -0
  82. data/t/GNUmakefile +74 -0
  83. data/t/README +42 -0
  84. data/t/bin/content-md5-put +36 -0
  85. data/t/bin/sha1sum.rb +17 -0
  86. data/t/bin/unused_listen +40 -0
  87. data/t/broken-app.ru +12 -0
  88. data/t/detach.ru +11 -0
  89. data/t/env.ru +3 -0
  90. data/t/fails-rack-lint.ru +5 -0
  91. data/t/heartbeat-timeout.ru +12 -0
  92. data/t/hijack.ru +43 -0
  93. data/t/listener_names.ru +4 -0
  94. data/t/my-tap-lib.sh +201 -0
  95. data/t/oob_gc.ru +20 -0
  96. data/t/oob_gc_path.ru +20 -0
  97. data/t/pid.ru +3 -0
  98. data/t/preread_input.ru +17 -0
  99. data/t/rack-input-tests.ru +21 -0
  100. data/t/t0000-http-basic.sh +50 -0
  101. data/t/t0001-reload-bad-config.sh +53 -0
  102. data/t/t0002-config-conflict.sh +49 -0
  103. data/t/t0002-parser-error.sh +94 -0
  104. data/t/t0003-working_directory.sh +51 -0
  105. data/t/t0004-heartbeat-timeout.sh +69 -0
  106. data/t/t0004-working_directory_broken.sh +24 -0
  107. data/t/t0005-working_directory_app.rb.sh +40 -0
  108. data/t/t0006-reopen-logs.sh +83 -0
  109. data/t/t0006.ru +13 -0
  110. data/t/t0007-working_directory_no_embed_cli.sh +44 -0
  111. data/t/t0008-back_out_of_upgrade.sh +110 -0
  112. data/t/t0009-broken-app.sh +56 -0
  113. data/t/t0009-winch_ttin.sh +59 -0
  114. data/t/t0010-reap-logging.sh +55 -0
  115. data/t/t0011-active-unix-socket.sh +79 -0
  116. data/t/t0012-reload-empty-config.sh +85 -0
  117. data/t/t0013-rewindable-input-false.sh +24 -0
  118. data/t/t0013.ru +12 -0
  119. data/t/t0014-rewindable-input-true.sh +24 -0
  120. data/t/t0014.ru +12 -0
  121. data/t/t0015-configurator-internals.sh +25 -0
  122. data/t/t0018-write-on-close.sh +23 -0
  123. data/t/t0019-max_header_len.sh +49 -0
  124. data/t/t0020-at_exit-handler.sh +49 -0
  125. data/t/t0021-process_detach.sh +29 -0
  126. data/t/t0022-listener_names-preload_app.sh +32 -0
  127. data/t/t0100-rack-input-tests.sh +124 -0
  128. data/t/t0116-client_body_buffer_size.sh +80 -0
  129. data/t/t0116.ru +16 -0
  130. data/t/t0200-rack-hijack.sh +30 -0
  131. data/t/t0300-no-default-middleware.sh +20 -0
  132. data/t/t9000-preread-input.sh +48 -0
  133. data/t/t9001-oob_gc.sh +47 -0
  134. data/t/t9002-oob_gc-path.sh +75 -0
  135. data/t/test-lib.sh +128 -0
  136. data/t/write-on-close.ru +11 -0
  137. data/test/aggregate.rb +15 -0
  138. data/test/benchmark/README +50 -0
  139. data/test/benchmark/dd.ru +18 -0
  140. data/test/benchmark/stack.ru +8 -0
  141. data/test/exec/README +5 -0
  142. data/test/exec/test_exec.rb +1099 -0
  143. data/test/test_helper.rb +298 -0
  144. data/test/unit/test_configurator.rb +175 -0
  145. data/test/unit/test_droplet.rb +28 -0
  146. data/test/unit/test_http_parser.rb +886 -0
  147. data/test/unit/test_http_parser_ng.rb +633 -0
  148. data/test/unit/test_request.rb +182 -0
  149. data/test/unit/test_response.rb +111 -0
  150. data/test/unit/test_server.rb +268 -0
  151. data/test/unit/test_signals.rb +188 -0
  152. data/test/unit/test_socket_helper.rb +197 -0
  153. data/test/unit/test_stream_input.rb +203 -0
  154. data/test/unit/test_tee_input.rb +304 -0
  155. data/test/unit/test_upload.rb +306 -0
  156. data/test/unit/test_util.rb +105 -0
  157. data/unicorn.gemspec +50 -0
  158. metadata +310 -0
@@ -0,0 +1,53 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 7 "reload config.ru error with preload_app true"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ rtmpfiles ru
8
+
9
+ cat > $ru <<\EOF
10
+ use Rack::ContentLength
11
+ use Rack::ContentType, "text/plain"
12
+ x = { "hello" => "world" }
13
+ run lambda { |env| [ 200, {}, [ x.inspect << "\n" ] ] }
14
+ EOF
15
+ echo 'preload_app true' >> $unicorn_config
16
+ unicorn -D -c $unicorn_config $ru
17
+ unicorn_wait_start
18
+ }
19
+
20
+ t_begin "hit with curl" && {
21
+ out=$(curl -sSf http://$listen/)
22
+ test x"$out" = x'{"hello"=>"world"}'
23
+ }
24
+
25
+ t_begin "introduce syntax error in rackup file" && {
26
+ echo '...' >> $ru
27
+ }
28
+
29
+ t_begin "reload signal succeeds" && {
30
+ kill -HUP $unicorn_pid
31
+ while ! egrep '(done|error) reloading' $r_err >/dev/null
32
+ do
33
+ sleep 1
34
+ done
35
+
36
+ grep 'error reloading' $r_err >/dev/null
37
+ > $r_err
38
+ }
39
+
40
+ t_begin "hit with curl" && {
41
+ out=$(curl -sSf http://$listen/)
42
+ test x"$out" = x'{"hello"=>"world"}'
43
+ }
44
+
45
+ t_begin "killing succeeds" && {
46
+ kill $unicorn_pid
47
+ }
48
+
49
+ t_begin "check stderr" && {
50
+ check_stderr
51
+ }
52
+
53
+ t_done
@@ -0,0 +1,49 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 6 "config variables conflict with preload_app"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ rtmpfiles ru rutmp
8
+
9
+ cat > $ru <<\EOF
10
+ use Rack::ContentLength
11
+ use Rack::ContentType, "text/plain"
12
+ config = ru = { "hello" => "world" }
13
+ run lambda { |env| [ 200, {}, [ ru.inspect << "\n" ] ] }
14
+ EOF
15
+ echo 'preload_app true' >> $unicorn_config
16
+ unicorn -D -c $unicorn_config $ru
17
+ unicorn_wait_start
18
+ }
19
+
20
+ t_begin "hit with curl" && {
21
+ out=$(curl -sSf http://$listen/)
22
+ test x"$out" = x'{"hello"=>"world"}'
23
+ }
24
+
25
+ t_begin "modify rackup file" && {
26
+ sed -e 's/world/WORLD/' < $ru > $rutmp
27
+ mv $rutmp $ru
28
+ }
29
+
30
+ t_begin "reload signal succeeds" && {
31
+ kill -HUP $unicorn_pid
32
+ while ! egrep '(done|error) reloading' < $r_err >/dev/null
33
+ do
34
+ sleep 1
35
+ done
36
+
37
+ grep 'done reloading' $r_err >/dev/null
38
+ }
39
+
40
+ t_begin "hit with curl" && {
41
+ out=$(curl -sSf http://$listen/)
42
+ test x"$out" = x'{"hello"=>"WORLD"}'
43
+ }
44
+
45
+ t_begin "killing succeeds" && {
46
+ kill $unicorn_pid
47
+ }
48
+
49
+ t_done
@@ -0,0 +1,94 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 11 "parser error test"
4
+
5
+ t_begin "setup and startup" && {
6
+ unicorn_setup
7
+ unicorn -D env.ru -c $unicorn_config
8
+ unicorn_wait_start
9
+ }
10
+
11
+ t_begin "send a bad request" && {
12
+ (
13
+ printf 'GET / HTTP/1/1\r\nHost: example.com\r\n\r\n'
14
+ cat $fifo > $tmp &
15
+ wait
16
+ echo ok > $ok
17
+ ) | socat - TCP:$listen > $fifo
18
+ test xok = x$(cat $ok)
19
+ }
20
+
21
+ dbgcat tmp
22
+
23
+ t_begin "response should be a 400" && {
24
+ grep -F 'HTTP/1.1 400 Bad Request' $tmp
25
+ }
26
+
27
+ t_begin "send a huge Request URI (REQUEST_PATH > (12 * 1024))" && {
28
+ rm -f $tmp
29
+ cat $fifo > $tmp &
30
+ (
31
+ set -e
32
+ trap 'echo ok > $ok' EXIT
33
+ printf 'GET /'
34
+ for i in $(awk </dev/null 'BEGIN{for(i=0;i<1024;i++) print i}')
35
+ do
36
+ printf '0123456789ab'
37
+ done
38
+ printf ' HTTP/1.1\r\nHost: example.com\r\n\r\n'
39
+ ) | socat - TCP:$listen > $fifo || :
40
+ test xok = x$(cat $ok)
41
+ wait
42
+ }
43
+
44
+ t_begin "response should be a 414 (REQUEST_PATH)" && {
45
+ grep -F 'HTTP/1.1 414 ' $tmp
46
+ }
47
+
48
+ t_begin "send a huge Request URI (QUERY_STRING > (10 * 1024))" && {
49
+ rm -f $tmp
50
+ cat $fifo > $tmp &
51
+ (
52
+ set -e
53
+ trap 'echo ok > $ok' EXIT
54
+ printf 'GET /hello-world?a'
55
+ for i in $(awk </dev/null 'BEGIN{for(i=0;i<1024;i++) print i}')
56
+ do
57
+ printf '0123456789'
58
+ done
59
+ printf ' HTTP/1.1\r\nHost: example.com\r\n\r\n'
60
+ ) | socat - TCP:$listen > $fifo || :
61
+ test xok = x$(cat $ok)
62
+ wait
63
+ }
64
+
65
+ t_begin "response should be a 414 (QUERY_STRING)" && {
66
+ grep -F 'HTTP/1.1 414 ' $tmp
67
+ }
68
+
69
+ t_begin "send a huge Request URI (FRAGMENT > 1024)" && {
70
+ rm -f $tmp
71
+ cat $fifo > $tmp &
72
+ (
73
+ set -e
74
+ trap 'echo ok > $ok' EXIT
75
+ printf 'GET /hello-world#a'
76
+ for i in $(awk </dev/null 'BEGIN{for(i=0;i<64;i++) print i}')
77
+ do
78
+ printf '0123456789abcdef'
79
+ done
80
+ printf ' HTTP/1.1\r\nHost: example.com\r\n\r\n'
81
+ ) | socat - TCP:$listen > $fifo || :
82
+ test xok = x$(cat $ok)
83
+ wait
84
+ }
85
+
86
+ t_begin "response should be a 414 (FRAGMENT)" && {
87
+ grep -F 'HTTP/1.1 414 ' $tmp
88
+ }
89
+
90
+ t_begin "server stderr should be clean" && check_stderr
91
+
92
+ t_begin "term signal sent" && kill $unicorn_pid
93
+
94
+ t_done
@@ -0,0 +1,51 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 4 "config.ru inside alt working_directory"
5
+
6
+ t_begin "setup and start" && {
7
+ unicorn_setup
8
+ rtmpfiles unicorn_config_tmp
9
+ rm -rf $t_pfx.app
10
+ mkdir $t_pfx.app
11
+
12
+ cat > $t_pfx.app/config.ru <<EOF
13
+ #\--daemonize --host $host --port $port
14
+ use Rack::ContentLength
15
+ use Rack::ContentType, "text/plain"
16
+ run lambda { |env| [ 200, {}, [ "#{\$master_ppid}\\n" ] ] }
17
+ EOF
18
+ # we have --host/--port in config.ru instead
19
+ grep -v ^listen $unicorn_config > $unicorn_config_tmp
20
+
21
+ # the whole point of this exercise
22
+ echo "working_directory '$t_pfx.app'" >> $unicorn_config_tmp
23
+
24
+ # allows ppid to be 1 in before_fork
25
+ echo "preload_app true" >> $unicorn_config_tmp
26
+ cat >> $unicorn_config_tmp <<\EOF
27
+ before_fork do |server,worker|
28
+ $master_ppid = Process.ppid # should be zero to detect daemonization
29
+ end
30
+ EOF
31
+
32
+ mv $unicorn_config_tmp $unicorn_config
33
+
34
+ # rely on --daemonize switch, no & or -D
35
+ unicorn -c $unicorn_config
36
+ unicorn_wait_start
37
+ }
38
+
39
+ t_begin "hit with curl" && {
40
+ body=$(curl -sSf http://$listen/)
41
+ }
42
+
43
+ t_begin "killing succeeds" && {
44
+ kill $unicorn_pid
45
+ }
46
+
47
+ t_begin "response body ppid == 1 (daemonized)" && {
48
+ test "$body" -eq 1
49
+ }
50
+
51
+ t_done
@@ -0,0 +1,69 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 11 "heartbeat/timeout test"
5
+
6
+ t_begin "setup and startup" && {
7
+ unicorn_setup
8
+ echo timeout 3 >> $unicorn_config
9
+ echo preload_app true >> $unicorn_config
10
+ unicorn -D heartbeat-timeout.ru -c $unicorn_config
11
+ unicorn_wait_start
12
+ }
13
+
14
+ t_begin "read worker PID" && {
15
+ worker_pid=$(curl -sSf http://$listen/)
16
+ t_info "worker_pid=$worker_pid"
17
+ }
18
+
19
+ t_begin "sleep for a bit, ensure worker PID does not change" && {
20
+ sleep 4
21
+ test $(curl -sSf http://$listen/) -eq $worker_pid
22
+ }
23
+
24
+ t_begin "block the worker process to force it to die" && {
25
+ rm $ok
26
+ t0=$(unix_time)
27
+ err="$(curl -sSf http://$listen/block-forever 2>&1 || > $ok)"
28
+ t1=$(unix_time)
29
+ elapsed=$(($t1 - $t0))
30
+ t_info "elapsed=$elapsed err=$err"
31
+ test x"$err" != x"Should never get here"
32
+ test x"$err" != x"$worker_pid"
33
+ }
34
+
35
+ t_begin "ensure worker was killed" && {
36
+ test -e $ok
37
+ test 1 -eq $(grep timeout $r_err | grep killing | count_lines)
38
+ }
39
+
40
+ t_begin "ensure timeout took at least 3 seconds" && {
41
+ test $elapsed -ge 3
42
+ }
43
+
44
+ t_begin "we get a fresh new worker process" && {
45
+ new_worker_pid=$(curl -sSf http://$listen/)
46
+ test $new_worker_pid -ne $worker_pid
47
+ }
48
+
49
+ t_begin "truncate the server error log" && {
50
+ > $r_err
51
+ }
52
+
53
+ t_begin "SIGSTOP and SIGCONT on unicorn master does not kill worker" && {
54
+ kill -STOP $unicorn_pid
55
+ sleep 4
56
+ kill -CONT $unicorn_pid
57
+ sleep 2
58
+ test $new_worker_pid -eq $(curl -sSf http://$listen/)
59
+ }
60
+
61
+ t_begin "stop server" && {
62
+ kill -QUIT $unicorn_pid
63
+ }
64
+
65
+ t_begin "check stderr" && check_stderr
66
+
67
+ dbgcat r_err
68
+
69
+ t_done
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 3 "config.ru is missing inside alt working_directory"
5
+
6
+ t_begin "setup" && {
7
+ unicorn_setup
8
+ rtmpfiles unicorn_config_tmp ok
9
+ rm -rf $t_pfx.app
10
+ mkdir $t_pfx.app
11
+
12
+ # the whole point of this exercise
13
+ echo "working_directory '$t_pfx.app'" >> $unicorn_config_tmp
14
+ }
15
+
16
+ t_begin "fails to start up w/o config.ru" && {
17
+ unicorn -c $unicorn_config_tmp || echo ok > $ok
18
+ }
19
+
20
+ t_begin "fallback code was run" && {
21
+ test x"$(cat $ok)" = xok
22
+ }
23
+
24
+ t_done
@@ -0,0 +1,40 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 4 "fooapp.rb inside alt working_directory"
5
+
6
+ t_begin "setup and start" && {
7
+ unicorn_setup
8
+ rm -rf $t_pfx.app
9
+ mkdir $t_pfx.app
10
+
11
+ cat > $t_pfx.app/fooapp.rb <<\EOF
12
+ class Fooapp
13
+ def self.call(env)
14
+ # Rack::Lint in 1.5.0 requires headers to be a hash
15
+ h = [%w(Content-Type text/plain), %w(Content-Length 2)]
16
+ h = Rack::Utils::HeaderHash.new(h)
17
+ [ 200, h, %w(HI) ]
18
+ end
19
+ end
20
+ EOF
21
+ # the whole point of this exercise
22
+ echo "working_directory '$t_pfx.app'" >> $unicorn_config
23
+ cd /
24
+ unicorn -D -c $unicorn_config -I. fooapp.rb
25
+ unicorn_wait_start
26
+ }
27
+
28
+ t_begin "hit with curl" && {
29
+ body=$(curl -sSf http://$listen/)
30
+ }
31
+
32
+ t_begin "killing succeeds" && {
33
+ kill $unicorn_pid
34
+ }
35
+
36
+ t_begin "response body expected" && {
37
+ test x"$body" = xHI
38
+ }
39
+
40
+ t_done
@@ -0,0 +1,83 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 15 "reopen rotated logs"
5
+
6
+ t_begin "setup and startup" && {
7
+ rtmpfiles curl_out curl_err r_rot
8
+ unicorn_setup
9
+ unicorn -D t0006.ru -c $unicorn_config
10
+ unicorn_wait_start
11
+ }
12
+
13
+ t_begin "ensure server is responsive" && {
14
+ test xtrue = x$(curl -sSf http://$listen/ 2> $curl_err)
15
+ }
16
+
17
+ t_begin "ensure stderr log is clean" && check_stderr
18
+
19
+ t_begin "external log rotation" && {
20
+ rm -f $r_rot
21
+ mv $r_err $r_rot
22
+ }
23
+
24
+ t_begin "send reopen log signal (USR1)" && {
25
+ kill -USR1 $unicorn_pid
26
+ }
27
+
28
+ t_begin "wait for rotated log to reappear" && {
29
+ nr=60
30
+ while ! test -f $r_err && test $nr -ge 0
31
+ do
32
+ sleep 1
33
+ nr=$(( $nr - 1 ))
34
+ done
35
+ }
36
+
37
+ t_begin "ensure server is still responsive" && {
38
+ test xtrue = x$(curl -sSf http://$listen/ 2> $curl_err)
39
+ }
40
+
41
+ t_begin "wait for worker to reopen logs" && {
42
+ nr=60
43
+ re="worker=.* done reopening logs"
44
+ while ! grep "$re" < $r_err >/dev/null && test $nr -ge 0
45
+ do
46
+ sleep 1
47
+ nr=$(( $nr - 1 ))
48
+ done
49
+ }
50
+
51
+ dbgcat r_rot
52
+ dbgcat r_err
53
+
54
+ t_begin "ensure no errors from curl" && {
55
+ test ! -s $curl_err
56
+ }
57
+
58
+ t_begin "current server stderr is clean" && check_stderr
59
+
60
+ t_begin "rotated stderr is clean" && {
61
+ check_stderr $r_rot
62
+ }
63
+
64
+ t_begin "server is now writing logs to new stderr" && {
65
+ before_rot=$(count_bytes < $r_rot)
66
+ before_err=$(count_bytes < $r_err)
67
+ test xtrue = x$(curl -sSf http://$listen/ 2> $curl_err)
68
+ after_rot=$(count_bytes < $r_rot)
69
+ after_err=$(count_bytes < $r_err)
70
+ test $after_rot -eq $before_rot
71
+ test $after_err -gt $before_err
72
+ }
73
+
74
+ t_begin "stop server" && {
75
+ kill $unicorn_pid
76
+ }
77
+
78
+ dbgcat r_err
79
+
80
+ t_begin "current server stderr is clean" && check_stderr
81
+ t_begin "rotated stderr is clean" && check_stderr $r_rot
82
+
83
+ t_done
data/t/t0006.ru ADDED
@@ -0,0 +1,13 @@
1
+ use Rack::ContentLength
2
+ use Rack::ContentType, "text/plain"
3
+ run lambda { |env|
4
+
5
+ # our File objects for stderr/stdout should always have #path
6
+ # and be sync=true
7
+ ok = $stderr.sync &&
8
+ $stdout.sync &&
9
+ String === $stderr.path &&
10
+ String === $stdout.path
11
+
12
+ [ 200, {}, [ "#{ok}\n" ] ]
13
+ }
@@ -0,0 +1,44 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 4 "config.ru inside alt working_directory (no embedded switches)"
5
+
6
+ t_begin "setup and start" && {
7
+ unicorn_setup
8
+ rm -rf $t_pfx.app
9
+ mkdir $t_pfx.app
10
+
11
+ cat > $t_pfx.app/config.ru <<EOF
12
+ use Rack::ContentLength
13
+ use Rack::ContentType, "text/plain"
14
+ run lambda { |env| [ 200, {}, [ "#{\$master_ppid}\\n" ] ] }
15
+ EOF
16
+ # the whole point of this exercise
17
+ echo "working_directory '$t_pfx.app'" >> $unicorn_config
18
+
19
+ # allows ppid to be 1 in before_fork
20
+ echo "preload_app true" >> $unicorn_config
21
+ cat >> $unicorn_config <<\EOF
22
+ before_fork do |server,worker|
23
+ $master_ppid = Process.ppid # should be zero to detect daemonization
24
+ end
25
+ EOF
26
+
27
+ cd /
28
+ unicorn -D -c $unicorn_config
29
+ unicorn_wait_start
30
+ }
31
+
32
+ t_begin "hit with curl" && {
33
+ body=$(curl -sSf http://$listen/)
34
+ }
35
+
36
+ t_begin "killing succeeds" && {
37
+ kill $unicorn_pid
38
+ }
39
+
40
+ t_begin "response body ppid == 1 (daemonized)" && {
41
+ test "$body" -eq 1
42
+ }
43
+
44
+ t_done
@@ -0,0 +1,110 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 13 "backout of USR2 upgrade"
4
+
5
+ worker_wait_start () {
6
+ test xSTART = x"$(cat $fifo)"
7
+ unicorn_pid=$(cat $pid)
8
+ }
9
+
10
+ t_begin "setup and start" && {
11
+ unicorn_setup
12
+ rm -f $pid.oldbin
13
+
14
+ cat >> $unicorn_config <<EOF
15
+ after_fork do |server, worker|
16
+ # test script will block while reading from $fifo,
17
+ # so notify the script on the first worker we spawn
18
+ # by opening the FIFO
19
+ if worker.nr == 0
20
+ File.open("$fifo", "wb") { |fp| fp.syswrite "START" }
21
+ end
22
+ end
23
+ EOF
24
+ unicorn -D -c $unicorn_config pid.ru
25
+ worker_wait_start
26
+ orig_master_pid=$unicorn_pid
27
+ }
28
+
29
+ t_begin "read original worker pid" && {
30
+ orig_worker_pid=$(curl -sSf http://$listen/)
31
+ test -n "$orig_worker_pid" && kill -0 $orig_worker_pid
32
+ }
33
+
34
+ t_begin "upgrade to new master" && {
35
+ kill -USR2 $orig_master_pid
36
+ }
37
+
38
+ t_begin "kill old worker" && {
39
+ kill -WINCH $orig_master_pid
40
+ }
41
+
42
+ t_begin "wait for new worker to start" && {
43
+ worker_wait_start
44
+ test $unicorn_pid -ne $orig_master_pid
45
+ new_master_pid=$unicorn_pid
46
+ }
47
+
48
+ t_begin "old master pid is stashed in $pid.oldbin" && {
49
+ test -s "$pid.oldbin"
50
+ test $orig_master_pid -eq $(cat $pid.oldbin)
51
+ }
52
+
53
+ t_begin "ensure old worker is no longer running" && {
54
+ i=0
55
+ while kill -0 $orig_worker_pid 2>/dev/null
56
+ do
57
+ i=$(( $i + 1 ))
58
+ test $i -lt 600 || die "timed out"
59
+ sleep 1
60
+ done
61
+ }
62
+
63
+ t_begin "capture pid of new worker" && {
64
+ new_worker_pid=$(curl -sSf http://$listen/)
65
+ }
66
+
67
+ t_begin "reload old master process" && {
68
+ kill -HUP $orig_master_pid
69
+ worker_wait_start
70
+ }
71
+
72
+ t_begin "gracefully kill new master and ensure it dies" && {
73
+ kill -QUIT $new_master_pid
74
+ i=0
75
+ while kill -0 $new_worker_pid 2>/dev/null
76
+ do
77
+ i=$(( $i + 1 ))
78
+ test $i -lt 600 || die "timed out"
79
+ sleep 1
80
+ done
81
+ }
82
+
83
+ t_begin "ensure $pid.oldbin does not exist" && {
84
+ i=0
85
+ while test -s $pid.oldbin
86
+ do
87
+ i=$(( $i + 1 ))
88
+ test $i -lt 600 || die "timed out"
89
+ sleep 1
90
+ done
91
+ while ! test -s $pid
92
+ do
93
+ i=$(( $i + 1 ))
94
+ test $i -lt 600 || die "timed out"
95
+ sleep 1
96
+ done
97
+ }
98
+
99
+ t_begin "ensure $pid is correct" && {
100
+ cur_master_pid=$(cat $pid)
101
+ test $orig_master_pid -eq $cur_master_pid
102
+ }
103
+
104
+ t_begin "killing succeeds" && {
105
+ kill $orig_master_pid
106
+ }
107
+
108
+ dbgcat r_err
109
+
110
+ t_done
@@ -0,0 +1,56 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 9 "graceful handling of broken apps"
5
+
6
+ t_begin "setup and start" && {
7
+ unicorn_setup
8
+ unicorn -E none -D broken-app.ru -c $unicorn_config
9
+ unicorn_wait_start
10
+ }
11
+
12
+ t_begin "normal response is alright" && {
13
+ test xOK = x"$(curl -sSf http://$listen/)"
14
+ }
15
+
16
+ t_begin "app raised exception" && {
17
+ curl -sSf http://$listen/raise 2> $tmp || :
18
+ grep -F 500 $tmp
19
+ > $tmp
20
+ }
21
+
22
+ t_begin "app exception logged and backtrace not swallowed" && {
23
+ grep -F 'app error' $r_err
24
+ grep -A1 -F 'app error' $r_err | tail -1 | grep broken-app.ru:
25
+ dbgcat r_err
26
+ > $r_err
27
+ }
28
+
29
+ t_begin "trigger bad response" && {
30
+ curl -sSf http://$listen/nil 2> $tmp || :
31
+ grep -F 500 $tmp
32
+ > $tmp
33
+ }
34
+
35
+ t_begin "app exception logged" && {
36
+ grep -F 'app error' $r_err
37
+ > $r_err
38
+ }
39
+
40
+ t_begin "normal responses alright afterwards" && {
41
+ > $tmp
42
+ curl -sSf http://$listen/ >> $tmp &
43
+ curl -sSf http://$listen/ >> $tmp &
44
+ curl -sSf http://$listen/ >> $tmp &
45
+ curl -sSf http://$listen/ >> $tmp &
46
+ wait
47
+ test xOK = x$(sort < $tmp | uniq)
48
+ }
49
+
50
+ t_begin "teardown" && {
51
+ kill $unicorn_pid
52
+ }
53
+
54
+ t_begin "check stderr" && check_stderr
55
+
56
+ t_done