rhenium/plum

View on GitHub
test/plum/client/test_client.rb

Summary

Maintainability
B
4 hrs
Test Coverage
require "test_helper"

using Plum::BinaryString
class ClientTest < Minitest::Test
  def test_request_async
    res2 = nil
    client = nil
    server_thread = start_tls_server
    Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |c|
      client = c
      res1 = client.request({ ":path" => "/", ":method" => "GET", ":scheme" => "https", "header" => "ccc" }, nil) { |res1|
        assert(res1.headers)
      }
      assert_nil(res1.headers)

      res2 = client.get("/", headers: { "header" => "ccc" })
      assert_nil(res2.headers)
    }
    assert(res2.headers)
    assert_equal("GETccc", res2.body)
  ensure
    server_thread.join if server_thread
  end

  def test_verify
    client = nil
    server_thread = start_tls_server
    assert_raises(OpenSSL::SSL::SSLError) {
      client = Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_PEER)
    }
  ensure
    server_thread.join if server_thread
  end

  def test_raise_error_async_seq_resume
    server_thread = start_tls_server
    client = Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE)
    res = client.get("/error_in_data")
    assert_raises(LocalConnectionError) {
      client.resume
    }
    client.close
  ensure
    server_thread.join if server_thread
  end

  def test_raise_error_async_block
    client = nil
    server_thread = start_tls_server
    assert_raises(LocalConnectionError) {
      Client.start("127.0.0.1", LISTEN_PORT, https: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |c|
        client = c
        client.get("/connection_error") { |res| flunk "success??" }
      } # resume
    }
  ensure
    server_thread.join if server_thread
  end

  def test_session_socket_http2_https
    sock = StringSocket.new
    client = Client.start(sock, nil, https: true)
    assert(client.session.class == ClientSession)
  end

  def test_session_socket_http2_http
    sock = StringSocket.new("HTTP/1.1 100\r\n\r\n")
    client = Client.start(sock, nil, https: false)
    assert(client.session.class == UpgradeClientSession)
  end

  private
  def start_tls_server(&block)
    ctx = OpenSSL::SSL::SSLContext.new
    ctx.alpn_select_cb = -> protocols { "h2" }
    ctx.cert = TLS_CERT
    ctx.key = TLS_KEY
    tcp_server = TCPServer.new("127.0.0.1", LISTEN_PORT)
    ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)

    server_thread = Thread.new {
      plum = nil
      begin
        Timeout.timeout(1) {
          sock = ssl_server.accept
          plum = ServerConnection.new(sock.method(:write))

          plum.on(:stream) { |stream|
            headers = data = nil
            stream.on(:headers) { |h|
              headers = h.to_h }
            stream.on(:data) { |d|
              data = d }
            stream.on(:end_stream) {
              case headers[":path"]
              when "/connection_error"
                plum.goaway(:protocol_error)
              when "/error_in_data"
                stream.send_headers({ ":status" => 200 }, end_stream: false)
                stream.send_data("a", end_stream: false)
                raise ExampleError, "example error"
              else
                stream.send_headers({ ":status" => 200 }, end_stream: false)
                stream.send_data(headers.to_h[":method"] + headers.to_h["header"].to_s + data.to_s, end_stream: true)
              end } }

          yield plum if block_given?

          begin
            while !sock.closed? && !sock.eof?
              plum << sock.readpartial(1024)
            end
          rescue Errno::ECONNABORTED
            # Ignore, this happens only when running on mingw64(?)
          end
        }
      rescue OpenSSL::SSL::SSLError
      rescue Timeout::Error
        flunk "server timeout"
      rescue ExampleError => e
        plum.goaway(:internal_error) if plum
      ensure
        tcp_server.close
      end
    }
  end
end