diff --git a/test/session_test.rb b/test/session_test.rb index f5992343..f105aeda 100644 --- a/test/session_test.rb +++ b/test/session_test.rb @@ -69,6 +69,30 @@ class SessionTest < Minitest::Test end end + def test_session_timeouts_read_timeout + uri = build_uri("/drip?numbytes=10&duration=4&delay=2&code=200") + session = HTTPX.with_timeout(read_timeout: 3, operation_timeout: 10) + response = session.get(uri) + verify_error_response(response, HTTPX::ReadTimeoutError) + + uri = build_uri("/drip?numbytes=10&duration=2&delay=0&code=200") + response1 = session.get(uri) + verify_status(response1, 200) + end + + def test_session_timeouts_write_timeout + start_test_servlet(SlowReader) do |server| + uri = URI("#{server.origin}/") + session = HTTPX.with(timeout: { write_timeout: 4, operation_timeout: 10 }) + response = session.post(uri, body: StringIO.new("a" * 65_536 * 2 * 5)) + verify_error_response(response, HTTPX::WriteTimeoutError) + + session = HTTPX.with_timeout(write_timeout: 8, operation_timeout: 60) + response1 = session.post(uri, body: StringIO.new("a" * 65_536 * 2 * 5)) + verify_status(response1, 200) + end + end + # def test_http_timeouts_operation_timeout # uri = build_uri("/delay/2") # session = HTTPX.with_timeout(operation_timeout: 1) diff --git a/test/support/servlets/slow_reader.rb b/test/support/servlets/slow_reader.rb new file mode 100644 index 00000000..a40513c6 --- /dev/null +++ b/test/support/servlets/slow_reader.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "socket" + +class SlowReader + def initialize + @server = TCPServer.new("127.0.0.1", 0) + @server.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVBUF, 5) + @can_log = ENV.key?("HTTPX_DEBUG") + end + + def origin + _, sock, ip, _ = @server.addr + "http://#{ip}:#{sock}" + end + + def start + loop do + sock = @server.accept + + begin + sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVBUF, 5) + request = +"" + 5.times do + request << sock.readpartial(2048) + warn "buffered request: #{request.size} (closed? #{sock.closed?})" if @can_log + sleep(1) + end + sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVBUF, 65_535) + request << sock.readpartial(2048) + # warn "request: #{request.size}" if @can_log + response = "HTTP/1.1 200\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + sock.puts(response) + rescue IOError => e + warn e.message + ensure + sock.close + end + end + rescue IOError + end + + def shutdown + @server.close + end +end