unicorn-maintained 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) 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 +149 -0
  8. data/.olddoc.yml +25 -0
  9. data/Application_Timeouts +77 -0
  10. data/CONTRIBUTORS +39 -0
  11. data/COPYING +674 -0
  12. data/DESIGN +99 -0
  13. data/Documentation/.gitignore +3 -0
  14. data/Documentation/unicorn.1 +222 -0
  15. data/Documentation/unicorn_rails.1 +207 -0
  16. data/FAQ +70 -0
  17. data/GIT-VERSION-FILE +1 -0
  18. data/GIT-VERSION-GEN +39 -0
  19. data/GNUmakefile +317 -0
  20. data/HACKING +112 -0
  21. data/ISSUES +102 -0
  22. data/KNOWN_ISSUES +79 -0
  23. data/LATEST +1 -0
  24. data/LICENSE +67 -0
  25. data/Links +58 -0
  26. data/NEWS +1 -0
  27. data/PHILOSOPHY +139 -0
  28. data/README +156 -0
  29. data/Rakefile +16 -0
  30. data/SIGNALS +123 -0
  31. data/Sandbox +104 -0
  32. data/TODO +3 -0
  33. data/TUNING +119 -0
  34. data/archive/.gitignore +3 -0
  35. data/archive/slrnpull.conf +4 -0
  36. data/bin/unicorn +128 -0
  37. data/bin/unicorn_rails +209 -0
  38. data/examples/big_app_gc.rb +2 -0
  39. data/examples/echo.ru +26 -0
  40. data/examples/init.sh +102 -0
  41. data/examples/logger_mp_safe.rb +25 -0
  42. data/examples/logrotate.conf +44 -0
  43. data/examples/nginx.conf +156 -0
  44. data/examples/unicorn.conf.minimal.rb +13 -0
  45. data/examples/unicorn.conf.rb +110 -0
  46. data/examples/unicorn.socket +11 -0
  47. data/examples/unicorn@.service +40 -0
  48. data/ext/unicorn_http/CFLAGS +13 -0
  49. data/ext/unicorn_http/c_util.h +116 -0
  50. data/ext/unicorn_http/common_field_optimization.h +128 -0
  51. data/ext/unicorn_http/epollexclusive.h +128 -0
  52. data/ext/unicorn_http/ext_help.h +38 -0
  53. data/ext/unicorn_http/extconf.rb +39 -0
  54. data/ext/unicorn_http/global_variables.h +97 -0
  55. data/ext/unicorn_http/httpdate.c +91 -0
  56. data/ext/unicorn_http/unicorn_http.c +4334 -0
  57. data/ext/unicorn_http/unicorn_http.rl +1040 -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 +748 -0
  63. data/lib/unicorn/const.rb +21 -0
  64. data/lib/unicorn/http_request.rb +201 -0
  65. data/lib/unicorn/http_response.rb +93 -0
  66. data/lib/unicorn/http_server.rb +859 -0
  67. data/lib/unicorn/launcher.rb +62 -0
  68. data/lib/unicorn/oob_gc.rb +81 -0
  69. data/lib/unicorn/preread_input.rb +33 -0
  70. data/lib/unicorn/select_waiter.rb +6 -0
  71. data/lib/unicorn/socket_helper.rb +185 -0
  72. data/lib/unicorn/stream_input.rb +151 -0
  73. data/lib/unicorn/tee_input.rb +131 -0
  74. data/lib/unicorn/tmpio.rb +33 -0
  75. data/lib/unicorn/util.rb +90 -0
  76. data/lib/unicorn/version.rb +1 -0
  77. data/lib/unicorn/worker.rb +165 -0
  78. data/lib/unicorn.rb +136 -0
  79. data/man/man1/unicorn.1 +222 -0
  80. data/man/man1/unicorn_rails.1 +207 -0
  81. data/setup.rb +1586 -0
  82. data/t/.gitignore +4 -0
  83. data/t/GNUmakefile +5 -0
  84. data/t/README +49 -0
  85. data/t/active-unix-socket.t +117 -0
  86. data/t/bin/unused_listen +40 -0
  87. data/t/broken-app.ru +12 -0
  88. data/t/client_body_buffer_size.ru +14 -0
  89. data/t/client_body_buffer_size.t +80 -0
  90. data/t/detach.ru +11 -0
  91. data/t/env.ru +3 -0
  92. data/t/fails-rack-lint.ru +5 -0
  93. data/t/heartbeat-timeout.ru +12 -0
  94. data/t/heartbeat-timeout.t +62 -0
  95. data/t/integration.ru +115 -0
  96. data/t/integration.t +356 -0
  97. data/t/lib.perl +258 -0
  98. data/t/listener_names.ru +4 -0
  99. data/t/my-tap-lib.sh +201 -0
  100. data/t/oob_gc.ru +17 -0
  101. data/t/oob_gc_path.ru +17 -0
  102. data/t/pid.ru +3 -0
  103. data/t/preread_input.ru +22 -0
  104. data/t/reload-bad-config.t +54 -0
  105. data/t/reopen-logs.ru +13 -0
  106. data/t/reopen-logs.t +39 -0
  107. data/t/t0008-back_out_of_upgrade.sh +110 -0
  108. data/t/t0009-broken-app.sh +56 -0
  109. data/t/t0010-reap-logging.sh +55 -0
  110. data/t/t0012-reload-empty-config.sh +86 -0
  111. data/t/t0013-rewindable-input-false.sh +24 -0
  112. data/t/t0013.ru +12 -0
  113. data/t/t0014-rewindable-input-true.sh +24 -0
  114. data/t/t0014.ru +12 -0
  115. data/t/t0015-configurator-internals.sh +25 -0
  116. data/t/t0020-at_exit-handler.sh +49 -0
  117. data/t/t0021-process_detach.sh +29 -0
  118. data/t/t0022-listener_names-preload_app.sh +32 -0
  119. data/t/t0300-no-default-middleware.sh +20 -0
  120. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  121. data/t/t0301.ru +13 -0
  122. data/t/t9001-oob_gc.sh +47 -0
  123. data/t/t9002-oob_gc-path.sh +75 -0
  124. data/t/test-lib.sh +125 -0
  125. data/t/winch_ttin.t +67 -0
  126. data/t/working_directory.t +94 -0
  127. data/test/aggregate.rb +15 -0
  128. data/test/benchmark/README +60 -0
  129. data/test/benchmark/dd.ru +18 -0
  130. data/test/benchmark/ddstream.ru +50 -0
  131. data/test/benchmark/readinput.ru +40 -0
  132. data/test/benchmark/stack.ru +8 -0
  133. data/test/benchmark/uconnect.perl +66 -0
  134. data/test/exec/README +5 -0
  135. data/test/exec/test_exec.rb +1029 -0
  136. data/test/test_helper.rb +306 -0
  137. data/test/unit/test_ccc.rb +91 -0
  138. data/test/unit/test_configurator.rb +175 -0
  139. data/test/unit/test_droplet.rb +28 -0
  140. data/test/unit/test_http_parser.rb +884 -0
  141. data/test/unit/test_http_parser_ng.rb +714 -0
  142. data/test/unit/test_request.rb +169 -0
  143. data/test/unit/test_server.rb +244 -0
  144. data/test/unit/test_signals.rb +188 -0
  145. data/test/unit/test_socket_helper.rb +159 -0
  146. data/test/unit/test_stream_input.rb +210 -0
  147. data/test/unit/test_tee_input.rb +303 -0
  148. data/test/unit/test_util.rb +131 -0
  149. data/test/unit/test_waiter.rb +34 -0
  150. data/unicorn.gemspec +48 -0
  151. metadata +275 -0
