1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
| | # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
require_relative 'server_helper'
class TestClientExpire < Testcase
parallelize_me!
include ServerHelper
alias setup server_helper_setup
alias teardown server_helper_teardown
def test_client_expire_negative
err = @err
cfg = Yahns::Config.new
host, port = @srv.addr[3], @srv.addr[1]
cfg.instance_eval do
GTL.synchronize do
ru = lambda { |e| h = { "Content-Length" => "0" }; [ 200, h, [] ] }
app(:rack, ru) do
listen "#{host}:#{port}", sndbuf: 2048, rcvbuf: 2048
end
client_expire_threshold(-10)
end
logger(Logger.new(err.path))
end
srv = Yahns::Server.new(cfg)
pid = fork do
ENV["YAHNS_FD"] = @srv.fileno.to_s
srv.start.join
end
Net::HTTP.start(host, port) { |h|
res = h.get("/")
assert_empty res.body
}
ensure
quit_wait(pid)
end
def test_client_expire
nr = 32
err = @err
cfg = Yahns::Config.new
host, port = @srv.addr[3], @srv.addr[1]
cfg.instance_eval do
GTL.synchronize do
h = { "Content-Length" => "0" }
app(:rack, lambda { |e| [ 200, h, [] ]}) do
listen "#{host}:#{port}", sndbuf: 2048, rcvbuf: 2048
client_timeout 1
end
client_expire_threshold(32)
end
logger(Logger.new(err.path))
end
srv = Yahns::Server.new(cfg)
pid = fork do
ENV["YAHNS_FD"] = @srv.fileno.to_s
srv.start.join
end
f = TCPSocket.new(host, port)
s = TCPSocket.new(host, port)
req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
s.write(req)
str = Timeout.timeout(20) { s.readpartial(666) }
assert_match(%r{keep-alive}, str)
sleep 2
abe = tmpfile(%w(abe .err))
ab_res = `ab -c #{nr} -n 10000 -k http://#{host}:#{port}/ 2>#{abe.path}`
assert $?.success?, $?.inspect << abe.read
abe.close!
assert_match(/Complete requests:\s+10000\n/, ab_res)
[ f, s ].each do |io|
assert_raises(Errno::EPIPE,Errno::ECONNRESET) do
req.each_byte { |b| io.write(b.chr) }
end
io.close
end
rescue => e
Yahns::Log.exception(Logger.new($stderr), "test", e)
raise
ensure
quit_wait(pid)
end
def test_client_expire_desperate
skip "disabled since FD counts vary heavily in an MT process"
err = @err
cfg = Yahns::Config.new
host, port = @srv.addr[3], @srv.addr[1]
cfg.instance_eval do
GTL.synchronize do
h = { "Content-Length" => "0" }
app(:rack, lambda { |e| [ 200, h, [] ]}) do
listen "#{host}:#{port}", sndbuf: 2048, rcvbuf: 2048
client_timeout 1
end
client_expire_threshold 1.0
end
logger(Logger.new(err.path))
end
srv = Yahns::Server.new(cfg)
pid = fork do
Process.setrlimit :NOFILE, 512, 1024
ENV["YAHNS_FD"] = @srv.fileno.to_s
srv.start.join
end
f = TCPSocket.new(host, port)
s = TCPSocket.new(host, port)
req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
s.write(req)
str = Timeout.timeout(20) { s.readpartial(666) }
assert_match(%r{keep-alive}, str)
sleep 3
system "ab -c 1000 -n 10000 -k http://#{host}:#{port}/ 2>&1"
[ f, s ].each do |io|
assert_raises(Errno::EPIPE,Errno::ECONNRESET) do
req.each_byte { |b| io.write(b.chr) }
end
io.close
end
errs = File.readlines(err.path).grep(/ERROR/)
File.truncate(err.path, 0) # avoid error on teardown
re = %r{consider raising open file limits} # - accept, consider raising open file limits}
assert_equal errs.grep(re), errs
rescue => e
Yahns::Log.exception(Logger.new($stderr), "test", e)
raise
ensure
quit_wait(pid)
end
end
|