Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc
new file mode 100644
index 0000000..a0068d5
--- /dev/null
+++ b/quic/test_tools/quic_test_client.cc
@@ -0,0 +1,909 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "third_party/boringssl/src/include/openssl/x509.h"
+#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/tools/quic_url.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+// RecordingProofVerifier accepts any certificate chain and records the common
+// name of the leaf and then delegates the actual verification to an actual
+// verifier. If no optional verifier is provided, then VerifyProof will return
+// success.
+class RecordingProofVerifier : public ProofVerifier {
+ public:
+  explicit RecordingProofVerifier(std::unique_ptr<ProofVerifier> verifier)
+      : verifier_(std::move(verifier)) {}
+
+  // ProofVerifier interface.
+  QuicAsyncStatus VerifyProof(
+      const QuicString& hostname,
+      const uint16_t port,
+      const QuicString& server_config,
+      QuicTransportVersion transport_version,
+      QuicStringPiece chlo_hash,
+      const std::vector<QuicString>& certs,
+      const QuicString& cert_sct,
+      const QuicString& signature,
+      const ProofVerifyContext* context,
+      QuicString* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    common_name_.clear();
+    if (certs.empty()) {
+      return QUIC_FAILURE;
+    }
+
+    const uint8_t* data;
+    data = reinterpret_cast<const uint8_t*>(certs[0].data());
+    bssl::UniquePtr<X509> cert(d2i_X509(nullptr, &data, certs[0].size()));
+    if (!cert.get()) {
+      return QUIC_FAILURE;
+    }
+
+    static const unsigned kMaxCommonNameLength = 256;
+    char buf[kMaxCommonNameLength];
+    X509_NAME* subject_name = X509_get_subject_name(cert.get());
+    if (X509_NAME_get_text_by_NID(subject_name, NID_commonName, buf,
+                                  sizeof(buf)) <= 0) {
+      return QUIC_FAILURE;
+    }
+
+    common_name_ = buf;
+    cert_sct_ = cert_sct;
+
+    if (!verifier_) {
+      return QUIC_SUCCESS;
+    }
+
+    return verifier_->VerifyProof(hostname, port, server_config,
+                                  transport_version, chlo_hash, certs, cert_sct,
+                                  signature, context, error_details, details,
+                                  std::move(callback));
+  }
+
+  QuicAsyncStatus VerifyCertChain(
+      const QuicString& hostname,
+      const std::vector<QuicString>& certs,
+      const ProofVerifyContext* context,
+      QuicString* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    return QUIC_SUCCESS;
+  }
+
+  std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
+    return verifier_ != nullptr ? verifier_->CreateDefaultContext() : nullptr;
+  }
+
+  const QuicString& common_name() const { return common_name_; }
+
+  const QuicString& cert_sct() const { return cert_sct_; }
+
+ private:
+  std::unique_ptr<ProofVerifier> verifier_;
+  QuicString common_name_;
+  QuicString cert_sct_;
+};
+}  // namespace
+
+class MockableQuicClientEpollNetworkHelper
+    : public QuicClientEpollNetworkHelper {
+ public:
+  using QuicClientEpollNetworkHelper::QuicClientEpollNetworkHelper;
+  ~MockableQuicClientEpollNetworkHelper() override = default;
+
+  void ProcessPacket(const QuicSocketAddress& self_address,
+                     const QuicSocketAddress& peer_address,
+                     const QuicReceivedPacket& packet) override {
+    QuicClientEpollNetworkHelper::ProcessPacket(self_address, peer_address,
+                                                packet);
+    if (track_last_incoming_packet_) {
+      last_incoming_packet_ = packet.Clone();
+    }
+  }
+
+  QuicPacketWriter* CreateQuicPacketWriter() override {
+    QuicPacketWriter* writer =
+        QuicClientEpollNetworkHelper::CreateQuicPacketWriter();
+    if (!test_writer_) {
+      return writer;
+    }
+    test_writer_->set_writer(writer);
+    return test_writer_;
+  }
+
+  const QuicReceivedPacket* last_incoming_packet() {
+    return last_incoming_packet_.get();
+  }
+
+  void set_track_last_incoming_packet(bool track) {
+    track_last_incoming_packet_ = track;
+  }
+
+  void UseWriter(QuicPacketWriterWrapper* writer) {
+    CHECK(test_writer_ == nullptr);
+    test_writer_ = writer;
+  }
+
+  void set_peer_address(const QuicSocketAddress& address) {
+    CHECK(test_writer_ != nullptr);
+    test_writer_->set_peer_address(address);
+  }
+
+ private:
+  QuicPacketWriterWrapper* test_writer_ = nullptr;
+  // The last incoming packet, iff |track_last_incoming_packet_| is true.
+  std::unique_ptr<QuicReceivedPacket> last_incoming_packet_;
+  // If true, copy each packet from ProcessPacket into |last_incoming_packet_|
+  bool track_last_incoming_packet_ = false;
+};
+
+MockableQuicClient::MockableQuicClient(
+    QuicSocketAddress server_address,
+    const QuicServerId& server_id,
+    const ParsedQuicVersionVector& supported_versions,
+    QuicEpollServer* epoll_server)
+    : MockableQuicClient(server_address,
+                         server_id,
+                         QuicConfig(),
+                         supported_versions,
+                         epoll_server) {}
+
+MockableQuicClient::MockableQuicClient(
+    QuicSocketAddress server_address,
+    const QuicServerId& server_id,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    QuicEpollServer* epoll_server)
+    : MockableQuicClient(server_address,
+                         server_id,
+                         config,
+                         supported_versions,
+                         epoll_server,
+                         nullptr) {}
+
+MockableQuicClient::MockableQuicClient(
+    QuicSocketAddress server_address,
+    const QuicServerId& server_id,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    QuicEpollServer* epoll_server,
+    std::unique_ptr<ProofVerifier> proof_verifier)
+    : QuicClient(
+          server_address,
+          server_id,
+          supported_versions,
+          config,
+          epoll_server,
+          QuicMakeUnique<MockableQuicClientEpollNetworkHelper>(epoll_server,
+                                                               this),
+          QuicWrapUnique(
+              new RecordingProofVerifier(std::move(proof_verifier)))),
+      override_connection_id_(EmptyQuicConnectionId()),
+      connection_id_overridden_(false) {}
+
+MockableQuicClient::~MockableQuicClient() {
+  if (connected()) {
+    Disconnect();
+  }
+}
+
+MockableQuicClientEpollNetworkHelper*
+MockableQuicClient::mockable_network_helper() {
+  return static_cast<MockableQuicClientEpollNetworkHelper*>(
+      epoll_network_helper());
+}
+
+const MockableQuicClientEpollNetworkHelper*
+MockableQuicClient::mockable_network_helper() const {
+  return static_cast<const MockableQuicClientEpollNetworkHelper*>(
+      epoll_network_helper());
+}
+
+QuicConnectionId MockableQuicClient::GenerateNewConnectionId() {
+  return connection_id_overridden_ ? override_connection_id_
+                                   : QuicClient::GenerateNewConnectionId();
+}
+
+void MockableQuicClient::UseConnectionId(QuicConnectionId connection_id) {
+  connection_id_overridden_ = true;
+  override_connection_id_ = connection_id;
+}
+
+void MockableQuicClient::UseWriter(QuicPacketWriterWrapper* writer) {
+  mockable_network_helper()->UseWriter(writer);
+}
+
+void MockableQuicClient::set_peer_address(const QuicSocketAddress& address) {
+  mockable_network_helper()->set_peer_address(address);
+}
+
+const QuicReceivedPacket* MockableQuicClient::last_incoming_packet() {
+  return mockable_network_helper()->last_incoming_packet();
+}
+
+void MockableQuicClient::set_track_last_incoming_packet(bool track) {
+  mockable_network_helper()->set_track_last_incoming_packet(track);
+}
+
+QuicTestClient::QuicTestClient(
+    QuicSocketAddress server_address,
+    const QuicString& server_hostname,
+    const ParsedQuicVersionVector& supported_versions)
+    : QuicTestClient(server_address,
+                     server_hostname,
+                     QuicConfig(),
+                     supported_versions) {}
+
+QuicTestClient::QuicTestClient(
+    QuicSocketAddress server_address,
+    const QuicString& server_hostname,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions)
+    : client_(new MockableQuicClient(
+          server_address,
+          QuicServerId(server_hostname, server_address.port(), false),
+          config,
+          supported_versions,
+          &epoll_server_)) {
+  Initialize();
+}
+
+QuicTestClient::QuicTestClient(
+    QuicSocketAddress server_address,
+    const QuicString& server_hostname,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    std::unique_ptr<ProofVerifier> proof_verifier)
+    : client_(new MockableQuicClient(
+          server_address,
+          QuicServerId(server_hostname, server_address.port(), false),
+          config,
+          supported_versions,
+          &epoll_server_,
+          std::move(proof_verifier))) {
+  Initialize();
+}
+
+QuicTestClient::QuicTestClient() = default;
+
+QuicTestClient::~QuicTestClient() {
+  for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
+    stream.second->set_visitor(nullptr);
+  }
+}
+
+void QuicTestClient::Initialize() {
+  priority_ = 3;
+  connect_attempted_ = false;
+  auto_reconnect_ = false;
+  buffer_body_ = true;
+  num_requests_ = 0;
+  num_responses_ = 0;
+  ClearPerConnectionState();
+  // As chrome will generally do this, we want it to be the default when it's
+  // not overridden.
+  if (!client_->config()->HasSetBytesForConnectionIdToSend()) {
+    client_->config()->SetBytesForConnectionIdToSend(0);
+  }
+}
+
+void QuicTestClient::SetUserAgentID(const QuicString& user_agent_id) {
+  client_->SetUserAgentID(user_agent_id);
+}
+
+ssize_t QuicTestClient::SendRequest(const QuicString& uri) {
+  spdy::SpdyHeaderBlock headers;
+  if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
+    return 0;
+  }
+  return SendMessage(headers, "");
+}
+
+ssize_t QuicTestClient::SendRequestAndRstTogether(const QuicString& uri) {
+  spdy::SpdyHeaderBlock headers;
+  if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
+    return 0;
+  }
+
+  QuicSpdyClientSession* session = client()->client_session();
+  QuicConnection::ScopedPacketFlusher flusher(
+      session->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+  ssize_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false);
+
+  QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId(
+      session->connection()->transport_version(), 0);
+  session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0);
+  return ret;
+}
+
+void QuicTestClient::SendRequestsAndWaitForResponses(
+    const std::vector<QuicString>& url_list) {
+  for (const QuicString& url : url_list) {
+    SendRequest(url);
+  }
+  while (client()->WaitForEvents()) {
+  }
+}
+
+ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
+    const spdy::SpdyHeaderBlock* headers,
+    QuicStringPiece body,
+    bool fin,
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+  if (headers) {
+    QuicClientPushPromiseIndex::TryHandle* handle;
+    QuicAsyncStatus rv =
+        client()->push_promise_index()->Try(*headers, this, &handle);
+    if (rv == QUIC_SUCCESS)
+      return 1;
+    if (rv == QUIC_PENDING) {
+      // May need to retry request if asynchronous rendezvous fails.
+      std::unique_ptr<spdy::SpdyHeaderBlock> new_headers(
+          new spdy::SpdyHeaderBlock(headers->Clone()));
+      push_promise_data_to_resend_ = QuicMakeUnique<TestClientDataToResend>(
+          std::move(new_headers), body, fin, this, std::move(ack_listener));
+      return 1;
+    }
+  }
+
+  // Maybe it's better just to overload this.  it's just that we need
+  // for the GetOrCreateStream function to call something else...which
+  // is icky and complicated, but maybe not worse than this.
+  QuicSpdyClientStream* stream = GetOrCreateStream();
+  if (stream == nullptr) {
+    return 0;
+  }
+  QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener);
+
+  ssize_t ret = 0;
+  if (headers != nullptr) {
+    spdy::SpdyHeaderBlock spdy_headers(headers->Clone());
+    if (spdy_headers[":authority"].as_string().empty()) {
+      spdy_headers[":authority"] = client_->server_id().host();
+    }
+    ret = stream->SendRequest(std::move(spdy_headers), body, fin);
+    ++num_requests_;
+  } else {
+    stream->WriteOrBufferBody(QuicString(body), fin);
+    ret = body.length();
+  }
+  if (GetQuicReloadableFlag(enable_quic_stateless_reject_support)) {
+    std::unique_ptr<spdy::SpdyHeaderBlock> new_headers;
+    if (headers) {
+      new_headers = QuicMakeUnique<spdy::SpdyHeaderBlock>(headers->Clone());
+    }
+    std::unique_ptr<QuicSpdyClientBase::QuicDataToResend> data_to_resend(
+        new TestClientDataToResend(std::move(new_headers), body, fin, this,
+                                   ack_listener));
+    client()->MaybeAddQuicDataToResend(std::move(data_to_resend));
+  }
+  return ret;
+}
+
+ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
+                                    QuicStringPiece body) {
+  return SendMessage(headers, body, /*fin=*/true);
+}
+
+ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
+                                    QuicStringPiece body,
+                                    bool fin) {
+  return SendMessage(headers, body, fin, /*flush=*/true);
+}
+
+ssize_t QuicTestClient::SendMessage(const spdy::SpdyHeaderBlock& headers,
+                                    QuicStringPiece body,
+                                    bool fin,
+                                    bool flush) {
+  // Always force creation of a stream for SendMessage.
+  latest_created_stream_ = nullptr;
+
+  ssize_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr);
+
+  if (flush) {
+    WaitForWriteToFlush();
+  }
+  return ret;
+}
+
+ssize_t QuicTestClient::SendData(const QuicString& data, bool last_data) {
+  return SendData(data, last_data, nullptr);
+}
+
+ssize_t QuicTestClient::SendData(
+    const QuicString& data,
+    bool last_data,
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+  return GetOrCreateStreamAndSendRequest(nullptr, QuicStringPiece(data),
+                                         last_data, std::move(ack_listener));
+}
+
+bool QuicTestClient::response_complete() const {
+  return response_complete_;
+}
+
+int64_t QuicTestClient::response_body_size() const {
+  return response_body_size_;
+}
+
+bool QuicTestClient::buffer_body() const {
+  return buffer_body_;
+}
+
+void QuicTestClient::set_buffer_body(bool buffer_body) {
+  buffer_body_ = buffer_body;
+}
+
+const QuicString& QuicTestClient::response_body() const {
+  return response_;
+}
+
+QuicString QuicTestClient::SendCustomSynchronousRequest(
+    const spdy::SpdyHeaderBlock& headers,
+    const QuicString& body) {
+  // Clear connection state here and only track this synchronous request.
+  ClearPerConnectionState();
+  if (SendMessage(headers, body) == 0) {
+    QUIC_DLOG(ERROR) << "Failed the request for: " << headers.DebugString();
+    // Set the response_ explicitly.  Otherwise response_ will contain the
+    // response from the previously successful request.
+    response_ = "";
+  } else {
+    WaitForResponse();
+  }
+  return response_;
+}
+
+QuicString QuicTestClient::SendSynchronousRequest(const QuicString& uri) {
+  spdy::SpdyHeaderBlock headers;
+  if (!PopulateHeaderBlockFromUrl(uri, &headers)) {
+    return "";
+  }
+  return SendCustomSynchronousRequest(headers, "");
+}
+
+void QuicTestClient::SendConnectivityProbing() {
+  QuicConnection* connection = client()->client_session()->connection();
+  connection->SendConnectivityProbingPacket(connection->writer(),
+                                            connection->peer_address());
+}
+
+void QuicTestClient::SetLatestCreatedStream(QuicSpdyClientStream* stream) {
+  latest_created_stream_ = stream;
+  if (latest_created_stream_ != nullptr) {
+    open_streams_[stream->id()] = stream;
+    stream->set_visitor(this);
+  }
+}
+
+QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
+  if (!connect_attempted_ || auto_reconnect_) {
+    if (!connected()) {
+      Connect();
+    }
+    if (!connected()) {
+      return nullptr;
+    }
+  }
+  if (open_streams_.empty()) {
+    ClearPerConnectionState();
+  }
+  if (!latest_created_stream_) {
+    SetLatestCreatedStream(client_->CreateClientStream());
+    if (latest_created_stream_) {
+      latest_created_stream_->SetPriority(priority_);
+    }
+  }
+
+  return latest_created_stream_;
+}
+
+QuicErrorCode QuicTestClient::connection_error() {
+  return client()->connection_error();
+}
+
+MockableQuicClient* QuicTestClient::client() {
+  return client_.get();
+}
+
+const QuicString& QuicTestClient::cert_common_name() const {
+  return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
+      ->common_name();
+}
+
+const QuicString& QuicTestClient::cert_sct() const {
+  return reinterpret_cast<RecordingProofVerifier*>(client_->proof_verifier())
+      ->cert_sct();
+}
+
+QuicTagValueMap QuicTestClient::GetServerConfig() const {
+  QuicCryptoClientConfig* config = client_->crypto_config();
+  QuicCryptoClientConfig::CachedState* state =
+      config->LookupOrCreate(client_->server_id());
+  const CryptoHandshakeMessage* handshake_msg = state->GetServerConfig();
+  if (handshake_msg != nullptr) {
+    return handshake_msg->tag_value_map();
+  } else {
+    return QuicTagValueMap();
+  }
+}
+
+bool QuicTestClient::connected() const {
+  return client_->connected();
+}
+
+void QuicTestClient::Connect() {
+  DCHECK(!connected());
+  if (!connect_attempted_) {
+    client_->Initialize();
+  }
+
+  // If we've been asked to override SNI, set it now
+  if (override_sni_set_) {
+    client_->set_server_id(
+        QuicServerId(override_sni_, address().port(), false));
+  }
+
+  client_->Connect();
+  connect_attempted_ = true;
+}
+
+void QuicTestClient::ResetConnection() {
+  Disconnect();
+  Connect();
+}
+
+void QuicTestClient::Disconnect() {
+  ClearPerConnectionState();
+  client_->Disconnect();
+  connect_attempted_ = false;
+}
+
+QuicSocketAddress QuicTestClient::local_address() const {
+  return client_->network_helper()->GetLatestClientAddress();
+}
+
+void QuicTestClient::ClearPerRequestState() {
+  stream_error_ = QUIC_STREAM_NO_ERROR;
+  response_ = "";
+  response_complete_ = false;
+  response_headers_complete_ = false;
+  preliminary_headers_.clear();
+  response_headers_.clear();
+  response_trailers_.clear();
+  bytes_read_ = 0;
+  bytes_written_ = 0;
+  response_body_size_ = 0;
+}
+
+bool QuicTestClient::HaveActiveStream() {
+  return push_promise_data_to_resend_.get() || !open_streams_.empty();
+}
+
+bool QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) {
+  int64_t timeout_us = timeout_ms * kNumMicrosPerMilli;
+  int64_t old_timeout_us = epoll_server()->timeout_in_us_for_test();
+  if (timeout_us > 0) {
+    epoll_server()->set_timeout_in_us(timeout_us);
+  }
+  const QuicClock* clock =
+      QuicConnectionPeer::GetHelper(client()->session()->connection())
+          ->GetClock();
+  QuicTime end_waiting_time =
+      clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
+  while (HaveActiveStream() && !(trigger && trigger()) &&
+         (timeout_us < 0 || clock->Now() < end_waiting_time)) {
+    client_->WaitForEvents();
+  }
+  ReadNextResponse();
+  if (timeout_us > 0) {
+    epoll_server()->set_timeout_in_us(old_timeout_us);
+  }
+  if (trigger && !trigger()) {
+    VLOG(1) << "Client WaitUntil returning with trigger returning false."
+            << QuicStackTrace();
+    return false;
+  }
+  return true;
+}
+
+ssize_t QuicTestClient::Send(const void* buffer, size_t size) {
+  return SendData(QuicString(static_cast<const char*>(buffer), size), false);
+}
+
+bool QuicTestClient::response_headers_complete() const {
+  for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
+    if (stream.second->headers_decompressed()) {
+      return true;
+    }
+  }
+  return response_headers_complete_;
+}
+
+const spdy::SpdyHeaderBlock* QuicTestClient::response_headers() const {
+  for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
+    size_t bytes_read =
+        stream.second->stream_bytes_read() + stream.second->header_bytes_read();
+    if (bytes_read > 0) {
+      response_headers_ = stream.second->response_headers().Clone();
+      break;
+    }
+  }
+  return &response_headers_;
+}
+
+const spdy::SpdyHeaderBlock* QuicTestClient::preliminary_headers() const {
+  for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
+    size_t bytes_read =
+        stream.second->stream_bytes_read() + stream.second->header_bytes_read();
+    if (bytes_read > 0) {
+      preliminary_headers_ = stream.second->preliminary_headers().Clone();
+      break;
+    }
+  }
+  return &preliminary_headers_;
+}
+
+const spdy::SpdyHeaderBlock& QuicTestClient::response_trailers() const {
+  return response_trailers_;
+}
+
+int64_t QuicTestClient::response_size() const {
+  return bytes_read();
+}
+
+size_t QuicTestClient::bytes_read() const {
+  for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
+    size_t bytes_read = stream.second->total_body_bytes_read() +
+                        stream.second->header_bytes_read();
+    if (bytes_read > 0) {
+      return bytes_read;
+    }
+  }
+  return bytes_read_;
+}
+
+size_t QuicTestClient::bytes_written() const {
+  for (std::pair<QuicStreamId, QuicSpdyClientStream*> stream : open_streams_) {
+    size_t bytes_written = stream.second->stream_bytes_written() +
+                           stream.second->header_bytes_written();
+    if (bytes_written > 0) {
+      return bytes_written;
+    }
+  }
+  return bytes_written_;
+}
+
+void QuicTestClient::OnClose(QuicSpdyStream* stream) {
+  if (stream == nullptr) {
+    return;
+  }
+  // Always close the stream, regardless of whether it was the last stream
+  // written.
+  client()->OnClose(stream);
+  ++num_responses_;
+  if (!QuicContainsKey(open_streams_, stream->id())) {
+    return;
+  }
+  if (latest_created_stream_ == stream) {
+    latest_created_stream_ = nullptr;
+  }
+  QuicSpdyClientStream* client_stream =
+      static_cast<QuicSpdyClientStream*>(stream);
+  QuicStreamId id = client_stream->id();
+  closed_stream_states_.insert(std::make_pair(
+      id,
+      PerStreamState(
+          client_stream->stream_error(), true,
+          client_stream->headers_decompressed(),
+          client_stream->response_headers(),
+          client_stream->preliminary_headers(),
+          (buffer_body() ? client_stream->data() : ""),
+          client_stream->received_trailers(),
+          // Use NumBytesConsumed to avoid counting retransmitted stream frames.
+          client_stream->total_body_bytes_read() +
+              client_stream->header_bytes_read(),
+          client_stream->stream_bytes_written() +
+              client_stream->header_bytes_written(),
+          client_stream->data().size())));
+  open_streams_.erase(id);
+}
+
+bool QuicTestClient::CheckVary(const spdy::SpdyHeaderBlock& client_request,
+                               const spdy::SpdyHeaderBlock& promise_request,
+                               const spdy::SpdyHeaderBlock& promise_response) {
+  return true;
+}
+
+void QuicTestClient::OnRendezvousResult(QuicSpdyStream* stream) {
+  std::unique_ptr<TestClientDataToResend> data_to_resend =
+      std::move(push_promise_data_to_resend_);
+  SetLatestCreatedStream(static_cast<QuicSpdyClientStream*>(stream));
+  if (stream) {
+    stream->OnBodyAvailable();
+  } else if (data_to_resend) {
+    data_to_resend->Resend();
+  }
+}
+
+void QuicTestClient::UseWriter(QuicPacketWriterWrapper* writer) {
+  client_->UseWriter(writer);
+}
+
+void QuicTestClient::UseConnectionId(QuicConnectionId connection_id) {
+  DCHECK(!connected());
+  client_->UseConnectionId(connection_id);
+}
+
+bool QuicTestClient::MigrateSocket(const QuicIpAddress& new_host) {
+  return client_->MigrateSocket(new_host);
+}
+
+bool QuicTestClient::MigrateSocketWithSpecifiedPort(
+    const QuicIpAddress& new_host,
+    int port) {
+  client_->set_local_port(port);
+  return client_->MigrateSocket(new_host);
+}
+
+QuicIpAddress QuicTestClient::bind_to_address() const {
+  return client_->bind_to_address();
+}
+
+void QuicTestClient::set_bind_to_address(QuicIpAddress address) {
+  client_->set_bind_to_address(address);
+}
+
+const QuicSocketAddress& QuicTestClient::address() const {
+  return client_->server_address();
+}
+
+void QuicTestClient::WaitForWriteToFlush() {
+  while (connected() && client()->session()->HasDataToWrite()) {
+    client_->WaitForEvents();
+  }
+}
+
+QuicTestClient::TestClientDataToResend::TestClientDataToResend(
+    std::unique_ptr<spdy::SpdyHeaderBlock> headers,
+    QuicStringPiece body,
+    bool fin,
+    QuicTestClient* test_client,
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener)
+    : QuicClient::QuicDataToResend(std::move(headers), body, fin),
+      test_client_(test_client),
+      ack_listener_(std::move(ack_listener)) {}
+
+QuicTestClient::TestClientDataToResend::~TestClientDataToResend() = default;
+
+void QuicTestClient::TestClientDataToResend::Resend() {
+  test_client_->GetOrCreateStreamAndSendRequest(headers_.get(), body_, fin_,
+                                                ack_listener_);
+  headers_.reset();
+}
+
+QuicTestClient::PerStreamState::PerStreamState(const PerStreamState& other)
+    : stream_error(other.stream_error),
+      response_complete(other.response_complete),
+      response_headers_complete(other.response_headers_complete),
+      response_headers(other.response_headers.Clone()),
+      preliminary_headers(other.preliminary_headers.Clone()),
+      response(other.response),
+      response_trailers(other.response_trailers.Clone()),
+      bytes_read(other.bytes_read),
+      bytes_written(other.bytes_written),
+      response_body_size(other.response_body_size) {}
+
+QuicTestClient::PerStreamState::PerStreamState(
+    QuicRstStreamErrorCode stream_error,
+    bool response_complete,
+    bool response_headers_complete,
+    const spdy::SpdyHeaderBlock& response_headers,
+    const spdy::SpdyHeaderBlock& preliminary_headers,
+    const QuicString& response,
+    const spdy::SpdyHeaderBlock& response_trailers,
+    uint64_t bytes_read,
+    uint64_t bytes_written,
+    int64_t response_body_size)
+    : stream_error(stream_error),
+      response_complete(response_complete),
+      response_headers_complete(response_headers_complete),
+      response_headers(response_headers.Clone()),
+      preliminary_headers(preliminary_headers.Clone()),
+      response(response),
+      response_trailers(response_trailers.Clone()),
+      bytes_read(bytes_read),
+      bytes_written(bytes_written),
+      response_body_size(response_body_size) {}
+
+QuicTestClient::PerStreamState::~PerStreamState() = default;
+
+bool QuicTestClient::PopulateHeaderBlockFromUrl(
+    const QuicString& uri,
+    spdy::SpdyHeaderBlock* headers) {
+  QuicString url;
+  if (QuicTextUtils::StartsWith(uri, "https://") ||
+      QuicTextUtils::StartsWith(uri, "http://")) {
+    url = uri;
+  } else if (uri[0] == '/') {
+    url = "https://" + client_->server_id().host() + uri;
+  } else {
+    url = "https://" + uri;
+  }
+  return SpdyUtils::PopulateHeaderBlockFromUrl(url, headers);
+}
+
+void QuicTestClient::ReadNextResponse() {
+  if (closed_stream_states_.empty()) {
+    return;
+  }
+
+  PerStreamState state(closed_stream_states_.front().second);
+
+  stream_error_ = state.stream_error;
+  response_ = state.response;
+  response_complete_ = state.response_complete;
+  response_headers_complete_ = state.response_headers_complete;
+  preliminary_headers_ = state.preliminary_headers.Clone();
+  response_headers_ = state.response_headers.Clone();
+  response_trailers_ = state.response_trailers.Clone();
+  bytes_read_ = state.bytes_read;
+  bytes_written_ = state.bytes_written;
+  response_body_size_ = state.response_body_size;
+
+  closed_stream_states_.pop_front();
+}
+
+void QuicTestClient::ClearPerConnectionState() {
+  ClearPerRequestState();
+  open_streams_.clear();
+  closed_stream_states_.clear();
+  latest_created_stream_ = nullptr;
+}
+
+void QuicTestClient::WaitForDelayedAcks() {
+  // kWaitDuration is a period of time that is long enough for all delayed
+  // acks to be sent and received on the other end.
+  const QuicTime::Delta kWaitDuration =
+      4 * QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+
+  const QuicClock* clock = client()->client_session()->connection()->clock();
+
+  QuicTime wait_until = clock->ApproximateNow() + kWaitDuration;
+  while (clock->ApproximateNow() < wait_until) {
+    // This waits for up to 50 ms.
+    client()->WaitForEvents();
+  }
+}
+
+}  // namespace test
+}  // namespace quic