unicorn-shopify 4.8.2.5.23

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 (150) hide show
  1. checksums.yaml +7 -0
  2. data/.CHANGELOG.old +25 -0
  3. data/.document +28 -0
  4. data/.gitignore +25 -0
  5. data/.mailmap +26 -0
  6. data/.olddoc.yml +15 -0
  7. data/Application_Timeouts +77 -0
  8. data/CONTRIBUTORS +35 -0
  9. data/COPYING +674 -0
  10. data/DESIGN +97 -0
  11. data/Documentation/.gitignore +5 -0
  12. data/Documentation/GNUmakefile +30 -0
  13. data/Documentation/unicorn.1.txt +185 -0
  14. data/Documentation/unicorn_rails.1.txt +175 -0
  15. data/FAQ +61 -0
  16. data/GIT-VERSION-GEN +39 -0
  17. data/GNUmakefile +252 -0
  18. data/HACKING +120 -0
  19. data/ISSUES +100 -0
  20. data/KNOWN_ISSUES +79 -0
  21. data/LICENSE +67 -0
  22. data/Links +59 -0
  23. data/PHILOSOPHY +145 -0
  24. data/README +145 -0
  25. data/Rakefile +16 -0
  26. data/SIGNALS +123 -0
  27. data/Sandbox +103 -0
  28. data/TODO +5 -0
  29. data/TUNING +101 -0
  30. data/archive/.gitignore +3 -0
  31. data/archive/slrnpull.conf +4 -0
  32. data/bin/unicorn +126 -0
  33. data/bin/unicorn_rails +209 -0
  34. data/examples/big_app_gc.rb +2 -0
  35. data/examples/echo.ru +27 -0
  36. data/examples/init.sh +74 -0
  37. data/examples/logger_mp_safe.rb +25 -0
  38. data/examples/logrotate.conf +29 -0
  39. data/examples/nginx.conf +156 -0
  40. data/examples/unicorn.conf.minimal.rb +13 -0
  41. data/examples/unicorn.conf.rb +113 -0
  42. data/ext/unicorn_http/CFLAGS +13 -0
  43. data/ext/unicorn_http/c_util.h +124 -0
  44. data/ext/unicorn_http/common_field_optimization.h +111 -0
  45. data/ext/unicorn_http/ext_help.h +82 -0
  46. data/ext/unicorn_http/extconf.rb +10 -0
  47. data/ext/unicorn_http/global_variables.h +97 -0
  48. data/ext/unicorn_http/httpdate.c +78 -0
  49. data/ext/unicorn_http/unicorn_http.rl +934 -0
  50. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  51. data/lib/unicorn.rb +112 -0
  52. data/lib/unicorn/app/old_rails.rb +35 -0
  53. data/lib/unicorn/app/old_rails/static.rb +59 -0
  54. data/lib/unicorn/cgi_wrapper.rb +147 -0
  55. data/lib/unicorn/configurator.rb +686 -0
  56. data/lib/unicorn/const.rb +21 -0
  57. data/lib/unicorn/http_request.rb +125 -0
  58. data/lib/unicorn/http_response.rb +73 -0
  59. data/lib/unicorn/http_server.rb +816 -0
  60. data/lib/unicorn/launcher.rb +62 -0
  61. data/lib/unicorn/oob_gc.rb +81 -0
  62. data/lib/unicorn/preread_input.rb +33 -0
  63. data/lib/unicorn/socket_helper.rb +197 -0
  64. data/lib/unicorn/stream_input.rb +146 -0
  65. data/lib/unicorn/tee_input.rb +133 -0
  66. data/lib/unicorn/tmpio.rb +27 -0
  67. data/lib/unicorn/util.rb +90 -0
  68. data/lib/unicorn/worker.rb +140 -0
  69. data/setup.rb +1586 -0
  70. data/t/.gitignore +4 -0
  71. data/t/GNUmakefile +74 -0
  72. data/t/README +42 -0
  73. data/t/before_murder.ru +7 -0
  74. data/t/bin/content-md5-put +36 -0
  75. data/t/bin/sha1sum.rb +17 -0
  76. data/t/bin/unused_listen +40 -0
  77. data/t/broken-app.ru +12 -0
  78. data/t/detach.ru +11 -0
  79. data/t/env.ru +3 -0
  80. data/t/fails-rack-lint.ru +5 -0
  81. data/t/heartbeat-timeout.ru +12 -0
  82. data/t/hijack.ru +42 -0
  83. data/t/listener_names.ru +4 -0
  84. data/t/my-tap-lib.sh +201 -0
  85. data/t/oob_gc.ru +20 -0
  86. data/t/oob_gc_path.ru +20 -0
  87. data/t/pid.ru +3 -0
  88. data/t/preread_input.ru +17 -0
  89. data/t/rack-input-tests.ru +21 -0
  90. data/t/t0000-http-basic.sh +50 -0
  91. data/t/t0001-reload-bad-config.sh +53 -0
  92. data/t/t0002-config-conflict.sh +49 -0
  93. data/t/t0002-parser-error.sh +94 -0
  94. data/t/t0003-working_directory.sh +51 -0
  95. data/t/t0004-heartbeat-timeout.sh +69 -0
  96. data/t/t0004-working_directory_broken.sh +24 -0
  97. data/t/t0005-working_directory_app.rb.sh +40 -0
  98. data/t/t0006-reopen-logs.sh +83 -0
  99. data/t/t0006.ru +13 -0
  100. data/t/t0007-working_directory_no_embed_cli.sh +44 -0
  101. data/t/t0008-back_out_of_upgrade.sh +110 -0
  102. data/t/t0009-broken-app.sh +56 -0
  103. data/t/t0009-winch_ttin.sh +59 -0
  104. data/t/t0010-reap-logging.sh +55 -0
  105. data/t/t0011-active-unix-socket.sh +79 -0
  106. data/t/t0012-reload-empty-config.sh +85 -0
  107. data/t/t0013-rewindable-input-false.sh +24 -0
  108. data/t/t0013.ru +12 -0
  109. data/t/t0014-rewindable-input-true.sh +24 -0
  110. data/t/t0014.ru +12 -0
  111. data/t/t0015-configurator-internals.sh +25 -0
  112. data/t/t0018-write-on-close.sh +23 -0
  113. data/t/t0019-max_header_len.sh +49 -0
  114. data/t/t0020-at_exit-handler.sh +49 -0
  115. data/t/t0021-process_detach.sh +29 -0
  116. data/t/t0022-listener_names-preload_app.sh +32 -0
  117. data/t/t0023-before-murder.sh +40 -0
  118. data/t/t0024-before-murder_once.sh +52 -0
  119. data/t/t0100-rack-input-tests.sh +124 -0
  120. data/t/t0116-client_body_buffer_size.sh +80 -0
  121. data/t/t0116.ru +16 -0
  122. data/t/t0200-rack-hijack.sh +27 -0
  123. data/t/t0300-no-default-middleware.sh +20 -0
  124. data/t/t9000-preread-input.sh +48 -0
  125. data/t/t9001-oob_gc.sh +47 -0
  126. data/t/t9002-oob_gc-path.sh +75 -0
  127. data/t/test-lib.sh +128 -0
  128. data/t/write-on-close.ru +11 -0
  129. data/test/aggregate.rb +15 -0
  130. data/test/benchmark/README +50 -0
  131. data/test/benchmark/dd.ru +18 -0
  132. data/test/benchmark/stack.ru +8 -0
  133. data/test/exec/README +5 -0
  134. data/test/exec/test_exec.rb +1047 -0
  135. data/test/test_helper.rb +297 -0
  136. data/test/unit/test_configurator.rb +175 -0
  137. data/test/unit/test_droplet.rb +28 -0
  138. data/test/unit/test_http_parser.rb +854 -0
  139. data/test/unit/test_http_parser_ng.rb +622 -0
  140. data/test/unit/test_request.rb +182 -0
  141. data/test/unit/test_response.rb +93 -0
  142. data/test/unit/test_server.rb +268 -0
  143. data/test/unit/test_signals.rb +188 -0
  144. data/test/unit/test_socket_helper.rb +197 -0
  145. data/test/unit/test_stream_input.rb +203 -0
  146. data/test/unit/test_tee_input.rb +304 -0
  147. data/test/unit/test_upload.rb +306 -0
  148. data/test/unit/test_util.rb +105 -0
  149. data/unicorn.gemspec +41 -0
  150. metadata +311 -0
