raindrops 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.document +2 -1
  2. data/.gitignore +4 -0
  3. data/.wrongdoc.yml +4 -0
  4. data/GIT-VERSION-GEN +1 -1
  5. data/GNUmakefile +2 -196
  6. data/Gemfile +7 -0
  7. data/LICENSE +1 -1
  8. data/README +17 -47
  9. data/Rakefile +0 -104
  10. data/examples/linux-listener-stats.rb +123 -0
  11. data/examples/{config.ru → middleware.ru} +1 -1
  12. data/examples/watcher.ru +4 -0
  13. data/examples/watcher_demo.ru +13 -0
  14. data/examples/zbatery.conf.rb +13 -0
  15. data/ext/raindrops/extconf.rb +5 -0
  16. data/ext/raindrops/linux_inet_diag.c +449 -151
  17. data/ext/raindrops/linux_tcp_info.c +170 -0
  18. data/ext/raindrops/my_fileno.h +36 -0
  19. data/ext/raindrops/raindrops.c +232 -20
  20. data/lib/raindrops.rb +20 -7
  21. data/lib/raindrops/aggregate.rb +8 -0
  22. data/lib/raindrops/aggregate/last_data_recv.rb +86 -0
  23. data/lib/raindrops/aggregate/pmq.rb +239 -0
  24. data/lib/raindrops/last_data_recv.rb +100 -0
  25. data/lib/raindrops/linux.rb +26 -16
  26. data/lib/raindrops/middleware.rb +112 -41
  27. data/lib/raindrops/middleware/proxy.rb +34 -0
  28. data/lib/raindrops/struct.rb +15 -0
  29. data/lib/raindrops/watcher.rb +362 -0
  30. data/pkg.mk +171 -0
  31. data/raindrops.gemspec +10 -20
  32. data/test/ipv6_enabled.rb +10 -0
  33. data/test/rack_unicorn.rb +12 -0
  34. data/test/test_aggregate_pmq.rb +65 -0
  35. data/test/test_inet_diag_socket.rb +13 -0
  36. data/test/test_last_data_recv_unicorn.rb +69 -0
  37. data/test/test_linux.rb +55 -57
  38. data/test/test_linux_all_tcp_listen_stats.rb +66 -0
  39. data/test/test_linux_all_tcp_listen_stats_leak.rb +43 -0
  40. data/test/test_linux_ipv6.rb +158 -0
  41. data/test/test_linux_tcp_info.rb +61 -0
  42. data/test/test_middleware.rb +15 -2
  43. data/test/test_middleware_unicorn.rb +37 -0
  44. data/test/test_middleware_unicorn_ipv6.rb +37 -0
  45. data/test/test_raindrops.rb +65 -1
  46. data/test/test_raindrops_gc.rb +23 -1
  47. data/test/test_watcher.rb +85 -0
  48. metadata +69 -22
  49. data/examples/linux-tcp-listener-stats.rb +0 -44
