unicorn 0.91.0 → 0.92.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.
- data/{CHANGELOG → .CHANGELOG.old} +0 -0
- data/.document +4 -0
- data/.gitignore +5 -0
- data/.mailmap +26 -0
- data/CONTRIBUTORS +1 -1
- data/Documentation/.gitignore +5 -0
- data/Documentation/GNUmakefile +30 -0
- data/Documentation/unicorn.1.txt +158 -0
- data/Documentation/unicorn_rails.1.txt +150 -0
- data/GIT-VERSION-GEN +40 -0
- data/GNUmakefile +102 -14
- data/README +3 -2
- data/Rakefile +104 -32
- data/SIGNALS +2 -4
- data/TODO +3 -9
- data/bin/unicorn +5 -2
- data/bin/unicorn_rails +5 -3
- data/ext/unicorn_http/c_util.h +2 -2
- data/ext/unicorn_http/common_field_optimization.h +2 -1
- data/ext/unicorn_http/ext_help.h +29 -4
- data/ext/unicorn_http/extconf.rb +5 -0
- data/ext/unicorn_http/unicorn_http.rl +131 -76
- data/lib/unicorn.rb +6 -2
- data/lib/unicorn/app/exec_cgi.rb +3 -1
- data/lib/unicorn/app/inetd.rb +2 -0
- data/lib/unicorn/app/old_rails.rb +2 -0
- data/lib/unicorn/app/old_rails/static.rb +3 -1
- data/lib/unicorn/cgi_wrapper.rb +3 -1
- data/lib/unicorn/configurator.rb +2 -0
- data/lib/unicorn/const.rb +8 -6
- data/lib/unicorn/http_request.rb +6 -5
- data/lib/unicorn/http_response.rb +4 -2
- data/lib/unicorn/launcher.rb +6 -0
- data/lib/unicorn/socket_helper.rb +5 -5
- data/lib/unicorn/tee_input.rb +2 -0
- data/lib/unicorn/util.rb +2 -0
- data/local.mk.sample +4 -2
- data/setup.rb +1 -0
- data/test/aggregate.rb +2 -0
- data/test/exec/test_exec.rb +157 -0
- data/test/rails/app-1.2.3/app/controllers/application.rb +2 -0
- data/test/rails/app-1.2.3/app/controllers/foo_controller.rb +2 -0
- data/test/rails/app-1.2.3/app/helpers/application_helper.rb +2 -0
- data/test/rails/app-1.2.3/config/boot.rb +2 -0
- data/test/rails/app-1.2.3/config/environment.rb +2 -0
- data/test/rails/app-1.2.3/config/environments/development.rb +2 -0
- data/test/rails/app-1.2.3/config/environments/production.rb +2 -0
- data/test/rails/app-1.2.3/config/routes.rb +2 -0
- data/test/rails/app-2.0.2/app/controllers/application.rb +2 -0
- data/test/rails/app-2.0.2/app/controllers/foo_controller.rb +2 -0
- data/test/rails/app-2.0.2/app/helpers/application_helper.rb +2 -0
- data/test/rails/app-2.0.2/config/boot.rb +2 -0
- data/test/rails/app-2.0.2/config/environment.rb +2 -0
- data/test/rails/app-2.0.2/config/environments/development.rb +2 -0
- data/test/rails/app-2.0.2/config/environments/production.rb +2 -0
- data/test/rails/app-2.0.2/config/routes.rb +2 -0
- data/test/rails/app-2.1.2/app/controllers/application.rb +2 -0
- data/test/rails/app-2.1.2/app/controllers/foo_controller.rb +2 -0
- data/test/rails/app-2.1.2/app/helpers/application_helper.rb +2 -0
- data/test/rails/app-2.1.2/config/boot.rb +2 -0
- data/test/rails/app-2.1.2/config/environment.rb +2 -0
- data/test/rails/app-2.1.2/config/environments/development.rb +2 -0
- data/test/rails/app-2.1.2/config/environments/production.rb +2 -0
- data/test/rails/app-2.1.2/config/routes.rb +2 -0
- data/test/rails/app-2.2.2/app/controllers/application.rb +2 -0
- data/test/rails/app-2.2.2/app/controllers/foo_controller.rb +2 -0
- data/test/rails/app-2.2.2/app/helpers/application_helper.rb +2 -0
- data/test/rails/app-2.2.2/config/boot.rb +2 -0
- data/test/rails/app-2.2.2/config/environment.rb +2 -0
- data/test/rails/app-2.2.2/config/environments/development.rb +2 -0
- data/test/rails/app-2.2.2/config/environments/production.rb +2 -0
- data/test/rails/app-2.2.2/config/routes.rb +2 -0
- data/test/rails/app-2.3.3.1/app/controllers/application_controller.rb +2 -0
- data/test/rails/app-2.3.3.1/app/controllers/foo_controller.rb +2 -0
- data/test/rails/app-2.3.3.1/app/helpers/application_helper.rb +2 -0
- data/test/rails/app-2.3.3.1/config/boot.rb +2 -0
- data/test/rails/app-2.3.3.1/config/environment.rb +2 -0
- data/test/rails/app-2.3.3.1/config/environments/development.rb +2 -0
- data/test/rails/app-2.3.3.1/config/environments/production.rb +2 -0
- data/test/rails/app-2.3.3.1/config/routes.rb +2 -0
- data/test/rails/test_rails.rb +2 -0
- data/test/test_helper.rb +8 -0
- data/test/unit/test_configurator.rb +2 -0
- data/test/unit/test_http_parser.rb +13 -0
- data/test/unit/test_http_parser_ng.rb +2 -0
- data/test/unit/test_request.rb +2 -0
- data/test/unit/test_response.rb +2 -0
- data/test/unit/test_server.rb +2 -0
- data/test/unit/test_signals.rb +2 -0
- data/test/unit/test_socket_helper.rb +2 -0
- data/test/unit/test_tee_input.rb +2 -1
- data/test/unit/test_upload.rb +2 -0
- data/test/unit/test_util.rb +2 -0
- data/unicorn.gemspec +38 -28
- metadata +38 -42
- data/Manifest +0 -137
data/lib/unicorn/app/exec_cgi.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
require 'unicorn'
|
|
2
4
|
|
|
3
5
|
module Unicorn::App
|
|
@@ -24,7 +26,7 @@ module Unicorn::App
|
|
|
24
26
|
SERVER_PORT
|
|
25
27
|
SERVER_PROTOCOL
|
|
26
28
|
SERVER_SOFTWARE
|
|
27
|
-
).map { |x| x.freeze }
|
|
29
|
+
).map { |x| x.freeze } # frozen strings are faster for Hash assignments
|
|
28
30
|
|
|
29
31
|
# Intializes the app, example of usage in a config.ru
|
|
30
32
|
# map "/cgit" do
|
data/lib/unicorn/app/inetd.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
# This code is based on the original Rails handler in Mongrel
|
|
2
4
|
# Copyright (c) 2005 Zed A. Shaw
|
|
3
5
|
# Copyright (c) 2009 Eric Wong
|
|
@@ -18,7 +20,7 @@
|
|
|
18
20
|
# with Unicorn and you should see a decent speed boost (but not as
|
|
19
21
|
# fast as if you use a static server like nginx).
|
|
20
22
|
class Unicorn::App::OldRails::Static < Struct.new(:app, :root, :file_server)
|
|
21
|
-
FILE_METHODS = { 'GET' => true, 'HEAD' => true }
|
|
23
|
+
FILE_METHODS = { 'GET' => true, 'HEAD' => true }
|
|
22
24
|
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
|
23
25
|
REQUEST_URI = 'REQUEST_URI'.freeze
|
|
24
26
|
PATH_INFO = 'PATH_INFO'.freeze
|
data/lib/unicorn/cgi_wrapper.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
# This code is based on the original CGIWrapper from Mongrel
|
|
2
4
|
# Copyright (c) 2005 Zed A. Shaw
|
|
3
5
|
# Copyright (c) 2009 Eric Wong
|
|
@@ -44,7 +46,7 @@ class Unicorn::CGIWrapper < ::CGI
|
|
|
44
46
|
'language' => 'Content-Language'.freeze,
|
|
45
47
|
'expires' => 'Expires'.freeze,
|
|
46
48
|
'length' => CONTENT_LENGTH,
|
|
47
|
-
}
|
|
49
|
+
}
|
|
48
50
|
|
|
49
51
|
# Takes an a Rackable environment, plus any additional CGI.new
|
|
50
52
|
# arguments These are used internally to create a wrapper around the
|
data/lib/unicorn/configurator.rb
CHANGED
data/lib/unicorn/const.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
module Unicorn
|
|
2
4
|
|
|
3
5
|
# Frequently used constants when constructing requests or responses. Many times
|
|
@@ -5,11 +7,11 @@ module Unicorn
|
|
|
5
7
|
# gave about a 3% to 10% performance improvement over using the strings directly.
|
|
6
8
|
# Symbols did not really improve things much compared to constants.
|
|
7
9
|
module Const
|
|
8
|
-
UNICORN_VERSION="0.
|
|
10
|
+
UNICORN_VERSION="0.92.0"
|
|
9
11
|
|
|
10
|
-
DEFAULT_HOST = "0.0.0.0"
|
|
11
|
-
DEFAULT_PORT = "8080"
|
|
12
|
-
DEFAULT_LISTEN = "#{DEFAULT_HOST}:#{DEFAULT_PORT}"
|
|
12
|
+
DEFAULT_HOST = "0.0.0.0" # default TCP listen host address
|
|
13
|
+
DEFAULT_PORT = "8080" # default TCP listen port
|
|
14
|
+
DEFAULT_LISTEN = "#{DEFAULT_HOST}:#{DEFAULT_PORT}"
|
|
13
15
|
|
|
14
16
|
# The basic max request size we'll try to read.
|
|
15
17
|
CHUNK_SIZE=(16 * 1024)
|
|
@@ -22,8 +24,8 @@ module Unicorn
|
|
|
22
24
|
MAX_BODY=MAX_HEADER
|
|
23
25
|
|
|
24
26
|
# common errors we'll send back
|
|
25
|
-
ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n"
|
|
26
|
-
ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
|
27
|
+
ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n"
|
|
28
|
+
ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
|
27
29
|
EXPECT_100_RESPONSE = "HTTP/1.1 100 Continue\r\n\r\n"
|
|
28
30
|
|
|
29
31
|
# A frozen format for this is about 15% faster
|
data/lib/unicorn/http_request.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
2
3
|
require 'stringio'
|
|
3
4
|
require 'unicorn_http'
|
|
4
5
|
|
|
@@ -11,15 +12,15 @@ module Unicorn
|
|
|
11
12
|
"rack.multiprocess" => true,
|
|
12
13
|
"rack.multithread" => false,
|
|
13
14
|
"rack.run_once" => false,
|
|
14
|
-
"rack.version" => [1, 0]
|
|
15
|
-
"SCRIPT_NAME" => ""
|
|
15
|
+
"rack.version" => [1, 0],
|
|
16
|
+
"SCRIPT_NAME" => "",
|
|
16
17
|
|
|
17
18
|
# this is not in the Rack spec, but some apps may rely on it
|
|
18
|
-
"SERVER_SOFTWARE" => "Unicorn #{Const::UNICORN_VERSION}"
|
|
19
|
+
"SERVER_SOFTWARE" => "Unicorn #{Const::UNICORN_VERSION}"
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
NULL_IO = StringIO.new(Z)
|
|
22
|
-
LOCALHOST = '127.0.0.1'
|
|
23
|
+
LOCALHOST = '127.0.0.1'
|
|
23
24
|
|
|
24
25
|
# Being explicitly single-threaded, we have certain advantages in
|
|
25
26
|
# not having to worry about variables being clobbered :)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
require 'time'
|
|
2
4
|
|
|
3
5
|
module Unicorn
|
|
@@ -30,7 +32,7 @@ module Unicorn
|
|
|
30
32
|
# Rack does not set/require a Date: header. We always override the
|
|
31
33
|
# Connection: and Date: headers no matter what (if anything) our
|
|
32
34
|
# Rack application sent us.
|
|
33
|
-
SKIP = { 'connection' => true, 'date' => true, 'status' => true }
|
|
35
|
+
SKIP = { 'connection' => true, 'date' => true, 'status' => true }
|
|
34
36
|
OUT = [] # :nodoc
|
|
35
37
|
|
|
36
38
|
def self.write_header(socket, status, headers)
|
|
@@ -67,7 +69,7 @@ module Unicorn
|
|
|
67
69
|
body.each { |chunk| socket.write(chunk) }
|
|
68
70
|
socket.close # flushes and uncorks the socket immediately
|
|
69
71
|
ensure
|
|
70
|
-
body.respond_to?(:close) and body.close
|
|
72
|
+
body.respond_to?(:close) and body.close
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
end
|
data/lib/unicorn/launcher.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
require 'socket'
|
|
2
4
|
|
|
3
5
|
module Unicorn
|
|
@@ -18,10 +20,8 @@ module Unicorn
|
|
|
18
20
|
# Use the HTTP accept filter if available.
|
|
19
21
|
# The struct made by pack() is defined in /usr/include/sys/socket.h
|
|
20
22
|
# as accept_filter_arg
|
|
21
|
-
# We won't be seupportin the "dataready" filter unlike nginx
|
|
22
|
-
# since we only support HTTP and no other protocols
|
|
23
23
|
unless `/sbin/sysctl -nq net.inet.accf.http`.empty?
|
|
24
|
-
|
|
24
|
+
FILTER_ARG = ['httpready', nil].pack('a16a240')
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -44,8 +44,8 @@ module Unicorn
|
|
|
44
44
|
# No good reason to ever have deferred accepts off
|
|
45
45
|
if defined?(TCP_DEFER_ACCEPT)
|
|
46
46
|
sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, 1) rescue nil
|
|
47
|
-
elsif defined?(SO_ACCEPTFILTER) && defined?(
|
|
48
|
-
sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER,
|
|
47
|
+
elsif defined?(SO_ACCEPTFILTER) && defined?(FILTER_ARG)
|
|
48
|
+
sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, FILTER_ARG) rescue nil
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
data/lib/unicorn/tee_input.rb
CHANGED
data/lib/unicorn/util.rb
CHANGED
data/local.mk.sample
CHANGED
|
@@ -31,6 +31,7 @@ test-19:
|
|
|
31
31
|
publish_doc:
|
|
32
32
|
-git set-file-times
|
|
33
33
|
$(MAKE) doc
|
|
34
|
+
awk 'BEGIN{RS="=== ";ORS=""}NR==2{ print RS""$$0 }' NEWS > doc/LATEST
|
|
34
35
|
$(MAKE) doc_gz
|
|
35
36
|
rsync -av --delete doc/ dcvr:/srv/unicorn/
|
|
36
37
|
git ls-files | xargs touch
|
|
@@ -38,7 +39,8 @@ publish_doc:
|
|
|
38
39
|
# Create gzip variants of the same timestamp as the original so nginx
|
|
39
40
|
# "gzip_static on" can serve the gzipped versions directly.
|
|
40
41
|
doc_gz: suf := html js css
|
|
41
|
-
doc_gz: docs = $(shell find doc
|
|
42
|
+
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
|
42
43
|
doc_gz:
|
|
44
|
+
touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
|
|
43
45
|
for i in $(docs); do \
|
|
44
|
-
gzip --rsyncable < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
|
46
|
+
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
data/setup.rb
CHANGED
data/test/aggregate.rb
CHANGED
data/test/exec/test_exec.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
# -*- encoding: binary -*-
|
|
2
|
+
|
|
1
3
|
# Copyright (c) 2009 Eric Wong
|
|
4
|
+
FLOCK_PATH = File.expand_path(__FILE__)
|
|
2
5
|
require 'test/test_helper'
|
|
3
6
|
|
|
4
7
|
do_test = true
|
|
@@ -695,4 +698,158 @@ end
|
|
|
695
698
|
wait_for_death(pid)
|
|
696
699
|
end
|
|
697
700
|
|
|
701
|
+
def hup_test_common(preload)
|
|
702
|
+
File.open("config.ru", "wb") { |fp| fp.syswrite(HI.gsub("HI", '#$$')) }
|
|
703
|
+
pid_file = Tempfile.new('pid')
|
|
704
|
+
ucfg = Tempfile.new('unicorn_test_config')
|
|
705
|
+
ucfg.syswrite("listen '#@addr:#@port'\n")
|
|
706
|
+
ucfg.syswrite("pid '#{pid_file.path}'\n")
|
|
707
|
+
ucfg.syswrite("preload_app true\n") if preload
|
|
708
|
+
ucfg.syswrite("stderr_path 'test_stderr.#$$.log'\n")
|
|
709
|
+
ucfg.syswrite("stdout_path 'test_stdout.#$$.log'\n")
|
|
710
|
+
pid = xfork {
|
|
711
|
+
redirect_test_io { exec($unicorn_bin, "-D", "-c", ucfg.path) }
|
|
712
|
+
}
|
|
713
|
+
_, status = Process.waitpid2(pid)
|
|
714
|
+
assert status.success?
|
|
715
|
+
wait_master_ready("test_stderr.#$$.log")
|
|
716
|
+
wait_workers_ready("test_stderr.#$$.log", 1)
|
|
717
|
+
uri = URI.parse("http://#@addr:#@port/")
|
|
718
|
+
pids = Tempfile.new('worker_pids')
|
|
719
|
+
hitter = fork {
|
|
720
|
+
bodies = Hash.new(0)
|
|
721
|
+
at_exit { pids.syswrite(bodies.inspect) }
|
|
722
|
+
trap(:TERM) { exit(0) }
|
|
723
|
+
loop {
|
|
724
|
+
rv = Net::HTTP.get(uri)
|
|
725
|
+
pid = rv.to_i
|
|
726
|
+
exit!(1) if pid <= 0
|
|
727
|
+
bodies[pid] += 1
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
sleep 1 # racy
|
|
731
|
+
daemon_pid = pid_file.read.to_i
|
|
732
|
+
assert daemon_pid > 0
|
|
733
|
+
Process.kill(:HUP, daemon_pid)
|
|
734
|
+
sleep 1 # racy
|
|
735
|
+
assert_nothing_raised { Process.kill(:TERM, hitter) }
|
|
736
|
+
_, hitter_status = Process.waitpid2(hitter)
|
|
737
|
+
assert hitter_status.success?
|
|
738
|
+
pids.sysseek(0)
|
|
739
|
+
pids = eval(pids.read)
|
|
740
|
+
assert_kind_of(Hash, pids)
|
|
741
|
+
assert_equal 2, pids.size
|
|
742
|
+
pids.keys.each { |x|
|
|
743
|
+
assert_kind_of(Integer, x)
|
|
744
|
+
assert x > 0
|
|
745
|
+
assert pids[x] > 0
|
|
746
|
+
}
|
|
747
|
+
assert_nothing_raised { Process.kill(:QUIT, daemon_pid) }
|
|
748
|
+
wait_for_death(daemon_pid)
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
def test_preload_app_hup
|
|
752
|
+
hup_test_common(true)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
def test_hup
|
|
756
|
+
hup_test_common(false)
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
def test_default_listen_hup_holds_listener
|
|
760
|
+
default_listen_lock do
|
|
761
|
+
res, pid_path = default_listen_setup
|
|
762
|
+
daemon_pid = File.read(pid_path).to_i
|
|
763
|
+
assert_nothing_raised { Process.kill(:HUP, daemon_pid) }
|
|
764
|
+
wait_workers_ready("test_stderr.#$$.log", 1)
|
|
765
|
+
res2 = hit(["http://#{Unicorn::Const::DEFAULT_LISTEN}/"])
|
|
766
|
+
assert_match %r{\d+}, res2.first
|
|
767
|
+
assert res2.first != res.first
|
|
768
|
+
assert_nothing_raised { Process.kill(:QUIT, daemon_pid) }
|
|
769
|
+
wait_for_death(daemon_pid)
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
def test_default_listen_upgrade_holds_listener
|
|
774
|
+
default_listen_lock do
|
|
775
|
+
res, pid_path = default_listen_setup
|
|
776
|
+
daemon_pid = File.read(pid_path).to_i
|
|
777
|
+
assert_nothing_raised {
|
|
778
|
+
Process.kill(:USR2, daemon_pid)
|
|
779
|
+
wait_for_file("#{pid_path}.oldbin")
|
|
780
|
+
wait_for_file(pid_path)
|
|
781
|
+
Process.kill(:QUIT, daemon_pid)
|
|
782
|
+
wait_for_death(daemon_pid)
|
|
783
|
+
}
|
|
784
|
+
daemon_pid = File.read(pid_path).to_i
|
|
785
|
+
wait_workers_ready("test_stderr.#$$.log", 1)
|
|
786
|
+
File.truncate("test_stderr.#$$.log", 0)
|
|
787
|
+
|
|
788
|
+
res2 = hit(["http://#{Unicorn::Const::DEFAULT_LISTEN}/"])
|
|
789
|
+
assert_match %r{\d+}, res2.first
|
|
790
|
+
assert res2.first != res.first
|
|
791
|
+
|
|
792
|
+
assert_nothing_raised { Process.kill(:HUP, daemon_pid) }
|
|
793
|
+
wait_workers_ready("test_stderr.#$$.log", 1)
|
|
794
|
+
File.truncate("test_stderr.#$$.log", 0)
|
|
795
|
+
res3 = hit(["http://#{Unicorn::Const::DEFAULT_LISTEN}/"])
|
|
796
|
+
assert res2.first != res3.first
|
|
797
|
+
|
|
798
|
+
assert_nothing_raised { Process.kill(:QUIT, daemon_pid) }
|
|
799
|
+
wait_for_death(daemon_pid)
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
def default_listen_setup
|
|
804
|
+
File.open("config.ru", "wb") { |fp| fp.syswrite(HI.gsub("HI", '#$$')) }
|
|
805
|
+
pid_path = (tmp = Tempfile.new('pid')).path
|
|
806
|
+
tmp.close!
|
|
807
|
+
ucfg = Tempfile.new('unicorn_test_config')
|
|
808
|
+
ucfg.syswrite("pid '#{pid_path}'\n")
|
|
809
|
+
ucfg.syswrite("stderr_path 'test_stderr.#$$.log'\n")
|
|
810
|
+
ucfg.syswrite("stdout_path 'test_stdout.#$$.log'\n")
|
|
811
|
+
pid = xfork {
|
|
812
|
+
redirect_test_io { exec($unicorn_bin, "-D", "-c", ucfg.path) }
|
|
813
|
+
}
|
|
814
|
+
_, status = Process.waitpid2(pid)
|
|
815
|
+
assert status.success?
|
|
816
|
+
wait_master_ready("test_stderr.#$$.log")
|
|
817
|
+
wait_workers_ready("test_stderr.#$$.log", 1)
|
|
818
|
+
File.truncate("test_stderr.#$$.log", 0)
|
|
819
|
+
res = hit(["http://#{Unicorn::Const::DEFAULT_LISTEN}/"])
|
|
820
|
+
assert_match %r{\d+}, res.first
|
|
821
|
+
[ res, pid_path ]
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
# we need to flock() something to prevent these tests from running
|
|
825
|
+
def default_listen_lock(&block)
|
|
826
|
+
fp = File.open(FLOCK_PATH, "rb")
|
|
827
|
+
begin
|
|
828
|
+
fp.flock(File::LOCK_EX)
|
|
829
|
+
begin
|
|
830
|
+
TCPServer.new(Unicorn::Const::DEFAULT_HOST,
|
|
831
|
+
Unicorn::Const::DEFAULT_PORT).close
|
|
832
|
+
rescue Errno::EADDRINUSE, Errno::EACCES
|
|
833
|
+
warn "can't bind to #{Unicorn::Const::DEFAULT_LISTEN}"
|
|
834
|
+
return false
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
# unused_port should never take this, but we may run an environment
|
|
838
|
+
# where tests are being run against older unicorns...
|
|
839
|
+
lock_path = "#{Dir::tmpdir}/unicorn_test." \
|
|
840
|
+
"#{Unicorn::Const::DEFAULT_LISTEN}.lock"
|
|
841
|
+
begin
|
|
842
|
+
lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
|
|
843
|
+
yield
|
|
844
|
+
rescue Errno::EEXIST
|
|
845
|
+
lock_path = nil
|
|
846
|
+
return false
|
|
847
|
+
ensure
|
|
848
|
+
File.unlink(lock_path) if lock_path
|
|
849
|
+
end
|
|
850
|
+
ensure
|
|
851
|
+
fp.flock(File::LOCK_UN)
|
|
852
|
+
end
|
|
853
|
+
end
|
|
854
|
+
|
|
698
855
|
end if do_test
|