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