unicorn-rupcio 6.1.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 +144 -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 +318 -0
- data/HACKING +117 -0
- data/ISSUES +102 -0
- data/KNOWN_ISSUES +79 -0
- data/LICENSE +67 -0
- data/Links +58 -0
- data/PHILOSOPHY +139 -0
- data/README +165 -0
- data/Rakefile +17 -0
- data/SIGNALS +123 -0
- data/Sandbox +104 -0
- data/TODO +1 -0
- data/TUNING +119 -0
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/bin/unicorn +129 -0
- data/bin/unicorn_rails +210 -0
- data/examples/big_app_gc.rb +3 -0
- data/examples/echo.ru +27 -0
- data/examples/init.sh +102 -0
- data/examples/logger_mp_safe.rb +26 -0
- data/examples/logrotate.conf +44 -0
- data/examples/nginx.conf +156 -0
- data/examples/unicorn.conf.minimal.rb +14 -0
- data/examples/unicorn.conf.rb +111 -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 +115 -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 +40 -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 +4348 -0
- data/ext/unicorn_http/unicorn_http.rl +1054 -0
- data/ext/unicorn_http/unicorn_http_common.rl +76 -0
- data/lib/unicorn/app/old_rails/static.rb +60 -0
- data/lib/unicorn/app/old_rails.rb +36 -0
- data/lib/unicorn/cgi_wrapper.rb +148 -0
- data/lib/unicorn/configurator.rb +749 -0
- data/lib/unicorn/const.rb +22 -0
- data/lib/unicorn/http_request.rb +180 -0
- data/lib/unicorn/http_response.rb +95 -0
- data/lib/unicorn/http_server.rb +860 -0
- data/lib/unicorn/launcher.rb +63 -0
- data/lib/unicorn/oob_gc.rb +82 -0
- data/lib/unicorn/preread_input.rb +34 -0
- data/lib/unicorn/select_waiter.rb +7 -0
- data/lib/unicorn/socket_helper.rb +186 -0
- data/lib/unicorn/stream_input.rb +152 -0
- data/lib/unicorn/tee_input.rb +132 -0
- data/lib/unicorn/tmpio.rb +34 -0
- data/lib/unicorn/util.rb +91 -0
- data/lib/unicorn/version.rb +1 -0
- data/lib/unicorn/worker.rb +166 -0
- data/lib/unicorn.rb +137 -0
- data/man/man1/unicorn.1 +222 -0
- data/man/man1/unicorn_rails.1 +207 -0
- data/setup.rb +1587 -0
- data/t/.gitignore +4 -0
- data/t/GNUmakefile +5 -0
- data/t/README +49 -0
- data/t/active-unix-socket.t +110 -0
- data/t/back-out-of-upgrade.t +44 -0
- data/t/bin/unused_listen +40 -0
- data/t/client_body_buffer_size.ru +15 -0
- data/t/client_body_buffer_size.t +79 -0
- data/t/detach.ru +12 -0
- data/t/env.ru +4 -0
- data/t/fails-rack-lint.ru +6 -0
- data/t/heartbeat-timeout.ru +13 -0
- data/t/heartbeat-timeout.t +60 -0
- data/t/integration.ru +129 -0
- data/t/integration.t +509 -0
- data/t/lib.perl +309 -0
- data/t/listener_names.ru +5 -0
- data/t/my-tap-lib.sh +201 -0
- data/t/oob_gc.ru +18 -0
- data/t/oob_gc_path.ru +18 -0
- data/t/pid.ru +4 -0
- data/t/preread_input.ru +23 -0
- data/t/reload-bad-config.t +49 -0
- data/t/reopen-logs.ru +14 -0
- data/t/reopen-logs.t +36 -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 +13 -0
- data/t/t0014-rewindable-input-true.sh +24 -0
- data/t/t0014.ru +13 -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 +14 -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 +64 -0
- data/t/working_directory.t +86 -0
- data/test/aggregate.rb +16 -0
- data/test/benchmark/README +60 -0
- data/test/benchmark/dd.ru +19 -0
- data/test/benchmark/ddstream.ru +51 -0
- data/test/benchmark/readinput.ru +41 -0
- data/test/benchmark/stack.ru +9 -0
- data/test/benchmark/uconnect.perl +66 -0
- data/test/exec/README +5 -0
- data/test/exec/test_exec.rb +1030 -0
- data/test/test_helper.rb +307 -0
- data/test/unit/test_configurator.rb +176 -0
- data/test/unit/test_droplet.rb +29 -0
- data/test/unit/test_http_parser.rb +885 -0
- data/test/unit/test_http_parser_ng.rb +715 -0
- data/test/unit/test_server.rb +245 -0
- data/test/unit/test_signals.rb +189 -0
- data/test/unit/test_socket_helper.rb +160 -0
- data/test/unit/test_stream_input.rb +211 -0
- data/test/unit/test_tee_input.rb +304 -0
- data/test/unit/test_util.rb +132 -0
- data/test/unit/test_waiter.rb +35 -0
- data/unicorn.gemspec +49 -0
- metadata +266 -0
data/test/test_helper.rb
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
# Copyright (c) 2005 Zed A. Shaw
|
5
|
+
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
6
|
+
# the GPLv2+ (GPLv3+ preferred)
|
7
|
+
#
|
8
|
+
# Additional work donated by contributors. See git history
|
9
|
+
# for more information.
|
10
|
+
|
11
|
+
STDIN.sync = STDOUT.sync = STDERR.sync = true # buffering makes debugging hard
|
12
|
+
|
13
|
+
# FIXME: move curl-dependent tests into t/
|
14
|
+
ENV['NO_PROXY'] ||= ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
|
15
|
+
|
16
|
+
# Some tests watch a log file or a pid file to spring up to check state
|
17
|
+
# Can't rely on inotify on non-Linux and logging to a pipe makes things
|
18
|
+
# more complicated
|
19
|
+
DEFAULT_TRIES = 1000
|
20
|
+
DEFAULT_RES = 0.2
|
21
|
+
|
22
|
+
require 'test/unit'
|
23
|
+
require 'net/http'
|
24
|
+
require 'digest/sha1'
|
25
|
+
require 'uri'
|
26
|
+
require 'stringio'
|
27
|
+
require 'pathname'
|
28
|
+
require 'tempfile'
|
29
|
+
require 'fileutils'
|
30
|
+
require 'logger'
|
31
|
+
require 'unicorn'
|
32
|
+
require 'io/nonblock'
|
33
|
+
|
34
|
+
if ENV['DEBUG']
|
35
|
+
require 'ruby-debug'
|
36
|
+
Debugger.start
|
37
|
+
end
|
38
|
+
|
39
|
+
unless RUBY_VERSION < '3.1'
|
40
|
+
warn "Unicorn was only tested against MRI up to 3.0.\n" \
|
41
|
+
"It might not properly work with #{RUBY_VERSION}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def redirect_test_io
|
45
|
+
orig_err = STDERR.dup
|
46
|
+
orig_out = STDOUT.dup
|
47
|
+
rdr_pid = $$
|
48
|
+
new_out = File.open("test_stdout.#$$.log", "a")
|
49
|
+
new_err = File.open("test_stderr.#$$.log", "a")
|
50
|
+
new_out.sync = new_err.sync = true
|
51
|
+
|
52
|
+
if tail = ENV['TAIL'] # "tail -F" if GNU, "tail -f" otherwise
|
53
|
+
require 'shellwords'
|
54
|
+
cmd = tail.shellsplit
|
55
|
+
cmd << new_out.path
|
56
|
+
cmd << new_err.path
|
57
|
+
pid = Process.spawn(*cmd, { 1 => 2, :pgroup => true })
|
58
|
+
sleep 0.1 # wait for tail(1) to startup
|
59
|
+
end
|
60
|
+
STDERR.reopen(new_err)
|
61
|
+
STDOUT.reopen(new_out)
|
62
|
+
STDERR.sync = STDOUT.sync = true
|
63
|
+
|
64
|
+
at_exit do
|
65
|
+
if rdr_pid == $$
|
66
|
+
File.unlink(new_out.path) rescue nil
|
67
|
+
File.unlink(new_err.path) rescue nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
yield
|
73
|
+
ensure
|
74
|
+
STDERR.reopen(orig_err)
|
75
|
+
STDOUT.reopen(orig_out)
|
76
|
+
Process.kill(:TERM, pid) if pid
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# which(1) exit codes cannot be trusted on some systems
|
81
|
+
# We use UNIX shell utilities in some tests because we don't trust
|
82
|
+
# ourselves to write Ruby 100% correctly :)
|
83
|
+
def which(bin)
|
84
|
+
ex = ENV['PATH'].split(/:/).detect do |x|
|
85
|
+
x << "/#{bin}"
|
86
|
+
File.executable?(x)
|
87
|
+
end or warn "`#{bin}' not found in PATH=#{ENV['PATH']}"
|
88
|
+
ex
|
89
|
+
end
|
90
|
+
|
91
|
+
# Either takes a string to do a get request against, or a tuple of [URI, HTTP] where
|
92
|
+
# HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.)
|
93
|
+
def hit(uris)
|
94
|
+
results = []
|
95
|
+
uris.each do |u|
|
96
|
+
res = nil
|
97
|
+
|
98
|
+
if u.kind_of? String
|
99
|
+
u = 'http://127.0.0.1:8080/' if u == 'http://0.0.0.0:8080/'
|
100
|
+
res = Net::HTTP.get(URI.parse(u))
|
101
|
+
else
|
102
|
+
url = URI.parse(u[0])
|
103
|
+
res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) }
|
104
|
+
end
|
105
|
+
|
106
|
+
assert res != nil, "Didn't get a response: #{u}"
|
107
|
+
results << res
|
108
|
+
end
|
109
|
+
|
110
|
+
return results
|
111
|
+
end
|
112
|
+
|
113
|
+
# unused_port provides an unused port on +addr+ usable for TCP that is
|
114
|
+
# guaranteed to be unused across all unicorn builds on that system. It
|
115
|
+
# prevents race conditions by using a lock file other unicorn builds
|
116
|
+
# will see. This is required if you perform several builds in parallel
|
117
|
+
# with a continuous integration system or run tests in parallel via
|
118
|
+
# gmake. This is NOT guaranteed to be race-free if you run other
|
119
|
+
# processes that bind to random ports for testing (but the window
|
120
|
+
# for a race condition is very small). You may also set UNICORN_TEST_ADDR
|
121
|
+
# to override the default test address (127.0.0.1).
|
122
|
+
def unused_port(addr = '127.0.0.1')
|
123
|
+
retries = 100
|
124
|
+
base = 5000
|
125
|
+
port = sock = nil
|
126
|
+
begin
|
127
|
+
begin
|
128
|
+
port = base + rand(32768 - base)
|
129
|
+
while port == Unicorn::Const::DEFAULT_PORT
|
130
|
+
port = base + rand(32768 - base)
|
131
|
+
end
|
132
|
+
|
133
|
+
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
134
|
+
sock.bind(Socket.pack_sockaddr_in(port, addr))
|
135
|
+
sock.listen(5)
|
136
|
+
rescue Errno::EADDRINUSE, Errno::EACCES
|
137
|
+
sock.close rescue nil
|
138
|
+
retry if (retries -= 1) >= 0
|
139
|
+
end
|
140
|
+
|
141
|
+
# since we'll end up closing the random port we just got, there's a race
|
142
|
+
# condition could allow the random port we just chose to reselect itself
|
143
|
+
# when running tests in parallel with gmake. Create a lock file while
|
144
|
+
# we have the port here to ensure that does not happen .
|
145
|
+
lock_path = "#{Dir::tmpdir}/unicorn_test.#{addr}:#{port}.lock"
|
146
|
+
File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600).close
|
147
|
+
at_exit { File.unlink(lock_path) rescue nil }
|
148
|
+
rescue Errno::EEXIST
|
149
|
+
sock.close rescue nil
|
150
|
+
retry
|
151
|
+
end
|
152
|
+
sock.close rescue nil
|
153
|
+
port
|
154
|
+
end
|
155
|
+
|
156
|
+
def try_require(lib)
|
157
|
+
begin
|
158
|
+
require lib
|
159
|
+
true
|
160
|
+
rescue LoadError
|
161
|
+
false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# sometimes the server may not come up right away
|
166
|
+
def retry_hit(uris = [])
|
167
|
+
tries = DEFAULT_TRIES
|
168
|
+
begin
|
169
|
+
hit(uris)
|
170
|
+
rescue Errno::EINVAL, Errno::ECONNREFUSED => err
|
171
|
+
if (tries -= 1) > 0
|
172
|
+
sleep DEFAULT_RES
|
173
|
+
retry
|
174
|
+
end
|
175
|
+
raise err
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def assert_shutdown(pid)
|
180
|
+
wait_master_ready("test_stderr.#{pid}.log")
|
181
|
+
Process.kill(:QUIT, pid)
|
182
|
+
pid, status = Process.waitpid2(pid)
|
183
|
+
assert status.success?, "exited successfully"
|
184
|
+
end
|
185
|
+
|
186
|
+
def wait_workers_ready(path, nr_workers)
|
187
|
+
tries = DEFAULT_TRIES
|
188
|
+
lines = []
|
189
|
+
while (tries -= 1) > 0
|
190
|
+
begin
|
191
|
+
lines = File.readlines(path).grep(/worker=\d+ ready/)
|
192
|
+
lines.size == nr_workers and return
|
193
|
+
rescue Errno::ENOENT
|
194
|
+
end
|
195
|
+
sleep DEFAULT_RES
|
196
|
+
end
|
197
|
+
raise "#{nr_workers} workers never became ready:" \
|
198
|
+
"\n\t#{lines.join("\n\t")}\n"
|
199
|
+
end
|
200
|
+
|
201
|
+
def wait_master_ready(master_log)
|
202
|
+
tries = DEFAULT_TRIES
|
203
|
+
while (tries -= 1) > 0
|
204
|
+
begin
|
205
|
+
File.readlines(master_log).grep(/master process ready/)[0] and return
|
206
|
+
rescue Errno::ENOENT
|
207
|
+
end
|
208
|
+
sleep DEFAULT_RES
|
209
|
+
end
|
210
|
+
raise "master process never became ready"
|
211
|
+
end
|
212
|
+
|
213
|
+
def reexec_usr2_quit_test(pid, pid_file)
|
214
|
+
assert File.exist?(pid_file), "pid file OK"
|
215
|
+
assert ! File.exist?("#{pid_file}.oldbin"), "oldbin pid file"
|
216
|
+
Process.kill(:USR2, pid)
|
217
|
+
retry_hit(["http://#{@addr}:#{@port}/"])
|
218
|
+
wait_for_file("#{pid_file}.oldbin")
|
219
|
+
wait_for_file(pid_file)
|
220
|
+
|
221
|
+
old_pid = File.read("#{pid_file}.oldbin").to_i
|
222
|
+
new_pid = File.read(pid_file).to_i
|
223
|
+
|
224
|
+
# kill old master process
|
225
|
+
assert_not_equal pid, new_pid
|
226
|
+
assert_equal pid, old_pid
|
227
|
+
Process.kill(:QUIT, old_pid)
|
228
|
+
retry_hit(["http://#{@addr}:#{@port}/"])
|
229
|
+
wait_for_death(old_pid)
|
230
|
+
assert_equal new_pid, File.read(pid_file).to_i
|
231
|
+
retry_hit(["http://#{@addr}:#{@port}/"])
|
232
|
+
Process.kill(:QUIT, new_pid)
|
233
|
+
end
|
234
|
+
|
235
|
+
def reexec_basic_test(pid, pid_file)
|
236
|
+
results = retry_hit(["http://#{@addr}:#{@port}/"])
|
237
|
+
assert_equal String, results[0].class
|
238
|
+
Process.kill(0, pid)
|
239
|
+
master_log = "#{@tmpdir}/test_stderr.#{pid}.log"
|
240
|
+
wait_master_ready(master_log)
|
241
|
+
File.truncate(master_log, 0)
|
242
|
+
nr = 50
|
243
|
+
kill_point = 2
|
244
|
+
nr.times do |i|
|
245
|
+
hit(["http://#{@addr}:#{@port}/#{i}"])
|
246
|
+
i == kill_point and Process.kill(:HUP, pid)
|
247
|
+
end
|
248
|
+
wait_master_ready(master_log)
|
249
|
+
assert File.exist?(pid_file), "pid=#{pid_file} exists"
|
250
|
+
new_pid = File.read(pid_file).to_i
|
251
|
+
assert_not_equal pid, new_pid
|
252
|
+
Process.kill(0, new_pid)
|
253
|
+
Process.kill(:QUIT, new_pid)
|
254
|
+
end
|
255
|
+
|
256
|
+
def wait_for_file(path)
|
257
|
+
tries = DEFAULT_TRIES
|
258
|
+
while (tries -= 1) > 0 && ! File.exist?(path)
|
259
|
+
sleep DEFAULT_RES
|
260
|
+
end
|
261
|
+
assert File.exist?(path), "path=#{path} exists #{caller.inspect}"
|
262
|
+
end
|
263
|
+
|
264
|
+
def xfork(&block)
|
265
|
+
fork do
|
266
|
+
ObjectSpace.each_object(Tempfile) do |tmp|
|
267
|
+
ObjectSpace.undefine_finalizer(tmp)
|
268
|
+
end
|
269
|
+
yield
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# can't waitpid on detached processes
|
274
|
+
def wait_for_death(pid)
|
275
|
+
tries = DEFAULT_TRIES
|
276
|
+
while (tries -= 1) > 0
|
277
|
+
begin
|
278
|
+
Process.kill(0, pid)
|
279
|
+
begin
|
280
|
+
Process.waitpid(pid, Process::WNOHANG)
|
281
|
+
rescue Errno::ECHILD
|
282
|
+
end
|
283
|
+
sleep(DEFAULT_RES)
|
284
|
+
rescue Errno::ESRCH
|
285
|
+
return
|
286
|
+
end
|
287
|
+
end
|
288
|
+
raise "PID:#{pid} never died!"
|
289
|
+
end
|
290
|
+
|
291
|
+
def reset_sig_handlers
|
292
|
+
%w(WINCH QUIT INT TERM USR1 USR2 HUP TTIN TTOU CHLD).each do |sig|
|
293
|
+
trap(sig, "DEFAULT")
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def tcp_socket(*args)
|
298
|
+
sock = TCPSocket.new(*args)
|
299
|
+
sock.nonblock = false
|
300
|
+
sock
|
301
|
+
end
|
302
|
+
|
303
|
+
def unix_socket(*args)
|
304
|
+
sock = UNIXSocket.new(*args)
|
305
|
+
sock.nonblock = false
|
306
|
+
sock
|
307
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'unicorn'
|
7
|
+
|
8
|
+
TestStruct = Struct.new(
|
9
|
+
*(Unicorn::Configurator::DEFAULTS.keys + %w(listener_opts listeners)))
|
10
|
+
class TestConfigurator < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_config_init
|
13
|
+
Unicorn::Configurator.new {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_expand_addr
|
17
|
+
meth = Unicorn::Configurator.new.method(:expand_addr)
|
18
|
+
|
19
|
+
assert_equal "/var/run/unicorn.sock", meth.call("/var/run/unicorn.sock")
|
20
|
+
assert_equal "#{Dir.pwd}/foo/bar.sock", meth.call("unix:foo/bar.sock")
|
21
|
+
|
22
|
+
path = meth.call("~/foo/bar.sock")
|
23
|
+
assert_equal "/", path[0..0]
|
24
|
+
assert_match %r{/foo/bar\.sock\z}, path
|
25
|
+
|
26
|
+
path = meth.call("~root/foo/bar.sock")
|
27
|
+
assert_equal "/", path[0..0]
|
28
|
+
assert_match %r{/foo/bar\.sock\z}, path
|
29
|
+
|
30
|
+
assert_equal "1.2.3.4:2007", meth.call('1.2.3.4:2007')
|
31
|
+
assert_equal "0.0.0.0:2007", meth.call('0.0.0.0:2007')
|
32
|
+
assert_equal "0.0.0.0:2007", meth.call(':2007')
|
33
|
+
assert_equal "0.0.0.0:2007", meth.call('*:2007')
|
34
|
+
assert_equal "0.0.0.0:2007", meth.call('2007')
|
35
|
+
assert_equal "0.0.0.0:2007", meth.call(2007)
|
36
|
+
|
37
|
+
%w([::1]:2007 [::]:2007).each do |addr|
|
38
|
+
assert_equal addr, meth.call(addr.dup)
|
39
|
+
end
|
40
|
+
|
41
|
+
# for Rainbows! users only
|
42
|
+
assert_equal "[::]:80", meth.call("[::]")
|
43
|
+
assert_equal "127.6.6.6:80", meth.call("127.6.6.6")
|
44
|
+
|
45
|
+
# the next two aren't portable, consider them unsupported for now
|
46
|
+
# assert_match %r{\A\d+\.\d+\.\d+\.\d+:2007\z}, meth.call('1:2007')
|
47
|
+
# assert_match %r{\A\d+\.\d+\.\d+\.\d+:2007\z}, meth.call('2:2007')
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_config_invalid
|
51
|
+
tmp = Tempfile.new('unicorn_config')
|
52
|
+
tmp.syswrite(%q(asdfasdf "hello-world"))
|
53
|
+
assert_raises(NoMethodError) do
|
54
|
+
Unicorn::Configurator.new(:config_file => tmp.path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_config_non_existent
|
59
|
+
tmp = Tempfile.new('unicorn_config')
|
60
|
+
path = tmp.path
|
61
|
+
tmp.close!
|
62
|
+
assert_raises(Errno::ENOENT) do
|
63
|
+
Unicorn::Configurator.new(:config_file => path)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_config_defaults
|
68
|
+
cfg = Unicorn::Configurator.new(:use_defaults => true)
|
69
|
+
test_struct = TestStruct.new
|
70
|
+
cfg.commit!(test_struct)
|
71
|
+
Unicorn::Configurator::DEFAULTS.each do |key,value|
|
72
|
+
assert_equal value, test_struct.__send__(key)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_config_defaults_skip
|
77
|
+
cfg = Unicorn::Configurator.new(:use_defaults => true)
|
78
|
+
skip = [ :logger ]
|
79
|
+
test_struct = TestStruct.new
|
80
|
+
cfg.commit!(test_struct, :skip => skip)
|
81
|
+
Unicorn::Configurator::DEFAULTS.each do |key,value|
|
82
|
+
next if skip.include?(key)
|
83
|
+
assert_equal value, test_struct.__send__(key)
|
84
|
+
end
|
85
|
+
assert_nil test_struct.logger
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_listen_options
|
89
|
+
tmp = Tempfile.new('unicorn_config')
|
90
|
+
expect = { :sndbuf => 1, :rcvbuf => 2, :backlog => 10 }.freeze
|
91
|
+
listener = "127.0.0.1:12345"
|
92
|
+
tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
|
93
|
+
cfg = Unicorn::Configurator.new(:config_file => tmp.path)
|
94
|
+
test_struct = TestStruct.new
|
95
|
+
cfg.commit!(test_struct)
|
96
|
+
assert(listener_opts = test_struct.listener_opts)
|
97
|
+
assert_equal expect, listener_opts[listener]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_listen_option_bad
|
101
|
+
tmp = Tempfile.new('unicorn_config')
|
102
|
+
expect = { :sndbuf => "five" }
|
103
|
+
listener = "127.0.0.1:12345"
|
104
|
+
tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
|
105
|
+
assert_raises(ArgumentError) do
|
106
|
+
Unicorn::Configurator.new(:config_file => tmp.path)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_listen_option_bad_delay
|
111
|
+
tmp = Tempfile.new('unicorn_config')
|
112
|
+
expect = { :delay => "five" }
|
113
|
+
listener = "127.0.0.1:12345"
|
114
|
+
tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
|
115
|
+
assert_raises(ArgumentError) do
|
116
|
+
Unicorn::Configurator.new(:config_file => tmp.path)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_listen_option_float_delay
|
121
|
+
tmp = Tempfile.new('unicorn_config')
|
122
|
+
expect = { :delay => 0.5 }
|
123
|
+
listener = "127.0.0.1:12345"
|
124
|
+
tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
|
125
|
+
Unicorn::Configurator.new(:config_file => tmp.path)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_listen_option_int_delay
|
129
|
+
tmp = Tempfile.new('unicorn_config')
|
130
|
+
expect = { :delay => 5 }
|
131
|
+
listener = "127.0.0.1:12345"
|
132
|
+
tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
|
133
|
+
Unicorn::Configurator.new(:config_file => tmp.path)
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_check_client_connection
|
137
|
+
tmp = Tempfile.new('unicorn_config')
|
138
|
+
test_struct = TestStruct.new
|
139
|
+
tmp.syswrite("check_client_connection true\n")
|
140
|
+
|
141
|
+
assert_nothing_raised do
|
142
|
+
Unicorn::Configurator.new(:config_file => tmp.path).commit!(test_struct)
|
143
|
+
end
|
144
|
+
|
145
|
+
assert test_struct.check_client_connection
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_check_client_connection_with_tcp_bad
|
149
|
+
tmp = Tempfile.new('unicorn_config')
|
150
|
+
test_struct = TestStruct.new
|
151
|
+
listener = "127.0.0.1:12345"
|
152
|
+
tmp.syswrite("check_client_connection true\n")
|
153
|
+
tmp.syswrite("listen '#{listener}', :tcp_nopush => true\n")
|
154
|
+
|
155
|
+
assert_raises(ArgumentError) do
|
156
|
+
Unicorn::Configurator.new(:config_file => tmp.path).commit!(test_struct)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_after_fork_proc
|
161
|
+
test_struct = TestStruct.new
|
162
|
+
[ proc { |a,b| }, Proc.new { |a,b| }, lambda { |a,b| } ].each do |my_proc|
|
163
|
+
Unicorn::Configurator.new(:after_fork => my_proc).commit!(test_struct)
|
164
|
+
assert_equal my_proc, test_struct.after_fork
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_after_fork_wrong_arity
|
169
|
+
[ proc { |a| }, Proc.new { }, lambda { |a,b,c| } ].each do |my_proc|
|
170
|
+
assert_raises(ArgumentError) do
|
171
|
+
Unicorn::Configurator.new(:after_fork => my_proc)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require 'test/unit'
|
3
|
+
require 'unicorn'
|
4
|
+
|
5
|
+
class TestDroplet < Test::Unit::TestCase
|
6
|
+
def test_create_many_droplets
|
7
|
+
now = Time.now.to_i
|
8
|
+
(0..1024).each do |i|
|
9
|
+
droplet = Unicorn::Worker.new(i)
|
10
|
+
assert droplet.respond_to?(:tick)
|
11
|
+
assert_equal 0, droplet.tick
|
12
|
+
assert_equal(now, droplet.tick = now)
|
13
|
+
assert_equal now, droplet.tick
|
14
|
+
assert_equal(0, droplet.tick = 0)
|
15
|
+
assert_equal 0, droplet.tick
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_shared_process
|
20
|
+
droplet = Unicorn::Worker.new(0)
|
21
|
+
_, status = Process.waitpid2(fork { droplet.tick += 1; exit!(0) })
|
22
|
+
assert status.success?, status.inspect
|
23
|
+
assert_equal 1, droplet.tick
|
24
|
+
|
25
|
+
_, status = Process.waitpid2(fork { droplet.tick += 1; exit!(0) })
|
26
|
+
assert status.success?, status.inspect
|
27
|
+
assert_equal 2, droplet.tick
|
28
|
+
end
|
29
|
+
end
|