data/pkg.mk ADDED
@@ -0,0 +1,171 @@
1
+ RUBY = ruby
2
+ RAKE = rake
3
+ RSYNC = rsync
4
+ WRONGDOC = wrongdoc
5
+
6
+ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
7
+ @./GIT-VERSION-GEN
8
+ -include GIT-VERSION-FILE
9
+ -include local.mk
10
+ DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts RbConfig::CONFIG["DLEXT"]')
11
+ RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
12
+ RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
13
+ lib := lib
14
+
15
+ ifeq ($(shell test -f script/isolate_for_tests && echo t),t)
16
+ isolate_libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/isolate.mk
17
+ $(isolate_libs): script/isolate_for_tests
18
+ @$(RUBY) script/isolate_for_tests
19
+ -include $(isolate_libs)
20
+ lib := $(lib):$(ISOLATE_LIBS)
21
+ endif
22
+
23
+ ext := $(firstword $(wildcard ext/*))
24
+ ifneq ($(ext),)
25
+ ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
26
+ ext_h := $(wildcard $(ext)/*/*.h $(ext)/*.h)
27
+ ext_src := $(wildcard $(ext)/*.c $(ext_h))
28
+ ext_pfx_src := $(addprefix $(ext_pfx)/,$(ext_src))
29
+ ext_d := $(ext_pfx)/$(ext)/.d
30
+ $(ext)/extconf.rb: $(wildcard $(ext)/*.h)
31
+ @>> $@
32
+ $(ext_d):
33
+ @mkdir -p $(@D)
34
+ @> $@
35
+ $(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
36
+ install -m 644 $< $@
37
+ $(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
38
+ $(RM) -f $(@D)/*.o
39
+ cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb
40
+ ext_sfx := _ext.$(DLEXT)
41
+ ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
42
+ $(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
43
+ @echo $^ == $@
44
+ $(MAKE) -C $(@D)
45
+ lib := $(lib):$(ext_pfx)/$(ext)
46
+ build: $(ext_dl)
47
+ else
48
+ build:
49
+ endif
50
+
51
+ pkg_extra += GIT-VERSION-FILE NEWS ChangeLog LATEST
52
+ ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
53
+ $(WRONGDOC) prepare
54
+ NEWS LATEST: ChangeLog
55
+
56
+ manifest:
57
+ $(RM) .manifest
58
+ $(MAKE) .manifest
59
+
60
+ .manifest: $(pkg_extra)
61
+ (git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
62
+ LC_ALL=C sort > $@+
63
+ cmp $@+ $@ || mv $@+ $@
64
+ $(RM) $@+
65
+
66
+ doc:: .document .wrongdoc.yml $(pkg_extra)
67
+ -find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
68
+ -find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
69
+ $(RM) -r doc
70
+ $(WRONGDOC) all
71
+ install -m644 COPYING doc/COPYING
72
+ install -m644 $(shell grep '^[A-Z]' .document) doc/
73
+
74
+ ifneq ($(VERSION),)
75
+ pkggem := pkg/$(rfpackage)-$(VERSION).gem
76
+ pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
77
+ release_notes := release_notes-$(VERSION)
78
+ release_changes := release_changes-$(VERSION)
79
+
80
+ release-notes: $(release_notes)
81
+ release-changes: $(release_changes)
82
+ $(release_changes):
83
+ $(WRONGDOC) release_changes > $@+
84
+ $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
85
+ $(release_notes):
86
+ $(WRONGDOC) release_notes > $@+
87
+ $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
88
+
89
+ # ensures we're actually on the tagged $(VERSION), only used for release
90
+ verify:
91
+ test x"$(shell umask)" = x0022
92
+ git rev-parse --verify refs/tags/v$(VERSION)^{}
93
+ git diff-index --quiet HEAD^0
94
+ test $$(git rev-parse --verify HEAD^0) = \
95
+ $$(git rev-parse --verify refs/tags/v$(VERSION)^{})
96
+
97
+ fix-perms:
98
+ -git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
99
+ -git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
100
+
101
+ gem: $(pkggem)
102
+
103
+ install-gem: $(pkggem)
104
+ gem install $(CURDIR)/$<
105
+
106
+ $(pkggem): manifest fix-perms
107
+ gem build $(rfpackage).gemspec
108
+ mkdir -p pkg
109
+ mv $(@F) $@
110
+
111
+ $(pkgtgz): distdir = $(basename $@)
112
+ $(pkgtgz): HEAD = v$(VERSION)
113
+ $(pkgtgz): manifest fix-perms
114
+ @test -n "$(distdir)"
115
+ $(RM) -r $(distdir)
116
+ mkdir -p $(distdir)
117
+ tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
118
+ cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
119
+ mv $@+ $@
120
+
121
+ package: $(pkgtgz) $(pkggem)
122
+
123
+ test-release:: verify package $(release_notes) $(release_changes)
124
+ # make tgz release on RubyForge
125
+ @echo rubyforge add_release -f \
126
+ -n $(release_notes) -a $(release_changes) \
127
+ $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
128
+ @echo gem push $(pkggem)
129
+ @echo rubyforge add_file \
130
+ $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
131
+ release:: verify package $(release_notes) $(release_changes)
132
+ # make tgz release on RubyForge
133
+ rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
134
+ $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
135
+ # push gem to RubyGems.org
136
+ gem push $(pkggem)
137
+ # in case of gem downloads from RubyForge releases page
138
+ rubyforge add_file \
139
+ $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
140
+ else
141
+ gem install-gem: GIT-VERSION-FILE
142
+ $(MAKE) $@ VERSION=$(GIT_VERSION)
143
+ endif
144
+
145
+ all:: test
146
+ test_units := $(wildcard test/test_*.rb)
147
+ test: test-unit
148
+ test-unit: $(test_units)
149
+ $(test_units): build
150
+ $(RUBY) -I $(lib) $@ $(RUBY_TEST_OPTS)
151
+
152
+ # this requires GNU coreutils variants
153
+ ifneq ($(RSYNC_DEST),)
154
+ publish_doc:
155
+ -git set-file-times
156
+ $(MAKE) doc
157
+ find doc/images -type f | \
158
+ TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
159
+ $(MAKE) doc_gz
160
+ $(RSYNC) -av doc/ $(RSYNC_DEST)/
161
+ git ls-files | xargs touch
162
+ endif
163
+
164
+ # Create gzip variants of the same timestamp as the original so nginx
165
+ # "gzip_static on" can serve the gzipped versions directly.
166
+ doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
167
+ doc_gz:
168
+ for i in $(docs); do \
169
+ gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
170
+
171
+ .PHONY: all .FORCE-GIT-VERSION-FILE doc test $(test_units) manifest
data/raindrops.gemspec CHANGED
@@ -1,38 +1,28 @@
1
1
  # -*- encoding: binary -*-
2
-
3
2
  ENV["VERSION"] or abort "VERSION= must be specified"
4
3
  manifest = File.readlines('.manifest').map! { |x| x.chomp! }
5
4
  test_files = manifest.grep(%r{\Atest/test_.*\.rb\z})
5
+ require 'wrongdoc'
6
+ extend Wrongdoc::Gemspec
7
+ name, summary, title = readme_metadata
6
8
 
7
9
  Gem::Specification.new do |s|
8
10
  s.name = %q{raindrops}
9
- s.version = ENV["VERSION"]
11
+ s.version = ENV["VERSION"].dup
10
12
 
11
13
  s.authors = ["raindrops hackers"]
12
14
  s.date = Time.now.utc.strftime('%Y-%m-%d')
13
- s.description = File.read("README").split(/\n\n/)[1]
15
+ s.description = readme_description
14
16
  s.email = %q{raindrops@librelist.com}
15
17
  s.extensions = %w(ext/raindrops/extconf.rb)
16
-
17
- s.extra_rdoc_files = File.readlines('.document').map! do |x|
18
- x.chomp!
19
- if File.directory?(x)
20
- manifest.grep(%r{\A#{x}/})
21
- elsif File.file?(x)
22
- x
23
- else
24
- nil
25
- end
26
- end.flatten.compact
27
-
18
+ s.extra_rdoc_files = extra_rdoc_files(manifest)
28
19
  s.files = manifest
29
- s.homepage = %q{http://raindrops.bogomips.org/}
30
- s.summary = %q{real-time stats for preforking Rack servers}
31
- s.rdoc_options = [ "-Na", "-t", "raindrops - #{s.summary}" ]
32
- s.require_paths = %w(lib)
20
+ s.homepage = Wrongdoc.config[:rdoc_url]
21
+ s.summary = summary
22
+ s.rdoc_options = rdoc_options
33
23
  s.rubyforge_project = %q{rainbows}
34
-
35
24
  s.test_files = test_files
25
+ s.add_development_dependency('bundler', '~> 1.0.10')
36
26
 
37
27
  # s.licenses = %w(LGPLv3) # accessor not compatible with older RubyGems
38
28
  end
@@ -0,0 +1,10 @@
1
+ def ipv6_enabled?
2
+ tmp = TCPServer.new(ENV["TEST_HOST6"] || '::1', 0)
3
+ tmp.close
4
+ true
5
+ rescue => e
6
+ warn "skipping IPv6 tests, host does not seem to be IPv6 enabled:"
7
+ warn " #{e.class}: #{e}"
8
+ return false
9
+ ipv6_enabled = false
10
+ end
@@ -0,0 +1,12 @@
1
+ # -*- encoding: binary -*-
2
+ require "test/unit"
3
+ require "raindrops"
4
+ require "rack"
5
+ require "rack/lobster"
6
+ require "open-uri"
7
+ begin
8
+ require "unicorn"
9
+ require "rack/lobster"
10
+ rescue LoadError => e
11
+ warn "W: #{e} skipping test since Rack or Unicorn was not found"
12
+ end
@@ -0,0 +1,65 @@
1
+ require "test/unit"
2
+ require "raindrops"
3
+ pmq = begin
4
+ Raindrops::Aggregate::PMQ
5
+ rescue => LoadError
6
+ warn "W: #{e} skipping test"
7
+ false
8
+ end
9
+ if RUBY_VERSION.to_f < 1.9
10
+ pmq = false
11
+ warn "W: skipping #{__FILE__}, only Ruby 1.9 supported for now"
12
+ end
13
+
14
+ Thread.abort_on_exception = true
15
+
16
+ class TestAggregatePMQ < Test::Unit::TestCase
17
+
18
+ def setup
19
+ @queue = "/test.#{rand}"
20
+ end
21
+
22
+ def teardown
23
+ POSIX_MQ.unlink @queue
24
+ end
25
+
26
+ def test_run
27
+ pmq = Raindrops::Aggregate::PMQ.new :queue => @queue
28
+ thr = Thread.new { pmq.master_loop }
29
+ agg = Aggregate.new
30
+ (1..10).each { |i| pmq << i; agg << i }
31
+ pmq.stop_master_loop
32
+ assert thr.join
33
+ assert_equal agg.count, pmq.count
34
+ assert_equal agg.mean, pmq.mean
35
+ assert_equal agg.std_dev, pmq.std_dev
36
+ assert_equal agg.min, pmq.min
37
+ assert_equal agg.max, pmq.max
38
+ assert_equal agg.to_s, pmq.to_s
39
+ end
40
+
41
+ def test_multi_process
42
+ nr_workers = 4
43
+ nr = 100
44
+ pmq = Raindrops::Aggregate::PMQ.new :queue => @queue
45
+ pid = fork { pmq.master_loop }
46
+ workers = (1..nr_workers).map {
47
+ fork {
48
+ (1..nr).each { |i| pmq << i }
49
+ pmq.flush
50
+ }
51
+ }
52
+ workers.each { |pid| assert Process.waitpid2(pid).last.success? }
53
+ pmq.stop_master_loop
54
+ assert Process.waitpid2(pid).last.success?
55
+ assert_equal 400, pmq.count
56
+ agg = Aggregate.new
57
+ (1..nr_workers).map { (1..nr).each { |i| agg << i } }
58
+ assert_equal agg.to_s, pmq.to_s
59
+ assert_equal agg.mean, pmq.mean
60
+ assert_equal agg.std_dev, pmq.std_dev
61
+ assert_equal agg.min, pmq.min
62
+ assert_equal agg.max, pmq.max
63
+ assert_equal agg.to_s, pmq.to_s
64
+ end
65
+ end if pmq
@@ -0,0 +1,13 @@
1
+ # -*- encoding: binary -*-
2
+ require 'test/unit'
3
+ require 'raindrops'
4
+ $stderr.sync = $stdout.sync = true
5
+
6
+ class TestInetDiagSocket < Test::Unit::TestCase
7
+ def test_new
8
+ sock = Raindrops::InetDiagSocket.new
9
+ assert_kind_of Socket, sock
10
+ assert_kind_of Fixnum, sock.fileno
11
+ assert_nil sock.close
12
+ end
13
+ end if RUBY_PLATFORM =~ /linux/
@@ -0,0 +1,69 @@
1
+ # -*- encoding: binary -*-
2
+ require "./test/rack_unicorn"
3
+ require "tempfile"
4
+ require "net/http"
5
+
6
+ $stderr.sync = $stdout.sync = true
7
+ pmq = begin
8
+ Raindrops::Aggregate::PMQ
9
+ rescue => LoadError
10
+ warn "W: #{e} skipping test"
11
+ false
12
+ end
13
+ if RUBY_VERSION.to_f < 1.9
14
+ pmq = false
15
+ warn "W: skipping test=#{__FILE__}, only Ruby 1.9 supported for now"
16
+ end
17
+
18
+ class TestLastDataRecvUnicorn < Test::Unit::TestCase
19
+ def setup
20
+ @queue = "/test.#{rand}"
21
+ @host = ENV["UNICORN_TEST_ADDR"] || "127.0.0.1"
22
+ @sock = TCPServer.new @host, 0
23
+ @port = @sock.addr[1]
24
+ ENV["UNICORN_FD"] = @sock.fileno.to_s
25
+ @host_with_port = "#@host:#@port"
26
+ @cfg = Tempfile.new 'unicorn_config_file'
27
+ @cfg.puts "require 'raindrops'"
28
+ @cfg.puts "preload_app true"
29
+ ENV['RAINDROPS_MQUEUE'] = @queue
30
+ # @cfg.puts "worker_processes 4"
31
+ @opts = { :listeners => [ @host_with_port ], :config_file => @cfg.path }
32
+ end
33
+
34
+ def test_auto_listener
35
+ @srv = fork {
36
+ Thread.abort_on_exception = true
37
+ app = %q!Rack::Builder.new do
38
+ map("/ldr") { run Raindrops::LastDataRecv.new }
39
+ map("/") { run Rack::Lobster.new }
40
+ end.to_app!
41
+ def app.arity; 0; end
42
+ def app.call; eval self; end
43
+ Unicorn.run(app, @opts)
44
+ }
45
+ 400.times { assert_kind_of Net::HTTPSuccess, get("/") }
46
+ resp = get("/ldr")
47
+ # # p(resp.methods - Object.methods)
48
+ # resp.each_header { |k,v| p [k, "=" , v] }
49
+ assert resp.header["x-count"]
50
+ assert resp.header["x-min"]
51
+ assert resp.header["x-max"]
52
+ assert resp.header["x-mean"]
53
+ assert resp.header["x-std-dev"]
54
+ assert resp.header["x-outliers-low"]
55
+ assert resp.header["x-outliers-high"]
56
+ assert resp.body.size > 0
57
+ end
58
+
59
+ def get(path)
60
+ Net::HTTP.start(@host, @port) { |http| http.get path }
61
+ end
62
+
63
+ def teardown
64
+ Process.kill :QUIT, @srv
65
+ _, status = Process.waitpid2 @srv
66
+ assert status.success?
67
+ POSIX_MQ.unlink @queue
68
+ end
69
+ end if defined?(Unicorn) && RUBY_PLATFORM =~ /linux/ && pmq
data/test/test_linux.rb CHANGED
@@ -39,9 +39,29 @@ class TestLinux < Test::Unit::TestCase
39
39
  assert_equal 1, stats[tmp.path].queued
40
40
  end
41
41
 
42
+ def test_unix_all
43
+ tmp = Tempfile.new("\xde\xad\xbe\xef") # valid path, really :)
44
+ File.unlink(tmp.path)
45
+ us = UNIXServer.new(tmp.path)
46
+ uc0 = UNIXSocket.new(tmp.path)
47
+ stats = unix_listener_stats
48
+ assert_equal 0, stats[tmp.path].active
49
+ assert_equal 1, stats[tmp.path].queued
50
+
51
+ uc1 = UNIXSocket.new(tmp.path)
52
+ stats = unix_listener_stats
53
+ assert_equal 0, stats[tmp.path].active
54
+ assert_equal 2, stats[tmp.path].queued
55
+
56
+ ua0 = us.accept
57
+ stats = unix_listener_stats
58
+ assert_equal 1, stats[tmp.path].active
59
+ assert_equal 1, stats[tmp.path].queued
60
+ end
61
+
42
62
  def test_tcp
43
- port = unused_port
44
- s = TCPServer.new(TEST_ADDR, port)
63
+ s = TCPServer.new(TEST_ADDR, 0)
64
+ port = s.addr[1]
45
65
  addr = "#{TEST_ADDR}:#{port}"
46
66
  addrs = [ addr ]
47
67
  stats = tcp_listener_stats(addrs)
@@ -62,10 +82,36 @@ class TestLinux < Test::Unit::TestCase
62
82
  assert_equal 1, stats[addr].active
63
83
  end
64
84
 
85
+ def test_tcp_reuse_sock
86
+ nlsock = Raindrops::InetDiagSocket.new
87
+ s = TCPServer.new(TEST_ADDR, 0)
88
+ port = s.addr[1]
89
+ addr = "#{TEST_ADDR}:#{port}"
90
+ addrs = [ addr ]
91
+ stats = tcp_listener_stats(addrs, nlsock)
92
+ assert_equal 1, stats.size
93
+ assert_equal 0, stats[addr].queued
94
+ assert_equal 0, stats[addr].active
95
+
96
+ c = TCPSocket.new(TEST_ADDR, port)
97
+ stats = tcp_listener_stats(addrs, nlsock)
98
+ assert_equal 1, stats.size
99
+ assert_equal 1, stats[addr].queued
100
+ assert_equal 0, stats[addr].active
101
+
102
+ sc = s.accept
103
+ stats = tcp_listener_stats(addrs, nlsock)
104
+ assert_equal 1, stats.size
105
+ assert_equal 0, stats[addr].queued
106
+ assert_equal 1, stats[addr].active
107
+ ensure
108
+ nlsock.close
109
+ end
110
+
65
111
  def test_tcp_multi
66
- port1, port2 = unused_port, unused_port
67
- s1 = TCPServer.new(TEST_ADDR, port1)
68
- s2 = TCPServer.new(TEST_ADDR, port2)
112
+ s1 = TCPServer.new(TEST_ADDR, 0)
113
+ s2 = TCPServer.new(TEST_ADDR, 0)
114
+ port1, port2 = s1.addr[1], s2.addr[1]
69
115
  addr1, addr2 = "#{TEST_ADDR}:#{port1}", "#{TEST_ADDR}:#{port2}"
70
116
  addrs = [ addr1, addr2 ]
71
117
  stats = tcp_listener_stats(addrs)
@@ -127,10 +173,10 @@ class TestLinux < Test::Unit::TestCase
127
173
  def test_tcp_stress_test
128
174
  nr_proc = 32
129
175
  nr_sock = 500
130
- port = unused_port
176
+ s = TCPServer.new(TEST_ADDR, 0)
177
+ port = s.addr[1]
131
178
  addr = "#{TEST_ADDR}:#{port}"
132
179
  addrs = [ addr ]
133
- s = TCPServer.new(TEST_ADDR, port)
134
180
  rda, wra = IO.pipe
135
181
  rdb, wrb = IO.pipe
136
182
 
@@ -138,7 +184,7 @@ class TestLinux < Test::Unit::TestCase
138
184
  fork do
139
185
  rda.close
140
186
  wrb.close
141
- socks = (1..nr_sock).times.map { s.accept }
187
+ socks = (1..nr_sock).map { s.accept }
142
188
  wra.syswrite('.')
143
189
  wra.close
144
190
  rdb.sysread(1) # wait for parent to nuke us
@@ -149,7 +195,7 @@ class TestLinux < Test::Unit::TestCase
149
195
  fork do
150
196
  rda.close
151
197
  wrb.close
152
- socks = (1..nr_sock).times.map { TCPSocket.new(TEST_ADDR, port) }
198
+ socks = (1..nr_sock).map { TCPSocket.new(TEST_ADDR, port) }
153
199
  wra.syswrite('.')
154
200
  wra.close
155
201
  rdb.sysread(1) # wait for parent to nuke us
@@ -177,52 +223,4 @@ class TestLinux < Test::Unit::TestCase
177
223
  statuses = Process.waitall
178
224
  statuses.each { |(pid,status)| assert status.success?, status.inspect }
179
225
  end if ENV["STRESS"].to_i != 0
180
-
181
- private
182
-
183
- # Stolen from Unicorn, also a version of this is used by the Rainbows!
184
- # test suite.
185
- # unused_port provides an unused port on +addr+ usable for TCP that is
186
- # guaranteed to be unused across all compatible tests on that system. It
187
- # prevents race conditions by using a lock file other tests
188
- # will see. This is required if you perform several builds in parallel
189
- # with a continuous integration system or run tests in parallel via
190
- # gmake. This is NOT guaranteed to be race-free if you run other
191
- # systems that bind to random ports for testing (but the window
192
- # for a race condition is very small). You may also set UNICORN_TEST_ADDR
193
- # to override the default test address (127.0.0.1).
194
- def unused_port(addr = TEST_ADDR)
195
- retries = 100
196
- base = 5000
197
- port = sock = nil
198
- begin
199
- begin
200
- port = base + rand(32768 - base)
201
- while port == 8080
202
- port = base + rand(32768 - base)
203
- end
204
-
205
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
206
- sock.bind(Socket.pack_sockaddr_in(port, addr))
207
- sock.listen(5)
208
- rescue Errno::EADDRINUSE, Errno::EACCES
209
- sock.close rescue nil
210
- retry if (retries -= 1) >= 0
211
- end
212
-
213
- # since we'll end up closing the random port we just got, there's a race
214
- # condition could allow the random port we just chose to reselect itself
215
- # when running tests in parallel with gmake. Create a lock file while
216
- # we have the port here to ensure that does not happen .
217
- lock_path = "#{Dir::tmpdir}/unicorn_test.#{addr}:#{port}.lock"
218
- lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
219
- at_exit { File.unlink(lock_path) rescue nil }
220
- rescue Errno::EEXIST
221
- sock.close rescue nil
222
- retry
223
- end
224
- sock.close rescue nil
225
- port
226
- end
227
-
228
226
  end if RUBY_PLATFORM =~ /linux/