yahns.git  about / heads / tags
sleepy, multi-threaded, non-blocking application server for Ruby
blob 269d487c2fe0aff5984bc064fc27e43dddceec6e 3858 bytes (raw)
$ git show v0.0.1:test/test_client_expire.rb	# shows this blob on the CLI

  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

git clone git://yhbt.net/yahns.git
git clone https://yhbt.net/yahns.git