diff options
author | Eric Wong <e@80x24.org> | 2013-10-24 02:37:00 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2013-10-24 02:43:36 +0000 |
commit | c9ad7f3a7b83e990fd2fc731ec796eec4ed4130b (patch) | |
tree | 7373b003cf5c113fc45a73c4e85b3cf9c15474ec /test | |
parent | 6b545cb2bf4fb3e4ec0ad5050e19647815520dfd (diff) | |
download | yahns-c9ad7f3a7b83e990fd2fc731ec796eec4ed4130b.tar.gz |
Walking ObjectSpace should be acceptable for this test (due to MT FD allocation). Using check_client_connection saves us a bunch of time when recovering from an overload scenario.
Diffstat (limited to 'test')
-rw-r--r-- | test/test_client_expire.rb | 73 |
1 files changed, 62 insertions, 11 deletions
diff --git a/test/test_client_expire.rb b/test/test_client_expire.rb index 8ee914b..9e2ac54 100644 --- a/test/test_client_expire.rb +++ b/test/test_client_expire.rb @@ -60,7 +60,8 @@ class TestClientExpire < Testcase s = get_tcp_client(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) } + str = "" + Timeout.timeout(20) { str << s.readpartial(666) until str =~ /\r\n\r\n/ } assert_match(%r{keep-alive}, str) sleep 2 abe = tmpfile(%w(abe .err)) @@ -79,46 +80,96 @@ class TestClientExpire < Testcase quit_wait(pid) end + # test EMFILE handling 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 + queue { worker_threads 1 } + ru = lambda { |e| + sleep(0.01) unless e["PATH_INFO"] == "/_" + [ 200, h, [] ] + } + app(:rack, ru) do listen "#{host}:#{port}", sndbuf: 2048, rcvbuf: 2048 client_timeout 1 + check_client_connection true end client_expire_threshold 1.0 end - logger(Logger.new(err.path)) + stderr_path 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 + keep = { $stderr => true, $stdout => true, $stdin => true, @srv => true } + ObjectSpace.each_object(IO) do |obj| + next if keep[obj] + begin + obj.close unless obj.closed? + rescue IOError # could be uninitialized + end + end + Yahns::Server.new(cfg).start.join + exit!($!.nil?) end f = get_tcp_client(host, port) + f.write "G" s = get_tcp_client(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) } + str = "" + Timeout.timeout(20) { str << s.readpartial(666) until str =~ /\r\n\r\n/ } assert_match(%r{keep-alive}, str) - sleep 3 - system "ab -c 1000 -n 10000 -k http://#{host}:#{port}/ 2>&1" + sleep 1 + # ignore errors, just beat the crap out of the process + nr = Process.getrlimit(:NOFILE)[0] # 1024 is common + assert_operator nr, :>, 666, "increase RLIM_NOFILE (ulimit -n)" + nr -= 50 + opts = { out: "/dev/null", err: "/dev/null", close_others: true } + begin + pids = 2.times.map do + fork do + exec(*%W(ab -c #{nr} -n 9999999 -v1 -k http://#{host}:#{port}/), opts) + end + end + + re1 = %r{consider raising open file limits} + re2 = %r{dropping (\d+) of \d+ clients for timeout=\d+} + Timeout.timeout(30) do + n = 0 + begin + buf = File.read(err.path) + if buf =~ re1 && buf =~ re2 + n += $1.to_i + break if n >= 2 + end + end while sleep(0.01) + end + ensure + # don't care for ab errors, they're likely + pids.each do |_pid| + Process.kill(:KILL, _pid) + Process.waitpid2(_pid) + end + end [ f, s ].each do |io| assert_raises(Errno::EPIPE,Errno::ECONNRESET) do req.each_byte { |b| io.write(b.chr) } end io.close end + + # make sure the server still works + res = Net::HTTP.start(host, port) { |h| h.get("/_") } + assert_equal 200, res.code.to_i + 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} + re = %r{consider raising open file limits} assert_equal errs.grep(re), errs ensure quit_wait(pid) |