boourns-unicorn 4.4.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 (155) hide show
  1. data/.CHANGELOG.old +25 -0
  2. data/.document +29 -0
  3. data/.gitignore +24 -0
  4. data/.mailmap +26 -0
  5. data/.wrongdoc.yml +10 -0
  6. data/Application_Timeouts +77 -0
  7. data/CONTRIBUTORS +35 -0
  8. data/COPYING +674 -0
  9. data/DESIGN +97 -0
  10. data/Documentation/.gitignore +5 -0
  11. data/Documentation/GNUmakefile +30 -0
  12. data/Documentation/unicorn.1.txt +174 -0
  13. data/Documentation/unicorn_rails.1.txt +175 -0
  14. data/FAQ +53 -0
  15. data/GIT-VERSION-GEN +40 -0
  16. data/GNUmakefile +267 -0
  17. data/HACKING +134 -0
  18. data/ISSUES +36 -0
  19. data/KNOWN_ISSUES +79 -0
  20. data/LICENSE +64 -0
  21. data/Links +56 -0
  22. data/PHILOSOPHY +145 -0
  23. data/README +149 -0
  24. data/Rakefile +97 -0
  25. data/SIGNALS +114 -0
  26. data/Sandbox +96 -0
  27. data/TODO +5 -0
  28. data/TUNING +98 -0
  29. data/bin/unicorn +121 -0
  30. data/bin/unicorn_rails +209 -0
  31. data/examples/big_app_gc.rb +2 -0
  32. data/examples/echo.ru +27 -0
  33. data/examples/git.ru +13 -0
  34. data/examples/init.sh +74 -0
  35. data/examples/logger_mp_safe.rb +25 -0
  36. data/examples/logrotate.conf +29 -0
  37. data/examples/nginx.conf +156 -0
  38. data/examples/unicorn.conf.minimal.rb +13 -0
  39. data/examples/unicorn.conf.rb +94 -0
  40. data/ext/unicorn_http/CFLAGS +13 -0
  41. data/ext/unicorn_http/c_util.h +124 -0
  42. data/ext/unicorn_http/common_field_optimization.h +111 -0
  43. data/ext/unicorn_http/ext_help.h +86 -0
  44. data/ext/unicorn_http/extconf.rb +10 -0
  45. data/ext/unicorn_http/global_variables.h +97 -0
  46. data/ext/unicorn_http/httpdate.c +82 -0
  47. data/ext/unicorn_http/unicorn_http.rl +1036 -0
  48. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  49. data/lib/unicorn.rb +107 -0
  50. data/lib/unicorn/app/exec_cgi.rb +154 -0
  51. data/lib/unicorn/app/inetd.rb +109 -0
  52. data/lib/unicorn/app/old_rails.rb +35 -0
  53. data/lib/unicorn/app/old_rails/static.rb +59 -0
  54. data/lib/unicorn/cgi_wrapper.rb +147 -0
  55. data/lib/unicorn/configurator.rb +630 -0
  56. data/lib/unicorn/const.rb +40 -0
  57. data/lib/unicorn/http_request.rb +83 -0
  58. data/lib/unicorn/http_response.rb +45 -0
  59. data/lib/unicorn/http_server.rb +755 -0
  60. data/lib/unicorn/launcher.rb +62 -0
  61. data/lib/unicorn/oob_gc.rb +71 -0
  62. data/lib/unicorn/preread_input.rb +33 -0
  63. data/lib/unicorn/socket_helper.rb +208 -0
  64. data/lib/unicorn/ssl_client.rb +11 -0
  65. data/lib/unicorn/ssl_configurator.rb +104 -0
  66. data/lib/unicorn/ssl_server.rb +42 -0
  67. data/lib/unicorn/stream_input.rb +149 -0
  68. data/lib/unicorn/tee_input.rb +126 -0
  69. data/lib/unicorn/tmpio.rb +29 -0
  70. data/lib/unicorn/util.rb +69 -0
  71. data/lib/unicorn/worker.rb +88 -0
  72. data/local.mk.sample +59 -0
  73. data/script/isolate_for_tests +32 -0
  74. data/setup.rb +1586 -0
  75. data/t/.gitignore +5 -0
  76. data/t/GNUmakefile +82 -0
  77. data/t/README +42 -0
  78. data/t/bin/content-md5-put +36 -0
  79. data/t/bin/sha1sum.rb +17 -0
  80. data/t/bin/unused_listen +40 -0
  81. data/t/bin/utee +12 -0
  82. data/t/broken-app.ru +12 -0
  83. data/t/detach.ru +11 -0
  84. data/t/env.ru +3 -0
  85. data/t/heartbeat-timeout.ru +12 -0
  86. data/t/listener_names.ru +4 -0
  87. data/t/my-tap-lib.sh +201 -0
  88. data/t/oob_gc.ru +21 -0
  89. data/t/oob_gc_path.ru +21 -0
  90. data/t/pid.ru +3 -0
  91. data/t/preread_input.ru +17 -0
  92. data/t/rack-input-tests.ru +21 -0
  93. data/t/sslgen.sh +71 -0
  94. data/t/t0000-http-basic.sh +50 -0
  95. data/t/t0001-reload-bad-config.sh +53 -0
  96. data/t/t0002-config-conflict.sh +49 -0
  97. data/t/t0002-parser-error.sh +94 -0
  98. data/t/t0003-working_directory.sh +51 -0
  99. data/t/t0004-heartbeat-timeout.sh +69 -0
  100. data/t/t0004-working_directory_broken.sh +24 -0
  101. data/t/t0005-working_directory_app.rb.sh +37 -0
  102. data/t/t0006-reopen-logs.sh +83 -0
  103. data/t/t0006.ru +13 -0
  104. data/t/t0007-working_directory_no_embed_cli.sh +44 -0
  105. data/t/t0008-back_out_of_upgrade.sh +110 -0
  106. data/t/t0009-broken-app.sh +56 -0
  107. data/t/t0009-winch_ttin.sh +59 -0
  108. data/t/t0010-reap-logging.sh +55 -0
  109. data/t/t0011-active-unix-socket.sh +79 -0
  110. data/t/t0012-reload-empty-config.sh +85 -0
  111. data/t/t0013-rewindable-input-false.sh +24 -0
  112. data/t/t0013.ru +12 -0
  113. data/t/t0014-rewindable-input-true.sh +24 -0
  114. data/t/t0014.ru +12 -0
  115. data/t/t0015-configurator-internals.sh +25 -0
  116. data/t/t0016-trust-x-forwarded-false.sh +30 -0
  117. data/t/t0017-trust-x-forwarded-true.sh +30 -0
  118. data/t/t0018-write-on-close.sh +23 -0
  119. data/t/t0019-max_header_len.sh +49 -0
  120. data/t/t0020-at_exit-handler.sh +49 -0
  121. data/t/t0021-process_detach.sh +29 -0
  122. data/t/t0022-listener_names-preload_app.sh +32 -0
  123. data/t/t0100-rack-input-tests.sh +124 -0
  124. data/t/t0116-client_body_buffer_size.sh +80 -0
  125. data/t/t0116.ru +16 -0
  126. data/t/t0600-https-server-basic.sh +48 -0
  127. data/t/t9000-preread-input.sh +48 -0
  128. data/t/t9001-oob_gc.sh +47 -0
  129. data/t/t9002-oob_gc-path.sh +75 -0
  130. data/t/test-lib.sh +113 -0
  131. data/t/write-on-close.ru +11 -0
  132. data/test/aggregate.rb +15 -0
  133. data/test/benchmark/README +50 -0
  134. data/test/benchmark/dd.ru +18 -0
  135. data/test/benchmark/stack.ru +8 -0
  136. data/test/exec/README +5 -0
  137. data/test/exec/test_exec.rb +1041 -0
  138. data/test/test_helper.rb +300 -0
  139. data/test/unit/test_configurator.rb +158 -0
  140. data/test/unit/test_droplet.rb +28 -0
  141. data/test/unit/test_http_parser.rb +860 -0
  142. data/test/unit/test_http_parser_ng.rb +716 -0
  143. data/test/unit/test_http_parser_xftrust.rb +38 -0
  144. data/test/unit/test_request.rb +197 -0
  145. data/test/unit/test_response.rb +99 -0
  146. data/test/unit/test_server.rb +289 -0
  147. data/test/unit/test_signals.rb +207 -0
  148. data/test/unit/test_sni_hostnames.rb +47 -0
  149. data/test/unit/test_socket_helper.rb +192 -0
  150. data/test/unit/test_stream_input.rb +204 -0
  151. data/test/unit/test_tee_input.rb +296 -0
  152. data/test/unit/test_upload.rb +306 -0
  153. data/test/unit/test_util.rb +99 -0
  154. data/unicorn.gemspec +44 -0
  155. metadata +333 -0