data/t/my-tap-lib.sh ADDED
@@ -0,0 +1,201 @@
1
+ #!/bin/sh
2
+ # Copyright (c) 2009, 2010 Eric Wong <normalperson@yhbt.net>
3
+ #
4
+ # TAP-producing shell library for POSIX-compliant Bourne shells We do
5
+ # not _rely_ on Bourne Again features, though we will use "set -o
6
+ # pipefail" from ksh93 or bash 3 if available
7
+ #
8
+ # Only generic, non-project/non-language-specific stuff goes here. We
9
+ # only have POSIX dependencies for the core tests (without --verbose),
10
+ # though we'll enable useful non-POSIX things if they're available.
11
+ #
12
+ # This test library is intentionally unforgiving, it does not support
13
+ # skipping tests nor continuing after any failure. Any failures
14
+ # immediately halt execution as do any references to undefined
15
+ # variables.
16
+ #
17
+ # When --verbose is specified, we always prefix stdout/stderr
18
+ # output with "#" to avoid confusing TAP consumers. Otherwise
19
+ # the normal stdout/stderr streams are redirected to /dev/null
20
+
21
+ # dup normal stdout(fd=1) and stderr (fd=2) to fd=3 and fd=4 respectively
22
+ # normal TAP output goes to fd=3, nothing should go to fd=4
23
+ exec 3>&1 4>&2
24
+
25
+ # ensure a sane environment
26
+ TZ=UTC LC_ALL=C LANG=C
27
+ export LANG LC_ALL TZ
28
+ unset CDPATH
29
+
30
+ # pipefail is non-POSIX, but very useful in ksh93/bash
31
+ ( set -o pipefail 2>/dev/null ) && set -o pipefail
32
+
33
+ SED=${SED-sed}
34
+
35
+ # Unlike other test frameworks, we are unforgiving and bail immediately
36
+ # on any failures. We do this because we're lazy about error handling
37
+ # and also because we believe anything broken should not be allowed to
38
+ # propagate throughout the rest of the test
39
+ set -e
40
+ set -u
41
+
42
+ # name of our test
43
+ T=${0##*/}
44
+
45
+ t_expect_nr=-1
46
+ t_nr=0
47
+ t_current=
48
+ t_complete=false
49
+
50
+ # list of files to remove unconditionally on exit
51
+ T_RM_LIST=
52
+
53
+ # list of files to remove only on successful exit
54
+ T_OK_RM_LIST=
55
+
56
+ # emit output to stdout, it'll be parsed by the TAP consumer
57
+ # so it must be TAP-compliant output
58
+ t_echo () {
59
+ echo >&3 "$@"
60
+ }
61
+
62
+ # emits non-parsed information to stdout, it will be prefixed with a '#'
63
+ # to not throw off TAP consumers
64
+ t_info () {
65
+ t_echo '#' "$@"
66
+ }
67
+
68
+ # exit with an error and print a diagnostic
69
+ die () {
70
+ echo >&2 "$@"
71
+ exit 1
72
+ }
73
+
74
+ # our at_exit handler, it'll fire for all exits except SIGKILL (unavoidable)
75
+ t_at_exit () {
76
+ code=$?
77
+ set +e
78
+ if test $code -eq 0
79
+ then
80
+ $t_complete || {
81
+ t_info "t_done not called"
82
+ code=1
83
+ }
84
+ elif test -n "$t_current"
85
+ then
86
+ t_echo "not ok $t_nr - $t_current"
87
+ fi
88
+ if test $t_expect_nr -ne -1
89
+ then
90
+ test $t_expect_nr -eq $t_nr || {
91
+ t_info "planned $t_expect_nr tests but ran $t_nr"
92
+ test $code -ne 0 || code=1
93
+ }
94
+ fi
95
+ $t_complete || {
96
+ t_info "unexpected test failure"
97
+ test $code -ne 0 || code=1
98
+ }
99
+ rm -f $T_RM_LIST
100
+ test $code -eq 0 && rm -f $T_OK_RM_LIST
101
+ set +x
102
+ exec >&3 2>&4
103
+ t_close_fds
104
+ exit $code
105
+ }
106
+
107
+ # close test-specific extra file descriptors
108
+ t_close_fds () {
109
+ exec 3>&- 4>&-
110
+ }
111
+
112
+ # call this at the start of your test to specify the number of tests
113
+ # you plan to run
114
+ t_plan () {
115
+ test "$1" -ge 1 || die "must plan at least one test"
116
+ test $t_expect_nr -eq -1 || die "tried to plan twice in one test"
117
+ t_expect_nr=$1
118
+ shift
119
+ t_echo 1..$t_expect_nr "#" "$@"
120
+ trap t_at_exit EXIT
121
+ }
122
+
123
+ _t_checkup () {
124
+ test $t_expect_nr -le 0 && die "no tests planned"
125
+ test -n "$t_current" && t_echo "ok $t_nr - $t_current"
126
+ true
127
+ }
128
+
129
+ # finalizes any previously test and starts a new one
130
+ t_begin () {
131
+ _t_checkup
132
+ t_nr=$(( $t_nr + 1 ))
133
+ t_current="$1"
134
+
135
+ # just in case somebody wanted to cheat us:
136
+ set -e
137
+ }
138
+
139
+ # finalizes the current test without starting a new one
140
+ t_end () {
141
+ _t_checkup
142
+ t_current=
143
+ }
144
+
145
+ # run this to signify the end of your test
146
+ t_done () {
147
+ _t_checkup
148
+ t_current=
149
+ t_complete=true
150
+ test $t_expect_nr -eq $t_nr || exit 1
151
+ exit 0
152
+ }
153
+
154
+ # create and assign named-pipes to variable _names_ passed to this function
155
+ t_fifos () {
156
+ for _id in "$@"
157
+ do
158
+ _name=$_id
159
+ _tmp=$(mktemp -t $T.$$.$_id.XXXXXXXX)
160
+ eval "$_id=$_tmp"
161
+ rm -f $_tmp
162
+ mkfifo $_tmp
163
+ T_RM_LIST="$T_RM_LIST $_tmp"
164
+ done
165
+ }
166
+
167
+ t_verbose=false t_trace=false
168
+
169
+ while test "$#" -ne 0
170
+ do
171
+ arg="$1"
172
+ shift
173
+ case $arg in
174
+ -v|--verbose) t_verbose=true ;;
175
+ --trace) t_trace=true t_verbose=true ;;
176
+ *) die "Unknown option: $arg" ;;
177
+ esac
178
+ done
179
+
180
+ # we always only setup stdout, nothing should end up in the "real" stderr
181
+ if $t_verbose
182
+ then
183
+ if test x"$(which mktemp 2>/dev/null)" = x
184
+ then
185
+ die "mktemp(1) not available for --verbose"
186
+ fi
187
+ t_fifos t_stdout t_stderr
188
+
189
+ (
190
+ # use a subshell so seds are not waitable
191
+ $SED -e 's/^/#: /' < $t_stdout &
192
+ $SED -e 's/^/#! /' < $t_stderr &
193
+ ) &
194
+ wait
195
+ exec > $t_stdout 2> $t_stderr
196
+ else
197
+ exec > /dev/null 2> /dev/null
198
+ fi
199
+
200
+ $t_trace && set -x
201
+ true
data/t/oob_gc.ru ADDED
@@ -0,0 +1,17 @@
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
+ $gc_started = true
11
+ end
12
+ run lambda { |env|
13
+ if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
14
+ $gc_started = false
15
+ end
16
+ [ 200, {}, [ "#$gc_started\n" ] ]
17
+ }
data/t/oob_gc_path.ru ADDED
@@ -0,0 +1,17 @@
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
+ $gc_started = true
11
+ end
12
+ run lambda { |env|
13
+ if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
14
+ $gc_started = false
15
+ end
16
+ [ 200, {}, [ "#$gc_started\n" ] ]
17
+ }
data/t/pid.ru ADDED
@@ -0,0 +1,3 @@
1
+ use Rack::ContentLength
2
+ use Rack::ContentType, "text/plain"
3
+ run lambda { |env| [ 200, {}, [ "#$$\n" ] ] }
@@ -0,0 +1,22 @@
1
+ #\-E none
2
+ require 'digest/md5'
3
+ require 'unicorn/preread_input'
4
+ use Unicorn::PrereadInput
5
+ nr = 0
6
+ run lambda { |env|
7
+ $stderr.write "app dispatch: #{nr += 1}\n"
8
+ input = env["rack.input"]
9
+ dig = Digest::MD5.new
10
+ if buf = input.read(16384)
11
+ begin
12
+ dig.update(buf)
13
+ end while input.read(16384, buf)
14
+ buf.clear # remove this call if Ruby ever gets escape analysis
15
+ end
16
+ if env['HTTP_TRAILER'] =~ /\bContent-MD5\b/i
17
+ cmd5_b64 = env['HTTP_CONTENT_MD5'] or return [500, {}, ['No Content-MD5']]
18
+ cmd5_bin = cmd5_b64.unpack('m')[0]
19
+ return [500, {}, [ cmd5_b64 ] ] if cmd5_bin != dig.digest
20
+ end
21
+ [ 200, {}, [ dig.hexdigest ] ]
22
+ }
@@ -0,0 +1,54 @@
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
+ my $srv = tcp_server();
7
+ my $host_port = tcp_host_port($srv);
8
+ my $ru = "$tmpdir/config.ru";
9
+ my $u_conf = "$tmpdir/u.conf.rb";
10
+
11
+ open my $fh, '>', $ru;
12
+ print $fh <<'EOM';
13
+ use Rack::ContentLength
14
+ use Rack::ContentType, 'text/plain'
15
+ config = ru = "hello world\n" # check for config variable conflicts, too
16
+ run lambda { |env| [ 200, {}, [ ru.to_s ] ] }
17
+ EOM
18
+ close $fh;
19
+
20
+ open $fh, '>', $u_conf;
21
+ print $fh <<EOM;
22
+ preload_app true
23
+ stderr_path "$err_log"
24
+ EOM
25
+ close $fh;
26
+
27
+ my $ar = unicorn(qw(-E none -c), $u_conf, $ru, { 3 => $srv });
28
+ my ($status, $hdr, $bdy) = do_req($srv, 'GET / HTTP/1.0');
29
+ like($status, qr!\AHTTP/1\.[01] 200\b!, 'status line valid at start');
30
+ is($bdy, "hello world\n", 'body matches expected');
31
+
32
+ open $fh, '>>', $ru;
33
+ say $fh '....this better be a syntax error in any version of ruby...';
34
+ close $fh;
35
+
36
+ $ar->do_kill('HUP'); # reload
37
+ my @l;
38
+ for (1..1000) {
39
+ @l = grep(/(?:done|error) reloading/, slurp($err_log)) and
40
+ last;
41
+ sleep 0.011;
42
+ }
43
+ diag slurp($err_log) if $ENV{V};
44
+ ok(grep(/error reloading/, @l), 'got error reloading');
45
+ open $fh, '>', $err_log;
46
+ close $fh;
47
+
48
+ ($status, $hdr, $bdy) = do_req($srv, 'GET / HTTP/1.0');
49
+ like($status, qr!\AHTTP/1\.[01] 200\b!, 'status line valid afte reload');
50
+ is($bdy, "hello world\n", 'body matches expected after reload');
51
+
52
+ check_stderr;
53
+ undef $tmpdir; # quiet t/lib.perl END{}
54
+ done_testing;
data/t/reopen-logs.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
+ }
data/t/reopen-logs.t ADDED
@@ -0,0 +1,39 @@
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
+ my $srv = tcp_server();
7
+ my $u_conf = "$tmpdir/u.conf.rb";
8
+ my $out_log = "$tmpdir/out.log";
9
+ open my $fh, '>', $u_conf;
10
+ print $fh <<EOM;
11
+ stderr_path "$err_log"
12
+ stdout_path "$out_log"
13
+ EOM
14
+ close $fh;
15
+
16
+ my $auto_reap = unicorn('-c', $u_conf, 't/reopen-logs.ru', { 3 => $srv } );
17
+ my ($status, $hdr, $bdy) = do_req($srv, 'GET / HTTP/1.0');
18
+ is($bdy, "true\n", 'logs opened');
19
+
20
+ rename($err_log, "$err_log.rot");
21
+ rename($out_log, "$out_log.rot");
22
+
23
+ $auto_reap->do_kill('USR1');
24
+
25
+ my $tries = 1000;
26
+ while (!-f $err_log && --$tries) { sleep 0.01 };
27
+ while (!-f $out_log && --$tries) { sleep 0.01 };
28
+
29
+ ok(-f $out_log, 'stdout_path recreated after USR1');
30
+ ok(-f $err_log, 'stderr_path recreated after USR1');
31
+
32
+ ($status, $hdr, $bdy) = do_req($srv, 'GET / HTTP/1.0');
33
+ is($bdy, "true\n", 'logs reopened with sync==true');
34
+
35
+ $auto_reap->join('QUIT');
36
+ is($?, 0, 'no error on exit');
37
+ check_stderr;
38
+ undef $tmpdir;
39
+ done_testing;
@@ -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
@@ -0,0 +1,55 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 9 "reap worker logging messages"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ cat >> $unicorn_config <<EOF
8
+ after_fork { |s,w| File.open('$fifo','w') { |f| f.write '.' } }
9
+ EOF
10
+ unicorn -c $unicorn_config pid.ru &
11
+ test '.' = $(cat $fifo)
12
+ unicorn_wait_start
13
+ }
14
+
15
+ t_begin "kill 1st worker=0" && {
16
+ pid_1=$(curl http://$listen/)
17
+ kill -9 $pid_1
18
+ }
19
+
20
+ t_begin "wait for 2nd worker to start" && {
21
+ test '.' = $(cat $fifo)
22
+ }
23
+
24
+ t_begin "ensure log of 1st reap is an ERROR" && {
25
+ dbgcat r_err
26
+ grep 'ERROR.*reaped.*worker=0' $r_err | grep $pid_1
27
+ dbgcat r_err
28
+ > $r_err
29
+ }
30
+
31
+ t_begin "kill 2nd worker gracefully" && {
32
+ pid_2=$(curl http://$listen/)
33
+ kill -QUIT $pid_2
34
+ }
35
+
36
+ t_begin "wait for 3rd worker=0 to start " && {
37
+ test '.' = $(cat $fifo)
38
+ }
39
+
40
+ t_begin "ensure log of 2nd reap is a INFO" && {
41
+ grep 'INFO.*reaped.*worker=0' $r_err | grep $pid_2
42
+ > $r_err
43
+ }
44
+
45
+ t_begin "killing succeeds" && {
46
+ kill $unicorn_pid
47
+ wait
48
+ kill -0 $unicorn_pid && false
49
+ }
50
+
51
+ t_begin "check stderr" && {
52
+ check_stderr
53
+ }
54
+
55
+ t_done
@@ -0,0 +1,86 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 9 "reloading unset config resets defaults"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ rtmpfiles unicorn_config_orig before_reload after_reload
8
+ cat $unicorn_config > $unicorn_config_orig
9
+ cat >> $unicorn_config <<EOF
10
+ logger Logger.new(STDOUT)
11
+ preload_app true
12
+ timeout 0x7fffffff
13
+ worker_processes 2
14
+ after_fork { |s,w| }
15
+ \$dump_cfg = lambda { |fp,srv|
16
+ defaults = Unicorn::Configurator::DEFAULTS
17
+ defaults.keys.map { |x| x.to_s }.sort.each do |key|
18
+ next if key =~ %r{\Astd(?:err|out)_path\z}
19
+ key = key.to_sym
20
+ def_value = defaults[key]
21
+ srv_value = srv.respond_to?(key) ? srv.__send__(key)
22
+ : srv.instance_variable_get("@#{key}")
23
+ fp << "#{key}|#{srv_value}|#{def_value}\\n"
24
+ end
25
+ }
26
+ before_fork { |s,w|
27
+ File.open("$before_reload", "a") { |fp| \$dump_cfg.call(fp, s) }
28
+ }
29
+ before_exec { |s| }
30
+ EOF
31
+ unicorn -D -c $unicorn_config env.ru
32
+ unicorn_wait_start
33
+ }
34
+
35
+ t_begin "ensure worker is started" && {
36
+ curl -sSf http://$listen/ > $tmp
37
+ }
38
+
39
+ t_begin "replace config file with original(-ish)" && {
40
+ grep -v ^pid < $unicorn_config_orig > $unicorn_config
41
+ cat >> $unicorn_config <<EOF
42
+ before_fork { |s,w|
43
+ File.open("$after_reload", "a") { |fp| \$dump_cfg.call(fp, s) }
44
+ }
45
+ EOF
46
+ }
47
+
48
+ t_begin "reload signal succeeds" && {
49
+ kill -HUP $unicorn_pid
50
+ while ! egrep '(done|error) reloading' $r_err >/dev/null
51
+ do
52
+ sleep 1
53
+ done
54
+ while ! grep reaped < $r_err >/dev/null
55
+ do
56
+ sleep 1
57
+ done
58
+ grep 'done reloading' $r_err >/dev/null
59
+ }
60
+
61
+ t_begin "ensure worker is started" && {
62
+ curl -sSf http://$listen/ > $tmp
63
+ }
64
+
65
+ t_begin "pid file no longer exists" && {
66
+ if test -f $pid
67
+ then
68
+ die "pid=$pid should not exist"
69
+ fi
70
+ }
71
+
72
+ t_begin "killing succeeds" && {
73
+ kill $unicorn_pid
74
+ }
75
+
76
+ t_begin "check stderr" && {
77
+ check_stderr
78
+ }
79
+
80
+ t_begin "ensure reloading restored settings" && {
81
+ awk < $after_reload -F'|' '
82
+ $1 != "before_fork" && $2 != $3 { print $0; exit(1) }
83
+ '
84
+ }
85
+
86
+ t_done
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 4 "rewindable_input toggled to false"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ echo rewindable_input false >> $unicorn_config
8
+ unicorn -D -c $unicorn_config t0013.ru
9
+ unicorn_wait_start
10
+ }
11
+
12
+ t_begin "ensure worker is started" && {
13
+ test xOK = x$(curl -T t0013.ru -H Expect: -vsSf 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