raindrops 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +2 -1
- data/.gitignore +4 -0
- data/.wrongdoc.yml +4 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +2 -196
- data/Gemfile +7 -0
- data/LICENSE +1 -1
- data/README +17 -47
- data/Rakefile +0 -104
- data/examples/linux-listener-stats.rb +123 -0
- data/examples/{config.ru → middleware.ru} +1 -1
- data/examples/watcher.ru +4 -0
- data/examples/watcher_demo.ru +13 -0
- data/examples/zbatery.conf.rb +13 -0
- data/ext/raindrops/extconf.rb +5 -0
- data/ext/raindrops/linux_inet_diag.c +449 -151
- data/ext/raindrops/linux_tcp_info.c +170 -0
- data/ext/raindrops/my_fileno.h +36 -0
- data/ext/raindrops/raindrops.c +232 -20
- data/lib/raindrops.rb +20 -7
- data/lib/raindrops/aggregate.rb +8 -0
- data/lib/raindrops/aggregate/last_data_recv.rb +86 -0
- data/lib/raindrops/aggregate/pmq.rb +239 -0
- data/lib/raindrops/last_data_recv.rb +100 -0
- data/lib/raindrops/linux.rb +26 -16
- data/lib/raindrops/middleware.rb +112 -41
- data/lib/raindrops/middleware/proxy.rb +34 -0
- data/lib/raindrops/struct.rb +15 -0
- data/lib/raindrops/watcher.rb +362 -0
- data/pkg.mk +171 -0
- data/raindrops.gemspec +10 -20
- data/test/ipv6_enabled.rb +10 -0
- data/test/rack_unicorn.rb +12 -0
- data/test/test_aggregate_pmq.rb +65 -0
- data/test/test_inet_diag_socket.rb +13 -0
- data/test/test_last_data_recv_unicorn.rb +69 -0
- data/test/test_linux.rb +55 -57
- data/test/test_linux_all_tcp_listen_stats.rb +66 -0
- data/test/test_linux_all_tcp_listen_stats_leak.rb +43 -0
- data/test/test_linux_ipv6.rb +158 -0
- data/test/test_linux_tcp_info.rb +61 -0
- data/test/test_middleware.rb +15 -2
- data/test/test_middleware_unicorn.rb +37 -0
- data/test/test_middleware_unicorn_ipv6.rb +37 -0
- data/test/test_raindrops.rb +65 -1
- data/test/test_raindrops_gc.rb +23 -1
- data/test/test_watcher.rb +85 -0
- metadata +69 -22
- data/examples/linux-tcp-listener-stats.rb +0 -44
@@ -0,0 +1,66 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'socket'
|
4
|
+
require 'raindrops'
|
5
|
+
require 'pp'
|
6
|
+
$stderr.sync = $stdout.sync = true
|
7
|
+
|
8
|
+
class TestLinuxAllTcpListenStats < Test::Unit::TestCase
|
9
|
+
include Raindrops::Linux
|
10
|
+
TEST_ADDR = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
|
11
|
+
|
12
|
+
def test_print_all
|
13
|
+
puts "EVERYTHING"
|
14
|
+
pp Raindrops::Linux.tcp_listener_stats
|
15
|
+
puts("-" * 72)
|
16
|
+
end if $stdout.tty?
|
17
|
+
|
18
|
+
def setup
|
19
|
+
@socks = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
@socks.each { |io| io.closed? or io.close }
|
24
|
+
end
|
25
|
+
|
26
|
+
def new_server
|
27
|
+
s = TCPServer.new TEST_ADDR, 0
|
28
|
+
@socks << s
|
29
|
+
[ s, s.addr[1] ]
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_client(port)
|
33
|
+
s = TCPSocket.new("127.0.0.1", port)
|
34
|
+
@socks << s
|
35
|
+
s
|
36
|
+
end
|
37
|
+
|
38
|
+
def new_accept(srv)
|
39
|
+
c = srv.accept
|
40
|
+
@socks << c
|
41
|
+
c
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_all_ports
|
45
|
+
srv, port = new_server
|
46
|
+
addr = "#{TEST_ADDR}:#{port}"
|
47
|
+
all = Raindrops::Linux.tcp_listener_stats
|
48
|
+
assert_equal [0,0], all[addr].to_a
|
49
|
+
|
50
|
+
new_client(port)
|
51
|
+
all = Raindrops::Linux.tcp_listener_stats
|
52
|
+
assert_equal [0,1], all[addr].to_a
|
53
|
+
|
54
|
+
new_client(port)
|
55
|
+
all = Raindrops::Linux.tcp_listener_stats
|
56
|
+
assert_equal [0,2], all[addr].to_a
|
57
|
+
|
58
|
+
new_accept(srv)
|
59
|
+
all = Raindrops::Linux.tcp_listener_stats
|
60
|
+
assert_equal [1,1], all[addr].to_a
|
61
|
+
|
62
|
+
new_accept(srv)
|
63
|
+
all = Raindrops::Linux.tcp_listener_stats
|
64
|
+
assert_equal [2,0], all[addr].to_a
|
65
|
+
end
|
66
|
+
end if RUBY_PLATFORM =~ /linux/
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'raindrops'
|
4
|
+
require 'socket'
|
5
|
+
require 'benchmark'
|
6
|
+
$stderr.sync = $stdout.sync = true
|
7
|
+
|
8
|
+
class TestLinuxAllTcpListenStatsLeak < Test::Unit::TestCase
|
9
|
+
|
10
|
+
TEST_ADDR = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
|
11
|
+
|
12
|
+
|
13
|
+
def rss_kb
|
14
|
+
File.readlines("/proc/#$$/status").grep(/VmRSS:/)[0].split(/\s+/)[1].to_i
|
15
|
+
end
|
16
|
+
def test_leak
|
17
|
+
s = TCPServer.new(TEST_ADDR, 0)
|
18
|
+
start_kb = rss_kb
|
19
|
+
p [ :start_kb, start_kb ]
|
20
|
+
assert_nothing_raised do
|
21
|
+
p(Benchmark.measure {
|
22
|
+
1000.times { Raindrops::Linux.all_tcp_listener_stats }
|
23
|
+
})
|
24
|
+
end
|
25
|
+
cur_kb = rss_kb
|
26
|
+
p [ :cur_kb, cur_kb ]
|
27
|
+
now = Time.now.to_i
|
28
|
+
fin = now + 60
|
29
|
+
assert_nothing_raised do
|
30
|
+
1000000000.times { |i|
|
31
|
+
if (i % 1024) == 0
|
32
|
+
now = Time.now.to_i
|
33
|
+
break if now > fin
|
34
|
+
end
|
35
|
+
Raindrops::Linux.all_tcp_listener_stats
|
36
|
+
}
|
37
|
+
end
|
38
|
+
cur_kb = rss_kb
|
39
|
+
p [ :cur_kb, cur_kb ]
|
40
|
+
ensure
|
41
|
+
s.close
|
42
|
+
end
|
43
|
+
end if ENV["STRESS"].to_i != 0
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'raindrops'
|
5
|
+
require 'socket'
|
6
|
+
require 'pp'
|
7
|
+
require "./test/ipv6_enabled"
|
8
|
+
$stderr.sync = $stdout.sync = true
|
9
|
+
|
10
|
+
class TestLinuxIPv6 < Test::Unit::TestCase
|
11
|
+
include Raindrops::Linux
|
12
|
+
|
13
|
+
TEST_ADDR = ENV["TEST_HOST6"] || "::1"
|
14
|
+
|
15
|
+
def test_tcp
|
16
|
+
s = TCPServer.new(TEST_ADDR, 0)
|
17
|
+
port = s.addr[1]
|
18
|
+
addr = "[#{TEST_ADDR}]:#{port}"
|
19
|
+
addrs = [ addr ]
|
20
|
+
stats = tcp_listener_stats(addrs)
|
21
|
+
assert_equal 1, stats.size
|
22
|
+
assert_equal 0, stats[addr].queued
|
23
|
+
assert_equal 0, stats[addr].active
|
24
|
+
|
25
|
+
c = TCPSocket.new(TEST_ADDR, port)
|
26
|
+
stats = tcp_listener_stats(addrs)
|
27
|
+
assert_equal 1, stats.size
|
28
|
+
assert_equal 1, stats[addr].queued
|
29
|
+
assert_equal 0, stats[addr].active
|
30
|
+
|
31
|
+
sc = s.accept
|
32
|
+
stats = tcp_listener_stats(addrs)
|
33
|
+
assert_equal 1, stats.size
|
34
|
+
assert_equal 0, stats[addr].queued
|
35
|
+
assert_equal 1, stats[addr].active
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_tcp_multi
|
39
|
+
s1 = TCPServer.new(TEST_ADDR, 0)
|
40
|
+
s2 = TCPServer.new(TEST_ADDR, 0)
|
41
|
+
port1, port2 = s1.addr[1], s2.addr[1]
|
42
|
+
addr1, addr2 = "[#{TEST_ADDR}]:#{port1}", "[#{TEST_ADDR}]:#{port2}"
|
43
|
+
addrs = [ addr1, addr2 ]
|
44
|
+
stats = tcp_listener_stats(addrs)
|
45
|
+
assert_equal 2, stats.size
|
46
|
+
assert_equal 0, stats[addr1].queued
|
47
|
+
assert_equal 0, stats[addr1].active
|
48
|
+
assert_equal 0, stats[addr2].queued
|
49
|
+
assert_equal 0, stats[addr2].active
|
50
|
+
|
51
|
+
c1 = TCPSocket.new(TEST_ADDR, port1)
|
52
|
+
stats = tcp_listener_stats(addrs)
|
53
|
+
assert_equal 2, stats.size
|
54
|
+
assert_equal 1, stats[addr1].queued
|
55
|
+
assert_equal 0, stats[addr1].active
|
56
|
+
assert_equal 0, stats[addr2].queued
|
57
|
+
assert_equal 0, stats[addr2].active
|
58
|
+
|
59
|
+
sc1 = s1.accept
|
60
|
+
stats = tcp_listener_stats(addrs)
|
61
|
+
assert_equal 2, stats.size
|
62
|
+
assert_equal 0, stats[addr1].queued
|
63
|
+
assert_equal 1, stats[addr1].active
|
64
|
+
assert_equal 0, stats[addr2].queued
|
65
|
+
assert_equal 0, stats[addr2].active
|
66
|
+
|
67
|
+
c2 = TCPSocket.new(TEST_ADDR, port2)
|
68
|
+
stats = tcp_listener_stats(addrs)
|
69
|
+
assert_equal 2, stats.size
|
70
|
+
assert_equal 0, stats[addr1].queued
|
71
|
+
assert_equal 1, stats[addr1].active
|
72
|
+
assert_equal 1, stats[addr2].queued
|
73
|
+
assert_equal 0, stats[addr2].active
|
74
|
+
|
75
|
+
c3 = TCPSocket.new(TEST_ADDR, port2)
|
76
|
+
stats = tcp_listener_stats(addrs)
|
77
|
+
assert_equal 2, stats.size
|
78
|
+
assert_equal 0, stats[addr1].queued
|
79
|
+
assert_equal 1, stats[addr1].active
|
80
|
+
assert_equal 2, stats[addr2].queued
|
81
|
+
assert_equal 0, stats[addr2].active
|
82
|
+
|
83
|
+
sc2 = s2.accept
|
84
|
+
stats = tcp_listener_stats(addrs)
|
85
|
+
assert_equal 2, stats.size
|
86
|
+
assert_equal 0, stats[addr1].queued
|
87
|
+
assert_equal 1, stats[addr1].active
|
88
|
+
assert_equal 1, stats[addr2].queued
|
89
|
+
assert_equal 1, stats[addr2].active
|
90
|
+
|
91
|
+
sc1.close
|
92
|
+
stats = tcp_listener_stats(addrs)
|
93
|
+
assert_equal 0, stats[addr1].queued
|
94
|
+
assert_equal 0, stats[addr1].active
|
95
|
+
assert_equal 1, stats[addr2].queued
|
96
|
+
assert_equal 1, stats[addr2].active
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_invalid_addresses
|
100
|
+
assert_raises(ArgumentError) { tcp_listener_stats(%w([1:::5)) }
|
101
|
+
assert_raises(ArgumentError) { tcp_listener_stats(%w([1:::]5)) }
|
102
|
+
end
|
103
|
+
|
104
|
+
# tries to overflow buffers
|
105
|
+
def test_tcp_stress_test
|
106
|
+
nr_proc = 32
|
107
|
+
nr_sock = 500
|
108
|
+
s = TCPServer.new(TEST_ADDR, 0)
|
109
|
+
port = s.addr[1]
|
110
|
+
addr = "[#{TEST_ADDR}]:#{port}"
|
111
|
+
addrs = [ addr ]
|
112
|
+
rda, wra = IO.pipe
|
113
|
+
rdb, wrb = IO.pipe
|
114
|
+
|
115
|
+
nr_proc.times do
|
116
|
+
fork do
|
117
|
+
rda.close
|
118
|
+
wrb.close
|
119
|
+
socks = (1..nr_sock).map { s.accept }
|
120
|
+
wra.syswrite('.')
|
121
|
+
wra.close
|
122
|
+
rdb.sysread(1) # wait for parent to nuke us
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
nr_proc.times do
|
127
|
+
fork do
|
128
|
+
rda.close
|
129
|
+
wrb.close
|
130
|
+
socks = (1..nr_sock).map { TCPSocket.new(TEST_ADDR, port) }
|
131
|
+
wra.syswrite('.')
|
132
|
+
wra.close
|
133
|
+
rdb.sysread(1) # wait for parent to nuke us
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_equal('.' * (nr_proc * 2), rda.read(nr_proc * 2))
|
138
|
+
|
139
|
+
rda.close
|
140
|
+
stats = tcp_listener_stats(addrs)
|
141
|
+
expect = { addr => Raindrops::ListenStats[nr_sock * nr_proc, 0] }
|
142
|
+
assert_equal expect, stats
|
143
|
+
|
144
|
+
uno_mas = TCPSocket.new(TEST_ADDR, port)
|
145
|
+
stats = tcp_listener_stats(addrs)
|
146
|
+
expect = { addr => Raindrops::ListenStats[nr_sock * nr_proc, 1] }
|
147
|
+
assert_equal expect, stats
|
148
|
+
|
149
|
+
if ENV["BENCHMARK"].to_i != 0
|
150
|
+
require 'benchmark'
|
151
|
+
puts(Benchmark.measure{1000.times { tcp_listener_stats(addrs) }})
|
152
|
+
end
|
153
|
+
|
154
|
+
wrb.syswrite('.' * (nr_proc * 2)) # broadcast a wakeup
|
155
|
+
statuses = Process.waitall
|
156
|
+
statuses.each { |(pid,status)| assert status.success?, status.inspect }
|
157
|
+
end if ENV["STRESS"].to_i != 0
|
158
|
+
end if RUBY_PLATFORM =~ /linux/ && ipv6_enabled?
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'raindrops'
|
5
|
+
require 'socket'
|
6
|
+
require 'pp'
|
7
|
+
$stderr.sync = $stdout.sync = true
|
8
|
+
class TestLinuxTCP_Info < Test::Unit::TestCase
|
9
|
+
|
10
|
+
TEST_ADDR = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
|
11
|
+
|
12
|
+
# Linux kernel commit 5ee3afba88f5a79d0bff07ddd87af45919259f91
|
13
|
+
TCP_INFO_useful_listenq = `uname -r`.strip >= '2.6.24'
|
14
|
+
|
15
|
+
def test_tcp_server
|
16
|
+
s = TCPServer.new(TEST_ADDR, 0)
|
17
|
+
rv = Raindrops::TCP_Info.new s
|
18
|
+
c = TCPSocket.new TEST_ADDR, s.addr[1]
|
19
|
+
tmp = Raindrops::TCP_Info.new s
|
20
|
+
TCP_INFO_useful_listenq and assert_equal 1, tmp.unacked
|
21
|
+
|
22
|
+
assert_equal 0, rv.unacked
|
23
|
+
a = s.accept
|
24
|
+
tmp = Raindrops::TCP_Info.new s
|
25
|
+
assert_equal 0, tmp.unacked
|
26
|
+
ensure
|
27
|
+
c.close if c
|
28
|
+
a.close if a
|
29
|
+
s.close
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_accessors
|
33
|
+
s = TCPServer.new TEST_ADDR, 0
|
34
|
+
tmp = Raindrops::TCP_Info.new s
|
35
|
+
tcp_info_methods = tmp.methods - Object.new.methods
|
36
|
+
assert tcp_info_methods.size >= 32
|
37
|
+
tcp_info_methods.each do |m|
|
38
|
+
val = tmp.__send__ m
|
39
|
+
assert_kind_of Integer, val
|
40
|
+
assert val >= 0
|
41
|
+
end
|
42
|
+
ensure
|
43
|
+
s.close
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_tcp_server_delayed
|
47
|
+
delay = 0.010
|
48
|
+
delay_ms = (delay * 1000).to_i
|
49
|
+
s = TCPServer.new(TEST_ADDR, 0)
|
50
|
+
c = TCPSocket.new TEST_ADDR, s.addr[1]
|
51
|
+
c.syswrite "."
|
52
|
+
sleep delay
|
53
|
+
a = s.accept
|
54
|
+
i = Raindrops::TCP_Info.new(a)
|
55
|
+
assert i.last_data_recv >= delay_ms, "#{i.last_data_recv} < #{delay_ms}"
|
56
|
+
ensure
|
57
|
+
c.close if c
|
58
|
+
a.close if a
|
59
|
+
s.close
|
60
|
+
end
|
61
|
+
end
|
data/test/test_middleware.rb
CHANGED
@@ -14,7 +14,7 @@ class TestMiddleware < Test::Unit::TestCase
|
|
14
14
|
app = Raindrops::Middleware.new(@app)
|
15
15
|
response = app.call({})
|
16
16
|
assert_equal @response[0,2], response[0,2]
|
17
|
-
assert response.last.kind_of?(Raindrops::Middleware)
|
17
|
+
assert response.last.kind_of?(Raindrops::Middleware::Proxy)
|
18
18
|
assert response.last.object_id != app.object_id
|
19
19
|
tmp = []
|
20
20
|
response.last.each { |y| tmp << y }
|
@@ -35,7 +35,7 @@ class TestMiddleware < Test::Unit::TestCase
|
|
35
35
|
assert_equal 0, stats.calling
|
36
36
|
assert_equal 1, stats.writing
|
37
37
|
assert_equal 200, response[0]
|
38
|
-
assert response.last.kind_of?(Raindrops::Middleware)
|
38
|
+
assert response.last.kind_of?(Raindrops::Middleware::Proxy)
|
39
39
|
tmp = []
|
40
40
|
response.last.each do |y|
|
41
41
|
assert_equal 1, stats.writing
|
@@ -108,4 +108,17 @@ class TestMiddleware < Test::Unit::TestCase
|
|
108
108
|
assert_equal expect, response
|
109
109
|
end
|
110
110
|
|
111
|
+
def test_middleware_proxy_to_path_missing
|
112
|
+
app = Raindrops::Middleware.new(@app)
|
113
|
+
response = app.call({})
|
114
|
+
body = response[2]
|
115
|
+
assert_kind_of Raindrops::Middleware::Proxy, body
|
116
|
+
assert ! body.respond_to?(:to_path)
|
117
|
+
assert body.respond_to?(:close)
|
118
|
+
orig_body = @response[2]
|
119
|
+
|
120
|
+
def orig_body.to_path; "/dev/null"; end
|
121
|
+
assert body.respond_to?(:to_path)
|
122
|
+
assert_equal "/dev/null", body.to_path
|
123
|
+
end
|
111
124
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/rack_unicorn"
|
3
|
+
$stderr.sync = $stdout.sync = true
|
4
|
+
|
5
|
+
class TestMiddlewareUnicorn < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@host = ENV["UNICORN_TEST_ADDR"] || "127.0.0.1"
|
9
|
+
@sock = TCPServer.new @host, 0
|
10
|
+
@port = @sock.addr[1]
|
11
|
+
ENV["UNICORN_FD"] = @sock.fileno.to_s
|
12
|
+
@host_with_port = "#@host:#@port"
|
13
|
+
@opts = { :listeners => [ @host_with_port ] }
|
14
|
+
@addr_regexp = Regexp.escape @host_with_port
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_auto_listener
|
18
|
+
@app = Rack::Builder.new do
|
19
|
+
use Raindrops::Middleware
|
20
|
+
run Rack::Lobster.new
|
21
|
+
end
|
22
|
+
@srv = fork { Unicorn.run(@app, @opts) }
|
23
|
+
|
24
|
+
s = TCPSocket.new @host, @port
|
25
|
+
s.write "GET /_raindrops HTTP/1.0\r\n\r\n"
|
26
|
+
resp = s.read
|
27
|
+
head, body = resp.split /\r\n\r\n/, 2
|
28
|
+
assert_match %r{^#@addr_regexp active: 1$}, body
|
29
|
+
assert_match %r{^#@addr_regexp queued: 0$}, body
|
30
|
+
end
|
31
|
+
|
32
|
+
def teardown
|
33
|
+
Process.kill :QUIT, @srv
|
34
|
+
_, status = Process.waitpid2 @srv
|
35
|
+
assert status.success?
|
36
|
+
end
|
37
|
+
end if defined?(Unicorn) && RUBY_PLATFORM =~ /linux/
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/rack_unicorn"
|
3
|
+
require "./test/ipv6_enabled"
|
4
|
+
$stderr.sync = $stdout.sync = true
|
5
|
+
|
6
|
+
class TestMiddlewareUnicornIPv6 < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@host = ENV["TEST_HOST6"] || "::1"
|
10
|
+
sock = TCPServer.new @host, 0
|
11
|
+
@port = sock.addr[1]
|
12
|
+
ENV["UNICORN_FD"] = sock.fileno.to_s
|
13
|
+
@host_with_port = "[#@host]:#@port"
|
14
|
+
@opts = { :listeners => [ @host_with_port ] }
|
15
|
+
@addr_regexp = Regexp.escape @host_with_port
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_auto_listener
|
19
|
+
@app = Rack::Builder.new do
|
20
|
+
use Raindrops::Middleware
|
21
|
+
run Rack::Lobster.new
|
22
|
+
end
|
23
|
+
@srv = fork { Unicorn.run(@app, @opts) }
|
24
|
+
s = TCPSocket.new @host, @port
|
25
|
+
s.write "GET /_raindrops HTTP/1.0\r\n\r\n"
|
26
|
+
resp = s.read
|
27
|
+
head, body = resp.split /\r\n\r\n/, 2
|
28
|
+
assert_match %r{^#@addr_regexp active: 1$}, body
|
29
|
+
assert_match %r{^#@addr_regexp queued: 0$}, body
|
30
|
+
end
|
31
|
+
|
32
|
+
def teardown
|
33
|
+
Process.kill :QUIT, @srv
|
34
|
+
_, status = Process.waitpid2 @srv
|
35
|
+
assert status.success?
|
36
|
+
end
|
37
|
+
end if defined?(Unicorn) && RUBY_PLATFORM =~ /linux/ && ipv6_enabled?
|
data/test/test_raindrops.rb
CHANGED
@@ -4,15 +4,27 @@ require 'raindrops'
|
|
4
4
|
|
5
5
|
class TestRaindrops < Test::Unit::TestCase
|
6
6
|
|
7
|
+
def test_raindrop_counter_max
|
8
|
+
assert_kind_of Integer, Raindrops::MAX
|
9
|
+
assert Raindrops::MAX > 0
|
10
|
+
printf "Raindrops::MAX = 0x%x\n", Raindrops::MAX
|
11
|
+
end
|
12
|
+
|
7
13
|
def test_raindrop_size
|
8
14
|
assert_kind_of Integer, Raindrops::SIZE
|
9
15
|
assert Raindrops::SIZE > 0
|
10
16
|
puts "Raindrops::SIZE = #{Raindrops::SIZE}"
|
11
17
|
end
|
12
18
|
|
13
|
-
def
|
19
|
+
def test_page_size
|
20
|
+
assert_kind_of Integer, Raindrops::PAGE_SIZE
|
21
|
+
assert Raindrops::PAGE_SIZE > Raindrops::SIZE
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_size_and_capa
|
14
25
|
rd = Raindrops.new(4)
|
15
26
|
assert_equal 4, rd.size
|
27
|
+
assert rd.capa >= rd.size
|
16
28
|
end
|
17
29
|
|
18
30
|
def test_ary
|
@@ -98,4 +110,56 @@ class TestRaindrops < Test::Unit::TestCase
|
|
98
110
|
assert_equal expect, rd.to_ary
|
99
111
|
end
|
100
112
|
|
113
|
+
def test_resize
|
114
|
+
rd = Raindrops.new(4)
|
115
|
+
assert_equal 4, rd.size
|
116
|
+
assert_equal rd.capa, rd.size = rd.capa
|
117
|
+
assert_equal rd.capa, rd.to_ary.size
|
118
|
+
assert_equal 0, rd[rd.capa - 1]
|
119
|
+
assert_equal 1, rd.incr(rd.capa - 1)
|
120
|
+
assert_raises(ArgumentError) { rd[rd.capa] }
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_resize_mremap
|
124
|
+
rd = Raindrops.new(4)
|
125
|
+
assert_equal 4, rd.size
|
126
|
+
old_capa = rd.capa
|
127
|
+
rd.size = rd.capa + 1
|
128
|
+
assert_equal old_capa * 2, rd.capa
|
129
|
+
|
130
|
+
# mremap() is currently broken with MAP_SHARED
|
131
|
+
# https://bugzilla.kernel.org/show_bug.cgi?id=8691
|
132
|
+
assert_equal 0, rd[old_capa]
|
133
|
+
assert_equal rd.capa, rd.to_ary.size
|
134
|
+
assert_equal 0, rd[rd.capa - 1]
|
135
|
+
assert_equal 1, rd.incr(rd.capa - 1)
|
136
|
+
assert_raises(ArgumentError) { rd[rd.capa] }
|
137
|
+
rescue RangeError
|
138
|
+
end # if RUBY_PLATFORM =~ /linux/
|
139
|
+
|
140
|
+
def test_evaporate
|
141
|
+
rd = Raindrops.new 1
|
142
|
+
assert_nil rd.evaporate!
|
143
|
+
assert_raises(StandardError) { rd.evaporate! }
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_evaporate_with_fork
|
147
|
+
tmp = Raindrops.new 2
|
148
|
+
pid = fork do
|
149
|
+
tmp.incr 0
|
150
|
+
exit(tmp.evaporate! == nil)
|
151
|
+
end
|
152
|
+
_, status = Process.waitpid2(pid)
|
153
|
+
assert status.success?
|
154
|
+
assert_equal [ 1, 0 ], tmp.to_ary
|
155
|
+
tmp.incr 1
|
156
|
+
assert_equal [ 1, 1 ], tmp.to_ary
|
157
|
+
pid = fork do
|
158
|
+
tmp.incr 1
|
159
|
+
exit([ 1, 2 ] == tmp.to_ary)
|
160
|
+
end
|
161
|
+
_, status = Process.waitpid2(pid)
|
162
|
+
assert status.success?
|
163
|
+
assert_equal [ 1, 2 ], tmp.to_ary
|
164
|
+
end
|
101
165
|
end
|