unicorn-fork 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) 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 +144 -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 +318 -0
  20. data/HACKING +117 -0
  21. data/ISSUES +102 -0
  22. data/KNOWN_ISSUES +79 -0
  23. data/LICENSE +67 -0
  24. data/Links +58 -0
  25. data/PHILOSOPHY +139 -0
  26. data/README +165 -0
  27. data/Rakefile +17 -0
  28. data/SIGNALS +123 -0
  29. data/Sandbox +104 -0
  30. data/TODO +1 -0
  31. data/TUNING +119 -0
  32. data/archive/.gitignore +3 -0
  33. data/archive/slrnpull.conf +4 -0
  34. data/bin/unicorn +129 -0
  35. data/bin/unicorn_rails +210 -0
  36. data/examples/big_app_gc.rb +3 -0
  37. data/examples/echo.ru +27 -0
  38. data/examples/init.sh +102 -0
  39. data/examples/logger_mp_safe.rb +26 -0
  40. data/examples/logrotate.conf +44 -0
  41. data/examples/nginx.conf +156 -0
  42. data/examples/unicorn.conf.minimal.rb +14 -0
  43. data/examples/unicorn.conf.rb +111 -0
  44. data/examples/unicorn.socket +11 -0
  45. data/examples/unicorn@.service +40 -0
  46. data/ext/unicorn_http/CFLAGS +13 -0
  47. data/ext/unicorn_http/c_util.h +115 -0
  48. data/ext/unicorn_http/common_field_optimization.h +128 -0
  49. data/ext/unicorn_http/epollexclusive.h +128 -0
  50. data/ext/unicorn_http/ext_help.h +38 -0
  51. data/ext/unicorn_http/extconf.rb +40 -0
  52. data/ext/unicorn_http/global_variables.h +97 -0
  53. data/ext/unicorn_http/httpdate.c +91 -0
  54. data/ext/unicorn_http/unicorn_http.c +4348 -0
  55. data/ext/unicorn_http/unicorn_http.rl +1054 -0
  56. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  57. data/lib/unicorn/app/old_rails/static.rb +60 -0
  58. data/lib/unicorn/app/old_rails.rb +36 -0
  59. data/lib/unicorn/cgi_wrapper.rb +148 -0
  60. data/lib/unicorn/configurator.rb +749 -0
  61. data/lib/unicorn/const.rb +22 -0
  62. data/lib/unicorn/http_request.rb +180 -0
  63. data/lib/unicorn/http_response.rb +95 -0
  64. data/lib/unicorn/http_server.rb +860 -0
  65. data/lib/unicorn/launcher.rb +63 -0
  66. data/lib/unicorn/oob_gc.rb +82 -0
  67. data/lib/unicorn/preread_input.rb +34 -0
  68. data/lib/unicorn/select_waiter.rb +7 -0
  69. data/lib/unicorn/socket_helper.rb +186 -0
  70. data/lib/unicorn/stream_input.rb +152 -0
  71. data/lib/unicorn/tee_input.rb +132 -0
  72. data/lib/unicorn/tmpio.rb +34 -0
  73. data/lib/unicorn/util.rb +91 -0
  74. data/lib/unicorn/version.rb +1 -0
  75. data/lib/unicorn/worker.rb +166 -0
  76. data/lib/unicorn.rb +137 -0
  77. data/man/man1/unicorn.1 +222 -0
  78. data/man/man1/unicorn_rails.1 +207 -0
  79. data/setup.rb +1587 -0
  80. data/t/.gitignore +4 -0
  81. data/t/GNUmakefile +5 -0
  82. data/t/README +49 -0
  83. data/t/active-unix-socket.t +110 -0
  84. data/t/back-out-of-upgrade.t +44 -0
  85. data/t/bin/unused_listen +40 -0
  86. data/t/client_body_buffer_size.ru +15 -0
  87. data/t/client_body_buffer_size.t +79 -0
  88. data/t/detach.ru +12 -0
  89. data/t/env.ru +4 -0
  90. data/t/fails-rack-lint.ru +6 -0
  91. data/t/heartbeat-timeout.ru +13 -0
  92. data/t/heartbeat-timeout.t +60 -0
  93. data/t/integration.ru +129 -0
  94. data/t/integration.t +509 -0
  95. data/t/lib.perl +309 -0
  96. data/t/listener_names.ru +5 -0
  97. data/t/my-tap-lib.sh +201 -0
  98. data/t/oob_gc.ru +18 -0
  99. data/t/oob_gc_path.ru +18 -0
  100. data/t/pid.ru +4 -0
  101. data/t/preread_input.ru +23 -0
  102. data/t/reload-bad-config.t +49 -0
  103. data/t/reopen-logs.ru +14 -0
  104. data/t/reopen-logs.t +36 -0
  105. data/t/t0010-reap-logging.sh +55 -0
  106. data/t/t0012-reload-empty-config.sh +86 -0
  107. data/t/t0013-rewindable-input-false.sh +24 -0
  108. data/t/t0013.ru +13 -0
  109. data/t/t0014-rewindable-input-true.sh +24 -0
  110. data/t/t0014.ru +13 -0
  111. data/t/t0015-configurator-internals.sh +25 -0
  112. data/t/t0020-at_exit-handler.sh +49 -0
  113. data/t/t0021-process_detach.sh +29 -0
  114. data/t/t0022-listener_names-preload_app.sh +32 -0
  115. data/t/t0300-no-default-middleware.sh +20 -0
  116. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  117. data/t/t0301.ru +14 -0
  118. data/t/t9001-oob_gc.sh +47 -0
  119. data/t/t9002-oob_gc-path.sh +75 -0
  120. data/t/test-lib.sh +125 -0
  121. data/t/winch_ttin.t +64 -0
  122. data/t/working_directory.t +86 -0
  123. data/test/aggregate.rb +16 -0
  124. data/test/benchmark/README +60 -0
  125. data/test/benchmark/dd.ru +19 -0
  126. data/test/benchmark/ddstream.ru +51 -0
  127. data/test/benchmark/readinput.ru +41 -0
  128. data/test/benchmark/stack.ru +9 -0
  129. data/test/benchmark/uconnect.perl +66 -0
  130. data/test/exec/README +5 -0
  131. data/test/exec/test_exec.rb +1030 -0
  132. data/test/test_helper.rb +307 -0
  133. data/test/unit/test_configurator.rb +176 -0
  134. data/test/unit/test_droplet.rb +29 -0
  135. data/test/unit/test_http_parser.rb +885 -0
  136. data/test/unit/test_http_parser_ng.rb +715 -0
  137. data/test/unit/test_server.rb +245 -0
  138. data/test/unit/test_signals.rb +189 -0
  139. data/test/unit/test_socket_helper.rb +160 -0
  140. data/test/unit/test_stream_input.rb +211 -0
  141. data/test/unit/test_tee_input.rb +304 -0
  142. data/test/unit/test_util.rb +132 -0
  143. data/test/unit/test_waiter.rb +35 -0
  144. data/unicorn.gemspec +49 -0
  145. metadata +266 -0
@@ -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