Repository: puma/puma
File: test/helpers/integration.rb (Ruby)

Code before:

  # used to define correct 'refused' errors
  def thread_run_refused(unix: false)
    if unix
      [Errno::ENOENT, IOError]
    else
      DARWIN ? [Errno::ECONNREFUSED, Errno::EPIPE, EOFError] :
        [Errno::ECONNREFUSED]
    end
  end

  def cli_pumactl(argv, unix: false)
    if unix
      pumactl = IO.popen("#{BASE} bin/pumactl -C unix://#{@control_path} -T #{TOKEN} #{argv}", "r")
    else
      pumactl = IO.popen("#{BASE} bin/pumactl -C tcp://#{HOST}:#{@control_tcp_port} -T #{TOKEN} #{argv}", "r")
    end
    @ios_to_close << pumactl
    Process.wait pumactl.pid
    pumactl
  end

  def hot_restart_does_not_drop_connections(num_threads: 1, ttl_requests: 500)
    skipped = true
    skip_on :jruby, suffix: <<-MSG
 - file descriptors are not preserved on exec on JRuby; connection reset errors are expected during restarts
    MSG
    skip_on :truffleruby, suffix: ' - Undiagnosed failures on TruffleRuby'
    skip "Undiagnosed failures on Ruby 2.2" if RUBY_VERSION < '2.3'

    args = "-w #{workers} -t 0:5 -q test/rackup/hello_with_delay.ru"
    if Puma.windows?
      @control_tcp_port = UniquePort.call
      cli_server "#{args} --control-url tcp://#{HOST}:#{@control_tcp_port} --control-token #{TOKEN}"
    else
      cli_server args
    end

    skipped = false
    replies = Hash.new 0
    refused = thread_run_refused unix: false
    message = 'A' * 16_256  # 2^14 - 128

    mutex = Mutex.new
    restart_count = 0
    client_threads = []

    num_requests = (ttl_requests/num_threads).to_i

    num_threads.times do |thread|
      client_threads << Thread.new do

Review comment (suggestion):
Seems like the behavior on JRuby should be the same as on Windows: Since `exec` doesn't preserve file descriptors on those platforms, puma has to unbind-and-rebind the listening socket, so we lose some connections during restart.

Is there any reason why we run the test on Windows (with the expectation that the number of connection reset errors per thread is bound from above by the number of restarts), but skip the test on JRuby? Seems like we can make the same decision in both places.

Either we can skip on both platforms (connection reset errors are expected on both, so maybe not worth having explicit tests for), or we can run it on both.

Code after:

  # used to define correct 'refused' errors
  def thread_run_refused(unix: false)
    if unix
      [Errno::ENOENT, IOError]
    else
      DARWIN ? [Errno::ECONNREFUSED, Errno::EPIPE, EOFError] :
        [Errno::ECONNREFUSED]
    end
  end

  def cli_pumactl(argv, unix: false)
    if unix
      pumactl = IO.popen("#{BASE} bin/pumactl -C unix://#{@control_path} -T #{TOKEN} #{argv}", "r")
    else
      pumactl = IO.popen("#{BASE} bin/pumactl -C tcp://#{HOST}:#{@control_tcp_port} -T #{TOKEN} #{argv}", "r")
    end
    @ios_to_close << pumactl
    Process.wait pumactl.pid
    pumactl
  end

  def hot_restart_does_not_drop_connections(num_threads: 1, total_requests: 500)
    skipped = true
    skip_on :jruby, suffix: <<-MSG
 - file descriptors are not preserved on exec on JRuby; connection reset errors are expected during restarts
    MSG
    skip_on :truffleruby, suffix: ' - Undiagnosed failures on TruffleRuby'
    skip "Undiagnosed failures on Ruby 2.2" if RUBY_VERSION < '2.3'

    args = "-w #{workers} -t 0:5 -q test/rackup/hello_with_delay.ru"
    if Puma.windows?
      @control_tcp_port = UniquePort.call
      cli_server "#{args} --control-url tcp://#{HOST}:#{@control_tcp_port} --control-token #{TOKEN}"
    else
      cli_server args
    end

    skipped = false
    replies = Hash.new 0
    refused = thread_run_refused unix: false
    message = 'A' * 16_256  # 2^14 - 128

    mutex = Mutex.new
    restart_count = 0
    client_threads = []

    num_requests = (total_requests/num_threads).to_i

    num_threads.times do |thread|
      client_threads << Thread.new do