unicorn-maintained 6.2.0
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.
- 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/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
data/t/preread_input.ru
ADDED
|
@@ -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
|