@@ -0,0 +1,20 @@
1
+ #\-E none
2
+ require 'unicorn/oob_gc'
3
+ use Rack::ContentLength
4
+ use Rack::ContentType, "text/plain"
5
+ use Unicorn::OobGC
6
+ $gc_started = false
7
+
8
+ # Mock GC.start
9
+ def GC.start
10
+ ObjectSpace.each_object(Kgio::Socket) do |x|
11
+ x.closed? or abort "not closed #{x}"
12
+ end
13
+ $gc_started = true
14
+ end
15
+ run lambda { |env|
16
+ if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
17
+ $gc_started = false
18
+ end
19
+ [ 200, {}, [ "#$gc_started\n" ] ]
20
+ }
@@ -0,0 +1,20 @@
1
+ #\-E none
2
+ require 'unicorn/oob_gc'
3
+ use Rack::ContentLength
4
+ use Rack::ContentType, "text/plain"
5
+ use Unicorn::OobGC, 5, /BAD/
6
+ $gc_started = false
7
+
8
+ # Mock GC.start
9
+ def GC.start
10
+ ObjectSpace.each_object(Kgio::Socket) do |x|
11
+ x.closed? or abort "not closed #{x}"
12
+ end
13
+ $gc_started = true
14
+ end
15
+ run lambda { |env|
16
+ if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
17
+ $gc_started = false
18
+ end
19
+ [ 200, {}, [ "#$gc_started\n" ] ]
20
+ }
@@ -0,0 +1,3 @@
1
+ use Rack::ContentLength
2
+ use Rack::ContentType, "text/plain"
3
+ run lambda { |env| [ 200, {}, [ "#$$\n" ] ] }
@@ -0,0 +1,17 @@
1
+ #\-E none
2
+ require 'digest/sha1'
3
+ require 'unicorn/preread_input'
4
+ use Rack::ContentLength
5
+ use Rack::ContentType, "text/plain"
6
+ use Unicorn::PrereadInput
7
+ nr = 0
8
+ run lambda { |env|
9
+ $stderr.write "app dispatch: #{nr += 1}\n"
10
+ input = env["rack.input"]
11
+ dig = Digest::SHA1.new
12
+ while buf = input.read(16384)
13
+ dig.update(buf)
14
+ end
15
+
16
+ [ 200, {}, [ "#{dig.hexdigest}\n" ] ]
17
+ }
@@ -0,0 +1,21 @@
1
+ # SHA1 checksum generator
2
+ require 'digest/sha1'
3
+ use Rack::ContentLength
4
+ cap = 16384
5
+ app = lambda do |env|
6
+ /\A100-continue\z/i =~ env['HTTP_EXPECT'] and
7
+ return [ 100, {}, [] ]
8
+ digest = Digest::SHA1.new
9
+ input = env['rack.input']
10
+ input.size if env["PATH_INFO"] == "/size_first"
11
+ input.rewind if env["PATH_INFO"] == "/rewind_first"
12
+ if buf = input.read(rand(cap))
13
+ begin
14
+ raise "#{buf.size} > #{cap}" if buf.size > cap
15
+ digest.update(buf)
16
+ end while input.read(rand(cap), buf)
17
+ end
18
+
19
+ [ 200, {'Content-Type' => 'text/plain'}, [ digest.hexdigest << "\n" ] ]
20
+ end
21
+ run app
@@ -0,0 +1,50 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 8 "simple HTTP connection tests"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ unicorn -D -c $unicorn_config env.ru
8
+ unicorn_wait_start
9
+ }
10
+
11
+ t_begin "single request" && {
12
+ curl -sSfv http://$listen/
13
+ }
14
+
15
+ t_begin "check stderr has no errors" && {
16
+ check_stderr
17
+ }
18
+
19
+ t_begin "HTTP/0.9 request should not return headers" && {
20
+ (
21
+ printf 'GET /\r\n'
22
+ cat $fifo > $tmp &
23
+ wait
24
+ echo ok > $ok
25
+ ) | socat - TCP:$listen > $fifo
26
+ }
27
+
28
+ t_begin "env.inspect should've put everything on one line" && {
29
+ test 1 -eq $(count_lines < $tmp)
30
+ }
31
+
32
+ t_begin "no headers in output" && {
33
+ if grep ^Connection: $tmp
34
+ then
35
+ die "Connection header found in $tmp"
36
+ elif grep ^HTTP/ $tmp
37
+ then
38
+ die "HTTP/ found in $tmp"
39
+ fi
40
+ }
41
+
42
+ t_begin "killing succeeds" && {
43
+ kill $unicorn_pid
44
+ }
45
+
46
+ t_begin "check stderr has no errors" && {
47
+ check_stderr
48
+ }
49
+
50
+ t_done
@@ -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