@@ -0,0 +1,300 @@
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 GPLv3
6
+ #
7
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
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
+ assert_nothing_raised { Process.kill(:QUIT, pid) }
159
+ status = nil
160
+ assert_nothing_raised { pid, status = Process.waitpid2(pid) }
161
+ assert status.success?, "exited successfully"
162
+ end
163
+
164
+ def wait_workers_ready(path, nr_workers)
165
+ tries = DEFAULT_TRIES
166
+ lines = []
167
+ while (tries -= 1) > 0
168
+ begin
169
+ lines = File.readlines(path).grep(/worker=\d+ ready/)
170
+ lines.size == nr_workers and return
171
+ rescue Errno::ENOENT
172
+ end
173
+ sleep DEFAULT_RES
174
+ end
175
+ raise "#{nr_workers} workers never became ready:" \
176
+ "\n\t#{lines.join("\n\t")}\n"
177
+ end
178
+
179
+ def wait_master_ready(master_log)
180
+ tries = DEFAULT_TRIES
181
+ while (tries -= 1) > 0
182
+ begin
183
+ File.readlines(master_log).grep(/master process ready/)[0] and return
184
+ rescue Errno::ENOENT
185
+ end
186
+ sleep DEFAULT_RES
187
+ end
188
+ raise "master process never became ready"
189
+ end
190
+
191
+ def reexec_usr2_quit_test(pid, pid_file)
192
+ assert File.exist?(pid_file), "pid file OK"
193
+ assert ! File.exist?("#{pid_file}.oldbin"), "oldbin pid file"
194
+ assert_nothing_raised { Process.kill(:USR2, pid) }
195
+ assert_nothing_raised { retry_hit(["http://#{@addr}:#{@port}/"]) }
196
+ wait_for_file("#{pid_file}.oldbin")
197
+ wait_for_file(pid_file)
198
+
199
+ old_pid = File.read("#{pid_file}.oldbin").to_i
200
+ new_pid = File.read(pid_file).to_i
201
+
202
+ # kill old master process
203
+ assert_not_equal pid, new_pid
204
+ assert_equal pid, old_pid
205
+ assert_nothing_raised { Process.kill(:QUIT, old_pid) }
206
+ assert_nothing_raised { retry_hit(["http://#{@addr}:#{@port}/"]) }
207
+ wait_for_death(old_pid)
208
+ assert_equal new_pid, File.read(pid_file).to_i
209
+ assert_nothing_raised { retry_hit(["http://#{@addr}:#{@port}/"]) }
210
+ assert_nothing_raised { Process.kill(:QUIT, new_pid) }
211
+ end
212
+
213
+ def reexec_basic_test(pid, pid_file)
214
+ results = retry_hit(["http://#{@addr}:#{@port}/"])
215
+ assert_equal String, results[0].class
216
+ assert_nothing_raised { Process.kill(0, pid) }
217
+ master_log = "#{@tmpdir}/test_stderr.#{pid}.log"
218
+ wait_master_ready(master_log)
219
+ File.truncate(master_log, 0)
220
+ nr = 50
221
+ kill_point = 2
222
+ assert_nothing_raised do
223
+ nr.times do |i|
224
+ hit(["http://#{@addr}:#{@port}/#{i}"])
225
+ i == kill_point and Process.kill(:HUP, pid)
226
+ end
227
+ end
228
+ wait_master_ready(master_log)
229
+ assert File.exist?(pid_file), "pid=#{pid_file} exists"
230
+ new_pid = File.read(pid_file).to_i
231
+ assert_not_equal pid, new_pid
232
+ assert_nothing_raised { Process.kill(0, new_pid) }
233
+ assert_nothing_raised { Process.kill(:QUIT, new_pid) }
234
+ end
235
+
236
+ def wait_for_file(path)
237
+ tries = DEFAULT_TRIES
238
+ while (tries -= 1) > 0 && ! File.exist?(path)
239
+ sleep DEFAULT_RES
240
+ end
241
+ assert File.exist?(path), "path=#{path} exists #{caller.inspect}"
242
+ end
243
+
244
+ def xfork(&block)
245
+ fork do
246
+ ObjectSpace.each_object(Tempfile) do |tmp|
247
+ ObjectSpace.undefine_finalizer(tmp)
248
+ end
249
+ yield
250
+ end
251
+ end
252
+
253
+ # can't waitpid on detached processes
254
+ def wait_for_death(pid)
255
+ tries = DEFAULT_TRIES
256
+ while (tries -= 1) > 0
257
+ begin
258
+ Process.kill(0, pid)
259
+ begin
260
+ Process.waitpid(pid, Process::WNOHANG)
261
+ rescue Errno::ECHILD
262
+ end
263
+ sleep(DEFAULT_RES)
264
+ rescue Errno::ESRCH
265
+ return
266
+ end
267
+ end
268
+ raise "PID:#{pid} never died!"
269
+ end
270
+
271
+ # executes +cmd+ and chunks its STDOUT
272
+ def chunked_spawn(stdout, *cmd)
273
+ fork {
274
+ crd, cwr = IO.pipe
275
+ crd.binmode
276
+ cwr.binmode
277
+ crd.sync = cwr.sync = true
278
+
279
+ pid = fork {
280
+ STDOUT.reopen(cwr)
281
+ crd.close
282
+ cwr.close
283
+ exec(*cmd)
284
+ }
285
+ cwr.close
286
+ begin
287
+ buf = crd.readpartial(16384)
288
+ stdout.write("#{'%x' % buf.size}\r\n#{buf}")
289
+ rescue EOFError
290
+ stdout.write("0\r\n")
291
+ pid, status = Process.waitpid(pid)
292
+ exit status.exitstatus
293
+ end while true
294
+ }
295
+ end
296
+
297
+ def reset_sig_handlers
298
+ sigs = %w(CHLD).concat(Unicorn::HttpServer::QUEUE_SIGS)
299
+ sigs.each { |sig| trap(sig, "DEFAULT") }
300
+ end
@@ -0,0 +1,158 @@
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
+ assert_nothing_raised { 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
+ assert_nothing_raised { 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
+ assert_nothing_raised { 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 = nil
93
+ assert_nothing_raised do
94
+ cfg = Unicorn::Configurator.new(:config_file => tmp.path)
95
+ end
96
+ test_struct = TestStruct.new
97
+ assert_nothing_raised { cfg.commit!(test_struct) }
98
+ assert(listener_opts = test_struct.listener_opts)
99
+ assert_equal expect, listener_opts[listener]
100
+ end
101
+
102
+ def test_listen_option_bad
103
+ tmp = Tempfile.new('unicorn_config')
104
+ expect = { :sndbuf => "five" }
105
+ listener = "127.0.0.1:12345"
106
+ tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
107
+ assert_raises(ArgumentError) do
108
+ Unicorn::Configurator.new(:config_file => tmp.path)
109
+ end
110
+ end
111
+
112
+ def test_listen_option_bad_delay
113
+ tmp = Tempfile.new('unicorn_config')
114
+ expect = { :delay => "five" }
115
+ listener = "127.0.0.1:12345"
116
+ tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
117
+ assert_raises(ArgumentError) do
118
+ Unicorn::Configurator.new(:config_file => tmp.path)
119
+ end
120
+ end
121
+
122
+ def test_listen_option_float_delay
123
+ tmp = Tempfile.new('unicorn_config')
124
+ expect = { :delay => 0.5 }
125
+ listener = "127.0.0.1:12345"
126
+ tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
127
+ assert_nothing_raised do
128
+ Unicorn::Configurator.new(:config_file => tmp.path)
129
+ end
130
+ end
131
+
132
+ def test_listen_option_int_delay
133
+ tmp = Tempfile.new('unicorn_config')
134
+ expect = { :delay => 5 }
135
+ listener = "127.0.0.1:12345"
136
+ tmp.syswrite("listen '#{listener}', #{expect.inspect}\n")
137
+ assert_nothing_raised do
138
+ Unicorn::Configurator.new(:config_file => tmp.path)
139
+ end
140
+ end
141
+
142
+ def test_after_fork_proc
143
+ test_struct = TestStruct.new
144
+ [ proc { |a,b| }, Proc.new { |a,b| }, lambda { |a,b| } ].each do |my_proc|
145
+ Unicorn::Configurator.new(:after_fork => my_proc).commit!(test_struct)
146
+ assert_equal my_proc, test_struct.after_fork
147
+ end
148
+ end
149
+
150
+ def test_after_fork_wrong_arity
151
+ [ proc { |a| }, Proc.new { }, lambda { |a,b,c| } ].each do |my_proc|
152
+ assert_raises(ArgumentError) do
153
+ Unicorn::Configurator.new(:after_fork => my_proc)
154
+ end
155
+ end
156
+ end
157
+
158
+ end