Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/test_tools/bad_packet_writer.cc b/quic/test_tools/bad_packet_writer.cc
new file mode 100644
index 0000000..3d00f8e
--- /dev/null
+++ b/quic/test_tools/bad_packet_writer.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 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/bad_packet_writer.h"
+
+namespace quic {
+namespace test {
+
+BadPacketWriter::BadPacketWriter(size_t packet_causing_write_error,
+                                 int error_code)
+    : packet_causing_write_error_(packet_causing_write_error),
+      error_code_(error_code) {}
+
+BadPacketWriter::~BadPacketWriter() {}
+
+WriteResult BadPacketWriter::WritePacket(const char* buffer,
+                                         size_t buf_len,
+                                         const QuicIpAddress& self_address,
+                                         const QuicSocketAddress& peer_address,
+                                         PerPacketOptions* options) {
+  if (error_code_ == 0 || packet_causing_write_error_ > 0) {
+    if (packet_causing_write_error_ > 0) {
+      --packet_causing_write_error_;
+    }
+    return QuicPacketWriterWrapper::WritePacket(buffer, buf_len, self_address,
+                                                peer_address, options);
+  }
+  // It's time to cause write error.
+  int error_code = error_code_;
+  error_code_ = 0;
+  return WriteResult(WRITE_STATUS_ERROR, error_code);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/bad_packet_writer.h b/quic/test_tools/bad_packet_writer.h
new file mode 100644
index 0000000..35bf601
--- /dev/null
+++ b/quic/test_tools/bad_packet_writer.h
@@ -0,0 +1,36 @@
+// Copyright 2017 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_BAD_PACKET_WRITER_H_
+#define QUICHE_QUIC_TEST_TOOLS_BAD_PACKET_WRITER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+
+namespace quic {
+
+namespace test {
+// This packet writer allows causing packet write error with specified error
+// code when writing a particular packet.
+class BadPacketWriter : public QuicPacketWriterWrapper {
+ public:
+  BadPacketWriter(size_t packet_causing_write_error, int error_code);
+
+  ~BadPacketWriter() override;
+
+  WriteResult WritePacket(const char* buffer,
+                          size_t buf_len,
+                          const QuicIpAddress& self_address,
+                          const QuicSocketAddress& peer_address,
+                          PerPacketOptions* options) override;
+
+ private:
+  size_t packet_causing_write_error_;
+  int error_code_;
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_BAD_PACKET_WRITER_H_
diff --git a/quic/test_tools/crypto_test_utils.cc b/quic/test_tools/crypto_test_utils.cc
new file mode 100644
index 0000000..7179288
--- /dev/null
+++ b/quic/test_tools/crypto_test_utils.cc
@@ -0,0 +1,1046 @@
+// 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/crypto_test_utils.h"
+
+#include <memory>
+#include <string>
+
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
+#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.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/core/tls_client_handshaker.h"
+#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.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_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
+
+namespace quic {
+namespace test {
+
+TestChannelIDKey::TestChannelIDKey(EVP_PKEY* ecdsa_key)
+    : ecdsa_key_(ecdsa_key) {}
+TestChannelIDKey::~TestChannelIDKey() {}
+
+bool TestChannelIDKey::Sign(QuicStringPiece signed_data,
+                            QuicString* out_signature) const {
+  bssl::ScopedEVP_MD_CTX md_ctx;
+  if (EVP_DigestSignInit(md_ctx.get(), nullptr, EVP_sha256(), nullptr,
+                         ecdsa_key_.get()) != 1) {
+    return false;
+  }
+
+  EVP_DigestUpdate(md_ctx.get(), ChannelIDVerifier::kContextStr,
+                   strlen(ChannelIDVerifier::kContextStr) + 1);
+  EVP_DigestUpdate(md_ctx.get(), ChannelIDVerifier::kClientToServerStr,
+                   strlen(ChannelIDVerifier::kClientToServerStr) + 1);
+  EVP_DigestUpdate(md_ctx.get(), signed_data.data(), signed_data.size());
+
+  size_t sig_len;
+  if (!EVP_DigestSignFinal(md_ctx.get(), nullptr, &sig_len)) {
+    return false;
+  }
+
+  std::unique_ptr<uint8_t[]> der_sig(new uint8_t[sig_len]);
+  if (!EVP_DigestSignFinal(md_ctx.get(), der_sig.get(), &sig_len)) {
+    return false;
+  }
+
+  uint8_t* derp = der_sig.get();
+  bssl::UniquePtr<ECDSA_SIG> sig(
+      d2i_ECDSA_SIG(nullptr, const_cast<const uint8_t**>(&derp), sig_len));
+  if (sig.get() == nullptr) {
+    return false;
+  }
+
+  // The signature consists of a pair of 32-byte numbers.
+  static const size_t kSignatureLength = 32 * 2;
+  std::unique_ptr<uint8_t[]> signature(new uint8_t[kSignatureLength]);
+  if (!BN_bn2bin_padded(&signature[0], 32, sig->r) ||
+      !BN_bn2bin_padded(&signature[32], 32, sig->s)) {
+    return false;
+  }
+
+  *out_signature =
+      QuicString(reinterpret_cast<char*>(signature.get()), kSignatureLength);
+
+  return true;
+}
+
+QuicString TestChannelIDKey::SerializeKey() const {
+  // i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256
+  // key, is 0x04 (meaning uncompressed) followed by the x and y field
+  // elements as 32-byte, big-endian numbers.
+  static const int kExpectedKeyLength = 65;
+
+  int len = i2d_PublicKey(ecdsa_key_.get(), nullptr);
+  if (len != kExpectedKeyLength) {
+    return "";
+  }
+
+  uint8_t buf[kExpectedKeyLength];
+  uint8_t* derp = buf;
+  i2d_PublicKey(ecdsa_key_.get(), &derp);
+
+  return QuicString(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1);
+}
+
+TestChannelIDSource::~TestChannelIDSource() {}
+
+QuicAsyncStatus TestChannelIDSource::GetChannelIDKey(
+    const QuicString& hostname,
+    std::unique_ptr<ChannelIDKey>* channel_id_key,
+    ChannelIDSourceCallback* /*callback*/) {
+  *channel_id_key = QuicMakeUnique<TestChannelIDKey>(HostnameToKey(hostname));
+  return QUIC_SUCCESS;
+}
+
+// static
+EVP_PKEY* TestChannelIDSource::HostnameToKey(const QuicString& hostname) {
+  // In order to generate a deterministic key for a given hostname the
+  // hostname is hashed with SHA-256 and the resulting digest is treated as a
+  // big-endian number. The most-significant bit is cleared to ensure that
+  // the resulting value is less than the order of the group and then it's
+  // taken as a private key. Given the private key, the public key is
+  // calculated with a group multiplication.
+  SHA256_CTX sha256;
+  SHA256_Init(&sha256);
+  SHA256_Update(&sha256, hostname.data(), hostname.size());
+
+  unsigned char digest[SHA256_DIGEST_LENGTH];
+  SHA256_Final(digest, &sha256);
+
+  // Ensure that the digest is less than the order of the P-256 group by
+  // clearing the most-significant bit.
+  digest[0] &= 0x7f;
+
+  bssl::UniquePtr<BIGNUM> k(BN_new());
+  CHECK(BN_bin2bn(digest, sizeof(digest), k.get()) != nullptr);
+
+  bssl::UniquePtr<EC_GROUP> p256(
+      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+  CHECK(p256);
+
+  bssl::UniquePtr<EC_KEY> ecdsa_key(EC_KEY_new());
+  CHECK(ecdsa_key && EC_KEY_set_group(ecdsa_key.get(), p256.get()));
+
+  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get()));
+  CHECK(EC_POINT_mul(p256.get(), point.get(), k.get(), nullptr, nullptr,
+                     nullptr));
+
+  EC_KEY_set_private_key(ecdsa_key.get(), k.get());
+  EC_KEY_set_public_key(ecdsa_key.get(), point.get());
+
+  bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+  // EVP_PKEY_set1_EC_KEY takes a reference so no |release| here.
+  EVP_PKEY_set1_EC_KEY(pkey.get(), ecdsa_key.get());
+
+  return pkey.release();
+}
+
+namespace crypto_test_utils {
+
+namespace {
+
+// CryptoFramerVisitor is a framer visitor that records handshake messages.
+class CryptoFramerVisitor : public CryptoFramerVisitorInterface {
+ public:
+  CryptoFramerVisitor() : error_(false) {}
+
+  void OnError(CryptoFramer* framer) override { error_ = true; }
+
+  void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
+    messages_.push_back(message);
+  }
+
+  bool error() const { return error_; }
+
+  const std::vector<CryptoHandshakeMessage>& messages() const {
+    return messages_;
+  }
+
+ private:
+  bool error_;
+  std::vector<CryptoHandshakeMessage> messages_;
+};
+
+// HexChar parses |c| as a hex character. If valid, it sets |*value| to the
+// value of the hex character and returns true. Otherwise it returns false.
+bool HexChar(char c, uint8_t* value) {
+  if (c >= '0' && c <= '9') {
+    *value = c - '0';
+    return true;
+  }
+  if (c >= 'a' && c <= 'f') {
+    *value = c - 'a' + 10;
+    return true;
+  }
+  if (c >= 'A' && c <= 'F') {
+    *value = c - 'A' + 10;
+    return true;
+  }
+  return false;
+}
+
+// A ChannelIDSource that works in asynchronous mode unless the |callback|
+// argument to GetChannelIDKey is nullptr.
+class AsyncTestChannelIDSource : public ChannelIDSource, public CallbackSource {
+ public:
+  // Takes ownership of |sync_source|, a synchronous ChannelIDSource.
+  explicit AsyncTestChannelIDSource(ChannelIDSource* sync_source)
+      : sync_source_(sync_source) {}
+  ~AsyncTestChannelIDSource() override {}
+
+  // ChannelIDSource implementation.
+  QuicAsyncStatus GetChannelIDKey(const QuicString& hostname,
+                                  std::unique_ptr<ChannelIDKey>* channel_id_key,
+                                  ChannelIDSourceCallback* callback) override {
+    // Synchronous mode.
+    if (!callback) {
+      return sync_source_->GetChannelIDKey(hostname, channel_id_key, nullptr);
+    }
+
+    // Asynchronous mode.
+    QuicAsyncStatus status =
+        sync_source_->GetChannelIDKey(hostname, &channel_id_key_, nullptr);
+    if (status != QUIC_SUCCESS) {
+      return QUIC_FAILURE;
+    }
+    callback_.reset(callback);
+    return QUIC_PENDING;
+  }
+
+  // CallbackSource implementation.
+  void RunPendingCallbacks() override {
+    if (callback_) {
+      callback_->Run(&channel_id_key_);
+      callback_.reset();
+    }
+  }
+
+ private:
+  std::unique_ptr<ChannelIDSource> sync_source_;
+  std::unique_ptr<ChannelIDSourceCallback> callback_;
+  std::unique_ptr<ChannelIDKey> channel_id_key_;
+};
+
+}  // anonymous namespace
+
+FakeServerOptions::FakeServerOptions() {}
+
+FakeServerOptions::~FakeServerOptions() {}
+
+FakeClientOptions::FakeClientOptions()
+    : channel_id_enabled(false), channel_id_source_async(false) {}
+
+FakeClientOptions::~FakeClientOptions() {}
+
+namespace {
+// This class is used by GenerateFullCHLO() to extract SCID and STK from
+// REJ/SREJ and to construct a full CHLO with these fields and given inchoate
+// CHLO.
+class FullChloGenerator {
+ public:
+  FullChloGenerator(
+      QuicCryptoServerConfig* crypto_config,
+      QuicSocketAddress server_addr,
+      QuicSocketAddress client_addr,
+      const QuicClock* clock,
+      QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
+      QuicCompressedCertsCache* compressed_certs_cache,
+      CryptoHandshakeMessage* out)
+      : crypto_config_(crypto_config),
+        server_addr_(server_addr),
+        client_addr_(client_addr),
+        clock_(clock),
+        signed_config_(signed_config),
+        compressed_certs_cache_(compressed_certs_cache),
+        out_(out),
+        params_(new QuicCryptoNegotiatedParameters) {}
+
+  class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
+   public:
+    explicit ValidateClientHelloCallback(FullChloGenerator* generator)
+        : generator_(generator) {}
+    void Run(QuicReferenceCountedPointer<
+                 ValidateClientHelloResultCallback::Result> result,
+             std::unique_ptr<ProofSource::Details> /* details */) override {
+      generator_->ValidateClientHelloDone(std::move(result));
+    }
+
+   private:
+    FullChloGenerator* generator_;
+  };
+
+  std::unique_ptr<ValidateClientHelloCallback>
+  GetValidateClientHelloCallback() {
+    return QuicMakeUnique<ValidateClientHelloCallback>(this);
+  }
+
+ private:
+  void ValidateClientHelloDone(
+      QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+          result) {
+    result_ = result;
+    crypto_config_->ProcessClientHello(
+        result_, /*reject_only=*/false, TestConnectionId(1), server_addr_,
+        client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
+        /*use_stateless_rejects=*/true,
+        /*server_designated_connection_id=*/TestConnectionId(2), clock_,
+        QuicRandom::GetInstance(), compressed_certs_cache_, params_,
+        signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
+        GetProcessClientHelloCallback());
+  }
+
+  class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
+   public:
+    explicit ProcessClientHelloCallback(FullChloGenerator* generator)
+        : generator_(generator) {}
+    void Run(
+        QuicErrorCode error,
+        const QuicString& error_details,
+        std::unique_ptr<CryptoHandshakeMessage> message,
+        std::unique_ptr<DiversificationNonce> diversification_nonce,
+        std::unique_ptr<ProofSource::Details> proof_source_details) override {
+      generator_->ProcessClientHelloDone(std::move(message));
+    }
+
+   private:
+    FullChloGenerator* generator_;
+  };
+
+  std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
+    return QuicMakeUnique<ProcessClientHelloCallback>(this);
+  }
+
+  void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) {
+    // Verify output is a REJ or SREJ.
+    EXPECT_THAT(rej->tag(),
+                testing::AnyOf(testing::Eq(kSREJ), testing::Eq(kREJ)));
+
+    VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString();
+    QuicStringPiece srct;
+    ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct));
+
+    QuicStringPiece scfg;
+    ASSERT_TRUE(rej->GetStringPiece(kSCFG, &scfg));
+    std::unique_ptr<CryptoHandshakeMessage> server_config(
+        CryptoFramer::ParseMessage(scfg));
+
+    QuicStringPiece scid;
+    ASSERT_TRUE(server_config->GetStringPiece(kSCID, &scid));
+
+    *out_ = result_->client_hello;
+    out_->SetStringPiece(kSCID, scid);
+    out_->SetStringPiece(kSourceAddressTokenTag, srct);
+    uint64_t xlct = LeafCertHashForTesting();
+    out_->SetValue(kXLCT, xlct);
+  }
+
+ protected:
+  QuicCryptoServerConfig* crypto_config_;
+  QuicSocketAddress server_addr_;
+  QuicSocketAddress client_addr_;
+  const QuicClock* clock_;
+  QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
+  QuicCompressedCertsCache* compressed_certs_cache_;
+  CryptoHandshakeMessage* out_;
+
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
+  QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+      result_;
+};
+
+}  // namespace
+
+int HandshakeWithFakeServer(QuicConfig* server_quic_config,
+                            MockQuicConnectionHelper* helper,
+                            MockAlarmFactory* alarm_factory,
+                            PacketSavingConnection* client_conn,
+                            QuicCryptoClientStream* client,
+                            const FakeServerOptions& options) {
+  PacketSavingConnection* server_conn = new PacketSavingConnection(
+      helper, alarm_factory, Perspective::IS_SERVER,
+      ParsedVersionOfIndex(client_conn->supported_versions(), 0));
+
+  QuicCryptoServerConfig crypto_config(
+      QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
+      ProofSourceForTesting(), KeyExchangeSource::Default(),
+      TlsServerHandshaker::CreateSslCtx());
+  QuicCompressedCertsCache compressed_certs_cache(
+      QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
+  SetupCryptoServerConfigForTest(server_conn->clock(),
+                                 server_conn->random_generator(),
+                                 &crypto_config, options);
+
+  TestQuicSpdyServerSession server_session(
+      server_conn, *server_quic_config, client_conn->supported_versions(),
+      &crypto_config, &compressed_certs_cache);
+  server_session.OnSuccessfulVersionNegotiation(
+      client_conn->supported_versions().front());
+  EXPECT_CALL(*server_session.helper(),
+              CanAcceptClientHello(testing::_, testing::_, testing::_,
+                                   testing::_, testing::_))
+      .Times(testing::AnyNumber());
+  EXPECT_CALL(*server_session.helper(),
+              GenerateConnectionIdForReject(testing::_, testing::_))
+      .Times(testing::AnyNumber());
+  EXPECT_CALL(*server_conn, OnCanWrite()).Times(testing::AnyNumber());
+  EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
+
+  // The client's handshake must have been started already.
+  CHECK_NE(0u, client_conn->encrypted_packets_.size());
+
+  CommunicateHandshakeMessages(client_conn, client, server_conn,
+                               server_session.GetMutableCryptoStream());
+  CompareClientAndServerKeys(client, server_session.GetMutableCryptoStream());
+
+  return client->num_sent_client_hellos();
+}
+
+int HandshakeWithFakeClient(MockQuicConnectionHelper* helper,
+                            MockAlarmFactory* alarm_factory,
+                            PacketSavingConnection* server_conn,
+                            QuicCryptoServerStream* server,
+                            const QuicServerId& server_id,
+                            const FakeClientOptions& options) {
+  ParsedQuicVersionVector supported_versions = AllSupportedVersions();
+  if (options.only_tls_versions) {
+    supported_versions.clear();
+    for (QuicTransportVersion transport_version :
+         AllSupportedTransportVersions()) {
+      supported_versions.push_back(
+          ParsedQuicVersion(PROTOCOL_TLS1_3, transport_version));
+    }
+  }
+  PacketSavingConnection* client_conn = new PacketSavingConnection(
+      helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
+  // Advance the time, because timers do not like uninitialized times.
+  client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+  QuicCryptoClientConfig crypto_config(ProofVerifierForTesting(),
+                                       TlsClientHandshaker::CreateSslCtx());
+  AsyncTestChannelIDSource* async_channel_id_source = nullptr;
+  if (options.channel_id_enabled) {
+    ChannelIDSource* source = ChannelIDSourceForTesting();
+    if (options.channel_id_source_async) {
+      async_channel_id_source = new AsyncTestChannelIDSource(source);
+      source = async_channel_id_source;
+    }
+    crypto_config.SetChannelIDSource(source);
+  }
+  if (!options.token_binding_params.empty()) {
+    crypto_config.tb_key_params = options.token_binding_params;
+  }
+  TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
+                                           supported_versions, server_id,
+                                           &crypto_config);
+
+  EXPECT_CALL(client_session, OnProofValid(testing::_))
+      .Times(testing::AnyNumber());
+  EXPECT_CALL(client_session, OnProofVerifyDetailsAvailable(testing::_))
+      .Times(testing::AnyNumber());
+  EXPECT_CALL(*client_conn, OnCanWrite()).Times(testing::AnyNumber());
+  client_session.GetMutableCryptoStream()->CryptoConnect();
+  CHECK_EQ(1u, client_conn->encrypted_packets_.size());
+
+  CommunicateHandshakeMessagesAndRunCallbacks(
+      client_conn, client_session.GetMutableCryptoStream(), server_conn, server,
+      async_channel_id_source);
+
+  if (server->handshake_confirmed() && server->encryption_established()) {
+    CompareClientAndServerKeys(client_session.GetMutableCryptoStream(), server);
+
+    if (options.channel_id_enabled) {
+      std::unique_ptr<ChannelIDKey> channel_id_key;
+      QuicAsyncStatus status =
+          crypto_config.channel_id_source()->GetChannelIDKey(
+              server_id.host(), &channel_id_key, nullptr);
+      EXPECT_EQ(QUIC_SUCCESS, status);
+      EXPECT_EQ(channel_id_key->SerializeKey(),
+                server->crypto_negotiated_params().channel_id);
+      EXPECT_EQ(
+          options.channel_id_source_async,
+          client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun());
+    }
+  }
+
+  return client_session.GetCryptoStream()->num_sent_client_hellos();
+}
+
+void SetupCryptoServerConfigForTest(const QuicClock* clock,
+                                    QuicRandom* rand,
+                                    QuicCryptoServerConfig* crypto_config,
+                                    const FakeServerOptions& fake_options) {
+  QuicCryptoServerConfig::ConfigOptions options;
+  options.channel_id_enabled = true;
+  options.token_binding_params = fake_options.token_binding_params;
+  std::unique_ptr<CryptoHandshakeMessage> scfg(
+      crypto_config->AddDefaultConfig(rand, clock, options));
+}
+
+void SendHandshakeMessageToStream(QuicCryptoStream* stream,
+                                  const CryptoHandshakeMessage& message,
+                                  Perspective perspective) {
+  const QuicData& data = message.GetSerialized();
+  QuicSession* session = QuicStreamPeer::session(stream);
+  if (session->connection()->transport_version() < QUIC_VERSION_47) {
+    QuicStreamFrame frame(QuicUtils::GetCryptoStreamId(
+                              session->connection()->transport_version()),
+                          false, stream->crypto_bytes_read(),
+                          data.AsStringPiece());
+    stream->OnStreamFrame(frame);
+  } else {
+    EncryptionLevel level = session->connection()->last_decrypted_level();
+    QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level),
+                          data.AsStringPiece());
+    stream->OnCryptoFrame(frame);
+  }
+}
+
+void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
+                                  QuicCryptoStream* client,
+                                  PacketSavingConnection* server_conn,
+                                  QuicCryptoStream* server) {
+  CommunicateHandshakeMessagesAndRunCallbacks(client_conn, client, server_conn,
+                                              server, nullptr);
+}
+
+void CommunicateHandshakeMessagesAndRunCallbacks(
+    PacketSavingConnection* client_conn,
+    QuicCryptoStream* client,
+    PacketSavingConnection* server_conn,
+    QuicCryptoStream* server,
+    CallbackSource* callback_source) {
+  size_t client_i = 0, server_i = 0;
+  while (!client->handshake_confirmed() || !server->handshake_confirmed()) {
+    ASSERT_GT(client_conn->encrypted_packets_.size(), client_i);
+    QUIC_LOG(INFO) << "Processing "
+                   << client_conn->encrypted_packets_.size() - client_i
+                   << " packets client->server";
+    MovePackets(client_conn, &client_i, server, server_conn,
+                Perspective::IS_SERVER);
+    if (callback_source) {
+      callback_source->RunPendingCallbacks();
+    }
+
+    if (client->handshake_confirmed() && server->handshake_confirmed()) {
+      break;
+    }
+    ASSERT_GT(server_conn->encrypted_packets_.size(), server_i);
+    QUIC_LOG(INFO) << "Processing "
+                   << server_conn->encrypted_packets_.size() - server_i
+                   << " packets server->client";
+    MovePackets(server_conn, &server_i, client, client_conn,
+                Perspective::IS_CLIENT);
+    if (callback_source) {
+      callback_source->RunPendingCallbacks();
+    }
+  }
+}
+
+std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
+                                           QuicCryptoStream* client,
+                                           size_t client_i,
+                                           PacketSavingConnection* server_conn,
+                                           QuicCryptoStream* server,
+                                           size_t server_i) {
+  QUIC_LOG(INFO) << "Processing "
+                 << client_conn->encrypted_packets_.size() - client_i
+                 << " packets client->server";
+  MovePackets(client_conn, &client_i, server, server_conn,
+              Perspective::IS_SERVER);
+
+  QUIC_LOG(INFO) << "Processing "
+                 << server_conn->encrypted_packets_.size() - server_i
+                 << " packets server->client";
+  if (server_conn->encrypted_packets_.size() - server_i == 2) {
+    QUIC_LOG(INFO) << "here";
+  }
+  MovePackets(server_conn, &server_i, client, client_conn,
+              Perspective::IS_CLIENT);
+
+  return std::make_pair(client_i, server_i);
+}
+
+QuicString GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag) {
+  auto it = message.tag_value_map().find(tag);
+  if (it == message.tag_value_map().end()) {
+    return QuicString();
+  }
+  return it->second;
+}
+
+uint64_t LeafCertHashForTesting() {
+  QuicReferenceCountedPointer<ProofSource::Chain> chain;
+  QuicSocketAddress server_address(QuicIpAddress::Any4(), 42);
+  QuicCryptoProof proof;
+  std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting());
+
+  class Callback : public ProofSource::Callback {
+   public:
+    Callback(bool* ok, QuicReferenceCountedPointer<ProofSource::Chain>* chain)
+        : ok_(ok), chain_(chain) {}
+
+    void Run(bool ok,
+             const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+             const QuicCryptoProof& /* proof */,
+             std::unique_ptr<ProofSource::Details> /* details */) override {
+      *ok_ = ok;
+      *chain_ = chain;
+    }
+
+   private:
+    bool* ok_;
+    QuicReferenceCountedPointer<ProofSource::Chain>* chain_;
+  };
+
+  // Note: relies on the callback being invoked synchronously
+  bool ok = false;
+  proof_source->GetProof(
+      server_address, "", "", AllSupportedTransportVersions().front(), "",
+      std::unique_ptr<ProofSource::Callback>(new Callback(&ok, &chain)));
+  if (!ok || chain->certs.empty()) {
+    DCHECK(false) << "Proof generation failed";
+    return 0;
+  }
+
+  return QuicUtils::FNV1a_64_Hash(chain->certs.at(0));
+}
+
+class MockCommonCertSets : public CommonCertSets {
+ public:
+  MockCommonCertSets(QuicStringPiece cert, uint64_t hash, uint32_t index)
+      : cert_(cert), hash_(hash), index_(index) {}
+
+  QuicStringPiece GetCommonHashes() const override {
+    QUIC_BUG << "not implemented";
+    return QuicStringPiece();
+  }
+
+  QuicStringPiece GetCert(uint64_t hash, uint32_t index) const override {
+    if (hash == hash_ && index == index_) {
+      return cert_;
+    }
+    return QuicStringPiece();
+  }
+
+  bool MatchCert(QuicStringPiece cert,
+                 QuicStringPiece common_set_hashes,
+                 uint64_t* out_hash,
+                 uint32_t* out_index) const override {
+    if (cert != cert_) {
+      return false;
+    }
+
+    if (common_set_hashes.size() % sizeof(uint64_t) != 0) {
+      return false;
+    }
+    bool client_has_set = false;
+    for (size_t i = 0; i < common_set_hashes.size(); i += sizeof(uint64_t)) {
+      uint64_t hash;
+      memcpy(&hash, common_set_hashes.data() + i, sizeof(hash));
+      if (hash == hash_) {
+        client_has_set = true;
+        break;
+      }
+    }
+
+    if (!client_has_set) {
+      return false;
+    }
+
+    *out_hash = hash_;
+    *out_index = index_;
+    return true;
+  }
+
+ private:
+  const QuicString cert_;
+  const uint64_t hash_;
+  const uint32_t index_;
+};
+
+CommonCertSets* MockCommonCertSets(QuicStringPiece cert,
+                                   uint64_t hash,
+                                   uint32_t index) {
+  return new class MockCommonCertSets(cert, hash, index);
+}
+
+void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless) {
+  if (reject_is_stateless) {
+    rej->set_tag(kSREJ);
+  } else {
+    rej->set_tag(kREJ);
+  }
+
+  // Minimum SCFG that passes config validation checks.
+  // clang-format off
+  unsigned char scfg[] = {
+    // SCFG
+    0x53, 0x43, 0x46, 0x47,
+    // num entries
+    0x01, 0x00,
+    // padding
+    0x00, 0x00,
+    // EXPY
+    0x45, 0x58, 0x50, 0x59,
+    // EXPY end offset
+    0x08, 0x00, 0x00, 0x00,
+    // Value
+    '1',  '2',  '3',  '4',
+    '5',  '6',  '7',  '8'
+  };
+  // clang-format on
+  rej->SetValue(kSCFG, scfg);
+  rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
+  int64_t ttl = 2 * 24 * 60 * 60;
+  rej->SetValue(kSTTL, ttl);
+  std::vector<QuicTag> reject_reasons;
+  reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
+  rej->SetVector(kRREJ, reject_reasons);
+}
+
+void CompareClientAndServerKeys(QuicCryptoClientStream* client,
+                                QuicCryptoServerStream* server) {
+  QuicFramer* client_framer = QuicConnectionPeer::GetFramer(
+      QuicStreamPeer::session(client)->connection());
+  QuicFramer* server_framer = QuicConnectionPeer::GetFramer(
+      QuicStreamPeer::session(server)->connection());
+  const QuicEncrypter* client_encrypter(
+      QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_ZERO_RTT));
+  const QuicDecrypter* client_decrypter(
+      QuicStreamPeer::session(client)->connection()->decrypter());
+  const QuicEncrypter* client_forward_secure_encrypter(
+      QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_FORWARD_SECURE));
+  const QuicDecrypter* client_forward_secure_decrypter(
+      QuicStreamPeer::session(client)->connection()->alternative_decrypter());
+  const QuicEncrypter* server_encrypter(
+      QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_ZERO_RTT));
+  const QuicDecrypter* server_decrypter(
+      QuicStreamPeer::session(server)->connection()->decrypter());
+  const QuicEncrypter* server_forward_secure_encrypter(
+      QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_FORWARD_SECURE));
+  const QuicDecrypter* server_forward_secure_decrypter(
+      QuicStreamPeer::session(server)->connection()->alternative_decrypter());
+
+  QuicStringPiece client_encrypter_key = client_encrypter->GetKey();
+  QuicStringPiece client_encrypter_iv = client_encrypter->GetNoncePrefix();
+  QuicStringPiece client_decrypter_key = client_decrypter->GetKey();
+  QuicStringPiece client_decrypter_iv = client_decrypter->GetNoncePrefix();
+  QuicStringPiece client_forward_secure_encrypter_key =
+      client_forward_secure_encrypter->GetKey();
+  QuicStringPiece client_forward_secure_encrypter_iv =
+      client_forward_secure_encrypter->GetNoncePrefix();
+  QuicStringPiece client_forward_secure_decrypter_key =
+      client_forward_secure_decrypter->GetKey();
+  QuicStringPiece client_forward_secure_decrypter_iv =
+      client_forward_secure_decrypter->GetNoncePrefix();
+  QuicStringPiece server_encrypter_key = server_encrypter->GetKey();
+  QuicStringPiece server_encrypter_iv = server_encrypter->GetNoncePrefix();
+  QuicStringPiece server_decrypter_key = server_decrypter->GetKey();
+  QuicStringPiece server_decrypter_iv = server_decrypter->GetNoncePrefix();
+  QuicStringPiece server_forward_secure_encrypter_key =
+      server_forward_secure_encrypter->GetKey();
+  QuicStringPiece server_forward_secure_encrypter_iv =
+      server_forward_secure_encrypter->GetNoncePrefix();
+  QuicStringPiece server_forward_secure_decrypter_key =
+      server_forward_secure_decrypter->GetKey();
+  QuicStringPiece server_forward_secure_decrypter_iv =
+      server_forward_secure_decrypter->GetNoncePrefix();
+
+  QuicStringPiece client_subkey_secret =
+      client->crypto_negotiated_params().subkey_secret;
+  QuicStringPiece server_subkey_secret =
+      server->crypto_negotiated_params().subkey_secret;
+
+  const char kSampleLabel[] = "label";
+  const char kSampleContext[] = "context";
+  const size_t kSampleOutputLength = 32;
+  QuicString client_key_extraction;
+  QuicString server_key_extraction;
+  QuicString client_tb_ekm;
+  QuicString server_tb_ekm;
+  EXPECT_TRUE(client->ExportKeyingMaterial(kSampleLabel, kSampleContext,
+                                           kSampleOutputLength,
+                                           &client_key_extraction));
+  EXPECT_TRUE(server->ExportKeyingMaterial(kSampleLabel, kSampleContext,
+                                           kSampleOutputLength,
+                                           &server_key_extraction));
+
+  CompareCharArraysWithHexError("client write key", client_encrypter_key.data(),
+                                client_encrypter_key.length(),
+                                server_decrypter_key.data(),
+                                server_decrypter_key.length());
+  CompareCharArraysWithHexError("client write IV", client_encrypter_iv.data(),
+                                client_encrypter_iv.length(),
+                                server_decrypter_iv.data(),
+                                server_decrypter_iv.length());
+  CompareCharArraysWithHexError("server write key", server_encrypter_key.data(),
+                                server_encrypter_key.length(),
+                                client_decrypter_key.data(),
+                                client_decrypter_key.length());
+  CompareCharArraysWithHexError("server write IV", server_encrypter_iv.data(),
+                                server_encrypter_iv.length(),
+                                client_decrypter_iv.data(),
+                                client_decrypter_iv.length());
+  CompareCharArraysWithHexError("client forward secure write key",
+                                client_forward_secure_encrypter_key.data(),
+                                client_forward_secure_encrypter_key.length(),
+                                server_forward_secure_decrypter_key.data(),
+                                server_forward_secure_decrypter_key.length());
+  CompareCharArraysWithHexError("client forward secure write IV",
+                                client_forward_secure_encrypter_iv.data(),
+                                client_forward_secure_encrypter_iv.length(),
+                                server_forward_secure_decrypter_iv.data(),
+                                server_forward_secure_decrypter_iv.length());
+  CompareCharArraysWithHexError("server forward secure write key",
+                                server_forward_secure_encrypter_key.data(),
+                                server_forward_secure_encrypter_key.length(),
+                                client_forward_secure_decrypter_key.data(),
+                                client_forward_secure_decrypter_key.length());
+  CompareCharArraysWithHexError("server forward secure write IV",
+                                server_forward_secure_encrypter_iv.data(),
+                                server_forward_secure_encrypter_iv.length(),
+                                client_forward_secure_decrypter_iv.data(),
+                                client_forward_secure_decrypter_iv.length());
+  CompareCharArraysWithHexError("subkey secret", client_subkey_secret.data(),
+                                client_subkey_secret.length(),
+                                server_subkey_secret.data(),
+                                server_subkey_secret.length());
+  CompareCharArraysWithHexError(
+      "sample key extraction", client_key_extraction.data(),
+      client_key_extraction.length(), server_key_extraction.data(),
+      server_key_extraction.length());
+
+  CompareCharArraysWithHexError("token binding key extraction",
+                                client_tb_ekm.data(), client_tb_ekm.length(),
+                                server_tb_ekm.data(), server_tb_ekm.length());
+}
+
+QuicTag ParseTag(const char* tagstr) {
+  const size_t len = strlen(tagstr);
+  CHECK_NE(0u, len);
+
+  QuicTag tag = 0;
+
+  if (tagstr[0] == '#') {
+    CHECK_EQ(static_cast<size_t>(1 + 2 * 4), len);
+    tagstr++;
+
+    for (size_t i = 0; i < 8; i++) {
+      tag <<= 4;
+
+      uint8_t v = 0;
+      CHECK(HexChar(tagstr[i], &v));
+      tag |= v;
+    }
+
+    return tag;
+  }
+
+  CHECK_LE(len, 4u);
+  for (size_t i = 0; i < 4; i++) {
+    tag >>= 8;
+    if (i < len) {
+      tag |= static_cast<uint32_t>(tagstr[i]) << 24;
+    }
+  }
+
+  return tag;
+}
+
+CryptoHandshakeMessage CreateCHLO(
+    std::vector<std::pair<QuicString, QuicString>> tags_and_values) {
+  return CreateCHLO(tags_and_values, -1);
+}
+
+CryptoHandshakeMessage CreateCHLO(
+    std::vector<std::pair<QuicString, QuicString>> tags_and_values,
+    int minimum_size_bytes) {
+  CryptoHandshakeMessage msg;
+  msg.set_tag(MakeQuicTag('C', 'H', 'L', 'O'));
+
+  if (minimum_size_bytes > 0) {
+    msg.set_minimum_size(minimum_size_bytes);
+  }
+
+  for (const auto& tag_and_value : tags_and_values) {
+    const QuicString& tag = tag_and_value.first;
+    const QuicString& value = tag_and_value.second;
+
+    const QuicTag quic_tag = ParseTag(tag.c_str());
+
+    size_t value_len = value.length();
+    if (value_len > 0 && value[0] == '#') {
+      // This is ascii encoded hex.
+      QuicString hex_value =
+          QuicTextUtils::HexDecode(QuicStringPiece(&value[1]));
+      msg.SetStringPiece(quic_tag, hex_value);
+      continue;
+    }
+    msg.SetStringPiece(quic_tag, value);
+  }
+
+  // The CryptoHandshakeMessage needs to be serialized and parsed to ensure
+  // that any padding is included.
+  std::unique_ptr<QuicData> bytes(CryptoFramer::ConstructHandshakeMessage(msg));
+  std::unique_ptr<CryptoHandshakeMessage> parsed(
+      CryptoFramer::ParseMessage(bytes->AsStringPiece()));
+  CHECK(parsed);
+
+  return *parsed;
+}
+
+ChannelIDSource* ChannelIDSourceForTesting() {
+  return new TestChannelIDSource();
+}
+
+void MovePackets(PacketSavingConnection* source_conn,
+                 size_t* inout_packet_index,
+                 QuicCryptoStream* dest_stream,
+                 PacketSavingConnection* dest_conn,
+                 Perspective dest_perspective) {
+  SimpleQuicFramer framer(source_conn->supported_versions(), dest_perspective);
+
+  SimpleQuicFramer null_encryption_framer(source_conn->supported_versions(),
+                                          dest_perspective);
+
+  size_t index = *inout_packet_index;
+  for (; index < source_conn->encrypted_packets_.size(); index++) {
+    // In order to properly test the code we need to perform encryption and
+    // decryption so that the crypters latch when expected. The crypters are in
+    // |dest_conn|, but we don't want to try and use them there. Instead we swap
+    // them into |framer|, perform the decryption with them, and then swap ther
+    // back.
+    QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
+    if (!framer.ProcessPacket(*source_conn->encrypted_packets_[index])) {
+      // The framer will be unable to decrypt forward-secure packets sent after
+      // the handshake is complete. Don't treat them as handshake packets.
+      break;
+    }
+    QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer());
+    dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
+
+    if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) {
+      // Try to process the packet with a framer that only has the NullDecrypter
+      // for decryption. If ProcessPacket succeeds, that means the packet was
+      // encrypted with the NullEncrypter. With the TLS handshaker in use, no
+      // packets should ever be encrypted with the NullEncrypter, instead
+      // they're encrypted with an obfuscation cipher based on QUIC version and
+      // connection ID.
+      ASSERT_FALSE(null_encryption_framer.ProcessPacket(
+          *source_conn->encrypted_packets_[index]))
+          << "No TLS packets should be encrypted with the NullEncrypter";
+    }
+
+    // Since we're using QuicFramers separate from the connections to move
+    // packets, the QuicConnection never gets notified about what level the last
+    // packet was decrypted at. This is needed by TLS to know what encryption
+    // level was used for the data it's receiving, so we plumb this information
+    // from the SimpleQuicFramer back into the connection.
+    dest_conn->OnDecryptedPacket(framer.last_decrypted_level());
+
+    QuicConnectionPeer::SetCurrentPacket(
+        dest_conn, source_conn->encrypted_packets_[index]->AsStringPiece());
+    for (const auto& stream_frame : framer.stream_frames()) {
+      dest_stream->OnStreamFrame(*stream_frame);
+    }
+    for (const auto& crypto_frame : framer.crypto_frames()) {
+      dest_stream->OnCryptoFrame(*crypto_frame);
+    }
+  }
+  *inout_packet_index = index;
+
+  QuicConnectionPeer::SetCurrentPacket(dest_conn, QuicStringPiece(nullptr, 0));
+}
+
+CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
+    const QuicClock* clock,
+    QuicTransportVersion version,
+    QuicCryptoServerConfig* crypto_config) {
+  // clang-format off
+  return CreateCHLO(
+      {{"PDMD", "X509"},
+       {"AEAD", "AESG"},
+       {"KEXS", "C255"},
+       {"PUBS", GenerateClientPublicValuesHex().c_str()},
+       {"NONC", GenerateClientNonceHex(clock, crypto_config).c_str()},
+       {"VER\0", QuicVersionLabelToString(
+           QuicVersionToQuicVersionLabel(version)).c_str()}},
+      kClientHelloMinimumSize);
+  // clang-format on
+}
+
+QuicString GenerateClientNonceHex(const QuicClock* clock,
+                                  QuicCryptoServerConfig* crypto_config) {
+  QuicCryptoServerConfig::ConfigOptions old_config_options;
+  QuicCryptoServerConfig::ConfigOptions new_config_options;
+  old_config_options.id = "old-config-id";
+  delete crypto_config->AddDefaultConfig(QuicRandom::GetInstance(), clock,
+                                         old_config_options);
+  std::unique_ptr<QuicServerConfigProtobuf> primary_config(
+      crypto_config->GenerateConfig(QuicRandom::GetInstance(), clock,
+                                    new_config_options));
+  primary_config->set_primary_time(clock->WallNow().ToUNIXSeconds());
+  std::unique_ptr<CryptoHandshakeMessage> msg(
+      crypto_config->AddConfig(std::move(primary_config), clock->WallNow()));
+  QuicStringPiece orbit;
+  CHECK(msg->GetStringPiece(kORBT, &orbit));
+  QuicString nonce;
+  CryptoUtils::GenerateNonce(clock->WallNow(), QuicRandom::GetInstance(), orbit,
+                             &nonce);
+  return ("#" + QuicTextUtils::HexEncode(nonce));
+}
+
+QuicString GenerateClientPublicValuesHex() {
+  char public_value[32];
+  memset(public_value, 42, sizeof(public_value));
+  return ("#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)));
+}
+
+void GenerateFullCHLO(const CryptoHandshakeMessage& inchoate_chlo,
+                      QuicCryptoServerConfig* crypto_config,
+                      QuicSocketAddress server_addr,
+                      QuicSocketAddress client_addr,
+                      QuicTransportVersion version,
+                      const QuicClock* clock,
+                      QuicReferenceCountedPointer<QuicSignedServerConfig> proof,
+                      QuicCompressedCertsCache* compressed_certs_cache,
+                      CryptoHandshakeMessage* out) {
+  // Pass a inchoate CHLO.
+  FullChloGenerator generator(crypto_config, server_addr, client_addr, clock,
+                              proof, compressed_certs_cache, out);
+  crypto_config->ValidateClientHello(
+      inchoate_chlo, client_addr.host(), server_addr, version, clock, proof,
+      generator.GetValidateClientHelloCallback());
+}
+
+}  // namespace crypto_test_utils
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/crypto_test_utils.h b/quic/test_tools/crypto_test_utils.h
new file mode 100644
index 0000000..8421895
--- /dev/null
+++ b/quic/test_tools/crypto_test_utils.h
@@ -0,0 +1,277 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_CRYPTO_TEST_UTILS_H_
+#define QUICHE_QUIC_TEST_TOOLS_CRYPTO_TEST_UTILS_H_
+
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+
+class ChannelIDSource;
+class CommonCertSets;
+class ProofSource;
+class ProofVerifier;
+class ProofVerifyContext;
+class QuicClock;
+class QuicConfig;
+class QuicCryptoClientStream;
+class QuicCryptoServerConfig;
+class QuicCryptoServerStream;
+class QuicCryptoStream;
+class QuicRandom;
+class QuicServerId;
+
+namespace test {
+
+class PacketSavingConnection;
+
+class TestChannelIDKey : public ChannelIDKey {
+ public:
+  explicit TestChannelIDKey(EVP_PKEY* ecdsa_key);
+  ~TestChannelIDKey() override;
+
+  // ChannelIDKey implementation.
+
+  bool Sign(QuicStringPiece signed_data,
+            QuicString* out_signature) const override;
+
+  QuicString SerializeKey() const override;
+
+ private:
+  bssl::UniquePtr<EVP_PKEY> ecdsa_key_;
+};
+
+class TestChannelIDSource : public ChannelIDSource {
+ public:
+  ~TestChannelIDSource() override;
+
+  // ChannelIDSource implementation.
+
+  QuicAsyncStatus GetChannelIDKey(
+      const QuicString& hostname,
+      std::unique_ptr<ChannelIDKey>* channel_id_key,
+      ChannelIDSourceCallback* /*callback*/) override;
+
+ private:
+  static EVP_PKEY* HostnameToKey(const QuicString& hostname);
+};
+
+namespace crypto_test_utils {
+
+// An interface for a source of callbacks. This is used for invoking
+// callbacks asynchronously.
+//
+// Call the RunPendingCallbacks method regularly to run the callbacks from
+// this source.
+class CallbackSource {
+ public:
+  virtual ~CallbackSource() {}
+
+  // Runs pending callbacks from this source. If there is no pending
+  // callback, does nothing.
+  virtual void RunPendingCallbacks() = 0;
+};
+
+// FakeServerOptions bundles together a number of options for configuring the
+// server in HandshakeWithFakeServer.
+struct FakeServerOptions {
+  FakeServerOptions();
+  ~FakeServerOptions();
+
+  // The Token Binding params that the server supports and will negotiate.
+  QuicTagVector token_binding_params;
+};
+
+// FakeClientOptions bundles together a number of options for configuring
+// HandshakeWithFakeClient.
+struct FakeClientOptions {
+  FakeClientOptions();
+  ~FakeClientOptions();
+
+  // If channel_id_enabled is true then the client will attempt to send a
+  // ChannelID.
+  bool channel_id_enabled;
+
+  // If channel_id_source_async is true then the client will use an async
+  // ChannelIDSource for testing. Ignored if channel_id_enabled is false.
+  bool channel_id_source_async;
+
+  // The Token Binding params that the client supports and will negotiate.
+  QuicTagVector token_binding_params;
+
+  // If only_tls_versions is set, then the client will only use TLS for the
+  // crypto handshake.
+  bool only_tls_versions = false;
+};
+
+// returns: the number of client hellos that the client sent.
+int HandshakeWithFakeServer(QuicConfig* server_quic_config,
+                            MockQuicConnectionHelper* helper,
+                            MockAlarmFactory* alarm_factory,
+                            PacketSavingConnection* client_conn,
+                            QuicCryptoClientStream* client,
+                            const FakeServerOptions& options);
+
+// returns: the number of client hellos that the client sent.
+int HandshakeWithFakeClient(MockQuicConnectionHelper* helper,
+                            MockAlarmFactory* alarm_factory,
+                            PacketSavingConnection* server_conn,
+                            QuicCryptoServerStream* server,
+                            const QuicServerId& server_id,
+                            const FakeClientOptions& options);
+
+// SetupCryptoServerConfigForTest configures |crypto_config|
+// with sensible defaults for testing.
+void SetupCryptoServerConfigForTest(const QuicClock* clock,
+                                    QuicRandom* rand,
+                                    QuicCryptoServerConfig* crypto_config,
+                                    const FakeServerOptions& options);
+
+// Sends the handshake message |message| to stream |stream| with the perspective
+// that the message is coming from |perspective|.
+void SendHandshakeMessageToStream(QuicCryptoStream* stream,
+                                  const CryptoHandshakeMessage& message,
+                                  Perspective perspective);
+
+// CommunicateHandshakeMessages moves messages from |client| to |server| and
+// back until |clients|'s handshake has completed.
+void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
+                                  QuicCryptoStream* client,
+                                  PacketSavingConnection* server_conn,
+                                  QuicCryptoStream* server);
+
+// CommunicateHandshakeMessagesAndRunCallbacks moves messages from |client|
+// to |server| and back until |client|'s handshake has completed. If
+// |callback_source| is not nullptr,
+// CommunicateHandshakeMessagesAndRunCallbacks also runs callbacks from
+// |callback_source| between processing messages.
+void CommunicateHandshakeMessagesAndRunCallbacks(
+    PacketSavingConnection* client_conn,
+    QuicCryptoStream* client,
+    PacketSavingConnection* server_conn,
+    QuicCryptoStream* server,
+    CallbackSource* callback_source);
+
+// AdvanceHandshake attempts to moves messages from |client| to |server| and
+// |server| to |client|. Returns the number of messages moved.
+std::pair<size_t, size_t> AdvanceHandshake(PacketSavingConnection* client_conn,
+                                           QuicCryptoStream* client,
+                                           size_t client_i,
+                                           PacketSavingConnection* server_conn,
+                                           QuicCryptoStream* server,
+                                           size_t server_i);
+
+// Returns the value for the tag |tag| in the tag value map of |message|.
+QuicString GetValueForTag(const CryptoHandshakeMessage& message, QuicTag tag);
+
+// Returns a new |ProofSource| that serves up test certificates.
+std::unique_ptr<ProofSource> ProofSourceForTesting();
+
+// Returns a new |ProofVerifier| that uses the QUIC testing root CA.
+std::unique_ptr<ProofVerifier> ProofVerifierForTesting();
+
+// Returns a hash of the leaf test certificate.
+uint64_t LeafCertHashForTesting();
+
+// Returns a |ProofVerifyContext| that must be used with the verifier
+// returned by |ProofVerifierForTesting|.
+std::unique_ptr<ProofVerifyContext> ProofVerifyContextForTesting();
+
+// MockCommonCertSets returns a CommonCertSets that contains a single set with
+// hash |hash|, consisting of the certificate |cert| at index |index|.
+CommonCertSets* MockCommonCertSets(QuicStringPiece cert,
+                                   uint64_t hash,
+                                   uint32_t index);
+
+// Creates a minimal dummy reject message that will pass the client-config
+// validation tests. This will include a server config, but no certs, proof
+// source address token, or server nonce.
+void FillInDummyReject(CryptoHandshakeMessage* rej, bool reject_is_stateless);
+
+// ParseTag returns a QuicTag from parsing |tagstr|. |tagstr| may either be
+// in the format "EXMP" (i.e. ASCII format), or "#11223344" (an explicit hex
+// format). It CHECK fails if there's a parse error.
+QuicTag ParseTag(const char* tagstr);
+
+// Message constructs a CHLO message from a provided vector of tag/value pairs.
+// The first of each pair is the tag of a tag/value and is given as an argument
+// to |ParseTag|. The second is the value of the tag/value pair and is either a
+// hex dump, preceeded by a '#', or a raw value. If minimum_size_bytes is
+// provided then the message will be padded to this minimum size.
+//
+//   CreateCHLO(
+//       {{"NOCE", "#11223344"},
+//        {"SNI", "www.example.com"}},
+//       optional_minimum_size_bytes);
+CryptoHandshakeMessage CreateCHLO(
+    std::vector<std::pair<QuicString, QuicString>> tags_and_values);
+CryptoHandshakeMessage CreateCHLO(
+    std::vector<std::pair<QuicString, QuicString>> tags_and_values,
+    int minimum_size_bytes);
+
+// ChannelIDSourceForTesting returns a ChannelIDSource that generates keys
+// deterministically based on the hostname given in the GetChannelIDKey call.
+// This ChannelIDSource works in synchronous mode, i.e., its GetChannelIDKey
+// method never returns QUIC_PENDING.
+ChannelIDSource* ChannelIDSourceForTesting();
+
+// MovePackets parses crypto handshake messages from packet number
+// |*inout_packet_index| through to the last packet (or until a packet fails
+// to decrypt) and has |dest_stream| process them. |*inout_packet_index| is
+// updated with an index one greater than the last packet processed.
+void MovePackets(PacketSavingConnection* source_conn,
+                 size_t* inout_packet_index,
+                 QuicCryptoStream* dest_stream,
+                 PacketSavingConnection* dest_conn,
+                 Perspective dest_perspective);
+
+// Return an inchoate CHLO with some basic tag value pairs.
+CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
+    const QuicClock* clock,
+    QuicTransportVersion version,
+    QuicCryptoServerConfig* crypto_config);
+
+// Takes a inchoate CHLO, returns a full CHLO in |out| which can pass
+// |crypto_config|'s validation.
+void GenerateFullCHLO(
+    const CryptoHandshakeMessage& inchoate_chlo,
+    QuicCryptoServerConfig* crypto_config,
+    QuicSocketAddress server_addr,
+    QuicSocketAddress client_addr,
+    QuicTransportVersion version,
+    const QuicClock* clock,
+    QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
+    QuicCompressedCertsCache* compressed_certs_cache,
+    CryptoHandshakeMessage* out);
+
+void CompareClientAndServerKeys(QuicCryptoClientStream* client,
+                                QuicCryptoServerStream* server);
+
+// Return a CHLO nonce in hexadecimal.
+QuicString GenerateClientNonceHex(const QuicClock* clock,
+                                  QuicCryptoServerConfig* crypto_config);
+
+// Return a CHLO PUBS in hexadecimal.
+QuicString GenerateClientPublicValuesHex();
+
+}  // namespace crypto_test_utils
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_CRYPTO_TEST_UTILS_H_
diff --git a/quic/test_tools/crypto_test_utils_test.cc b/quic/test_tools/crypto_test_utils_test.cc
new file mode 100644
index 0000000..cecdaa2
--- /dev/null
+++ b/quic/test_tools/crypto_test_utils_test.cc
@@ -0,0 +1,172 @@
+// 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/crypto_test_utils.h"
+
+#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+
+namespace quic {
+namespace test {
+
+class ShloVerifier {
+ public:
+  ShloVerifier(
+      QuicCryptoServerConfig* crypto_config,
+      QuicSocketAddress server_addr,
+      QuicSocketAddress client_addr,
+      const QuicClock* clock,
+      QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config,
+      QuicCompressedCertsCache* compressed_certs_cache)
+      : crypto_config_(crypto_config),
+        server_addr_(server_addr),
+        client_addr_(client_addr),
+        clock_(clock),
+        signed_config_(signed_config),
+        compressed_certs_cache_(compressed_certs_cache),
+        params_(new QuicCryptoNegotiatedParameters) {}
+
+  class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
+   public:
+    explicit ValidateClientHelloCallback(ShloVerifier* shlo_verifier)
+        : shlo_verifier_(shlo_verifier) {}
+    void Run(QuicReferenceCountedPointer<
+                 ValidateClientHelloResultCallback::Result> result,
+             std::unique_ptr<ProofSource::Details> /* details */) override {
+      shlo_verifier_->ValidateClientHelloDone(result);
+    }
+
+   private:
+    ShloVerifier* shlo_verifier_;
+  };
+
+  std::unique_ptr<ValidateClientHelloCallback>
+  GetValidateClientHelloCallback() {
+    return QuicMakeUnique<ValidateClientHelloCallback>(this);
+  }
+
+ private:
+  void ValidateClientHelloDone(
+      const QuicReferenceCountedPointer<
+          ValidateClientHelloResultCallback::Result>& result) {
+    result_ = result;
+    crypto_config_->ProcessClientHello(
+        result_, /*reject_only=*/false,
+        /*connection_id=*/TestConnectionId(1), server_addr_, client_addr_,
+        AllSupportedVersions().front(), AllSupportedVersions(),
+        /*use_stateless_rejects=*/true,
+        /*server_designated_connection_id=*/TestConnectionId(2), clock_,
+        QuicRandom::GetInstance(), compressed_certs_cache_, params_,
+        signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
+        GetProcessClientHelloCallback());
+  }
+
+  class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
+   public:
+    explicit ProcessClientHelloCallback(ShloVerifier* shlo_verifier)
+        : shlo_verifier_(shlo_verifier) {}
+    void Run(
+        QuicErrorCode error,
+        const QuicString& error_details,
+        std::unique_ptr<CryptoHandshakeMessage> message,
+        std::unique_ptr<DiversificationNonce> diversification_nonce,
+        std::unique_ptr<ProofSource::Details> proof_source_details) override {
+      shlo_verifier_->ProcessClientHelloDone(std::move(message));
+    }
+
+   private:
+    ShloVerifier* shlo_verifier_;
+  };
+
+  std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
+    return QuicMakeUnique<ProcessClientHelloCallback>(this);
+  }
+
+  void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> message) {
+    // Verify output is a SHLO.
+    EXPECT_EQ(message->tag(), kSHLO)
+        << "Fail to pass validation. Get " << message->DebugString();
+  }
+
+  QuicCryptoServerConfig* crypto_config_;
+  QuicSocketAddress server_addr_;
+  QuicSocketAddress client_addr_;
+  const QuicClock* clock_;
+  QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
+  QuicCompressedCertsCache* compressed_certs_cache_;
+
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
+  QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
+      result_;
+};
+
+class CryptoTestUtilsTest : public QuicTest {};
+
+TEST_F(CryptoTestUtilsTest, TestGenerateFullCHLO) {
+  MockClock clock;
+  QuicCryptoServerConfig crypto_config(
+      QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
+      crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default(),
+      TlsServerHandshaker::CreateSslCtx());
+  QuicSocketAddress server_addr(QuicIpAddress::Any4(), 5);
+  QuicSocketAddress client_addr(QuicIpAddress::Loopback4(), 1);
+  QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config(
+      new QuicSignedServerConfig);
+  QuicCompressedCertsCache compressed_certs_cache(
+      QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
+  CryptoHandshakeMessage full_chlo;
+
+  QuicCryptoServerConfig::ConfigOptions old_config_options;
+  old_config_options.id = "old-config-id";
+  delete crypto_config.AddDefaultConfig(QuicRandom::GetInstance(), &clock,
+                                        old_config_options);
+  QuicCryptoServerConfig::ConfigOptions new_config_options;
+  std::unique_ptr<QuicServerConfigProtobuf> primary_config(
+      crypto_config.GenerateConfig(QuicRandom::GetInstance(), &clock,
+                                   new_config_options));
+  primary_config->set_primary_time(clock.WallNow().ToUNIXSeconds());
+  std::unique_ptr<CryptoHandshakeMessage> msg(
+      crypto_config.AddConfig(std::move(primary_config), clock.WallNow()));
+  QuicStringPiece orbit;
+  ASSERT_TRUE(msg->GetStringPiece(kORBT, &orbit));
+  QuicString nonce;
+  CryptoUtils::GenerateNonce(clock.WallNow(), QuicRandom::GetInstance(), orbit,
+                             &nonce);
+  QuicString nonce_hex = "#" + QuicTextUtils::HexEncode(nonce);
+
+  char public_value[32];
+  memset(public_value, 42, sizeof(public_value));
+  QuicString pub_hex =
+      "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value));
+
+  QuicTransportVersion version(AllSupportedTransportVersions().front());
+  CryptoHandshakeMessage inchoate_chlo = crypto_test_utils::CreateCHLO(
+      {{"PDMD", "X509"},
+       {"AEAD", "AESG"},
+       {"KEXS", "C255"},
+       {"COPT", "SREJ"},
+       {"PUBS", pub_hex},
+       {"NONC", nonce_hex},
+       {"VER\0",
+        QuicVersionLabelToString(QuicVersionToQuicVersionLabel(version))}},
+      kClientHelloMinimumSize);
+
+  crypto_test_utils::GenerateFullCHLO(
+      inchoate_chlo, &crypto_config, server_addr, client_addr, version, &clock,
+      signed_config, &compressed_certs_cache, &full_chlo);
+  // Verify that full_chlo can pass crypto_config's verification.
+  ShloVerifier shlo_verifier(&crypto_config, server_addr, client_addr, &clock,
+                             signed_config, &compressed_certs_cache);
+  crypto_config.ValidateClientHello(
+      full_chlo, client_addr.host(), server_addr, version, &clock,
+      signed_config, shlo_verifier.GetValidateClientHelloCallback());
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/failing_proof_source.cc b/quic/test_tools/failing_proof_source.cc
new file mode 100644
index 0000000..2db5717
--- /dev/null
+++ b/quic/test_tools/failing_proof_source.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2017 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/failing_proof_source.h"
+
+namespace quic {
+namespace test {
+
+void FailingProofSource::GetProof(const QuicSocketAddress& server_address,
+                                  const QuicString& hostname,
+                                  const QuicString& server_config,
+                                  QuicTransportVersion transport_version,
+                                  QuicStringPiece chlo_hash,
+                                  std::unique_ptr<Callback> callback) {
+  callback->Run(false, nullptr, QuicCryptoProof(), nullptr);
+}
+
+QuicReferenceCountedPointer<ProofSource::Chain>
+FailingProofSource::GetCertChain(const QuicSocketAddress& server_address,
+                                 const QuicString& hostname) {
+  return QuicReferenceCountedPointer<Chain>();
+}
+
+void FailingProofSource::ComputeTlsSignature(
+    const QuicSocketAddress& server_address,
+    const QuicString& hostname,
+    uint16_t signature_algorithm,
+    QuicStringPiece in,
+    std::unique_ptr<SignatureCallback> callback) {
+  callback->Run(false, "");
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/failing_proof_source.h b/quic/test_tools/failing_proof_source.h
new file mode 100644
index 0000000..4427c4c
--- /dev/null
+++ b/quic/test_tools/failing_proof_source.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2017 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_FAILING_PROOF_SOURCE_H_
+#define QUICHE_QUIC_TEST_TOOLS_FAILING_PROOF_SOURCE_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+namespace test {
+
+class FailingProofSource : public ProofSource {
+ public:
+  void GetProof(const QuicSocketAddress& server_address,
+                const QuicString& hostname,
+                const QuicString& server_config,
+                QuicTransportVersion transport_version,
+                QuicStringPiece chlo_hash,
+                std::unique_ptr<Callback> callback) override;
+
+  QuicReferenceCountedPointer<Chain> GetCertChain(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname) override;
+
+  void ComputeTlsSignature(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname,
+      uint16_t signature_algorithm,
+      QuicStringPiece in,
+      std::unique_ptr<SignatureCallback> callback) override;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_FAILING_PROOF_SOURCE_H_
diff --git a/quic/test_tools/fake_proof_source.cc b/quic/test_tools/fake_proof_source.cc
new file mode 100644
index 0000000..3a02cd5
--- /dev/null
+++ b/quic/test_tools/fake_proof_source.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2016 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/fake_proof_source.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/test_tools/crypto_test_utils.h"
+
+namespace quic {
+namespace test {
+
+FakeProofSource::FakeProofSource()
+    : delegate_(crypto_test_utils::ProofSourceForTesting()) {}
+
+FakeProofSource::~FakeProofSource() {}
+
+FakeProofSource::PendingOp::~PendingOp() = default;
+
+FakeProofSource::GetProofOp::GetProofOp(
+    const QuicSocketAddress& server_addr,
+    QuicString hostname,
+    QuicString server_config,
+    QuicTransportVersion transport_version,
+    QuicString chlo_hash,
+    std::unique_ptr<ProofSource::Callback> callback,
+    ProofSource* delegate)
+    : server_address_(server_addr),
+      hostname_(std::move(hostname)),
+      server_config_(std::move(server_config)),
+      transport_version_(transport_version),
+      chlo_hash_(std::move(chlo_hash)),
+      callback_(std::move(callback)),
+      delegate_(delegate) {}
+
+FakeProofSource::GetProofOp::~GetProofOp() = default;
+
+void FakeProofSource::GetProofOp::Run() {
+  // Note: relies on the callback being invoked synchronously
+  delegate_->GetProof(server_address_, hostname_, server_config_,
+                      transport_version_, chlo_hash_, std::move(callback_));
+}
+
+FakeProofSource::ComputeSignatureOp::ComputeSignatureOp(
+    const QuicSocketAddress& server_address,
+    QuicString hostname,
+    uint16_t sig_alg,
+    QuicStringPiece in,
+    std::unique_ptr<ProofSource::SignatureCallback> callback,
+    ProofSource* delegate)
+    : server_address_(server_address),
+      hostname_(std::move(hostname)),
+      sig_alg_(sig_alg),
+      in_(in),
+      callback_(std::move(callback)),
+      delegate_(delegate) {}
+
+FakeProofSource::ComputeSignatureOp::~ComputeSignatureOp() = default;
+
+void FakeProofSource::ComputeSignatureOp::Run() {
+  delegate_->ComputeTlsSignature(server_address_, hostname_, sig_alg_, in_,
+                                 std::move(callback_));
+}
+
+void FakeProofSource::Activate() {
+  active_ = true;
+}
+
+void FakeProofSource::GetProof(
+    const QuicSocketAddress& server_address,
+    const QuicString& hostname,
+    const QuicString& server_config,
+    QuicTransportVersion transport_version,
+    QuicStringPiece chlo_hash,
+    std::unique_ptr<ProofSource::Callback> callback) {
+  if (!active_) {
+    delegate_->GetProof(server_address, hostname, server_config,
+                        transport_version, chlo_hash, std::move(callback));
+    return;
+  }
+
+  pending_ops_.push_back(QuicMakeUnique<GetProofOp>(
+      server_address, hostname, server_config, transport_version,
+      QuicString(chlo_hash), std::move(callback), delegate_.get()));
+}
+
+QuicReferenceCountedPointer<ProofSource::Chain> FakeProofSource::GetCertChain(
+    const QuicSocketAddress& server_address,
+    const QuicString& hostname) {
+  return delegate_->GetCertChain(server_address, hostname);
+}
+
+void FakeProofSource::ComputeTlsSignature(
+    const QuicSocketAddress& server_address,
+    const QuicString& hostname,
+    uint16_t signature_algorithm,
+    QuicStringPiece in,
+    std::unique_ptr<ProofSource::SignatureCallback> callback) {
+  QUIC_LOG(INFO) << "FakeProofSource::ComputeTlsSignature";
+  if (!active_) {
+    QUIC_LOG(INFO) << "Not active - directly calling delegate";
+    delegate_->ComputeTlsSignature(
+        server_address, hostname, signature_algorithm, in, std::move(callback));
+    return;
+  }
+
+  QUIC_LOG(INFO) << "Adding pending op";
+  pending_ops_.push_back(QuicMakeUnique<ComputeSignatureOp>(
+      server_address, hostname, signature_algorithm, in, std::move(callback),
+      delegate_.get()));
+}
+
+int FakeProofSource::NumPendingCallbacks() const {
+  return pending_ops_.size();
+}
+
+void FakeProofSource::InvokePendingCallback(int n) {
+  CHECK(NumPendingCallbacks() > n);
+
+  pending_ops_[n]->Run();
+
+  auto it = pending_ops_.begin() + n;
+  pending_ops_.erase(it);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/fake_proof_source.h b/quic/test_tools/fake_proof_source.h
new file mode 100644
index 0000000..27f63a3
--- /dev/null
+++ b/quic/test_tools/fake_proof_source.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_FAKE_PROOF_SOURCE_H_
+#define QUICHE_QUIC_TEST_TOOLS_FAKE_PROOF_SOURCE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+namespace test {
+
+// Implementation of ProofSource which delegates to a ProofSourceForTesting,
+// except that when the async GetProof is called, it captures the call and
+// allows tests to see that a call is pending, which they can then cause to
+// complete at a time of their choosing.
+class FakeProofSource : public ProofSource {
+ public:
+  FakeProofSource();
+  ~FakeProofSource() override;
+
+  // Before this object is "active", all calls to GetProof will be delegated
+  // immediately.  Once "active", the async ones will be intercepted.  This
+  // distinction is necessary to ensure that GetProof can be called without
+  // interference during test case setup.
+  void Activate();
+
+  // ProofSource interface
+  void GetProof(const QuicSocketAddress& server_address,
+                const QuicString& hostname,
+                const QuicString& server_config,
+                QuicTransportVersion transport_version,
+                QuicStringPiece chlo_hash,
+                std::unique_ptr<ProofSource::Callback> callback) override;
+  QuicReferenceCountedPointer<Chain> GetCertChain(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname) override;
+  void ComputeTlsSignature(
+      const QuicSocketAddress& server_address,
+      const QuicString& hostname,
+      uint16_t signature_algorithm,
+      QuicStringPiece in,
+      std::unique_ptr<ProofSource::SignatureCallback> callback) override;
+
+  // Get the number of callbacks which are pending
+  int NumPendingCallbacks() const;
+
+  // Invoke a pending callback.  The index refers to the position in
+  // pending_ops_ of the callback to be completed.
+  void InvokePendingCallback(int n);
+
+ private:
+  std::unique_ptr<ProofSource> delegate_;
+  bool active_ = false;
+
+  class PendingOp {
+   public:
+    virtual ~PendingOp();
+    virtual void Run() = 0;
+  };
+
+  class GetProofOp : public PendingOp {
+   public:
+    GetProofOp(const QuicSocketAddress& server_addr,
+               QuicString hostname,
+               QuicString server_config,
+               QuicTransportVersion transport_version,
+               QuicString chlo_hash,
+               std::unique_ptr<ProofSource::Callback> callback,
+               ProofSource* delegate);
+    ~GetProofOp() override;
+
+    void Run() override;
+
+   private:
+    QuicSocketAddress server_address_;
+    QuicString hostname_;
+    QuicString server_config_;
+    QuicTransportVersion transport_version_;
+    QuicString chlo_hash_;
+    std::unique_ptr<ProofSource::Callback> callback_;
+    ProofSource* delegate_;
+  };
+
+  class ComputeSignatureOp : public PendingOp {
+   public:
+    ComputeSignatureOp(const QuicSocketAddress& server_address,
+                       QuicString hostname,
+                       uint16_t sig_alg,
+                       QuicStringPiece in,
+                       std::unique_ptr<ProofSource::SignatureCallback> callback,
+                       ProofSource* delegate);
+    ~ComputeSignatureOp() override;
+
+    void Run() override;
+
+   private:
+    QuicSocketAddress server_address_;
+    QuicString hostname_;
+    uint16_t sig_alg_;
+    QuicString in_;
+    std::unique_ptr<ProofSource::SignatureCallback> callback_;
+    ProofSource* delegate_;
+  };
+
+  std::vector<std::unique_ptr<PendingOp>> pending_ops_;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_FAKE_PROOF_SOURCE_H_
diff --git a/quic/test_tools/fuzzing/quic_framer_fuzzer.cc b/quic/test_tools/fuzzing/quic_framer_fuzzer.cc
new file mode 100644
index 0000000..df997e6
--- /dev/null
+++ b/quic/test_tools/fuzzing/quic_framer_fuzzer.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2019 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 "base/commandlineflags.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  SetQuicFlag(&FLAGS_minloglevel, 3);
+
+  quic::QuicFramer framer(quic::AllSupportedVersions(), quic::QuicTime::Zero(),
+                          quic::Perspective::IS_SERVER,
+                          quic::kQuicDefaultConnectionIdLength);
+  const char* const packet_bytes = reinterpret_cast<const char*>(data);
+
+  // Test the CryptoFramer.
+  quic::QuicStringPiece crypto_input(packet_bytes, size);
+  std::unique_ptr<quic::CryptoHandshakeMessage> handshake_message(
+      quic::CryptoFramer::ParseMessage(crypto_input));
+
+  // Test the regular QuicFramer with the same input.
+  quic::test::NoOpFramerVisitor visitor;
+  framer.set_visitor(&visitor);
+  quic::QuicEncryptedPacket packet(packet_bytes, size);
+  framer.ProcessPacket(packet);
+
+  return 0;
+}
diff --git a/quic/test_tools/limited_mtu_test_writer.cc b/quic/test_tools/limited_mtu_test_writer.cc
new file mode 100644
index 0000000..bc71c7c
--- /dev/null
+++ b/quic/test_tools/limited_mtu_test_writer.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2015 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/limited_mtu_test_writer.h"
+
+namespace quic {
+namespace test {
+
+LimitedMtuTestWriter::LimitedMtuTestWriter(QuicByteCount mtu) : mtu_(mtu) {}
+
+LimitedMtuTestWriter::~LimitedMtuTestWriter() = default;
+
+WriteResult LimitedMtuTestWriter::WritePacket(
+    const char* buffer,
+    size_t buf_len,
+    const QuicIpAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    PerPacketOptions* options) {
+  if (buf_len > mtu_) {
+    // Drop the packet.
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
+
+  return QuicPacketWriterWrapper::WritePacket(buffer, buf_len, self_address,
+                                              peer_address, options);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/limited_mtu_test_writer.h b/quic/test_tools/limited_mtu_test_writer.h
new file mode 100644
index 0000000..7c95417
--- /dev/null
+++ b/quic/test_tools/limited_mtu_test_writer.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2015 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_LIMITED_MTU_TEST_WRITER_H_
+#define QUICHE_QUIC_TEST_TOOLS_LIMITED_MTU_TEST_WRITER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+namespace test {
+
+// Simulates a connection over a link with fixed MTU.  Drops packets which
+// exceed the MTU and passes the rest of them as-is.
+class LimitedMtuTestWriter : public QuicPacketWriterWrapper {
+ public:
+  explicit LimitedMtuTestWriter(QuicByteCount mtu);
+  LimitedMtuTestWriter(const LimitedMtuTestWriter&) = delete;
+  LimitedMtuTestWriter& operator=(const LimitedMtuTestWriter&) = delete;
+  ~LimitedMtuTestWriter() override;
+
+  // Inherited from QuicPacketWriterWrapper.
+  WriteResult WritePacket(const char* buffer,
+                          size_t buf_len,
+                          const QuicIpAddress& self_address,
+                          const QuicSocketAddress& peer_address,
+                          PerPacketOptions* options) override;
+
+ private:
+  QuicByteCount mtu_;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_LIMITED_MTU_TEST_WRITER_H_
diff --git a/quic/test_tools/mock_clock.cc b/quic/test_tools/mock_clock.cc
new file mode 100644
index 0000000..1761dd9
--- /dev/null
+++ b/quic/test_tools/mock_clock.cc
@@ -0,0 +1,29 @@
+// 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/mock_clock.h"
+
+namespace quic {
+
+MockClock::MockClock() : now_(QuicTime::Zero()) {}
+
+MockClock::~MockClock() {}
+
+void MockClock::AdvanceTime(QuicTime::Delta delta) {
+  now_ = now_ + delta;
+}
+
+QuicTime MockClock::Now() const {
+  return now_;
+}
+
+QuicTime MockClock::ApproximateNow() const {
+  return now_;
+}
+
+QuicWallTime MockClock::WallNow() const {
+  return QuicWallTime::FromUNIXSeconds((now_ - QuicTime::Zero()).ToSeconds());
+}
+
+}  // namespace quic
diff --git a/quic/test_tools/mock_clock.h b/quic/test_tools/mock_clock.h
new file mode 100644
index 0000000..dbd57d3
--- /dev/null
+++ b/quic/test_tools/mock_clock.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_CLOCK_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_CLOCK_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+
+namespace quic {
+
+class MockClock : public QuicClock {
+ public:
+  MockClock();
+  MockClock(const MockClock&) = delete;
+  MockClock& operator=(const MockClock&) = delete;
+  ~MockClock() override;
+
+  // QuicClock implementation:
+  QuicTime Now() const override;
+  QuicTime ApproximateNow() const override;
+  QuicWallTime WallNow() const override;
+
+  // Advances the current time by |delta|, which may be negative.
+  void AdvanceTime(QuicTime::Delta delta);
+
+ private:
+  QuicTime now_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_CLOCK_H_
diff --git a/quic/test_tools/mock_quic_client_promised_info.cc b/quic/test_tools/mock_quic_client_promised_info.cc
new file mode 100644
index 0000000..4400b03
--- /dev/null
+++ b/quic/test_tools/mock_quic_client_promised_info.cc
@@ -0,0 +1,19 @@
+// Copyright 2016 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/mock_quic_client_promised_info.h"
+
+namespace quic {
+namespace test {
+
+MockQuicClientPromisedInfo::MockQuicClientPromisedInfo(
+    QuicSpdyClientSessionBase* session,
+    QuicStreamId id,
+    QuicString url)
+    : QuicClientPromisedInfo(session, id, url) {}
+
+MockQuicClientPromisedInfo::~MockQuicClientPromisedInfo() {}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/mock_quic_client_promised_info.h b/quic/test_tools/mock_quic_client_promised_info.h
new file mode 100644
index 0000000..a157ac5
--- /dev/null
+++ b/quic/test_tools/mock_quic_client_promised_info.h
@@ -0,0 +1,33 @@
+// Copyright 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_CLIENT_PROMISED_INFO_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_CLIENT_PROMISED_INFO_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+namespace test {
+
+class MockQuicClientPromisedInfo : public QuicClientPromisedInfo {
+ public:
+  MockQuicClientPromisedInfo(QuicSpdyClientSessionBase* session,
+                             QuicStreamId id,
+                             QuicString url);
+  ~MockQuicClientPromisedInfo() override;
+
+  MOCK_METHOD2(HandleClientRequest,
+               QuicAsyncStatus(const spdy::SpdyHeaderBlock& headers,
+                               QuicClientPushPromiseIndex::Delegate* delegate));
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_CLIENT_PROMISED_INFO_H_
diff --git a/quic/test_tools/mock_quic_dispatcher.cc b/quic/test_tools/mock_quic_dispatcher.cc
new file mode 100644
index 0000000..3b3ca46
--- /dev/null
+++ b/quic/test_tools/mock_quic_dispatcher.cc
@@ -0,0 +1,32 @@
+// Copyright 2014 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/mock_quic_dispatcher.h"
+
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+
+MockQuicDispatcher::MockQuicDispatcher(
+    const QuicConfig* config,
+    const QuicCryptoServerConfig* crypto_config,
+    QuicVersionManager* version_manager,
+    std::unique_ptr<QuicConnectionHelperInterface> helper,
+    std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+    std::unique_ptr<QuicAlarmFactory> alarm_factory,
+    QuicSimpleServerBackend* quic_simple_server_backend)
+    : QuicSimpleDispatcher(config,
+                           crypto_config,
+                           version_manager,
+                           std::move(helper),
+                           std::move(session_helper),
+                           std::move(alarm_factory),
+                           quic_simple_server_backend,
+                           kQuicDefaultConnectionIdLength) {}
+
+MockQuicDispatcher::~MockQuicDispatcher() {}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/mock_quic_dispatcher.h b/quic/test_tools/mock_quic_dispatcher.h
new file mode 100644
index 0000000..93acda9
--- /dev/null
+++ b/quic/test_tools/mock_quic_dispatcher.h
@@ -0,0 +1,43 @@
+// Copyright 2014 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h"
+
+namespace quic {
+namespace test {
+
+class MockQuicDispatcher : public QuicSimpleDispatcher {
+ public:
+  MockQuicDispatcher(
+      const QuicConfig* config,
+      const QuicCryptoServerConfig* crypto_config,
+      QuicVersionManager* version_manager,
+      std::unique_ptr<QuicConnectionHelperInterface> helper,
+      std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+      std::unique_ptr<QuicAlarmFactory> alarm_factory,
+      QuicSimpleServerBackend* quic_simple_server_backend);
+  MockQuicDispatcher(const MockQuicDispatcher&) = delete;
+  MockQuicDispatcher& operator=(const MockQuicDispatcher&) = delete;
+
+  ~MockQuicDispatcher() override;
+
+  MOCK_METHOD3(ProcessPacket,
+               void(const QuicSocketAddress& server_address,
+                    const QuicSocketAddress& client_address,
+                    const QuicReceivedPacket& packet));
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_
diff --git a/quic/test_tools/mock_quic_session_visitor.cc b/quic/test_tools/mock_quic_session_visitor.cc
new file mode 100644
index 0000000..fea8414
--- /dev/null
+++ b/quic/test_tools/mock_quic_session_visitor.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2016 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/mock_quic_session_visitor.h"
+
+namespace quic {
+namespace test {
+
+MockQuicSessionVisitor::MockQuicSessionVisitor() = default;
+
+MockQuicSessionVisitor::~MockQuicSessionVisitor() = default;
+
+MockQuicCryptoServerStreamHelper::MockQuicCryptoServerStreamHelper() = default;
+
+MockQuicCryptoServerStreamHelper::~MockQuicCryptoServerStreamHelper() = default;
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/mock_quic_session_visitor.h b/quic/test_tools/mock_quic_session_visitor.h
new file mode 100644
index 0000000..fb01da6
--- /dev/null
+++ b/quic/test_tools/mock_quic_session_visitor.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SESSION_VISITOR_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SESSION_VISITOR_H_
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
+
+namespace quic {
+namespace test {
+
+class MockQuicSessionVisitor : public QuicTimeWaitListManager::Visitor {
+ public:
+  MockQuicSessionVisitor();
+  MockQuicSessionVisitor(const MockQuicSessionVisitor&) = delete;
+  MockQuicSessionVisitor& operator=(const MockQuicSessionVisitor&) = delete;
+  ~MockQuicSessionVisitor() override;
+  MOCK_METHOD4(OnConnectionClosed,
+               void(QuicConnectionId connection_id,
+                    QuicErrorCode error,
+                    const QuicString& error_details,
+                    ConnectionCloseSource source));
+  MOCK_METHOD1(OnWriteBlocked,
+               void(QuicBlockedWriterInterface* blocked_writer));
+  MOCK_METHOD1(OnRstStreamReceived, void(const QuicRstStreamFrame& frame));
+  MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
+  MOCK_METHOD1(OnConnectionAddedToTimeWaitList,
+               void(QuicConnectionId connection_id));
+};
+
+class MockQuicCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
+ public:
+  MockQuicCryptoServerStreamHelper();
+  MockQuicCryptoServerStreamHelper(const MockQuicCryptoServerStreamHelper&) =
+      delete;
+  MockQuicCryptoServerStreamHelper& operator=(
+      const MockQuicCryptoServerStreamHelper&) = delete;
+  ~MockQuicCryptoServerStreamHelper() override;
+  MOCK_CONST_METHOD2(GenerateConnectionIdForReject,
+                     QuicConnectionId(QuicTransportVersion version,
+                                      QuicConnectionId connection_id));
+  MOCK_CONST_METHOD5(CanAcceptClientHello,
+                     bool(const CryptoHandshakeMessage& message,
+                          const QuicSocketAddress& client_address,
+                          const QuicSocketAddress& peer_address,
+                          const QuicSocketAddress& self_address,
+                          QuicString* error_details));
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SESSION_VISITOR_H_
diff --git a/quic/test_tools/mock_quic_spdy_client_stream.cc b/quic/test_tools/mock_quic_spdy_client_stream.cc
new file mode 100644
index 0000000..1d6e2f9
--- /dev/null
+++ b/quic/test_tools/mock_quic_spdy_client_stream.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2016 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/mock_quic_spdy_client_stream.h"
+
+namespace quic {
+namespace test {
+
+MockQuicSpdyClientStream::MockQuicSpdyClientStream(
+    QuicStreamId id,
+    QuicSpdyClientSession* session,
+    StreamType type)
+    : QuicSpdyClientStream(id, session, type) {}
+
+MockQuicSpdyClientStream::~MockQuicSpdyClientStream() {}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/mock_quic_spdy_client_stream.h b/quic/test_tools/mock_quic_spdy_client_stream.h
new file mode 100644
index 0000000..2a5d6ab
--- /dev/null
+++ b/quic/test_tools/mock_quic_spdy_client_stream.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SPDY_CLIENT_STREAM_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SPDY_CLIENT_STREAM_H_
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+namespace test {
+
+class MockQuicSpdyClientStream : public QuicSpdyClientStream {
+ public:
+  MockQuicSpdyClientStream(QuicStreamId id,
+                           QuicSpdyClientSession* session,
+                           StreamType type);
+  ~MockQuicSpdyClientStream() override;
+
+  MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame& frame));
+  MOCK_METHOD3(OnPromiseHeaderList,
+               void(QuicStreamId promised_stream_id,
+                    size_t frame_len,
+                    const QuicHeaderList& list));
+  MOCK_METHOD0(OnDataAvailable, void());
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_SPDY_CLIENT_STREAM_H_
diff --git a/quic/test_tools/mock_quic_time_wait_list_manager.cc b/quic/test_tools/mock_quic_time_wait_list_manager.cc
new file mode 100644
index 0000000..b1890f0
--- /dev/null
+++ b/quic/test_tools/mock_quic_time_wait_list_manager.cc
@@ -0,0 +1,32 @@
+// 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/mock_quic_time_wait_list_manager.h"
+
+using testing::_;
+using testing::Invoke;
+
+namespace quic {
+namespace test {
+
+MockTimeWaitListManager::MockTimeWaitListManager(
+    QuicPacketWriter* writer,
+    Visitor* visitor,
+    const QuicClock* clock,
+    QuicAlarmFactory* alarm_factory)
+    : QuicTimeWaitListManager(writer, visitor, clock, alarm_factory) {
+  // Though AddConnectionIdToTimeWait is mocked, we want to retain its
+  // functionality.
+  EXPECT_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _, _))
+      .Times(testing::AnyNumber());
+  ON_CALL(*this, AddConnectionIdToTimeWait(_, _, _, _, _))
+      .WillByDefault(
+          Invoke(this, &MockTimeWaitListManager::
+                           QuicTimeWaitListManager_AddConnectionIdToTimeWait));
+}
+
+MockTimeWaitListManager::~MockTimeWaitListManager() = default;
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/mock_quic_time_wait_list_manager.h b/quic/test_tools/mock_quic_time_wait_list_manager.h
new file mode 100644
index 0000000..742fef2
--- /dev/null
+++ b/quic/test_tools/mock_quic_time_wait_list_manager.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_TIME_WAIT_LIST_MANAGER_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_TIME_WAIT_LIST_MANAGER_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
+
+namespace quic {
+namespace test {
+
+class MockTimeWaitListManager : public QuicTimeWaitListManager {
+ public:
+  MockTimeWaitListManager(QuicPacketWriter* writer,
+                          Visitor* visitor,
+                          const QuicClock* clock,
+                          QuicAlarmFactory* alarm_factory);
+  ~MockTimeWaitListManager() override;
+
+  MOCK_METHOD5(AddConnectionIdToTimeWait,
+               void(QuicConnectionId connection_id,
+                    bool ietf_quic,
+                    QuicTimeWaitListManager::TimeWaitAction action,
+                    EncryptionLevel encryption_level,
+                    std::vector<std::unique_ptr<QuicEncryptedPacket>>*
+                        termination_packets));
+
+  void QuicTimeWaitListManager_AddConnectionIdToTimeWait(
+      QuicConnectionId connection_id,
+      bool ietf_quic,
+      QuicTimeWaitListManager::TimeWaitAction action,
+      EncryptionLevel encryption_level,
+      std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets) {
+    QuicTimeWaitListManager::AddConnectionIdToTimeWait(connection_id, ietf_quic,
+                                                       action, encryption_level,
+                                                       termination_packets);
+  }
+
+  MOCK_METHOD5(ProcessPacket,
+               void(const QuicSocketAddress& server_address,
+                    const QuicSocketAddress& client_address,
+                    QuicConnectionId connection_id,
+                    PacketHeaderFormat header_format,
+                    std::unique_ptr<QuicPerPacketContext> packet_context));
+
+  MOCK_METHOD6(SendVersionNegotiationPacket,
+               void(QuicConnectionId connection_id,
+                    bool ietf_quic,
+                    const ParsedQuicVersionVector& supported_versions,
+                    const QuicSocketAddress& server_address,
+                    const QuicSocketAddress& client_address,
+                    std::unique_ptr<QuicPerPacketContext> packet_context));
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_QUIC_TIME_WAIT_LIST_MANAGER_H_
diff --git a/quic/test_tools/mock_random.cc b/quic/test_tools/mock_random.cc
new file mode 100644
index 0000000..a01a5a7
--- /dev/null
+++ b/quic/test_tools/mock_random.cc
@@ -0,0 +1,29 @@
+// 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/mock_random.h"
+
+#include <string.h>
+
+namespace quic {
+namespace test {
+
+MockRandom::MockRandom() : base_(0xDEADBEEF), increment_(0) {}
+
+MockRandom::MockRandom(uint32_t base) : base_(base), increment_(0) {}
+
+void MockRandom::RandBytes(void* data, size_t len) {
+  memset(data, increment_ + static_cast<uint8_t>('r'), len);
+}
+
+uint64_t MockRandom::RandUint64() {
+  return base_ + increment_;
+}
+
+void MockRandom::ChangeValue() {
+  increment_++;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/mock_random.h b/quic/test_tools/mock_random.h
new file mode 100644
index 0000000..e8229c0
--- /dev/null
+++ b/quic/test_tools/mock_random.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_MOCK_RANDOM_H_
+#define QUICHE_QUIC_TEST_TOOLS_MOCK_RANDOM_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+
+namespace quic {
+namespace test {
+
+class MockRandom : public QuicRandom {
+ public:
+  // Initializes base_ to 0xDEADBEEF.
+  MockRandom();
+  explicit MockRandom(uint32_t base);
+  MockRandom(const MockRandom&) = delete;
+  MockRandom& operator=(const MockRandom&) = delete;
+
+  // QuicRandom:
+  // Fills the |data| buffer with a repeating byte, initially 'r'.
+  void RandBytes(void* data, size_t len) override;
+  // Returns base + the current increment.
+  uint64_t RandUint64() override;
+
+  // ChangeValue increments |increment_|. This causes the value returned by
+  // |RandUint64| and the byte that |RandBytes| fills with, to change.
+  void ChangeValue();
+
+ private:
+  uint32_t base_;
+  uint8_t increment_;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_MOCK_RANDOM_H_
diff --git a/quic/test_tools/packet_dropping_test_writer.cc b/quic/test_tools/packet_dropping_test_writer.cc
new file mode 100644
index 0000000..87935d5
--- /dev/null
+++ b/quic/test_tools/packet_dropping_test_writer.cc
@@ -0,0 +1,252 @@
+// Copyright 2013 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/packet_dropping_test_writer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/quic/platform/impl/quic_socket_utils.h"
+
+namespace quic {
+namespace test {
+
+const int32_t kMaxConsecutivePacketLoss = 3;
+
+// An alarm that is scheduled if a blocked socket is simulated to indicate
+// it's writable again.
+class WriteUnblockedAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer)
+      : writer_(writer) {}
+
+  void OnAlarm() override {
+    QUIC_DLOG(INFO) << "Unblocking socket.";
+    writer_->OnCanWrite();
+  }
+
+ private:
+  PacketDroppingTestWriter* writer_;
+};
+
+// An alarm that is scheduled every time a new packet is to be written at a
+// later point.
+class DelayAlarm : public QuicAlarm::Delegate {
+ public:
+  explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {}
+
+  void OnAlarm() override {
+    QuicTime new_deadline = writer_->ReleaseOldPackets();
+    if (new_deadline.IsInitialized()) {
+      writer_->SetDelayAlarm(new_deadline);
+    }
+  }
+
+ private:
+  PacketDroppingTestWriter* writer_;
+};
+
+PacketDroppingTestWriter::PacketDroppingTestWriter()
+    : clock_(nullptr),
+      cur_buffer_size_(0),
+      num_calls_to_write_(0),
+      fake_packet_loss_percentage_(0),
+      fake_drop_first_n_packets_(0),
+      fake_blocked_socket_percentage_(0),
+      fake_packet_reorder_percentage_(0),
+      fake_packet_delay_(QuicTime::Delta::Zero()),
+      fake_bandwidth_(QuicBandwidth::Zero()),
+      buffer_size_(0),
+      num_consecutive_packet_lost_(0) {
+  uint64_t seed = QuicRandom::GetInstance()->RandUint64();
+  QUIC_LOG(INFO) << "Seeding packet loss with " << seed;
+  simple_random_.set_seed(seed);
+}
+
+PacketDroppingTestWriter::~PacketDroppingTestWriter() = default;
+
+void PacketDroppingTestWriter::Initialize(
+    QuicConnectionHelperInterface* helper,
+    QuicAlarmFactory* alarm_factory,
+    std::unique_ptr<Delegate> on_can_write) {
+  clock_ = helper->GetClock();
+  write_unblocked_alarm_.reset(
+      alarm_factory->CreateAlarm(new WriteUnblockedAlarm(this)));
+  delay_alarm_.reset(alarm_factory->CreateAlarm(new DelayAlarm(this)));
+  on_can_write_ = std::move(on_can_write);
+}
+
+WriteResult PacketDroppingTestWriter::WritePacket(
+    const char* buffer,
+    size_t buf_len,
+    const QuicIpAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    PerPacketOptions* options) {
+  ++num_calls_to_write_;
+  ReleaseOldPackets();
+
+  QuicWriterMutexLock lock(&config_mutex_);
+  if (fake_drop_first_n_packets_ > 0 &&
+      num_calls_to_write_ <=
+          static_cast<uint64_t>(fake_drop_first_n_packets_)) {
+    QUIC_DVLOG(1) << "Dropping first " << fake_drop_first_n_packets_
+                  << " packets (packet number " << num_calls_to_write_ << ")";
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
+  const int32_t kMaxPacketLossPercentage =
+      kMaxConsecutivePacketLoss * 100.0 / (kMaxConsecutivePacketLoss + 1);
+  if (fake_packet_loss_percentage_ > 0 &&
+      // Do not allow too many consecutive packet drops to avoid test flakiness.
+      (num_consecutive_packet_lost_ <= kMaxConsecutivePacketLoss ||
+       // Allow as many consecutive packet drops as possbile if
+       // |fake_packet_lost_percentage_| is large enough. Without this exception
+       // it is hard to simulate high loss rate, like 100%.
+       fake_packet_loss_percentage_ > kMaxPacketLossPercentage) &&
+      (simple_random_.RandUint64() % 100 <
+       static_cast<uint64_t>(fake_packet_loss_percentage_))) {
+    QUIC_DVLOG(1) << "Dropping packet.";
+    ++num_consecutive_packet_lost_;
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  } else {
+    num_consecutive_packet_lost_ = 0;
+  }
+  if (fake_blocked_socket_percentage_ > 0 &&
+      simple_random_.RandUint64() % 100 <
+          static_cast<uint64_t>(fake_blocked_socket_percentage_)) {
+    CHECK(on_can_write_ != nullptr);
+    QUIC_DVLOG(1) << "Blocking socket.";
+    if (!write_unblocked_alarm_->IsSet()) {
+      // Set the alarm to fire immediately.
+      write_unblocked_alarm_->Set(clock_->ApproximateNow());
+    }
+    return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
+  }
+
+  if (!fake_packet_delay_.IsZero() || !fake_bandwidth_.IsZero()) {
+    if (buffer_size_ > 0 && buf_len + cur_buffer_size_ > buffer_size_) {
+      // Drop packets which do not fit into the buffer.
+      QUIC_DVLOG(1) << "Dropping packet because the buffer is full.";
+      return WriteResult(WRITE_STATUS_OK, buf_len);
+    }
+
+    // Queue it to be sent.
+    QuicTime send_time = clock_->ApproximateNow() + fake_packet_delay_;
+    if (!fake_bandwidth_.IsZero()) {
+      // Calculate a time the bandwidth limit would impose.
+      QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
+          (buf_len * kNumMicrosPerSecond) / fake_bandwidth_.ToBytesPerSecond());
+      send_time = delayed_packets_.empty()
+                      ? send_time + bandwidth_delay
+                      : delayed_packets_.back().send_time + bandwidth_delay;
+    }
+    std::unique_ptr<PerPacketOptions> delayed_options;
+    if (options != nullptr) {
+      delayed_options = options->Clone();
+    }
+    delayed_packets_.push_back(
+        DelayedWrite(buffer, buf_len, self_address, peer_address,
+                     std::move(delayed_options), send_time));
+    cur_buffer_size_ += buf_len;
+
+    // Set the alarm if it's not yet set.
+    if (!delay_alarm_->IsSet()) {
+      delay_alarm_->Set(send_time);
+    }
+
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
+
+  return QuicPacketWriterWrapper::WritePacket(buffer, buf_len, self_address,
+                                              peer_address, options);
+}
+
+bool PacketDroppingTestWriter::IsWriteBlocked() const {
+  if (write_unblocked_alarm_ != nullptr && write_unblocked_alarm_->IsSet()) {
+    return true;
+  }
+  return QuicPacketWriterWrapper::IsWriteBlocked();
+}
+
+void PacketDroppingTestWriter::SetWritable() {
+  if (write_unblocked_alarm_ != nullptr && write_unblocked_alarm_->IsSet()) {
+    write_unblocked_alarm_->Cancel();
+  }
+  QuicPacketWriterWrapper::SetWritable();
+}
+
+QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
+  if (delayed_packets_.empty()) {
+    return QuicTime::Zero();
+  }
+  QuicReaderMutexLock lock(&config_mutex_);
+  auto iter = delayed_packets_.begin();
+  // Determine if we should re-order.
+  if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
+      simple_random_.RandUint64() % 100 <
+          static_cast<uint64_t>(fake_packet_reorder_percentage_)) {
+    QUIC_DLOG(INFO) << "Reordering packets.";
+    ++iter;
+    // Swap the send times when re-ordering packets.
+    delayed_packets_.begin()->send_time = iter->send_time;
+  }
+
+  QUIC_DVLOG(1) << "Releasing packet.  " << (delayed_packets_.size() - 1)
+                << " remaining.";
+  // Grab the next one off the queue and send it.
+  QuicPacketWriterWrapper::WritePacket(
+      iter->buffer.data(), iter->buffer.length(), iter->self_address,
+      iter->peer_address, iter->options.get());
+  DCHECK_GE(cur_buffer_size_, iter->buffer.length());
+  cur_buffer_size_ -= iter->buffer.length();
+  delayed_packets_.erase(iter);
+
+  // If there are others, find the time for the next to be sent.
+  if (delayed_packets_.empty()) {
+    return QuicTime::Zero();
+  }
+  return delayed_packets_.begin()->send_time;
+}
+
+QuicTime PacketDroppingTestWriter::ReleaseOldPackets() {
+  while (!delayed_packets_.empty()) {
+    QuicTime next_send_time = delayed_packets_.front().send_time;
+    if (next_send_time > clock_->Now()) {
+      return next_send_time;
+    }
+    ReleaseNextPacket();
+  }
+  return QuicTime::Zero();
+}
+
+void PacketDroppingTestWriter::SetDelayAlarm(QuicTime new_deadline) {
+  delay_alarm_->Set(new_deadline);
+}
+
+void PacketDroppingTestWriter::OnCanWrite() {
+  on_can_write_->OnCanWrite();
+}
+
+void PacketDroppingTestWriter::set_fake_packet_loss_percentage(
+    int32_t fake_packet_loss_percentage) {
+  QuicWriterMutexLock lock(&config_mutex_);
+  fake_packet_loss_percentage_ = fake_packet_loss_percentage;
+  num_consecutive_packet_lost_ = 0;
+}
+
+PacketDroppingTestWriter::DelayedWrite::DelayedWrite(
+    const char* buffer,
+    size_t buf_len,
+    const QuicIpAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    std::unique_ptr<PerPacketOptions> options,
+    QuicTime send_time)
+    : buffer(buffer, buf_len),
+      self_address(self_address),
+      peer_address(peer_address),
+      options(std::move(options)),
+      send_time(send_time) {}
+
+PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() = default;
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/packet_dropping_test_writer.h b/quic/test_tools/packet_dropping_test_writer.h
new file mode 100644
index 0000000..9537944
--- /dev/null
+++ b/quic/test_tools/packet_dropping_test_writer.h
@@ -0,0 +1,177 @@
+// Copyright 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
+#define QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
+
+#include <cstdint>
+#include <list>
+#include <memory>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+
+// Simulates a connection that drops packets a configured percentage of the time
+// and has a blocked socket a configured percentage of the time.  Also provides
+// the options to delay packets and reorder packets if delay is enabled.
+class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+    virtual void OnCanWrite() = 0;
+  };
+
+  PacketDroppingTestWriter();
+  PacketDroppingTestWriter(const PacketDroppingTestWriter&) = delete;
+  PacketDroppingTestWriter& operator=(const PacketDroppingTestWriter&) = delete;
+
+  ~PacketDroppingTestWriter() override;
+
+  // Must be called before blocking, reordering or delaying (loss is OK). May be
+  // called after connecting if the helper is not available before.
+  // |on_can_write| will be triggered when fake-unblocking.
+  void Initialize(QuicConnectionHelperInterface* helper,
+                  QuicAlarmFactory* alarm_factory,
+                  std::unique_ptr<Delegate> on_can_write);
+
+  // QuicPacketWriter methods:
+  WriteResult WritePacket(const char* buffer,
+                          size_t buf_len,
+                          const QuicIpAddress& self_address,
+                          const QuicSocketAddress& peer_address,
+                          PerPacketOptions* options) override;
+
+  bool IsWriteBlocked() const override;
+
+  void SetWritable() override;
+
+  char* GetNextWriteLocation(const QuicIpAddress& self_address,
+                             const QuicSocketAddress& peer_address) override {
+    // If the wrapped writer supports zero-copy, disable it, because it is not
+    // compatible with delayed writes in this class.
+    return nullptr;
+  }
+
+  // Writes out any packet which should have been sent by now
+  // to the contained writer and returns the time
+  // for the next delayed packet to be written.
+  QuicTime ReleaseOldPackets();
+
+  // Sets |delay_alarm_| to fire at |new_deadline|.
+  void SetDelayAlarm(QuicTime new_deadline);
+
+  void OnCanWrite();
+
+  // The percent of time a packet is simulated as being lost.
+  void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage);
+
+  // Simulate dropping the first n packets unconditionally.
+  // Subsequent packets will be lost at fake_packet_loss_percentage_ if set.
+  void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) {
+    QuicWriterMutexLock lock(&config_mutex_);
+    fake_drop_first_n_packets_ = fake_drop_first_n_packets;
+  }
+
+  // The percent of time WritePacket will block and set WriteResult's status
+  // to WRITE_STATUS_BLOCKED.
+  void set_fake_blocked_socket_percentage(
+      int32_t fake_blocked_socket_percentage) {
+    DCHECK(clock_);
+    QuicWriterMutexLock lock(&config_mutex_);
+    fake_blocked_socket_percentage_ = fake_blocked_socket_percentage;
+  }
+
+  // The percent of time a packet is simulated as being reordered.
+  void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) {
+    DCHECK(clock_);
+    QuicWriterMutexLock lock(&config_mutex_);
+    DCHECK(!fake_packet_delay_.IsZero());
+    fake_packet_reorder_percentage_ = fake_packet_reorder_percentage;
+  }
+
+  // The delay before writing this packet.
+  void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) {
+    DCHECK(clock_);
+    QuicWriterMutexLock lock(&config_mutex_);
+    fake_packet_delay_ = fake_packet_delay;
+  }
+
+  // The maximum bandwidth and buffer size of the connection.  When these are
+  // set, packets will be delayed until a connection with that bandwidth would
+  // transmit it.  Once the |buffer_size| is reached, all new packets are
+  // dropped.
+  void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,
+                                         QuicByteCount buffer_size) {
+    DCHECK(clock_);
+    QuicWriterMutexLock lock(&config_mutex_);
+    fake_bandwidth_ = fake_bandwidth;
+    buffer_size_ = buffer_size;
+  }
+
+  // Useful for reproducing very flaky issues.
+  QUIC_UNUSED void set_seed(uint64_t seed) { simple_random_.set_seed(seed); }
+
+ private:
+  // Writes out the next packet to the contained writer and returns the time
+  // for the next delayed packet to be written.
+  QuicTime ReleaseNextPacket();
+
+  // A single packet which will be sent at the supplied send_time.
+  struct DelayedWrite {
+   public:
+    DelayedWrite(const char* buffer,
+                 size_t buf_len,
+                 const QuicIpAddress& self_address,
+                 const QuicSocketAddress& peer_address,
+                 std::unique_ptr<PerPacketOptions> options,
+                 QuicTime send_time);
+    DelayedWrite(const DelayedWrite&) = delete;
+    DelayedWrite(DelayedWrite&&) = default;
+    DelayedWrite& operator=(const DelayedWrite&) = delete;
+    DelayedWrite& operator=(DelayedWrite&&) = default;
+    ~DelayedWrite();
+
+    QuicString buffer;
+    QuicIpAddress self_address;
+    QuicSocketAddress peer_address;
+    std::unique_ptr<PerPacketOptions> options;
+    QuicTime send_time;
+  };
+
+  typedef std::list<DelayedWrite> DelayedPacketList;
+
+  const QuicClock* clock_;
+  std::unique_ptr<QuicAlarm> write_unblocked_alarm_;
+  std::unique_ptr<QuicAlarm> delay_alarm_;
+  std::unique_ptr<Delegate> on_can_write_;
+  SimpleRandom simple_random_;
+  // Stored packets delayed by fake packet delay or bandwidth restrictions.
+  DelayedPacketList delayed_packets_;
+  QuicByteCount cur_buffer_size_;
+  uint64_t num_calls_to_write_;
+
+  QuicMutex config_mutex_;
+  int32_t fake_packet_loss_percentage_ GUARDED_BY(config_mutex_);
+  int32_t fake_drop_first_n_packets_ GUARDED_BY(config_mutex_);
+  int32_t fake_blocked_socket_percentage_ GUARDED_BY(config_mutex_);
+  int32_t fake_packet_reorder_percentage_ GUARDED_BY(config_mutex_);
+  QuicTime::Delta fake_packet_delay_ GUARDED_BY(config_mutex_);
+  QuicBandwidth fake_bandwidth_ GUARDED_BY(config_mutex_);
+  QuicByteCount buffer_size_ GUARDED_BY(config_mutex_);
+  int32_t num_consecutive_packet_lost_ GUARDED_BY(config_mutex_);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_PACKET_DROPPING_TEST_WRITER_H_
diff --git a/quic/test_tools/packet_reordering_writer.cc b/quic/test_tools/packet_reordering_writer.cc
new file mode 100644
index 0000000..a8385d8
--- /dev/null
+++ b/quic/test_tools/packet_reordering_writer.cc
@@ -0,0 +1,53 @@
+// Copyright 2013 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/packet_reordering_writer.h"
+
+namespace quic {
+namespace test {
+
+PacketReorderingWriter::PacketReorderingWriter() = default;
+
+PacketReorderingWriter::~PacketReorderingWriter() = default;
+
+WriteResult PacketReorderingWriter::WritePacket(
+    const char* buffer,
+    size_t buf_len,
+    const QuicIpAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    PerPacketOptions* options) {
+  if (!delay_next_) {
+    VLOG(2) << "Writing a non-delayed packet";
+    WriteResult wr = QuicPacketWriterWrapper::WritePacket(
+        buffer, buf_len, self_address, peer_address, options);
+    --num_packets_to_wait_;
+    if (num_packets_to_wait_ == 0) {
+      VLOG(2) << "Writing a delayed packet";
+      // It's time to write the delayed packet.
+      QuicPacketWriterWrapper::WritePacket(
+          delayed_data_.data(), delayed_data_.length(), delayed_self_address_,
+          delayed_peer_address_, delayed_options_.get());
+    }
+    return wr;
+  }
+  // Still have packet to wait.
+  DCHECK_LT(0u, num_packets_to_wait_) << "Only allow one packet to be delayed";
+  delayed_data_ = QuicString(buffer, buf_len);
+  delayed_self_address_ = self_address;
+  delayed_peer_address_ = peer_address;
+  if (options != nullptr) {
+    delayed_options_ = options->Clone();
+  }
+  delay_next_ = false;
+  return WriteResult(WRITE_STATUS_OK, buf_len);
+}
+
+void PacketReorderingWriter::SetDelay(size_t num_packets_to_wait) {
+  DCHECK_GT(num_packets_to_wait, 0u);
+  num_packets_to_wait_ = num_packets_to_wait;
+  delay_next_ = true;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/packet_reordering_writer.h b/quic/test_tools/packet_reordering_writer.h
new file mode 100644
index 0000000..ec49269
--- /dev/null
+++ b/quic/test_tools/packet_reordering_writer.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
+#define QUICHE_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+
+namespace quic {
+
+namespace test {
+
+// This packet writer allows delaying writing the next packet after
+// SetDelay(num_packets_to_wait)
+// is called and buffer this packet and write it after it writes next
+// |num_packets_to_wait| packets. It doesn't support delaying a packet while
+// there is already a packet delayed.
+class PacketReorderingWriter : public QuicPacketWriterWrapper {
+ public:
+  PacketReorderingWriter();
+
+  ~PacketReorderingWriter() override;
+
+  WriteResult WritePacket(const char* buffer,
+                          size_t buf_len,
+                          const QuicIpAddress& self_address,
+                          const QuicSocketAddress& peer_address,
+                          PerPacketOptions* options) override;
+
+  void SetDelay(size_t num_packets_to_wait);
+
+ private:
+  bool delay_next_ = false;
+  size_t num_packets_to_wait_ = 0;
+  QuicString delayed_data_;
+  QuicIpAddress delayed_self_address_;
+  QuicSocketAddress delayed_peer_address_;
+  std::unique_ptr<PerPacketOptions> delayed_options_;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
diff --git a/quic/test_tools/quic_buffered_packet_store_peer.cc b/quic/test_tools/quic_buffered_packet_store_peer.cc
new file mode 100644
index 0000000..73b9e98
--- /dev/null
+++ b/quic/test_tools/quic_buffered_packet_store_peer.cc
@@ -0,0 +1,25 @@
+// Copyright 2016 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_buffered_packet_store_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_buffered_packet_store.h"
+
+namespace quic {
+namespace test {
+
+// static
+QuicAlarm* QuicBufferedPacketStorePeer::expiration_alarm(
+    QuicBufferedPacketStore* store) {
+  return store->expiration_alarm_.get();
+}
+
+// static
+void QuicBufferedPacketStorePeer::set_clock(QuicBufferedPacketStore* store,
+                                            const QuicClock* clock) {
+  store->clock_ = clock;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_buffered_packet_store_peer.h b/quic/test_tools/quic_buffered_packet_store_peer.h
new file mode 100644
index 0000000..e857dfb
--- /dev/null
+++ b/quic/test_tools/quic_buffered_packet_store_peer.h
@@ -0,0 +1,32 @@
+// Copyright 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_BUFFERED_PACKET_STORE_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_BUFFERED_PACKET_STORE_PEER_H_
+
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+
+namespace quic {
+
+class QuicBufferedPacketStore;
+
+namespace test {
+
+class QuicBufferedPacketStorePeer {
+ public:
+  QuicBufferedPacketStorePeer() = delete;
+
+  static QuicAlarm* expiration_alarm(QuicBufferedPacketStore* store);
+
+  static void set_clock(QuicBufferedPacketStore* store, const QuicClock* clock);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_BUFFERED_PACKET_STORE_PEER_H_
diff --git a/quic/test_tools/quic_client_peer.cc b/quic/test_tools/quic_client_peer.cc
new file mode 100644
index 0000000..c8bfa6a
--- /dev/null
+++ b/quic/test_tools/quic_client_peer.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2013 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_client_peer.h"
+
+#include "net/third_party/quiche/src/quic/tools/quic_client.h"
+
+namespace quic {
+namespace test {
+
+// static
+bool QuicClientPeer::CreateUDPSocketAndBind(QuicClient* client) {
+  return client->network_helper()->CreateUDPSocketAndBind(
+      client->server_address(), client->bind_to_address(),
+      client->local_port());
+}
+
+// static
+void QuicClientPeer::CleanUpUDPSocket(QuicClient* client, int fd) {
+  client->epoll_network_helper()->CleanUpUDPSocket(fd);
+}
+
+// static
+void QuicClientPeer::SetClientPort(QuicClient* client, int port) {
+  client->epoll_network_helper()->SetClientPort(port);
+}
+
+// static
+void QuicClientPeer::SetWriter(QuicClient* client, QuicPacketWriter* writer) {
+  client->set_writer(writer);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_client_peer.h b/quic/test_tools/quic_client_peer.h
new file mode 100644
index 0000000..66987e4
--- /dev/null
+++ b/quic/test_tools/quic_client_peer.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
+
+#include "base/macros.h"
+
+namespace quic {
+
+class QuicClient;
+class QuicPacketWriter;
+
+namespace test {
+
+class QuicClientPeer {
+ public:
+  QuicClientPeer() = delete;
+
+  static bool CreateUDPSocketAndBind(QuicClient* client);
+  static void CleanUpUDPSocket(QuicClient* client, int fd);
+  static void SetClientPort(QuicClient* client, int port);
+  static void SetWriter(QuicClient* client, QuicPacketWriter* writer);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
diff --git a/quic/test_tools/quic_client_promised_info_peer.cc b/quic/test_tools/quic_client_promised_info_peer.cc
new file mode 100644
index 0000000..91fec1d
--- /dev/null
+++ b/quic/test_tools/quic_client_promised_info_peer.cc
@@ -0,0 +1,17 @@
+// Copyright 2016 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_client_promised_info_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+QuicAlarm* QuicClientPromisedInfoPeer::GetAlarm(
+    QuicClientPromisedInfo* promised_stream) {
+  return promised_stream->cleanup_alarm_.get();
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_client_promised_info_peer.h b/quic/test_tools/quic_client_promised_info_peer.h
new file mode 100644
index 0000000..9b743f3
--- /dev/null
+++ b/quic/test_tools/quic_client_promised_info_peer.h
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_CLIENT_PROMISED_INFO_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_CLIENT_PROMISED_INFO_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h"
+
+namespace quic {
+namespace test {
+
+class QuicClientPromisedInfoPeer {
+ public:
+  QuicClientPromisedInfoPeer() = delete;
+
+  static QuicAlarm* GetAlarm(QuicClientPromisedInfo* promised_stream);
+};
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_CLIENT_PROMISED_INFO_PEER_H_
diff --git a/quic/test_tools/quic_config_peer.cc b/quic/test_tools/quic_config_peer.cc
new file mode 100644
index 0000000..f5a5b31
--- /dev/null
+++ b/quic/test_tools/quic_config_peer.cc
@@ -0,0 +1,67 @@
+// Copyright 2014 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_config_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
+    QuicConfig* config,
+    uint32_t window_bytes) {
+  config->initial_stream_flow_control_window_bytes_.SetReceivedValue(
+      window_bytes);
+}
+
+// static
+void QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
+    QuicConfig* config,
+    uint32_t window_bytes) {
+  config->initial_session_flow_control_window_bytes_.SetReceivedValue(
+      window_bytes);
+}
+
+// static
+void QuicConfigPeer::SetReceivedConnectionOptions(
+    QuicConfig* config,
+    const QuicTagVector& options) {
+  config->connection_options_.SetReceivedValues(options);
+}
+
+// static
+void QuicConfigPeer::SetReceivedBytesForConnectionId(QuicConfig* config,
+                                                     uint32_t bytes) {
+  DCHECK(bytes == 0 || bytes == 8);
+  config->bytes_for_connection_id_.SetReceivedValue(bytes);
+}
+
+// static
+void QuicConfigPeer::SetReceivedDisableConnectionMigration(QuicConfig* config) {
+  config->connection_migration_disabled_.SetReceivedValue(1);
+}
+
+// static
+void QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(
+    QuicConfig* config,
+    uint32_t max_streams) {
+  config->max_incoming_dynamic_streams_.SetReceivedValue(max_streams);
+}
+
+// static
+void QuicConfigPeer::SetConnectionOptionsToSend(QuicConfig* config,
+                                                const QuicTagVector& options) {
+  config->SetConnectionOptionsToSend(options);
+}
+
+// static
+void QuicConfigPeer::SetReceivedStatelessResetToken(QuicConfig* config,
+                                                    QuicUint128 token) {
+  config->stateless_reset_token_.SetReceivedValue(token);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_config_peer.h b/quic/test_tools/quic_config_peer.h
new file mode 100644
index 0000000..6e2653b
--- /dev/null
+++ b/quic/test_tools/quic_config_peer.h
@@ -0,0 +1,51 @@
+// Copyright 2014 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_CONFIG_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_CONFIG_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h"
+
+namespace quic {
+
+class QuicConfig;
+
+namespace test {
+
+class QuicConfigPeer {
+ public:
+  QuicConfigPeer() = delete;
+
+  static void SetReceivedInitialStreamFlowControlWindow(QuicConfig* config,
+                                                        uint32_t window_bytes);
+
+  static void SetReceivedInitialSessionFlowControlWindow(QuicConfig* config,
+                                                         uint32_t window_bytes);
+
+  static void SetReceivedConnectionOptions(QuicConfig* config,
+                                           const QuicTagVector& options);
+
+  static void SetReceivedBytesForConnectionId(QuicConfig* config,
+                                              uint32_t bytes);
+
+  static void SetReceivedDisableConnectionMigration(QuicConfig* config);
+
+  static void SetReceivedMaxIncomingDynamicStreams(QuicConfig* config,
+                                                   uint32_t max_streams);
+
+  static void SetConnectionOptionsToSend(QuicConfig* config,
+                                         const QuicTagVector& options);
+
+  static void SetReceivedStatelessResetToken(QuicConfig* config,
+                                             QuicUint128 token);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_CONFIG_PEER_H_
diff --git a/quic/test_tools/quic_connection_peer.cc b/quic/test_tools/quic_connection_peer.cc
new file mode 100644
index 0000000..100fe15
--- /dev/null
+++ b/quic/test_tools/quic_connection_peer.cc
@@ -0,0 +1,355 @@
+// 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_connection_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_packet_generator_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicConnectionPeer::SendAck(QuicConnection* connection) {
+  connection->SendAck();
+}
+
+// static
+void QuicConnectionPeer::SetSendAlgorithm(
+    QuicConnection* connection,
+    SendAlgorithmInterface* send_algorithm) {
+  GetSentPacketManager(connection)->SetSendAlgorithm(send_algorithm);
+}
+
+// static
+void QuicConnectionPeer::SetLossAlgorithm(
+    QuicConnection* connection,
+    LossDetectionInterface* loss_algorithm) {
+  GetSentPacketManager(connection)->loss_algorithm_ = loss_algorithm;
+}
+
+// static
+const QuicFrame QuicConnectionPeer::GetUpdatedAckFrame(
+    QuicConnection* connection) {
+  const bool ack_frame_updated = connection->ack_frame_updated();
+  const QuicFrame ack_frame = connection->GetUpdatedAckFrame();
+  connection->received_packet_manager_.ack_frame_updated_ = ack_frame_updated;
+  return ack_frame;
+}
+
+// static
+void QuicConnectionPeer::PopulateStopWaitingFrame(
+    QuicConnection* connection,
+    QuicStopWaitingFrame* stop_waiting) {
+  connection->PopulateStopWaitingFrame(stop_waiting);
+}
+
+// static
+QuicConnectionVisitorInterface* QuicConnectionPeer::GetVisitor(
+    QuicConnection* connection) {
+  return connection->visitor_;
+}
+
+// static
+QuicPacketCreator* QuicConnectionPeer::GetPacketCreator(
+    QuicConnection* connection) {
+  return QuicPacketGeneratorPeer::GetPacketCreator(
+      &connection->packet_generator_);
+}
+
+// static
+QuicPacketGenerator* QuicConnectionPeer::GetPacketGenerator(
+    QuicConnection* connection) {
+  return &connection->packet_generator_;
+}
+
+// static
+QuicSentPacketManager* QuicConnectionPeer::GetSentPacketManager(
+    QuicConnection* connection) {
+  return &connection->sent_packet_manager_;
+}
+
+// static
+QuicTime::Delta QuicConnectionPeer::GetNetworkTimeout(
+    QuicConnection* connection) {
+  return connection->idle_network_timeout_;
+}
+
+// static
+void QuicConnectionPeer::SetPerspective(QuicConnection* connection,
+                                        Perspective perspective) {
+  connection->perspective_ = perspective;
+  QuicFramerPeer::SetPerspective(&connection->framer_, perspective);
+}
+
+// static
+void QuicConnectionPeer::SetSelfAddress(QuicConnection* connection,
+                                        const QuicSocketAddress& self_address) {
+  connection->self_address_ = self_address;
+}
+
+// static
+void QuicConnectionPeer::SetPeerAddress(QuicConnection* connection,
+                                        const QuicSocketAddress& peer_address) {
+  connection->peer_address_ = peer_address;
+}
+
+// static
+void QuicConnectionPeer::SetDirectPeerAddress(
+    QuicConnection* connection,
+    const QuicSocketAddress& direct_peer_address) {
+  connection->direct_peer_address_ = direct_peer_address;
+}
+
+// static
+void QuicConnectionPeer::SetEffectivePeerAddress(
+    QuicConnection* connection,
+    const QuicSocketAddress& effective_peer_address) {
+  connection->effective_peer_address_ = effective_peer_address;
+}
+
+// static
+bool QuicConnectionPeer::IsSilentCloseEnabled(QuicConnection* connection) {
+  return connection->idle_timeout_connection_close_behavior_ ==
+         ConnectionCloseBehavior::SILENT_CLOSE;
+}
+
+// static
+void QuicConnectionPeer::SwapCrypters(QuicConnection* connection,
+                                      QuicFramer* framer) {
+  QuicFramerPeer::SwapCrypters(framer, &connection->framer_);
+}
+
+// static
+void QuicConnectionPeer::SetCurrentPacket(QuicConnection* connection,
+                                          QuicStringPiece current_packet) {
+  connection->current_packet_data_ = current_packet.data();
+  connection->last_size_ = current_packet.size();
+}
+
+// static
+QuicConnectionHelperInterface* QuicConnectionPeer::GetHelper(
+    QuicConnection* connection) {
+  return connection->helper_;
+}
+
+// static
+QuicAlarmFactory* QuicConnectionPeer::GetAlarmFactory(
+    QuicConnection* connection) {
+  return connection->alarm_factory_;
+}
+
+// static
+QuicFramer* QuicConnectionPeer::GetFramer(QuicConnection* connection) {
+  return &connection->framer_;
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetAckAlarm(QuicConnection* connection) {
+  return connection->ack_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetPingAlarm(QuicConnection* connection) {
+  return connection->ping_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetRetransmissionAlarm(
+    QuicConnection* connection) {
+  return connection->retransmission_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetSendAlarm(QuicConnection* connection) {
+  return connection->send_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetTimeoutAlarm(QuicConnection* connection) {
+  return connection->timeout_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetMtuDiscoveryAlarm(
+    QuicConnection* connection) {
+  return connection->mtu_discovery_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetPathDegradingAlarm(
+    QuicConnection* connection) {
+  return connection->path_degrading_alarm_.get();
+}
+
+// static
+QuicAlarm* QuicConnectionPeer::GetProcessUndecryptablePacketsAlarm(
+    QuicConnection* connection) {
+  return connection->process_undecryptable_packets_alarm_.get();
+}
+
+// static
+QuicPacketWriter* QuicConnectionPeer::GetWriter(QuicConnection* connection) {
+  return connection->writer_;
+}
+
+// static
+void QuicConnectionPeer::SetWriter(QuicConnection* connection,
+                                   QuicPacketWriter* writer,
+                                   bool owns_writer) {
+  if (connection->owns_writer_) {
+    delete connection->writer_;
+  }
+  connection->writer_ = writer;
+  connection->owns_writer_ = owns_writer;
+}
+
+// static
+void QuicConnectionPeer::TearDownLocalConnectionState(
+    QuicConnection* connection) {
+  connection->connected_ = false;
+}
+
+// static
+QuicEncryptedPacket* QuicConnectionPeer::GetConnectionClosePacket(
+    QuicConnection* connection) {
+  if (connection->termination_packets_ == nullptr ||
+      connection->termination_packets_->empty()) {
+    return nullptr;
+  }
+  return (*connection->termination_packets_)[0].get();
+}
+
+// static
+QuicPacketHeader* QuicConnectionPeer::GetLastHeader(
+    QuicConnection* connection) {
+  return &connection->last_header_;
+}
+
+// static
+QuicConnectionStats* QuicConnectionPeer::GetStats(QuicConnection* connection) {
+  return &connection->stats_;
+}
+
+// static
+QuicPacketCount QuicConnectionPeer::GetPacketsBetweenMtuProbes(
+    QuicConnection* connection) {
+  return connection->packets_between_mtu_probes_;
+}
+
+// static
+void QuicConnectionPeer::SetPacketsBetweenMtuProbes(QuicConnection* connection,
+                                                    QuicPacketCount packets) {
+  connection->packets_between_mtu_probes_ = packets;
+}
+
+// static
+void QuicConnectionPeer::SetNextMtuProbeAt(QuicConnection* connection,
+                                           QuicPacketNumber number) {
+  connection->next_mtu_probe_at_ = number;
+}
+
+// static
+void QuicConnectionPeer::SetAckMode(QuicConnection* connection,
+                                    AckMode ack_mode) {
+  if (connection->received_packet_manager_.decide_when_to_send_acks()) {
+    connection->received_packet_manager_.ack_mode_ = ack_mode;
+  } else {
+    connection->ack_mode_ = ack_mode;
+  }
+}
+
+// static
+void QuicConnectionPeer::SetFastAckAfterQuiescence(
+    QuicConnection* connection,
+    bool fast_ack_after_quiescence) {
+  if (connection->received_packet_manager_.decide_when_to_send_acks()) {
+    connection->received_packet_manager_.fast_ack_after_quiescence_ =
+        fast_ack_after_quiescence;
+  } else {
+    connection->fast_ack_after_quiescence_ = fast_ack_after_quiescence;
+  }
+}
+
+// static
+void QuicConnectionPeer::SetAckDecimationDelay(QuicConnection* connection,
+                                               float ack_decimation_delay) {
+  if (connection->received_packet_manager_.decide_when_to_send_acks()) {
+    connection->received_packet_manager_.ack_decimation_delay_ =
+        ack_decimation_delay;
+  } else {
+    connection->ack_decimation_delay_ = ack_decimation_delay;
+  }
+}
+
+// static
+bool QuicConnectionPeer::HasRetransmittableFrames(QuicConnection* connection,
+                                                  uint64_t packet_number) {
+  return QuicSentPacketManagerPeer::HasRetransmittableFrames(
+      GetSentPacketManager(connection), packet_number);
+}
+
+// static
+bool QuicConnectionPeer::GetNoStopWaitingFrames(QuicConnection* connection) {
+  return connection->no_stop_waiting_frames_;
+}
+
+// static
+void QuicConnectionPeer::SetNoStopWaitingFrames(QuicConnection* connection,
+                                                bool no_stop_waiting_frames) {
+  connection->no_stop_waiting_frames_ = no_stop_waiting_frames;
+}
+
+// static
+void QuicConnectionPeer::SetMaxTrackedPackets(
+    QuicConnection* connection,
+    QuicPacketCount max_tracked_packets) {
+  connection->max_tracked_packets_ = max_tracked_packets;
+}
+
+// static
+void QuicConnectionPeer::SetSessionDecidesWhatToWrite(
+    QuicConnection* connection) {
+  connection->sent_packet_manager_.SetSessionDecideWhatToWrite(true);
+  connection->packet_generator_.SetCanSetTransmissionType(true);
+}
+
+// static
+void QuicConnectionPeer::SetNegotiatedVersion(QuicConnection* connection) {
+  connection->version_negotiation_state_ = QuicConnection::NEGOTIATED_VERSION;
+}
+
+// static
+void QuicConnectionPeer::SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames(
+    QuicConnection* connection,
+    size_t new_value) {
+  connection->max_consecutive_num_packets_with_no_retransmittable_frames_ =
+      new_value;
+}
+
+// static
+void QuicConnectionPeer::SetNoVersionNegotiation(QuicConnection* connection,
+                                                 bool no_version_negotiation) {
+  *const_cast<bool*>(&connection->no_version_negotiation_) =
+      no_version_negotiation;
+}
+
+// static
+bool QuicConnectionPeer::SupportsReleaseTime(QuicConnection* connection) {
+  return connection->supports_release_time_;
+}
+
+// static
+QuicConnection::PacketContent QuicConnectionPeer::GetCurrentPacketContent(
+    QuicConnection* connection) {
+  return connection->current_packet_content_;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_connection_peer.h b/quic/test_tools/quic_connection_peer.h
new file mode 100644
index 0000000..b82c1b3
--- /dev/null
+++ b/quic/test_tools/quic_connection_peer.h
@@ -0,0 +1,147 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_CONNECTION_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_CONNECTION_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+struct QuicPacketHeader;
+class QuicAlarm;
+class QuicConnectionHelperInterface;
+class QuicConnectionVisitorInterface;
+class QuicEncryptedPacket;
+class QuicFramer;
+class QuicPacketCreator;
+class QuicPacketGenerator;
+class QuicPacketWriter;
+class QuicSentPacketManager;
+class SendAlgorithmInterface;
+
+namespace test {
+
+// Peer to make public a number of otherwise private QuicConnection methods.
+class QuicConnectionPeer {
+ public:
+  QuicConnectionPeer() = delete;
+
+  static void SendAck(QuicConnection* connection);
+
+  static void SetSendAlgorithm(QuicConnection* connection,
+                               SendAlgorithmInterface* send_algorithm);
+
+  static void SetLossAlgorithm(QuicConnection* connection,
+                               LossDetectionInterface* loss_algorithm);
+
+  static const QuicFrame GetUpdatedAckFrame(QuicConnection* connection);
+
+  static void PopulateStopWaitingFrame(QuicConnection* connection,
+                                       QuicStopWaitingFrame* stop_waiting);
+
+  static QuicConnectionVisitorInterface* GetVisitor(QuicConnection* connection);
+
+  static QuicPacketCreator* GetPacketCreator(QuicConnection* connection);
+
+  static QuicPacketGenerator* GetPacketGenerator(QuicConnection* connection);
+
+  static QuicSentPacketManager* GetSentPacketManager(
+      QuicConnection* connection);
+
+  static QuicTime::Delta GetNetworkTimeout(QuicConnection* connection);
+
+  static void SetPerspective(QuicConnection* connection,
+                             Perspective perspective);
+
+  static void SetSelfAddress(QuicConnection* connection,
+                             const QuicSocketAddress& self_address);
+
+  static void SetPeerAddress(QuicConnection* connection,
+                             const QuicSocketAddress& peer_address);
+
+  static void SetDirectPeerAddress(
+      QuicConnection* connection,
+      const QuicSocketAddress& direct_peer_address);
+
+  static void SetEffectivePeerAddress(
+      QuicConnection* connection,
+      const QuicSocketAddress& effective_peer_address);
+
+  static bool IsSilentCloseEnabled(QuicConnection* connection);
+
+  static void SwapCrypters(QuicConnection* connection, QuicFramer* framer);
+
+  static void SetCurrentPacket(QuicConnection* connection,
+                               QuicStringPiece current_packet);
+
+  static QuicConnectionHelperInterface* GetHelper(QuicConnection* connection);
+
+  static QuicAlarmFactory* GetAlarmFactory(QuicConnection* connection);
+
+  static QuicFramer* GetFramer(QuicConnection* connection);
+
+  static QuicAlarm* GetAckAlarm(QuicConnection* connection);
+  static QuicAlarm* GetPingAlarm(QuicConnection* connection);
+  static QuicAlarm* GetRetransmissionAlarm(QuicConnection* connection);
+  static QuicAlarm* GetSendAlarm(QuicConnection* connection);
+  static QuicAlarm* GetTimeoutAlarm(QuicConnection* connection);
+  static QuicAlarm* GetMtuDiscoveryAlarm(QuicConnection* connection);
+  static QuicAlarm* GetPathDegradingAlarm(QuicConnection* connection);
+  static QuicAlarm* GetProcessUndecryptablePacketsAlarm(
+      QuicConnection* connection);
+
+  static QuicPacketWriter* GetWriter(QuicConnection* connection);
+  // If |owns_writer| is true, takes ownership of |writer|.
+  static void SetWriter(QuicConnection* connection,
+                        QuicPacketWriter* writer,
+                        bool owns_writer);
+  static void TearDownLocalConnectionState(QuicConnection* connection);
+  static QuicEncryptedPacket* GetConnectionClosePacket(
+      QuicConnection* connection);
+
+  static QuicPacketHeader* GetLastHeader(QuicConnection* connection);
+
+  static QuicConnectionStats* GetStats(QuicConnection* connection);
+
+  static QuicPacketCount GetPacketsBetweenMtuProbes(QuicConnection* connection);
+
+  static void SetPacketsBetweenMtuProbes(QuicConnection* connection,
+                                         QuicPacketCount packets);
+  static void SetNextMtuProbeAt(QuicConnection* connection,
+                                QuicPacketNumber number);
+  static void SetAckMode(QuicConnection* connection, AckMode ack_mode);
+  static void SetFastAckAfterQuiescence(QuicConnection* connection,
+                                        bool fast_ack_after_quiescence);
+  static void SetAckDecimationDelay(QuicConnection* connection,
+                                    float ack_decimation_delay);
+  static bool HasRetransmittableFrames(QuicConnection* connection,
+                                       uint64_t packet_number);
+  static bool GetNoStopWaitingFrames(QuicConnection* connection);
+  static void SetNoStopWaitingFrames(QuicConnection* connection,
+                                     bool no_stop_waiting_frames);
+  static void SetMaxTrackedPackets(QuicConnection* connection,
+                                   QuicPacketCount max_tracked_packets);
+  static void SetSessionDecidesWhatToWrite(QuicConnection* connection);
+  static void SetNegotiatedVersion(QuicConnection* connection);
+  static void SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames(
+      QuicConnection* connection,
+      size_t new_value);
+  static void SetNoVersionNegotiation(QuicConnection* connection,
+                                      bool no_version_negotiation);
+  static bool SupportsReleaseTime(QuicConnection* connection);
+  static QuicConnection::PacketContent GetCurrentPacketContent(
+      QuicConnection* connection);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_CONNECTION_PEER_H_
diff --git a/quic/test_tools/quic_crypto_server_config_peer.cc b/quic/test_tools/quic_crypto_server_config_peer.cc
new file mode 100644
index 0000000..048e6bb
--- /dev/null
+++ b/quic/test_tools/quic_crypto_server_config_peer.cc
@@ -0,0 +1,162 @@
+// Copyright 2016 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_crypto_server_config_peer.h"
+
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+
+QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
+QuicCryptoServerConfigPeer::GetPrimaryConfig() {
+  QuicReaderMutexLock locked(&server_config_->configs_lock_);
+  return QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>(
+      server_config_->primary_config_);
+}
+
+QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
+QuicCryptoServerConfigPeer::GetConfig(QuicString config_id) {
+  QuicReaderMutexLock locked(&server_config_->configs_lock_);
+  if (config_id == "<primary>") {
+    return QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>(
+        server_config_->primary_config_);
+  } else {
+    return server_config_->GetConfigWithScid(config_id);
+  }
+}
+
+ProofSource* QuicCryptoServerConfigPeer::GetProofSource() const {
+  return server_config_->proof_source_.get();
+}
+
+void QuicCryptoServerConfigPeer::ResetProofSource(
+    std::unique_ptr<ProofSource> proof_source) {
+  server_config_->proof_source_ = std::move(proof_source);
+}
+
+QuicString QuicCryptoServerConfigPeer::NewSourceAddressToken(
+    QuicString config_id,
+    SourceAddressTokens previous_tokens,
+    const QuicIpAddress& ip,
+    QuicRandom* rand,
+    QuicWallTime now,
+    CachedNetworkParameters* cached_network_params) {
+  return server_config_->NewSourceAddressToken(*GetConfig(config_id),
+                                               previous_tokens, ip, rand, now,
+                                               cached_network_params);
+}
+
+HandshakeFailureReason QuicCryptoServerConfigPeer::ValidateSourceAddressTokens(
+    QuicString config_id,
+    QuicStringPiece srct,
+    const QuicIpAddress& ip,
+    QuicWallTime now,
+    CachedNetworkParameters* cached_network_params) {
+  SourceAddressTokens tokens;
+  HandshakeFailureReason reason = server_config_->ParseSourceAddressToken(
+      *GetConfig(config_id), srct, &tokens);
+  if (reason != HANDSHAKE_OK) {
+    return reason;
+  }
+
+  return server_config_->ValidateSourceAddressTokens(tokens, ip, now,
+                                                     cached_network_params);
+}
+
+HandshakeFailureReason
+QuicCryptoServerConfigPeer::ValidateSingleSourceAddressToken(
+    QuicStringPiece token,
+    const QuicIpAddress& ip,
+    QuicWallTime now) {
+  SourceAddressTokens tokens;
+  HandshakeFailureReason parse_status = server_config_->ParseSourceAddressToken(
+      *GetPrimaryConfig(), token, &tokens);
+  if (HANDSHAKE_OK != parse_status) {
+    return parse_status;
+  }
+  EXPECT_EQ(1, tokens.tokens_size());
+  return server_config_->ValidateSingleSourceAddressToken(tokens.tokens(0), ip,
+                                                          now);
+}
+
+void QuicCryptoServerConfigPeer::CheckConfigs(
+    std::vector<std::pair<QuicString, bool>> expected_ids_and_status) {
+  QuicReaderMutexLock locked(&server_config_->configs_lock_);
+
+  ASSERT_EQ(expected_ids_and_status.size(), server_config_->configs_.size())
+      << ConfigsDebug();
+
+  for (const std::pair<
+           const ServerConfigID,
+           QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>>& i :
+       server_config_->configs_) {
+    bool found = false;
+    for (std::pair<ServerConfigID, bool>& j : expected_ids_and_status) {
+      if (i.first == j.first && i.second->is_primary == j.second) {
+        found = true;
+        j.first.clear();
+        break;
+      }
+    }
+
+    ASSERT_TRUE(found) << "Failed to find match for " << i.first
+                       << " in configs:\n"
+                       << ConfigsDebug();
+  }
+}
+
+// ConfigsDebug returns a QuicString that contains debugging information about
+// the set of Configs loaded in |server_config_| and their status.
+QuicString QuicCryptoServerConfigPeer::ConfigsDebug() {
+  if (server_config_->configs_.empty()) {
+    return "No Configs in QuicCryptoServerConfig";
+  }
+
+  QuicString s;
+
+  for (const auto& i : server_config_->configs_) {
+    const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> config =
+        i.second;
+    if (config->is_primary) {
+      s += "(primary) ";
+    } else {
+      s += "          ";
+    }
+    s += config->id;
+    s += "\n";
+  }
+
+  return s;
+}
+
+void QuicCryptoServerConfigPeer::SelectNewPrimaryConfig(int seconds) {
+  QuicWriterMutexLock locked(&server_config_->configs_lock_);
+  server_config_->SelectNewPrimaryConfig(
+      QuicWallTime::FromUNIXSeconds(seconds));
+}
+
+QuicString QuicCryptoServerConfigPeer::CompressChain(
+    QuicCompressedCertsCache* compressed_certs_cache,
+    const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+    const QuicString& client_common_set_hashes,
+    const QuicString& client_cached_cert_hashes,
+    const CommonCertSets* common_sets) {
+  return QuicCryptoServerConfig::CompressChain(
+      compressed_certs_cache, chain, client_common_set_hashes,
+      client_cached_cert_hashes, common_sets);
+}
+
+uint32_t QuicCryptoServerConfigPeer::source_address_token_future_secs() {
+  return server_config_->source_address_token_future_secs_;
+}
+
+uint32_t QuicCryptoServerConfigPeer::source_address_token_lifetime_secs() {
+  return server_config_->source_address_token_lifetime_secs_;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_crypto_server_config_peer.h b/quic/test_tools/quic_crypto_server_config_peer.h
new file mode 100644
index 0000000..0034c4b
--- /dev/null
+++ b/quic/test_tools/quic_crypto_server_config_peer.h
@@ -0,0 +1,98 @@
+// Copyright 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_CRYPTO_SERVER_CONFIG_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_CRYPTO_SERVER_CONFIG_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+namespace test {
+
+// Peer for accessing otherwise private members of a QuicCryptoServerConfig.
+class QuicCryptoServerConfigPeer {
+ public:
+  explicit QuicCryptoServerConfigPeer(QuicCryptoServerConfig* server_config)
+      : server_config_(server_config) {}
+
+  // Returns the primary config.
+  QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>
+  GetPrimaryConfig();
+
+  // Returns the config associated with |config_id|.
+  QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> GetConfig(
+      QuicString config_id);
+
+  // Returns a pointer to the ProofSource object.
+  ProofSource* GetProofSource() const;
+
+  // Reset the proof_source_ member.
+  void ResetProofSource(std::unique_ptr<ProofSource> proof_source);
+
+  // Generates a new valid source address token.
+  QuicString NewSourceAddressToken(
+      QuicString config_id,
+      SourceAddressTokens previous_tokens,
+      const QuicIpAddress& ip,
+      QuicRandom* rand,
+      QuicWallTime now,
+      CachedNetworkParameters* cached_network_params);
+
+  // Attempts to validate the tokens in |tokens|.
+  HandshakeFailureReason ValidateSourceAddressTokens(
+      QuicString config_id,
+      QuicStringPiece tokens,
+      const QuicIpAddress& ip,
+      QuicWallTime now,
+      CachedNetworkParameters* cached_network_params);
+
+  // Attempts to validate the single source address token in |token|.
+  HandshakeFailureReason ValidateSingleSourceAddressToken(
+      QuicStringPiece token,
+      const QuicIpAddress& ip,
+      QuicWallTime now);
+
+  // CheckConfigs compares the state of the Configs in |server_config_| to the
+  // description given as arguments.
+  // The first of each pair is the server config ID of a Config. The second is a
+  // boolean describing whether the config is the primary. For example:
+  //   CheckConfigs(std::vector<std::pair<ServerConfigID, bool>>());  // checks
+  //   that no Configs are loaded.
+  //
+  //   // Checks that exactly three Configs are loaded with the given IDs and
+  //   // status.
+  //   CheckConfigs(
+  //     {{"id1", false},
+  //      {"id2", true},
+  //      {"id3", false}});
+  void CheckConfigs(
+      std::vector<std::pair<ServerConfigID, bool>> expected_ids_and_status);
+
+  // ConfigsDebug returns a QuicString that contains debugging information about
+  // the set of Configs loaded in |server_config_| and their status.
+  QuicString ConfigsDebug()
+      SHARED_LOCKS_REQUIRED(server_config_->configs_lock_);
+
+  void SelectNewPrimaryConfig(int seconds);
+
+  static QuicString CompressChain(
+      QuicCompressedCertsCache* compressed_certs_cache,
+      const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
+      const QuicString& client_common_set_hashes,
+      const QuicString& client_cached_cert_hashes,
+      const CommonCertSets* common_sets);
+
+  uint32_t source_address_token_future_secs();
+
+  uint32_t source_address_token_lifetime_secs();
+
+ private:
+  QuicCryptoServerConfig* server_config_;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_CRYPTO_SERVER_CONFIG_PEER_H_
diff --git a/quic/test_tools/quic_dispatcher_peer.cc b/quic/test_tools/quic_dispatcher_peer.cc
new file mode 100644
index 0000000..2590834
--- /dev/null
+++ b/quic/test_tools/quic_dispatcher_peer.cc
@@ -0,0 +1,111 @@
+// Copyright 2013 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_dispatcher_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicDispatcherPeer::SetTimeWaitListManager(
+    QuicDispatcher* dispatcher,
+    QuicTimeWaitListManager* time_wait_list_manager) {
+  dispatcher->time_wait_list_manager_.reset(time_wait_list_manager);
+}
+
+// static
+void QuicDispatcherPeer::UseWriter(QuicDispatcher* dispatcher,
+                                   QuicPacketWriterWrapper* writer) {
+  writer->set_writer(dispatcher->writer_.release());
+  dispatcher->writer_.reset(writer);
+}
+
+// static
+QuicPacketWriter* QuicDispatcherPeer::GetWriter(QuicDispatcher* dispatcher) {
+  return dispatcher->writer_.get();
+}
+
+// static
+QuicCompressedCertsCache* QuicDispatcherPeer::GetCache(
+    QuicDispatcher* dispatcher) {
+  return dispatcher->compressed_certs_cache();
+}
+
+// static
+QuicConnectionHelperInterface* QuicDispatcherPeer::GetHelper(
+    QuicDispatcher* dispatcher) {
+  return dispatcher->helper_.get();
+}
+
+// static
+QuicAlarmFactory* QuicDispatcherPeer::GetAlarmFactory(
+    QuicDispatcher* dispatcher) {
+  return dispatcher->alarm_factory_.get();
+}
+
+// static
+QuicDispatcher::WriteBlockedList* QuicDispatcherPeer::GetWriteBlockedList(
+    QuicDispatcher* dispatcher) {
+  return &dispatcher->write_blocked_list_;
+}
+
+// static
+QuicErrorCode QuicDispatcherPeer::GetAndClearLastError(
+    QuicDispatcher* dispatcher) {
+  QuicErrorCode ret = dispatcher->last_error_;
+  dispatcher->last_error_ = QUIC_NO_ERROR;
+  return ret;
+}
+
+// static
+QuicBufferedPacketStore* QuicDispatcherPeer::GetBufferedPackets(
+    QuicDispatcher* dispatcher) {
+  return &(dispatcher->buffered_packets_);
+}
+
+// static
+const QuicDispatcher::SessionMap& QuicDispatcherPeer::session_map(
+    QuicDispatcher* dispatcher) {
+  return dispatcher->session_map();
+}
+
+// static
+void QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
+    QuicDispatcher* dispatcher,
+    size_t num_session_allowed) {
+  return dispatcher->set_new_sessions_allowed_per_event_loop(
+      num_session_allowed);
+}
+
+// static
+void QuicDispatcherPeer::SendPublicReset(
+    QuicDispatcher* dispatcher,
+    const QuicSocketAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    QuicConnectionId connection_id,
+    bool ietf_quic,
+    std::unique_ptr<QuicPerPacketContext> packet_context) {
+  dispatcher->time_wait_list_manager()->SendPublicReset(
+      self_address, peer_address, connection_id, ietf_quic,
+      std::move(packet_context));
+}
+
+// static
+std::unique_ptr<QuicPerPacketContext> QuicDispatcherPeer::GetPerPacketContext(
+    QuicDispatcher* dispatcher) {
+  return dispatcher->GetPerPacketContext();
+}
+
+// static
+void QuicDispatcherPeer::RestorePerPacketContext(
+    QuicDispatcher* dispatcher,
+    std::unique_ptr<QuicPerPacketContext> context) {
+  dispatcher->RestorePerPacketContext(std::move(context));
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_dispatcher_peer.h b/quic/test_tools/quic_dispatcher_peer.h
new file mode 100644
index 0000000..e071938
--- /dev/null
+++ b/quic/test_tools/quic_dispatcher_peer.h
@@ -0,0 +1,72 @@
+// Copyright 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+
+namespace quic {
+
+class QuicPacketWriterWrapper;
+
+namespace test {
+
+class QuicDispatcherPeer {
+ public:
+  QuicDispatcherPeer() = delete;
+
+  static void SetTimeWaitListManager(
+      QuicDispatcher* dispatcher,
+      QuicTimeWaitListManager* time_wait_list_manager);
+
+  // Injects |writer| into |dispatcher| as the shared writer.
+  static void UseWriter(QuicDispatcher* dispatcher,
+                        QuicPacketWriterWrapper* writer);
+
+  static QuicPacketWriter* GetWriter(QuicDispatcher* dispatcher);
+
+  static QuicCompressedCertsCache* GetCache(QuicDispatcher* dispatcher);
+
+  static QuicConnectionHelperInterface* GetHelper(QuicDispatcher* dispatcher);
+
+  static QuicAlarmFactory* GetAlarmFactory(QuicDispatcher* dispatcher);
+
+  static QuicDispatcher::WriteBlockedList* GetWriteBlockedList(
+      QuicDispatcher* dispatcher);
+
+  // Get the dispatcher's record of the last error reported to its framer
+  // visitor's OnError() method.  Then set that record to QUIC_NO_ERROR.
+  static QuicErrorCode GetAndClearLastError(QuicDispatcher* dispatcher);
+
+  static QuicBufferedPacketStore* GetBufferedPackets(
+      QuicDispatcher* dispatcher);
+
+  static const QuicDispatcher::SessionMap& session_map(
+      QuicDispatcher* dispatcher);
+
+  static void set_new_sessions_allowed_per_event_loop(
+      QuicDispatcher* dispatcher,
+      size_t num_session_allowed);
+
+  static void SendPublicReset(
+      QuicDispatcher* dispatcher,
+      const QuicSocketAddress& self_address,
+      const QuicSocketAddress& peer_address,
+      QuicConnectionId connection_id,
+      bool ietf_quic,
+      std::unique_ptr<QuicPerPacketContext> packet_context);
+
+  static std::unique_ptr<QuicPerPacketContext> GetPerPacketContext(
+      QuicDispatcher* dispatcher);
+
+  static void RestorePerPacketContext(QuicDispatcher* dispatcher,
+                                      std::unique_ptr<QuicPerPacketContext>);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_DISPATCHER_PEER_H_
diff --git a/quic/test_tools/quic_flow_controller_peer.cc b/quic/test_tools/quic_flow_controller_peer.cc
new file mode 100644
index 0000000..32efe45
--- /dev/null
+++ b/quic/test_tools/quic_flow_controller_peer.cc
@@ -0,0 +1,68 @@
+// Copyright 2014 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_flow_controller_peer.h"
+
+#include <list>
+
+#include "net/third_party/quiche/src/quic/core/quic_flow_controller.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicFlowControllerPeer::SetSendWindowOffset(
+    QuicFlowController* flow_controller,
+    QuicStreamOffset offset) {
+  flow_controller->send_window_offset_ = offset;
+}
+
+// static
+void QuicFlowControllerPeer::SetReceiveWindowOffset(
+    QuicFlowController* flow_controller,
+    QuicStreamOffset offset) {
+  flow_controller->receive_window_offset_ = offset;
+}
+
+// static
+void QuicFlowControllerPeer::SetMaxReceiveWindow(
+    QuicFlowController* flow_controller,
+    QuicByteCount window_size) {
+  flow_controller->receive_window_size_ = window_size;
+}
+
+// static
+QuicStreamOffset QuicFlowControllerPeer::SendWindowOffset(
+    QuicFlowController* flow_controller) {
+  return flow_controller->send_window_offset_;
+}
+
+// static
+QuicByteCount QuicFlowControllerPeer::SendWindowSize(
+    QuicFlowController* flow_controller) {
+  return flow_controller->SendWindowSize();
+}
+
+// static
+QuicStreamOffset QuicFlowControllerPeer::ReceiveWindowOffset(
+    QuicFlowController* flow_controller) {
+  return flow_controller->receive_window_offset_;
+}
+
+// static
+QuicByteCount QuicFlowControllerPeer::ReceiveWindowSize(
+    QuicFlowController* flow_controller) {
+  return flow_controller->receive_window_offset_ -
+         flow_controller->highest_received_byte_offset_;
+}
+
+// static
+QuicByteCount QuicFlowControllerPeer::WindowUpdateThreshold(
+    QuicFlowController* flow_controller) {
+  return flow_controller->WindowUpdateThreshold();
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_flow_controller_peer.h b/quic/test_tools/quic_flow_controller_peer.h
new file mode 100644
index 0000000..1dc5a1a
--- /dev/null
+++ b/quic/test_tools/quic_flow_controller_peer.h
@@ -0,0 +1,46 @@
+// Copyright 2014 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_FLOW_CONTROLLER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_FLOW_CONTROLLER_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+
+class QuicFlowController;
+
+namespace test {
+
+class QuicFlowControllerPeer {
+ public:
+  QuicFlowControllerPeer() = delete;
+
+  static void SetSendWindowOffset(QuicFlowController* flow_controller,
+                                  QuicStreamOffset offset);
+
+  static void SetReceiveWindowOffset(QuicFlowController* flow_controller,
+                                     QuicStreamOffset offset);
+
+  static void SetMaxReceiveWindow(QuicFlowController* flow_controller,
+                                  QuicByteCount window_size);
+
+  static QuicStreamOffset SendWindowOffset(QuicFlowController* flow_controller);
+
+  static QuicByteCount SendWindowSize(QuicFlowController* flow_controller);
+
+  static QuicStreamOffset ReceiveWindowOffset(
+      QuicFlowController* flow_controller);
+
+  static QuicByteCount ReceiveWindowSize(QuicFlowController* flow_controller);
+
+  static QuicByteCount WindowUpdateThreshold(
+      QuicFlowController* flow_controller);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_FLOW_CONTROLLER_PEER_H_
diff --git a/quic/test_tools/quic_framer_peer.cc b/quic/test_tools/quic_framer_peer.cc
new file mode 100644
index 0000000..defdab4
--- /dev/null
+++ b/quic/test_tools/quic_framer_peer.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2013 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_framer_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+
+namespace quic {
+namespace test {
+
+// static
+uint64_t QuicFramerPeer::CalculatePacketNumberFromWire(
+    QuicFramer* framer,
+    QuicPacketNumberLength packet_number_length,
+    QuicPacketNumber last_packet_number,
+    uint64_t packet_number) {
+  return framer->CalculatePacketNumberFromWire(
+      packet_number_length, last_packet_number, packet_number);
+}
+
+// static
+void QuicFramerPeer::SetLastSerializedConnectionId(
+    QuicFramer* framer,
+    QuicConnectionId connection_id) {
+  framer->last_serialized_connection_id_ = connection_id;
+}
+
+// static
+void QuicFramerPeer::SetLargestPacketNumber(QuicFramer* framer,
+                                            QuicPacketNumber packet_number) {
+  framer->largest_packet_number_ = packet_number;
+}
+
+// static
+void QuicFramerPeer::SetPerspective(QuicFramer* framer,
+                                    Perspective perspective) {
+  framer->perspective_ = perspective;
+  framer->infer_packet_header_type_from_version_ =
+      perspective == Perspective::IS_CLIENT;
+}
+
+// static
+bool QuicFramerPeer::ProcessIetfStreamFrame(QuicFramer* framer,
+                                            QuicDataReader* reader,
+                                            uint8_t frame_type,
+                                            QuicStreamFrame* frame) {
+  return framer->ProcessIetfStreamFrame(reader, frame_type, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendIetfStreamFrame(QuicFramer* framer,
+                                           const QuicStreamFrame& frame,
+                                           bool last_frame_in_packet,
+                                           QuicDataWriter* writer) {
+  return framer->AppendIetfStreamFrame(frame, last_frame_in_packet, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessCryptoFrame(QuicFramer* framer,
+                                        QuicDataReader* reader,
+                                        QuicCryptoFrame* frame) {
+  return framer->ProcessCryptoFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendCryptoFrame(QuicFramer* framer,
+                                       const QuicCryptoFrame& frame,
+                                       QuicDataWriter* writer) {
+  return framer->AppendCryptoFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessIetfAckFrame(QuicFramer* framer,
+                                         QuicDataReader* reader,
+                                         uint64_t frame_type,
+                                         QuicAckFrame* ack_frame) {
+  return framer->ProcessIetfAckFrame(reader, frame_type, ack_frame);
+}
+
+// static
+bool QuicFramerPeer::AppendIetfAckFrameAndTypeByte(QuicFramer* framer,
+                                        const QuicAckFrame& frame,
+                                        QuicDataWriter* writer) {
+  return framer->AppendIetfAckFrameAndTypeByte(frame, writer);
+}
+// static
+size_t QuicFramerPeer::GetIetfAckFrameSize(QuicFramer* framer,
+                                           const QuicAckFrame& frame) {
+  return framer->GetIetfAckFrameSize(frame);
+}
+
+// static
+bool QuicFramerPeer::AppendIetfConnectionCloseFrame(
+    QuicFramer* framer,
+    const QuicConnectionCloseFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendIetfConnectionCloseFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::AppendApplicationCloseFrame(
+    QuicFramer* framer,
+    const QuicApplicationCloseFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendApplicationCloseFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessIetfConnectionCloseFrame(
+    QuicFramer* framer,
+    QuicDataReader* reader,
+    QuicConnectionCloseFrame* frame) {
+  return framer->ProcessIetfConnectionCloseFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::ProcessApplicationCloseFrame(
+    QuicFramer* framer,
+    QuicDataReader* reader,
+    QuicApplicationCloseFrame* frame) {
+  return framer->ProcessApplicationCloseFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::ProcessPathChallengeFrame(QuicFramer* framer,
+                                               QuicDataReader* reader,
+                                               QuicPathChallengeFrame* frame) {
+  return framer->ProcessPathChallengeFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::ProcessPathResponseFrame(QuicFramer* framer,
+                                              QuicDataReader* reader,
+                                              QuicPathResponseFrame* frame) {
+  return framer->ProcessPathResponseFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendPathChallengeFrame(
+    QuicFramer* framer,
+    const QuicPathChallengeFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendPathChallengeFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::AppendPathResponseFrame(QuicFramer* framer,
+                                             const QuicPathResponseFrame& frame,
+                                             QuicDataWriter* writer) {
+  return framer->AppendPathResponseFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::AppendIetfResetStreamFrame(QuicFramer* framer,
+                                                const QuicRstStreamFrame& frame,
+                                                QuicDataWriter* writer) {
+  return framer->AppendIetfResetStreamFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessIetfResetStreamFrame(QuicFramer* framer,
+                                                 QuicDataReader* reader,
+                                                 QuicRstStreamFrame* frame) {
+  return framer->ProcessIetfResetStreamFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::ProcessStopSendingFrame(
+    QuicFramer* framer,
+    QuicDataReader* reader,
+    QuicStopSendingFrame* stop_sending_frame) {
+  return framer->ProcessStopSendingFrame(reader, stop_sending_frame);
+}
+
+// static
+bool QuicFramerPeer::AppendStopSendingFrame(
+    QuicFramer* framer,
+    const QuicStopSendingFrame& stop_sending_frame,
+    QuicDataWriter* writer) {
+  return framer->AppendStopSendingFrame(stop_sending_frame, writer);
+}
+
+// static
+bool QuicFramerPeer::AppendMaxDataFrame(QuicFramer* framer,
+                                        const QuicWindowUpdateFrame& frame,
+                                        QuicDataWriter* writer) {
+  return framer->AppendMaxDataFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::AppendMaxStreamDataFrame(
+    QuicFramer* framer,
+    const QuicWindowUpdateFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendMaxStreamDataFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessMaxDataFrame(QuicFramer* framer,
+                                         QuicDataReader* reader,
+                                         QuicWindowUpdateFrame* frame) {
+  return framer->ProcessMaxDataFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::ProcessMaxStreamDataFrame(QuicFramer* framer,
+                                               QuicDataReader* reader,
+                                               QuicWindowUpdateFrame* frame) {
+  return framer->ProcessMaxStreamDataFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendMaxStreamsFrame(QuicFramer* framer,
+                                           const QuicMaxStreamIdFrame& frame,
+                                           QuicDataWriter* writer) {
+  return framer->AppendMaxStreamsFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessMaxStreamsFrame(QuicFramer* framer,
+                                            QuicDataReader* reader,
+                                            QuicMaxStreamIdFrame* frame,
+                                            uint64_t frame_type) {
+  return framer->ProcessMaxStreamsFrame(reader, frame, frame_type);
+}
+
+// static
+bool QuicFramerPeer::AppendIetfBlockedFrame(QuicFramer* framer,
+                                            const QuicBlockedFrame& frame,
+                                            QuicDataWriter* writer) {
+  return framer->AppendIetfBlockedFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessIetfBlockedFrame(QuicFramer* framer,
+                                             QuicDataReader* reader,
+                                             QuicBlockedFrame* frame) {
+  return framer->ProcessIetfBlockedFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendStreamBlockedFrame(QuicFramer* framer,
+                                              const QuicBlockedFrame& frame,
+                                              QuicDataWriter* writer) {
+  return framer->AppendStreamBlockedFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessStreamBlockedFrame(QuicFramer* framer,
+                                               QuicDataReader* reader,
+                                               QuicBlockedFrame* frame) {
+  return framer->ProcessStreamBlockedFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendStreamsBlockedFrame(
+    QuicFramer* framer,
+    const QuicStreamIdBlockedFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendStreamsBlockedFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessStreamsBlockedFrame(QuicFramer* framer,
+                                                QuicDataReader* reader,
+                                                QuicStreamIdBlockedFrame* frame,
+                                                uint64_t frame_type) {
+  return framer->ProcessStreamsBlockedFrame(reader, frame, frame_type);
+}
+
+// static
+bool QuicFramerPeer::AppendNewConnectionIdFrame(
+    QuicFramer* framer,
+    const QuicNewConnectionIdFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendNewConnectionIdFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessNewConnectionIdFrame(
+    QuicFramer* framer,
+    QuicDataReader* reader,
+    QuicNewConnectionIdFrame* frame) {
+  return framer->ProcessNewConnectionIdFrame(reader, frame);
+}
+
+// static
+bool QuicFramerPeer::AppendRetireConnectionIdFrame(
+    QuicFramer* framer,
+    const QuicRetireConnectionIdFrame& frame,
+    QuicDataWriter* writer) {
+  return framer->AppendRetireConnectionIdFrame(frame, writer);
+}
+
+// static
+bool QuicFramerPeer::ProcessRetireConnectionIdFrame(
+    QuicFramer* framer,
+    QuicDataReader* reader,
+    QuicRetireConnectionIdFrame* frame) {
+  return framer->ProcessRetireConnectionIdFrame(reader, frame);
+}
+
+// static
+void QuicFramerPeer::SwapCrypters(QuicFramer* framer1, QuicFramer* framer2) {
+  for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) {
+    framer1->encrypter_[i].swap(framer2->encrypter_[i]);
+  }
+  framer1->decrypter_.swap(framer2->decrypter_);
+  framer1->alternative_decrypter_.swap(framer2->alternative_decrypter_);
+
+  EncryptionLevel framer2_level = framer2->decrypter_level_;
+  framer2->decrypter_level_ = framer1->decrypter_level_;
+  framer1->decrypter_level_ = framer2_level;
+  framer2_level = framer2->alternative_decrypter_level_;
+  framer2->alternative_decrypter_level_ = framer1->alternative_decrypter_level_;
+  framer1->alternative_decrypter_level_ = framer2_level;
+
+  const bool framer2_latch = framer2->alternative_decrypter_latch_;
+  framer2->alternative_decrypter_latch_ = framer1->alternative_decrypter_latch_;
+  framer1->alternative_decrypter_latch_ = framer2_latch;
+}
+
+// static
+QuicEncrypter* QuicFramerPeer::GetEncrypter(QuicFramer* framer,
+                                            EncryptionLevel level) {
+  return framer->encrypter_[level].get();
+}
+
+// static
+size_t QuicFramerPeer::ComputeFrameLength(
+    QuicFramer* framer,
+    const QuicFrame& frame,
+    bool last_frame_in_packet,
+    QuicPacketNumberLength packet_number_length) {
+  return framer->ComputeFrameLength(frame, last_frame_in_packet,
+                                    packet_number_length);
+}
+
+// static
+void QuicFramerPeer::SetFirstSendingPacketNumber(QuicFramer* framer,
+                                                 uint64_t packet_number) {
+  *const_cast<QuicPacketNumber*>(&framer->first_sending_packet_number_) =
+      QuicPacketNumber(packet_number);
+}
+
+// static
+void QuicFramerPeer::SetExpectedConnectionIDLength(
+    QuicFramer* framer,
+    uint8_t expected_connection_id_length) {
+  *const_cast<uint8_t*>(&framer->expected_connection_id_length_) =
+      expected_connection_id_length;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h
new file mode 100644
index 0000000..94509b5
--- /dev/null
+++ b/quic/test_tools/quic_framer_peer.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+
+namespace test {
+
+class QuicFramerPeer {
+ public:
+  QuicFramerPeer() = delete;
+
+  static uint64_t CalculatePacketNumberFromWire(
+      QuicFramer* framer,
+      QuicPacketNumberLength packet_number_length,
+      QuicPacketNumber last_packet_number,
+      uint64_t packet_number);
+  static void SetLastSerializedConnectionId(QuicFramer* framer,
+                                            QuicConnectionId connection_id);
+  static void SetLargestPacketNumber(QuicFramer* framer,
+                                     QuicPacketNumber packet_number);
+  static void SetPerspective(QuicFramer* framer, Perspective perspective);
+
+  // SwapCrypters exchanges the state of the crypters of |framer1| with
+  // |framer2|.
+  static void SwapCrypters(QuicFramer* framer1, QuicFramer* framer2);
+
+  static QuicEncrypter* GetEncrypter(QuicFramer* framer, EncryptionLevel level);
+
+  // IETF defined frame append/process methods.
+  static bool ProcessIetfStreamFrame(QuicFramer* framer,
+                                     QuicDataReader* reader,
+                                     uint8_t frame_type,
+                                     QuicStreamFrame* frame);
+  static bool AppendIetfStreamFrame(QuicFramer* framer,
+                                    const QuicStreamFrame& frame,
+                                    bool last_frame_in_packet,
+                                    QuicDataWriter* writer);
+  static bool ProcessCryptoFrame(QuicFramer* framer,
+                                 QuicDataReader* reader,
+                                 QuicCryptoFrame* frame);
+  static bool AppendCryptoFrame(QuicFramer* framer,
+                                const QuicCryptoFrame& frame,
+                                QuicDataWriter* writer);
+
+  static bool AppendIetfConnectionCloseFrame(
+      QuicFramer* framer,
+      const QuicConnectionCloseFrame& frame,
+      QuicDataWriter* writer);
+  static bool AppendApplicationCloseFrame(
+      QuicFramer* framer,
+      const QuicApplicationCloseFrame& frame,
+      QuicDataWriter* writer);
+  static bool ProcessIetfConnectionCloseFrame(QuicFramer* framer,
+                                              QuicDataReader* reader,
+                                              QuicConnectionCloseFrame* frame);
+  static bool ProcessApplicationCloseFrame(QuicFramer* framer,
+                                           QuicDataReader* reader,
+                                           QuicApplicationCloseFrame* frame);
+  static bool ProcessIetfAckFrame(QuicFramer* framer,
+                                  QuicDataReader* reader,
+                                  uint64_t frame_type,
+                                  QuicAckFrame* ack_frame);
+  static bool AppendIetfAckFrameAndTypeByte(QuicFramer* framer,
+                                            const QuicAckFrame& frame,
+                                            QuicDataWriter* writer);
+  static size_t GetIetfAckFrameSize(QuicFramer* framer,
+                                    const QuicAckFrame& frame);
+  static bool AppendIetfResetStreamFrame(QuicFramer* framer,
+                                         const QuicRstStreamFrame& frame,
+                                         QuicDataWriter* writer);
+  static bool ProcessIetfResetStreamFrame(QuicFramer* framer,
+                                          QuicDataReader* reader,
+                                          QuicRstStreamFrame* frame);
+
+  static bool ProcessPathChallengeFrame(QuicFramer* framer,
+                                        QuicDataReader* reader,
+                                        QuicPathChallengeFrame* frame);
+  static bool ProcessPathResponseFrame(QuicFramer* framer,
+                                       QuicDataReader* reader,
+                                       QuicPathResponseFrame* frame);
+
+  static bool AppendPathChallengeFrame(QuicFramer* framer,
+                                       const QuicPathChallengeFrame& frame,
+                                       QuicDataWriter* writer);
+  static bool AppendPathResponseFrame(QuicFramer* framer,
+                                      const QuicPathResponseFrame& frame,
+                                      QuicDataWriter* writer);
+
+  static bool ProcessStopSendingFrame(QuicFramer* framer,
+                                      QuicDataReader* reader,
+                                      QuicStopSendingFrame* stop_sending_frame);
+  static bool AppendStopSendingFrame(
+      QuicFramer* framer,
+      const QuicStopSendingFrame& stop_sending_frame,
+      QuicDataWriter* writer);
+
+  // Append/consume IETF-Format MAX_DATA and MAX_STREAM_DATA frames
+  static bool AppendMaxDataFrame(QuicFramer* framer,
+                                 const QuicWindowUpdateFrame& frame,
+                                 QuicDataWriter* writer);
+  static bool AppendMaxStreamDataFrame(QuicFramer* framer,
+                                       const QuicWindowUpdateFrame& frame,
+                                       QuicDataWriter* writer);
+  static bool ProcessMaxDataFrame(QuicFramer* framer,
+                                  QuicDataReader* reader,
+                                  QuicWindowUpdateFrame* frame);
+  static bool ProcessMaxStreamDataFrame(QuicFramer* framer,
+                                        QuicDataReader* reader,
+                                        QuicWindowUpdateFrame* frame);
+  static bool AppendMaxStreamsFrame(QuicFramer* framer,
+                                    const QuicMaxStreamIdFrame& frame,
+                                    QuicDataWriter* writer);
+  static bool ProcessMaxStreamsFrame(QuicFramer* framer,
+                                     QuicDataReader* reader,
+                                     QuicMaxStreamIdFrame* frame,
+                                     uint64_t frame_type);
+  static bool AppendIetfBlockedFrame(QuicFramer* framer,
+                                     const QuicBlockedFrame& frame,
+                                     QuicDataWriter* writer);
+  static bool ProcessIetfBlockedFrame(QuicFramer* framer,
+                                      QuicDataReader* reader,
+                                      QuicBlockedFrame* frame);
+
+  static bool AppendStreamBlockedFrame(QuicFramer* framer,
+                                       const QuicBlockedFrame& frame,
+                                       QuicDataWriter* writer);
+  static bool ProcessStreamBlockedFrame(QuicFramer* framer,
+                                        QuicDataReader* reader,
+                                        QuicBlockedFrame* frame);
+
+  static bool AppendStreamsBlockedFrame(QuicFramer* framer,
+                                        const QuicStreamIdBlockedFrame& frame,
+                                        QuicDataWriter* writer);
+  static bool ProcessStreamsBlockedFrame(QuicFramer* framer,
+                                         QuicDataReader* reader,
+                                         QuicStreamIdBlockedFrame* frame,
+                                         uint64_t frame_type);
+
+  static bool AppendNewConnectionIdFrame(QuicFramer* framer,
+                                         const QuicNewConnectionIdFrame& frame,
+                                         QuicDataWriter* writer);
+  static bool ProcessNewConnectionIdFrame(QuicFramer* framer,
+                                          QuicDataReader* reader,
+                                          QuicNewConnectionIdFrame* frame);
+  static bool AppendRetireConnectionIdFrame(
+      QuicFramer* framer,
+      const QuicRetireConnectionIdFrame& frame,
+      QuicDataWriter* writer);
+  static bool ProcessRetireConnectionIdFrame(
+      QuicFramer* framer,
+      QuicDataReader* reader,
+      QuicRetireConnectionIdFrame* frame);
+  static size_t ComputeFrameLength(QuicFramer* framer,
+                                   const QuicFrame& frame,
+                                   bool last_frame_in_packet,
+                                   QuicPacketNumberLength packet_number_length);
+  static void SetFirstSendingPacketNumber(QuicFramer* framer,
+                                          uint64_t packet_number);
+  static void SetExpectedConnectionIDLength(
+      QuicFramer* framer,
+      uint8_t expected_connection_id_length);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
diff --git a/quic/test_tools/quic_packet_creator_peer.cc b/quic/test_tools/quic_packet_creator_peer.cc
new file mode 100644
index 0000000..51d9588
--- /dev/null
+++ b/quic/test_tools/quic_packet_creator_peer.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2013 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_packet_creator_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+
+namespace quic {
+namespace test {
+
+// static
+bool QuicPacketCreatorPeer::SendVersionInPacket(QuicPacketCreator* creator) {
+  return creator->IncludeVersionInHeader();
+}
+
+// static
+void QuicPacketCreatorPeer::SetSendVersionInPacket(
+    QuicPacketCreator* creator,
+    bool send_version_in_packet) {
+  if (creator->framer_->transport_version() != QUIC_VERSION_99) {
+    creator->send_version_in_packet_ = send_version_in_packet;
+    return;
+  }
+  if (!send_version_in_packet) {
+    creator->packet_.encryption_level = ENCRYPTION_FORWARD_SECURE;
+    return;
+  }
+  DCHECK(creator->packet_.encryption_level < ENCRYPTION_FORWARD_SECURE);
+}
+
+// static
+void QuicPacketCreatorPeer::SetPacketNumberLength(
+    QuicPacketCreator* creator,
+    QuicPacketNumberLength packet_number_length) {
+  creator->packet_.packet_number_length = packet_number_length;
+}
+
+// static
+QuicPacketNumberLength QuicPacketCreatorPeer::GetPacketNumberLength(
+    QuicPacketCreator* creator) {
+  return creator->GetPacketNumberLength();
+}
+
+// static
+QuicVariableLengthIntegerLength
+QuicPacketCreatorPeer::GetRetryTokenLengthLength(QuicPacketCreator* creator) {
+  return creator->GetRetryTokenLengthLength();
+}
+
+// static
+QuicVariableLengthIntegerLength QuicPacketCreatorPeer::GetLengthLength(
+    QuicPacketCreator* creator) {
+  return creator->GetLengthLength();
+}
+
+void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator,
+                                            uint64_t s) {
+  DCHECK_NE(0u, s);
+  creator->packet_.packet_number = QuicPacketNumber(s);
+}
+
+// static
+void QuicPacketCreatorPeer::ClearPacketNumber(QuicPacketCreator* creator) {
+  creator->packet_.packet_number.Clear();
+}
+
+// static
+void QuicPacketCreatorPeer::FillPacketHeader(QuicPacketCreator* creator,
+                                             QuicPacketHeader* header) {
+  creator->FillPacketHeader(header);
+}
+
+// static
+void QuicPacketCreatorPeer::CreateStreamFrame(QuicPacketCreator* creator,
+                                              QuicStreamId id,
+                                              size_t write_length,
+                                              size_t iov_offset,
+                                              QuicStreamOffset offset,
+                                              bool fin,
+                                              QuicFrame* frame) {
+  creator->CreateStreamFrame(id, write_length, iov_offset, offset, fin, frame);
+}
+
+// static
+SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames(
+    QuicPacketCreator* creator,
+    const QuicFrames& frames,
+    char* buffer,
+    size_t buffer_len) {
+  DCHECK(creator->queued_frames_.empty());
+  DCHECK(!frames.empty());
+  for (const QuicFrame& frame : frames) {
+    bool success = creator->AddFrame(frame, false, NOT_RETRANSMISSION);
+    DCHECK(success);
+  }
+  creator->SerializePacket(buffer, buffer_len);
+  SerializedPacket packet = creator->packet_;
+  // The caller takes ownership of the QuicEncryptedPacket.
+  creator->packet_.encrypted_buffer = nullptr;
+  DCHECK(packet.retransmittable_frames.empty());
+  return packet;
+}
+
+// static
+OwningSerializedPacketPointer
+QuicPacketCreatorPeer::SerializeConnectivityProbingPacket(
+    QuicPacketCreator* creator) {
+  return creator->SerializeConnectivityProbingPacket();
+}
+
+// static
+OwningSerializedPacketPointer
+QuicPacketCreatorPeer::SerializePathChallengeConnectivityProbingPacket(
+    QuicPacketCreator* creator,
+    QuicPathFrameBuffer* payload) {
+  return creator->SerializePathChallengeConnectivityProbingPacket(payload);
+}
+
+// static
+EncryptionLevel QuicPacketCreatorPeer::GetEncryptionLevel(
+    QuicPacketCreator* creator) {
+  return creator->packet_.encryption_level;
+}
+
+// static
+QuicFramer* QuicPacketCreatorPeer::framer(QuicPacketCreator* creator) {
+  return creator->framer_;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_packet_creator_peer.h b/quic/test_tools/quic_packet_creator_peer.h
new file mode 100644
index 0000000..c637ac2
--- /dev/null
+++ b/quic/test_tools/quic_packet_creator_peer.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_CREATOR_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_CREATOR_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+class QuicFramer;
+class QuicPacketCreator;
+
+namespace test {
+
+class QuicPacketCreatorPeer {
+ public:
+  QuicPacketCreatorPeer() = delete;
+
+  static bool SendVersionInPacket(QuicPacketCreator* creator);
+
+  static void SetSendVersionInPacket(QuicPacketCreator* creator,
+                                     bool send_version_in_packet);
+  static void SetPacketNumberLength(
+      QuicPacketCreator* creator,
+      QuicPacketNumberLength packet_number_length);
+  static QuicPacketNumberLength GetPacketNumberLength(
+      QuicPacketCreator* creator);
+  static QuicVariableLengthIntegerLength GetRetryTokenLengthLength(
+      QuicPacketCreator* creator);
+  static QuicVariableLengthIntegerLength GetLengthLength(
+      QuicPacketCreator* creator);
+  static void SetPacketNumber(QuicPacketCreator* creator, uint64_t s);
+  static void ClearPacketNumber(QuicPacketCreator* creator);
+  static void FillPacketHeader(QuicPacketCreator* creator,
+                               QuicPacketHeader* header);
+  static void CreateStreamFrame(QuicPacketCreator* creator,
+                                QuicStreamId id,
+                                size_t write_length,
+                                size_t iov_offset,
+                                QuicStreamOffset offset,
+                                bool fin,
+                                QuicFrame* frame);
+  static SerializedPacket SerializeAllFrames(QuicPacketCreator* creator,
+                                             const QuicFrames& frames,
+                                             char* buffer,
+                                             size_t buffer_len);
+  static OwningSerializedPacketPointer SerializeConnectivityProbingPacket(
+      QuicPacketCreator* creator);
+  static OwningSerializedPacketPointer
+  SerializePathChallengeConnectivityProbingPacket(QuicPacketCreator* creator,
+                                                  QuicPathFrameBuffer* payload);
+
+  static EncryptionLevel GetEncryptionLevel(QuicPacketCreator* creator);
+  static QuicFramer* framer(QuicPacketCreator* creator);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_CREATOR_PEER_H_
diff --git a/quic/test_tools/quic_packet_generator_peer.cc b/quic/test_tools/quic_packet_generator_peer.cc
new file mode 100644
index 0000000..91a8752
--- /dev/null
+++ b/quic/test_tools/quic_packet_generator_peer.cc
@@ -0,0 +1,20 @@
+// Copyright 2014 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_packet_generator_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_generator.h"
+
+namespace quic {
+namespace test {
+
+// static
+QuicPacketCreator* QuicPacketGeneratorPeer::GetPacketCreator(
+    QuicPacketGenerator* generator) {
+  return &generator->packet_creator_;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_packet_generator_peer.h b/quic/test_tools/quic_packet_generator_peer.h
new file mode 100644
index 0000000..5d8ff4b
--- /dev/null
+++ b/quic/test_tools/quic_packet_generator_peer.h
@@ -0,0 +1,29 @@
+// Copyright 2014 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+
+class QuicPacketCreator;
+class QuicPacketGenerator;
+
+namespace test {
+
+class QuicPacketGeneratorPeer {
+ public:
+  QuicPacketGeneratorPeer() = delete;
+
+  static QuicPacketCreator* GetPacketCreator(QuicPacketGenerator* generator);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.cc b/quic/test_tools/quic_sent_packet_manager_peer.cc
new file mode 100644
index 0000000..3057e5e
--- /dev/null
+++ b/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -0,0 +1,239 @@
+// Copyright 2013 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_sent_packet_manager_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+size_t QuicSentPacketManagerPeer::GetMaxTailLossProbes(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->max_tail_loss_probes_;
+}
+
+// static
+void QuicSentPacketManagerPeer::SetMaxTailLossProbes(
+    QuicSentPacketManager* sent_packet_manager,
+    size_t max_tail_loss_probes) {
+  sent_packet_manager->max_tail_loss_probes_ = max_tail_loss_probes;
+}
+
+// static
+bool QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->enable_half_rtt_tail_loss_probe_;
+}
+
+// static
+bool QuicSentPacketManagerPeer::GetUseNewRto(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->use_new_rto_;
+}
+
+// static
+void QuicSentPacketManagerPeer::SetPerspective(
+    QuicSentPacketManager* sent_packet_manager,
+    Perspective perspective) {
+  QuicUnackedPacketMapPeer::SetPerspective(
+      &sent_packet_manager->unacked_packets_, perspective);
+}
+
+// static
+SendAlgorithmInterface* QuicSentPacketManagerPeer::GetSendAlgorithm(
+    const QuicSentPacketManager& sent_packet_manager) {
+  return sent_packet_manager.send_algorithm_.get();
+}
+
+// static
+void QuicSentPacketManagerPeer::SetSendAlgorithm(
+    QuicSentPacketManager* sent_packet_manager,
+    SendAlgorithmInterface* send_algorithm) {
+  sent_packet_manager->SetSendAlgorithm(send_algorithm);
+}
+
+// static
+const LossDetectionInterface* QuicSentPacketManagerPeer::GetLossAlgorithm(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->loss_algorithm_;
+}
+
+// static
+void QuicSentPacketManagerPeer::SetLossAlgorithm(
+    QuicSentPacketManager* sent_packet_manager,
+    LossDetectionInterface* loss_detector) {
+  sent_packet_manager->loss_algorithm_ = loss_detector;
+}
+
+// static
+RttStats* QuicSentPacketManagerPeer::GetRttStats(
+    QuicSentPacketManager* sent_packet_manager) {
+  return &sent_packet_manager->rtt_stats_;
+}
+
+// static
+bool QuicSentPacketManagerPeer::HasPendingPackets(
+    const QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->unacked_packets_.HasInFlightPackets();
+}
+
+// static
+bool QuicSentPacketManagerPeer::IsRetransmission(
+    QuicSentPacketManager* sent_packet_manager,
+    uint64_t packet_number) {
+  DCHECK(HasRetransmittableFrames(sent_packet_manager, packet_number));
+  if (!HasRetransmittableFrames(sent_packet_manager, packet_number)) {
+    return false;
+  }
+  if (sent_packet_manager->session_decides_what_to_write()) {
+    return sent_packet_manager->unacked_packets_
+               .GetTransmissionInfo(QuicPacketNumber(packet_number))
+               .transmission_type != NOT_RETRANSMISSION;
+  }
+  for (auto transmission_info : sent_packet_manager->unacked_packets_) {
+    if (transmission_info.retransmission.IsInitialized() &&
+        transmission_info.retransmission == QuicPacketNumber(packet_number)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// static
+void QuicSentPacketManagerPeer::MarkForRetransmission(
+    QuicSentPacketManager* sent_packet_manager,
+    uint64_t packet_number,
+    TransmissionType transmission_type) {
+  sent_packet_manager->MarkForRetransmission(QuicPacketNumber(packet_number),
+                                             transmission_type);
+}
+
+// static
+QuicTime::Delta QuicSentPacketManagerPeer::GetRetransmissionDelay(
+    const QuicSentPacketManager* sent_packet_manager,
+    size_t consecutive_rto_count) {
+  return sent_packet_manager->GetRetransmissionDelay(consecutive_rto_count);
+}
+
+// static
+QuicTime::Delta QuicSentPacketManagerPeer::GetRetransmissionDelay(
+    const QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->GetRetransmissionDelay();
+}
+
+// static
+QuicTime::Delta QuicSentPacketManagerPeer::GetTailLossProbeDelay(
+    const QuicSentPacketManager* sent_packet_manager,
+    size_t consecutive_tlp_count) {
+  return sent_packet_manager->GetTailLossProbeDelay(consecutive_tlp_count);
+}
+
+// static
+QuicTime::Delta QuicSentPacketManagerPeer::GetTailLossProbeDelay(
+    const QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->GetTailLossProbeDelay();
+}
+
+// static
+bool QuicSentPacketManagerPeer::HasUnackedCryptoPackets(
+    const QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->unacked_packets_.HasPendingCryptoPackets();
+}
+
+// static
+size_t QuicSentPacketManagerPeer::GetNumRetransmittablePackets(
+    const QuicSentPacketManager* sent_packet_manager) {
+  size_t num_unacked_packets = 0;
+  for (auto it = sent_packet_manager->unacked_packets_.begin();
+       it != sent_packet_manager->unacked_packets_.end(); ++it) {
+    if (sent_packet_manager->unacked_packets_.HasRetransmittableFrames(*it)) {
+      ++num_unacked_packets;
+    }
+  }
+  return num_unacked_packets;
+}
+
+// static
+QuicByteCount QuicSentPacketManagerPeer::GetBytesInFlight(
+    const QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->unacked_packets_.bytes_in_flight();
+}
+
+// static
+void QuicSentPacketManagerPeer::SetConsecutiveRtoCount(
+    QuicSentPacketManager* sent_packet_manager,
+    size_t count) {
+  sent_packet_manager->consecutive_rto_count_ = count;
+}
+
+// static
+void QuicSentPacketManagerPeer::SetConsecutiveTlpCount(
+    QuicSentPacketManager* sent_packet_manager,
+    size_t count) {
+  sent_packet_manager->consecutive_tlp_count_ = count;
+}
+
+// static
+QuicSustainedBandwidthRecorder& QuicSentPacketManagerPeer::GetBandwidthRecorder(
+    QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->sustained_bandwidth_recorder_;
+}
+
+// static
+bool QuicSentPacketManagerPeer::UsingPacing(
+    const QuicSentPacketManager* sent_packet_manager) {
+  return sent_packet_manager->using_pacing_;
+}
+
+// static
+void QuicSentPacketManagerPeer::SetUsingPacing(
+    QuicSentPacketManager* sent_packet_manager,
+    bool using_pacing) {
+  sent_packet_manager->using_pacing_ = using_pacing;
+}
+
+// static
+bool QuicSentPacketManagerPeer::IsUnacked(
+    QuicSentPacketManager* sent_packet_manager,
+    uint64_t packet_number) {
+  return sent_packet_manager->unacked_packets_.IsUnacked(
+      QuicPacketNumber(packet_number));
+}
+
+// static
+bool QuicSentPacketManagerPeer::HasRetransmittableFrames(
+    QuicSentPacketManager* sent_packet_manager,
+    uint64_t packet_number) {
+  return sent_packet_manager->unacked_packets_.HasRetransmittableFrames(
+      QuicPacketNumber(packet_number));
+}
+
+// static
+QuicUnackedPacketMap* QuicSentPacketManagerPeer::GetUnackedPacketMap(
+    QuicSentPacketManager* sent_packet_manager) {
+  return &sent_packet_manager->unacked_packets_;
+}
+
+// static
+void QuicSentPacketManagerPeer::DisablePacerBursts(
+    QuicSentPacketManager* sent_packet_manager) {
+  sent_packet_manager->pacing_sender_.burst_tokens_ = 0;
+  sent_packet_manager->pacing_sender_.initial_burst_size_ = 0;
+}
+
+// static
+void QuicSentPacketManagerPeer::SetNextPacedPacketTime(
+    QuicSentPacketManager* sent_packet_manager,
+    QuicTime time) {
+  sent_packet_manager->pacing_sender_.ideal_next_packet_send_time_ = time;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.h b/quic/test_tools/quic_sent_packet_manager_peer.h
new file mode 100644
index 0000000..b8ec1d3
--- /dev/null
+++ b/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -0,0 +1,115 @@
+// Copyright 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SENT_PACKET_MANAGER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SENT_PACKET_MANAGER_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
+
+namespace quic {
+
+class SendAlgorithmInterface;
+
+namespace test {
+
+class QuicSentPacketManagerPeer {
+ public:
+  QuicSentPacketManagerPeer() = delete;
+
+  static size_t GetMaxTailLossProbes(
+      QuicSentPacketManager* sent_packet_manager);
+
+  static void SetMaxTailLossProbes(QuicSentPacketManager* sent_packet_manager,
+                                   size_t max_tail_loss_probes);
+
+  static bool GetEnableHalfRttTailLossProbe(
+      QuicSentPacketManager* sent_packet_manager);
+
+  static bool GetUseNewRto(QuicSentPacketManager* sent_packet_manager);
+
+  static void SetPerspective(QuicSentPacketManager* sent_packet_manager,
+                             Perspective perspective);
+
+  static SendAlgorithmInterface* GetSendAlgorithm(
+      const QuicSentPacketManager& sent_packet_manager);
+
+  static void SetSendAlgorithm(QuicSentPacketManager* sent_packet_manager,
+                               SendAlgorithmInterface* send_algorithm);
+
+  static const LossDetectionInterface* GetLossAlgorithm(
+      QuicSentPacketManager* sent_packet_manager);
+
+  static void SetLossAlgorithm(QuicSentPacketManager* sent_packet_manager,
+                               LossDetectionInterface* loss_detector);
+
+  static RttStats* GetRttStats(QuicSentPacketManager* sent_packet_manager);
+
+  static bool HasPendingPackets(
+      const QuicSentPacketManager* sent_packet_manager);
+
+  // Returns true if |packet_number| is a retransmission of a packet.
+  static bool IsRetransmission(QuicSentPacketManager* sent_packet_manager,
+                               uint64_t packet_number);
+
+  static void MarkForRetransmission(QuicSentPacketManager* sent_packet_manager,
+                                    uint64_t packet_number,
+                                    TransmissionType transmission_type);
+
+  static QuicTime::Delta GetRetransmissionDelay(
+      const QuicSentPacketManager* sent_packet_manager,
+      size_t consecutive_rto_count);
+  static QuicTime::Delta GetRetransmissionDelay(
+      const QuicSentPacketManager* sent_packet_manager);
+  static QuicTime::Delta GetTailLossProbeDelay(
+      const QuicSentPacketManager* sent_packet_manager,
+      size_t consecutive_tlp_count);
+  static QuicTime::Delta GetTailLossProbeDelay(
+      const QuicSentPacketManager* sent_packet_manager);
+
+  static bool HasUnackedCryptoPackets(
+      const QuicSentPacketManager* sent_packet_manager);
+
+  static size_t GetNumRetransmittablePackets(
+      const QuicSentPacketManager* sent_packet_manager);
+
+  static QuicByteCount GetBytesInFlight(
+      const QuicSentPacketManager* sent_packet_manager);
+
+  static void SetConsecutiveRtoCount(QuicSentPacketManager* sent_packet_manager,
+                                     size_t count);
+
+  static void SetConsecutiveTlpCount(QuicSentPacketManager* sent_packet_manager,
+                                     size_t count);
+
+  static QuicSustainedBandwidthRecorder& GetBandwidthRecorder(
+      QuicSentPacketManager* sent_packet_manager);
+
+  static void SetUsingPacing(QuicSentPacketManager* sent_packet_manager,
+                             bool using_pacing);
+
+  static bool UsingPacing(const QuicSentPacketManager* sent_packet_manager);
+
+  static bool IsUnacked(QuicSentPacketManager* sent_packet_manager,
+                        uint64_t packet_number);
+
+  static bool HasRetransmittableFrames(
+      QuicSentPacketManager* sent_packet_manager,
+      uint64_t packet_number);
+
+  static QuicUnackedPacketMap* GetUnackedPacketMap(
+      QuicSentPacketManager* sent_packet_manager);
+
+  static void DisablePacerBursts(QuicSentPacketManager* sent_packet_manager);
+
+  static void SetNextPacedPacketTime(QuicSentPacketManager* sent_packet_manager,
+                                     QuicTime time);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SENT_PACKET_MANAGER_PEER_H_
diff --git a/quic/test_tools/quic_server_peer.cc b/quic/test_tools/quic_server_peer.cc
new file mode 100644
index 0000000..9e8d962
--- /dev/null
+++ b/quic/test_tools/quic_server_peer.cc
@@ -0,0 +1,32 @@
+// Copyright 2013 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_server_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_reader.h"
+#include "net/third_party/quiche/src/quic/tools/quic_server.h"
+
+namespace quic {
+namespace test {
+
+// static
+bool QuicServerPeer::SetSmallSocket(QuicServer* server) {
+  int size = 1024 * 10;
+  return setsockopt(server->fd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) !=
+         -1;
+}
+
+// static
+QuicDispatcher* QuicServerPeer::GetDispatcher(QuicServer* server) {
+  return server->dispatcher_.get();
+}
+
+// static
+void QuicServerPeer::SetReader(QuicServer* server, QuicPacketReader* reader) {
+  server->packet_reader_.reset(reader);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_server_peer.h b/quic/test_tools/quic_server_peer.h
new file mode 100644
index 0000000..62243d6
--- /dev/null
+++ b/quic/test_tools/quic_server_peer.h
@@ -0,0 +1,30 @@
+// Copyright 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
+
+#include "base/macros.h"
+
+namespace quic {
+
+class QuicDispatcher;
+class QuicServer;
+class QuicPacketReader;
+
+namespace test {
+
+class QuicServerPeer {
+ public:
+  QuicServerPeer() = delete;
+
+  static bool SetSmallSocket(QuicServer* server);
+  static QuicDispatcher* GetDispatcher(QuicServer* server);
+  static void SetReader(QuicServer* server, QuicPacketReader* reader);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SERVER_PEER_H_
diff --git a/quic/test_tools/quic_server_session_base_peer.h b/quic/test_tools/quic_server_session_base_peer.h
new file mode 100644
index 0000000..30c9b22
--- /dev/null
+++ b/quic/test_tools/quic_server_session_base_peer.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SERVER_SESSION_BASE_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SERVER_SESSION_BASE_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+
+namespace quic {
+namespace test {
+
+class QuicServerSessionBasePeer {
+ public:
+  static QuicStream* GetOrCreateDynamicStream(QuicServerSessionBase* s,
+                                              QuicStreamId id) {
+    return s->GetOrCreateDynamicStream(id);
+  }
+  static void SetCryptoStream(QuicServerSessionBase* s,
+                              QuicCryptoServerStream* crypto_stream) {
+    s->crypto_stream_.reset(crypto_stream);
+    s->RegisterStaticStream(
+        QuicUtils::GetCryptoStreamId(s->connection()->transport_version()),
+        crypto_stream);
+  }
+  static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) {
+    return s->bandwidth_resumption_enabled_;
+  }
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SERVER_SESSION_BASE_PEER_H_
diff --git a/quic/test_tools/quic_session_peer.cc b/quic/test_tools/quic_session_peer.cc
new file mode 100644
index 0000000..37e5013
--- /dev/null
+++ b/quic/test_tools/quic_session_peer.cc
@@ -0,0 +1,197 @@
+// 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_session_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+
+namespace quic {
+namespace test {
+
+// static
+QuicStreamId QuicSessionPeer::GetNextOutgoingBidirectionalStreamId(
+    QuicSession* session) {
+  return session->GetNextOutgoingBidirectionalStreamId();
+}
+
+// static
+QuicStreamId QuicSessionPeer::GetNextOutgoingUnidirectionalStreamId(
+    QuicSession* session) {
+  return session->GetNextOutgoingUnidirectionalStreamId();
+}
+
+// static
+void QuicSessionPeer::SetNextOutgoingBidirectionalStreamId(QuicSession* session,
+                                                           QuicStreamId id) {
+  if (session->connection()->transport_version() == QUIC_VERSION_99) {
+    session->v99_streamid_manager_.bidirectional_stream_id_manager_
+        .next_outgoing_stream_id_ = id;
+    return;
+  }
+  session->stream_id_manager_.next_outgoing_stream_id_ = id;
+}
+
+// static
+void QuicSessionPeer::SetMaxOpenIncomingStreams(QuicSession* session,
+                                                uint32_t max_streams) {
+  if (session->connection()->transport_version() == QUIC_VERSION_99) {
+    session->v99_streamid_manager_.SetMaxOpenIncomingStreams(max_streams);
+    return;
+  }
+  session->stream_id_manager_.set_max_open_incoming_streams(max_streams);
+}
+
+// static
+void QuicSessionPeer::SetMaxOpenOutgoingStreams(QuicSession* session,
+                                                uint32_t max_streams) {
+  if (session->connection()->transport_version() == QUIC_VERSION_99) {
+    session->v99_streamid_manager_.SetMaxOpenOutgoingStreams(max_streams);
+    return;
+  }
+  session->stream_id_manager_.set_max_open_outgoing_streams(max_streams);
+}
+
+// static
+QuicCryptoStream* QuicSessionPeer::GetMutableCryptoStream(
+    QuicSession* session) {
+  return session->GetMutableCryptoStream();
+}
+
+// static
+QuicWriteBlockedList* QuicSessionPeer::GetWriteBlockedStreams(
+    QuicSession* session) {
+  return &session->write_blocked_streams_;
+}
+
+// static
+QuicStream* QuicSessionPeer::GetOrCreateDynamicStream(QuicSession* session,
+                                                      QuicStreamId stream_id) {
+  return session->GetOrCreateDynamicStream(stream_id);
+}
+
+// static
+std::map<QuicStreamId, QuicStreamOffset>&
+QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(QuicSession* session) {
+  return session->locally_closed_streams_highest_offset_;
+}
+
+// static
+QuicSession::StaticStreamMap& QuicSessionPeer::static_streams(
+    QuicSession* session) {
+  return session->static_stream_map_;
+}
+
+// static
+QuicSession::DynamicStreamMap& QuicSessionPeer::dynamic_streams(
+    QuicSession* session) {
+  return session->dynamic_streams();
+}
+
+// static
+const QuicSession::ClosedStreams& QuicSessionPeer::closed_streams(
+    QuicSession* session) {
+  return *session->closed_streams();
+}
+
+// static
+QuicSession::ZombieStreamMap& QuicSessionPeer::zombie_streams(
+    QuicSession* session) {
+  return session->zombie_streams_;
+}
+
+// static
+QuicUnorderedSet<QuicStreamId>* QuicSessionPeer::GetDrainingStreams(
+    QuicSession* session) {
+  return &session->draining_streams_;
+}
+
+// static
+void QuicSessionPeer::ActivateStream(QuicSession* session,
+                                     std::unique_ptr<QuicStream> stream) {
+  return session->ActivateStream(std::move(stream));
+}
+
+// static
+bool QuicSessionPeer::IsStreamClosed(QuicSession* session, QuicStreamId id) {
+  DCHECK_NE(0u, id);
+  return session->IsClosedStream(id);
+}
+
+// static
+bool QuicSessionPeer::IsStreamCreated(QuicSession* session, QuicStreamId id) {
+  DCHECK_NE(0u, id);
+  return QuicContainsKey(session->dynamic_streams(), id);
+}
+
+// static
+bool QuicSessionPeer::IsStreamAvailable(QuicSession* session, QuicStreamId id) {
+  DCHECK_NE(0u, id);
+  if (session->connection()->transport_version() == QUIC_VERSION_99) {
+    if (id % kV99StreamIdIncrement < 2) {
+      return QuicContainsKey(
+          session->v99_streamid_manager_.bidirectional_stream_id_manager_
+              .available_streams_,
+          id);
+    }
+    return QuicContainsKey(
+        session->v99_streamid_manager_.unidirectional_stream_id_manager_
+            .available_streams_,
+        id);
+  }
+  return QuicContainsKey(session->stream_id_manager_.available_streams_, id);
+}
+
+// static
+QuicStream* QuicSessionPeer::GetStream(QuicSession* session, QuicStreamId id) {
+  return session->GetStream(id);
+}
+
+// static
+bool QuicSessionPeer::IsStreamWriteBlocked(QuicSession* session,
+                                           QuicStreamId id) {
+  return session->write_blocked_streams_.IsStreamBlocked(id);
+}
+
+// static
+QuicAlarm* QuicSessionPeer::GetCleanUpClosedStreamsAlarm(QuicSession* session) {
+  return session->closed_streams_clean_up_alarm_.get();
+}
+
+// static
+LegacyQuicStreamIdManager* QuicSessionPeer::GetStreamIdManager(
+    QuicSession* session) {
+  return &session->stream_id_manager_;
+}
+
+// static
+UberQuicStreamIdManager* QuicSessionPeer::v99_streamid_manager(
+    QuicSession* session) {
+  return &session->v99_streamid_manager_;
+}
+
+// static
+QuicStreamIdManager* QuicSessionPeer::v99_bidirectional_stream_id_manager(
+    QuicSession* session) {
+  return &session->v99_streamid_manager_.bidirectional_stream_id_manager_;
+}
+
+// static
+QuicStreamIdManager* QuicSessionPeer::v99_unidirectional_stream_id_manager(
+    QuicSession* session) {
+  return &session->v99_streamid_manager_.unidirectional_stream_id_manager_;
+}
+
+// static
+void QuicSessionPeer::SendRstStreamInner(QuicSession* session,
+                                         QuicStreamId id,
+                                         QuicRstStreamErrorCode error,
+                                         QuicStreamOffset bytes_written,
+                                         bool close_write_side_only) {
+  session->SendRstStreamInner(id, error, bytes_written, close_write_side_only);
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_session_peer.h b/quic/test_tools/quic_session_peer.h
new file mode 100644
index 0000000..8c2e72c
--- /dev/null
+++ b/quic/test_tools/quic_session_peer.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
+
+#include <cstdint>
+#include <map>
+#include <memory>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+
+namespace quic {
+
+class QuicCryptoStream;
+class QuicSession;
+class QuicStream;
+
+namespace test {
+
+class QuicSessionPeer {
+ public:
+  QuicSessionPeer() = delete;
+
+  static QuicStreamId GetNextOutgoingBidirectionalStreamId(
+      QuicSession* session);
+  static QuicStreamId GetNextOutgoingUnidirectionalStreamId(
+      QuicSession* session);
+  static void SetNextOutgoingBidirectionalStreamId(QuicSession* session,
+                                                   QuicStreamId id);
+  static void SetMaxOpenIncomingStreams(QuicSession* session,
+                                        uint32_t max_streams);
+  static void SetMaxOpenOutgoingStreams(QuicSession* session,
+                                        uint32_t max_streams);
+  static QuicCryptoStream* GetMutableCryptoStream(QuicSession* session);
+  static QuicWriteBlockedList* GetWriteBlockedStreams(QuicSession* session);
+  static QuicStream* GetOrCreateDynamicStream(QuicSession* session,
+                                              QuicStreamId stream_id);
+  static std::map<QuicStreamId, QuicStreamOffset>&
+  GetLocallyClosedStreamsHighestOffset(QuicSession* session);
+  static QuicSession::StaticStreamMap& static_streams(QuicSession* session);
+  static QuicSession::DynamicStreamMap& dynamic_streams(QuicSession* session);
+  static const QuicSession::ClosedStreams& closed_streams(QuicSession* session);
+  static QuicSession::ZombieStreamMap& zombie_streams(QuicSession* session);
+  static QuicUnorderedSet<QuicStreamId>* GetDrainingStreams(
+      QuicSession* session);
+  static void ActivateStream(QuicSession* session,
+                             std::unique_ptr<QuicStream> stream);
+
+  // Discern the state of a stream.  Exactly one of these should be true at a
+  // time for any stream id > 0 (other than the special streams 1 and 3).
+  static bool IsStreamClosed(QuicSession* session, QuicStreamId id);
+  static bool IsStreamCreated(QuicSession* session, QuicStreamId id);
+  static bool IsStreamAvailable(QuicSession* session, QuicStreamId id);
+
+  static QuicStream* GetStream(QuicSession* session, QuicStreamId id);
+  static bool IsStreamWriteBlocked(QuicSession* session, QuicStreamId id);
+  static QuicAlarm* GetCleanUpClosedStreamsAlarm(QuicSession* session);
+  static LegacyQuicStreamIdManager* GetStreamIdManager(QuicSession* session);
+  static UberQuicStreamIdManager* v99_streamid_manager(QuicSession* session);
+  static QuicStreamIdManager* v99_bidirectional_stream_id_manager(
+      QuicSession* session);
+  static QuicStreamIdManager* v99_unidirectional_stream_id_manager(
+      QuicSession* session);
+  static void SendRstStreamInner(QuicSession* session,
+                                 QuicStreamId id,
+                                 QuicRstStreamErrorCode error,
+                                 QuicStreamOffset bytes_written,
+                                 bool close_write_side_only);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
diff --git a/quic/test_tools/quic_spdy_session_peer.cc b/quic/test_tools/quic_spdy_session_peer.cc
new file mode 100644
index 0000000..b739fa1
--- /dev/null
+++ b/quic/test_tools/quic_spdy_session_peer.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2015 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_spdy_session_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+
+namespace quic {
+namespace test {
+
+// static
+QuicHeadersStream* QuicSpdySessionPeer::GetHeadersStream(
+    QuicSpdySession* session) {
+  return session->headers_stream_.get();
+}
+
+// static
+void QuicSpdySessionPeer::SetHeadersStream(QuicSpdySession* session,
+                                           QuicHeadersStream* headers_stream) {
+  session->headers_stream_.reset(headers_stream);
+  if (headers_stream != nullptr) {
+    session->RegisterStaticStream(headers_stream->id(), headers_stream);
+  }
+}
+
+// static
+const spdy::SpdyFramer& QuicSpdySessionPeer::GetSpdyFramer(
+    QuicSpdySession* session) {
+  return session->spdy_framer_;
+}
+
+void QuicSpdySessionPeer::SetHpackEncoderDebugVisitor(
+    QuicSpdySession* session,
+    std::unique_ptr<QuicHpackDebugVisitor> visitor) {
+  session->SetHpackEncoderDebugVisitor(std::move(visitor));
+}
+
+void QuicSpdySessionPeer::SetHpackDecoderDebugVisitor(
+    QuicSpdySession* session,
+    std::unique_ptr<QuicHpackDebugVisitor> visitor) {
+  session->SetHpackDecoderDebugVisitor(std::move(visitor));
+}
+
+void QuicSpdySessionPeer::SetMaxUncompressedHeaderBytes(
+    QuicSpdySession* session,
+    size_t set_max_uncompressed_header_bytes) {
+  session->set_max_uncompressed_header_bytes(set_max_uncompressed_header_bytes);
+}
+
+// static
+size_t QuicSpdySessionPeer::WriteHeadersOnHeadersStream(
+    QuicSpdySession* session,
+    QuicStreamId id,
+    spdy::SpdyHeaderBlock headers,
+    bool fin,
+    spdy::SpdyPriority priority,
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+  return session->WriteHeadersOnHeadersStream(
+      id, std::move(headers), fin, priority, std::move(ack_listener));
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_spdy_session_peer.h b/quic/test_tools/quic_spdy_session_peer.h
new file mode 100644
index 0000000..1993ec5
--- /dev/null
+++ b/quic/test_tools/quic_spdy_session_peer.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2015 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
+
+namespace quic {
+
+class QuicHeadersStream;
+class QuicSpdySession;
+class QuicHpackDebugVisitor;
+
+namespace test {
+
+class QuicSpdySessionPeer {
+ public:
+  QuicSpdySessionPeer() = delete;
+
+  static QuicHeadersStream* GetHeadersStream(QuicSpdySession* session);
+  static void SetHeadersStream(QuicSpdySession* session,
+                               QuicHeadersStream* headers_stream);
+  static const spdy::SpdyFramer& GetSpdyFramer(QuicSpdySession* session);
+  static void SetHpackEncoderDebugVisitor(
+      QuicSpdySession* session,
+      std::unique_ptr<QuicHpackDebugVisitor> visitor);
+  static void SetHpackDecoderDebugVisitor(
+      QuicSpdySession* session,
+      std::unique_ptr<QuicHpackDebugVisitor> visitor);
+  static void SetMaxUncompressedHeaderBytes(
+      QuicSpdySession* session,
+      size_t set_max_uncompressed_header_bytes);
+  static size_t WriteHeadersOnHeadersStream(
+      QuicSpdySession* session,
+      QuicStreamId id,
+      spdy::SpdyHeaderBlock headers,
+      bool fin,
+      spdy::SpdyPriority priority,
+      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
diff --git a/quic/test_tools/quic_spdy_stream_peer.cc b/quic/test_tools/quic_spdy_stream_peer.cc
new file mode 100644
index 0000000..6632ec1
--- /dev/null
+++ b/quic/test_tools/quic_spdy_stream_peer.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2019 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_spdy_stream_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicSpdyStreamPeer::set_ack_listener(
+    QuicSpdyStream* stream,
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+  stream->set_ack_listener(std::move(ack_listener));
+}
+
+// static
+const QuicIntervalSet<QuicStreamOffset>&
+QuicSpdyStreamPeer::unacked_frame_headers_offsets(QuicSpdyStream* stream) {
+  return stream->unacked_frame_headers_offsets();
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_spdy_stream_peer.h b/quic/test_tools/quic_spdy_stream_peer.h
new file mode 100644
index 0000000..7b3fe7c
--- /dev/null
+++ b/quic/test_tools/quic_spdy_stream_peer.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+
+namespace quic {
+
+class QuicSpdyStream;
+
+namespace test {
+
+class QuicSpdyStreamPeer {
+ public:
+  static void set_ack_listener(
+      QuicSpdyStream* stream,
+      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+  static const QuicIntervalSet<QuicStreamOffset>& unacked_frame_headers_offsets(
+      QuicSpdyStream* stream);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
diff --git a/quic/test_tools/quic_stream_id_manager_peer.cc b/quic/test_tools/quic_stream_id_manager_peer.cc
new file mode 100644
index 0000000..705ee27
--- /dev/null
+++ b/quic/test_tools/quic_stream_id_manager_peer.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2018 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_stream_id_manager_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicStreamIdManagerPeer::IncrementMaximumAllowedOutgoingStreamId(
+    QuicStreamIdManager* stream_id_manager,
+    int increment) {
+  stream_id_manager->max_allowed_outgoing_stream_id_ +=
+      (increment * kV99StreamIdIncrement);
+}
+
+// static
+void QuicStreamIdManagerPeer::IncrementMaximumAllowedIncomingStreamId(
+    QuicStreamIdManager* stream_id_manager,
+    int increment) {
+  stream_id_manager->actual_max_allowed_incoming_stream_id_ +=
+      (increment * kV99StreamIdIncrement);
+  stream_id_manager->advertised_max_allowed_incoming_stream_id_ +=
+      (increment * kV99StreamIdIncrement);
+}
+
+// static
+void QuicStreamIdManagerPeer::SetMaxOpenIncomingStreams(
+    QuicStreamIdManager* stream_id_manager,
+    size_t max_streams) {
+  stream_id_manager->SetMaxOpenIncomingStreams(max_streams);
+}
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_stream_id_manager_peer.h b/quic/test_tools/quic_stream_id_manager_peer.h
new file mode 100644
index 0000000..2ec07b1
--- /dev/null
+++ b/quic/test_tools/quic_stream_id_manager_peer.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2018 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.
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_ID_MANAGER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_ID_MANAGER_PEER_H_
+
+#include <stddef.h>
+
+namespace quic {
+
+class QuicStreamIdManager;
+
+namespace test {
+
+class QuicStreamIdManagerPeer {
+ public:
+  QuicStreamIdManagerPeer() = delete;
+  static void IncrementMaximumAllowedOutgoingStreamId(
+      QuicStreamIdManager* stream_id_manager,
+      int increment);
+  static void IncrementMaximumAllowedIncomingStreamId(
+      QuicStreamIdManager* stream_id_manager,
+      int increment);
+  static void SetMaxOpenIncomingStreams(QuicStreamIdManager* stream_id_manager,
+                                        size_t max_streams);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
diff --git a/quic/test_tools/quic_stream_peer.cc b/quic/test_tools/quic_stream_peer.cc
new file mode 100644
index 0000000..7607523
--- /dev/null
+++ b/quic/test_tools/quic_stream_peer.cc
@@ -0,0 +1,91 @@
+// 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_stream_peer.h"
+
+#include <list>
+
+#include "net/third_party/quiche/src/quic/core/quic_stream.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicStreamPeer::SetWriteSideClosed(bool value, QuicStream* stream) {
+  stream->write_side_closed_ = value;
+}
+
+// static
+void QuicStreamPeer::SetStreamBytesWritten(
+    QuicStreamOffset stream_bytes_written,
+    QuicStream* stream) {
+  stream->send_buffer_.stream_bytes_written_ = stream_bytes_written;
+  stream->send_buffer_.stream_bytes_outstanding_ = stream_bytes_written;
+  QuicStreamSendBufferPeer::SetStreamOffset(&stream->send_buffer_,
+                                            stream_bytes_written);
+}
+
+// static
+bool QuicStreamPeer::read_side_closed(QuicStream* stream) {
+  return stream->read_side_closed();
+}
+
+// static
+bool QuicStreamPeer::write_side_closed(QuicStream* stream) {
+  return stream->write_side_closed();
+}
+
+// static
+void QuicStreamPeer::CloseReadSide(QuicStream* stream) {
+  stream->CloseReadSide();
+}
+
+// static
+bool QuicStreamPeer::FinSent(QuicStream* stream) {
+  return stream->fin_sent_;
+}
+
+// static
+bool QuicStreamPeer::RstSent(QuicStream* stream) {
+  return stream->rst_sent_;
+}
+
+// static
+uint32_t QuicStreamPeer::SizeOfQueuedData(QuicStream* stream) {
+  return stream->BufferedDataBytes();
+}
+
+// static
+bool QuicStreamPeer::StreamContributesToConnectionFlowControl(
+    QuicStream* stream) {
+  return stream->stream_contributes_to_connection_flow_control_;
+}
+
+// static
+void QuicStreamPeer::WriteOrBufferData(
+    QuicStream* stream,
+    QuicStringPiece data,
+    bool fin,
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
+  stream->WriteOrBufferData(data, fin, std::move(ack_listener));
+}
+
+// static
+QuicStreamSequencer* QuicStreamPeer::sequencer(QuicStream* stream) {
+  return &(stream->sequencer_);
+}
+
+// static
+QuicSession* QuicStreamPeer::session(QuicStream* stream) {
+  return stream->session();
+}
+
+// static
+QuicStreamSendBuffer& QuicStreamPeer::SendBuffer(QuicStream* stream) {
+  return stream->send_buffer_;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_stream_peer.h b/quic/test_tools/quic_stream_peer.h
new file mode 100644
index 0000000..e0058ba
--- /dev/null
+++ b/quic/test_tools/quic_stream_peer.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_PEER_H_
+
+#include <cstdint>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+class QuicStream;
+class QuicSession;
+
+namespace test {
+
+class QuicStreamPeer {
+ public:
+  QuicStreamPeer() = delete;
+
+  static void SetWriteSideClosed(bool value, QuicStream* stream);
+  static void SetStreamBytesWritten(QuicStreamOffset stream_bytes_written,
+                                    QuicStream* stream);
+  static bool write_side_closed(QuicStream* stream);
+  static bool read_side_closed(QuicStream* stream);
+  static void CloseReadSide(QuicStream* stream);
+
+  static bool FinSent(QuicStream* stream);
+  static bool RstSent(QuicStream* stream);
+
+  static uint32_t SizeOfQueuedData(QuicStream* stream);
+
+  static bool StreamContributesToConnectionFlowControl(QuicStream* stream);
+
+  static void WriteOrBufferData(
+      QuicStream* stream,
+      QuicStringPiece data,
+      bool fin,
+      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+
+  static QuicStreamSequencer* sequencer(QuicStream* stream);
+  static QuicSession* session(QuicStream* stream);
+
+  static QuicStreamSendBuffer& SendBuffer(QuicStream* stream);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_PEER_H_
diff --git a/quic/test_tools/quic_stream_send_buffer_peer.cc b/quic/test_tools/quic_stream_send_buffer_peer.cc
new file mode 100644
index 0000000..22e5e56
--- /dev/null
+++ b/quic/test_tools/quic_stream_send_buffer_peer.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 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_stream_send_buffer_peer.h"
+
+namespace quic {
+
+namespace test {
+
+// static
+void QuicStreamSendBufferPeer::SetStreamOffset(
+    QuicStreamSendBuffer* send_buffer,
+    QuicStreamOffset stream_offset) {
+  send_buffer->stream_offset_ = stream_offset;
+}
+
+// static
+const BufferedSlice* QuicStreamSendBufferPeer::CurrentWriteSlice(
+    QuicStreamSendBuffer* send_buffer) {
+  if (send_buffer->write_index_ == -1) {
+    return nullptr;
+  }
+  return &send_buffer->buffered_slices_[send_buffer->write_index_];
+}
+
+// static
+QuicByteCount QuicStreamSendBufferPeer::TotalLength(
+    QuicStreamSendBuffer* send_buffer) {
+  QuicByteCount length = 0;
+  for (const auto& slice : send_buffer->buffered_slices_) {
+    length += slice.slice.length();
+  }
+  return length;
+}
+
+}  // namespace test
+
+}  // namespace quic
diff --git a/quic/test_tools/quic_stream_send_buffer_peer.h b/quic/test_tools/quic_stream_send_buffer_peer.h
new file mode 100644
index 0000000..f61cb00
--- /dev/null
+++ b/quic/test_tools/quic_stream_send_buffer_peer.h
@@ -0,0 +1,29 @@
+// Copyright 2017 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEND_BUFFER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEND_BUFFER_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h"
+
+namespace quic {
+
+namespace test {
+
+class QuicStreamSendBufferPeer {
+ public:
+  static void SetStreamOffset(QuicStreamSendBuffer* send_buffer,
+                              QuicStreamOffset stream_offset);
+
+  static const BufferedSlice* CurrentWriteSlice(
+      QuicStreamSendBuffer* send_buffer);
+
+  static QuicByteCount TotalLength(QuicStreamSendBuffer* send_buffer);
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEND_BUFFER_PEER_H_
diff --git a/quic/test_tools/quic_stream_sequencer_buffer_peer.cc b/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
new file mode 100644
index 0000000..9c96c82
--- /dev/null
+++ b/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
@@ -0,0 +1,155 @@
+// Copyright 2016 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_stream_sequencer_buffer_peer.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_test.h"
+
+typedef quic::QuicStreamSequencerBuffer::BufferBlock BufferBlock;
+
+static const size_t kBlockSizeBytes =
+    quic::QuicStreamSequencerBuffer::kBlockSizeBytes;
+
+namespace quic {
+namespace test {
+
+QuicStreamSequencerBufferPeer::QuicStreamSequencerBufferPeer(
+    QuicStreamSequencerBuffer* buffer)
+    : buffer_(buffer) {}
+
+// Read from this buffer_ into the given destination buffer_ up to the
+// size of the destination. Returns the number of bytes read. Reading from
+// an empty buffer_->returns 0.
+size_t QuicStreamSequencerBufferPeer::Read(char* dest_buffer, size_t size) {
+  iovec dest;
+  dest.iov_base = dest_buffer, dest.iov_len = size;
+  size_t bytes_read;
+  QuicString error_details;
+  EXPECT_EQ(QUIC_NO_ERROR,
+            buffer_->Readv(&dest, 1, &bytes_read, &error_details));
+  return bytes_read;
+}
+
+// If buffer is empty, the blocks_ array must be empty, which means all
+// blocks are deallocated.
+bool QuicStreamSequencerBufferPeer::CheckEmptyInvariants() {
+  return !buffer_->Empty() || IsBlockArrayEmpty();
+}
+
+bool QuicStreamSequencerBufferPeer::IsBlockArrayEmpty() {
+  if (buffer_->blocks_ == nullptr) {
+    return true;
+  }
+
+  size_t count = buffer_->blocks_count_;
+  for (size_t i = 0; i < count; i++) {
+    if (buffer_->blocks_[i] != nullptr) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool QuicStreamSequencerBufferPeer::CheckInitialState() {
+  EXPECT_TRUE(buffer_->Empty() && buffer_->total_bytes_read_ == 0 &&
+              buffer_->num_bytes_buffered_ == 0);
+  return CheckBufferInvariants();
+}
+
+bool QuicStreamSequencerBufferPeer::CheckBufferInvariants() {
+  QuicStreamOffset data_span =
+      buffer_->NextExpectedByte() - buffer_->total_bytes_read_;
+  bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ &&
+                       data_span >= buffer_->num_bytes_buffered_;
+  if (!capacity_sane) {
+    QUIC_LOG(ERROR) << "data span is larger than capacity.";
+    QUIC_LOG(ERROR) << "total read: " << buffer_->total_bytes_read_
+                    << " last byte: " << buffer_->NextExpectedByte();
+  }
+  bool total_read_sane =
+      buffer_->FirstMissingByte() >= buffer_->total_bytes_read_;
+  if (!total_read_sane) {
+    QUIC_LOG(ERROR) << "read across 1st gap.";
+  }
+  bool read_offset_sane = buffer_->ReadOffset() < kBlockSizeBytes;
+  if (!capacity_sane) {
+    QUIC_LOG(ERROR) << "read offset go beyond 1st block";
+  }
+  bool block_match_capacity = (buffer_->max_buffer_capacity_bytes_ <=
+                               buffer_->blocks_count_ * kBlockSizeBytes) &&
+                              (buffer_->max_buffer_capacity_bytes_ >
+                               (buffer_->blocks_count_ - 1) * kBlockSizeBytes);
+  if (!capacity_sane) {
+    QUIC_LOG(ERROR) << "block number not match capcaity.";
+  }
+  bool block_retired_when_empty = CheckEmptyInvariants();
+  if (!block_retired_when_empty) {
+    QUIC_LOG(ERROR) << "block is not retired after use.";
+  }
+  return capacity_sane && total_read_sane && read_offset_sane &&
+         block_match_capacity && block_retired_when_empty;
+}
+
+size_t QuicStreamSequencerBufferPeer::GetInBlockOffset(
+    QuicStreamOffset offset) {
+  return buffer_->GetInBlockOffset(offset);
+}
+
+BufferBlock* QuicStreamSequencerBufferPeer::GetBlock(size_t index) {
+  return buffer_->blocks_[index];
+}
+
+int QuicStreamSequencerBufferPeer::IntervalSize() {
+  if (buffer_->bytes_received_.Empty()) {
+    return 1;
+  }
+  int gap_size = buffer_->bytes_received_.Size() + 1;
+  if (buffer_->bytes_received_.Empty()) {
+    return gap_size;
+  }
+  if (buffer_->bytes_received_.begin()->min() == 0) {
+    --gap_size;
+  }
+  if (buffer_->bytes_received_.rbegin()->max() ==
+      std::numeric_limits<uint64_t>::max()) {
+    --gap_size;
+  }
+  return gap_size;
+}
+
+size_t QuicStreamSequencerBufferPeer::max_buffer_capacity() {
+  return buffer_->max_buffer_capacity_bytes_;
+}
+
+size_t QuicStreamSequencerBufferPeer::ReadableBytes() {
+  return buffer_->ReadableBytes();
+}
+
+void QuicStreamSequencerBufferPeer::set_total_bytes_read(
+    QuicStreamOffset total_bytes_read) {
+  buffer_->total_bytes_read_ = total_bytes_read;
+}
+
+void QuicStreamSequencerBufferPeer::AddBytesReceived(QuicStreamOffset offset,
+                                                     QuicByteCount length) {
+  buffer_->bytes_received_.Add(offset, offset + length);
+}
+
+bool QuicStreamSequencerBufferPeer::IsBufferAllocated() {
+  return buffer_->blocks_ != nullptr;
+}
+
+size_t QuicStreamSequencerBufferPeer::block_count() {
+  return buffer_->blocks_count_;
+}
+
+const QuicIntervalSet<QuicStreamOffset>&
+QuicStreamSequencerBufferPeer::bytes_received() {
+  return buffer_->bytes_received_;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_stream_sequencer_buffer_peer.h b/quic/test_tools/quic_stream_sequencer_buffer_peer.h
new file mode 100644
index 0000000..da2d054
--- /dev/null
+++ b/quic/test_tools/quic_stream_sequencer_buffer_peer.h
@@ -0,0 +1,63 @@
+// Copyright 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_BUFFER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_BUFFER_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h"
+
+namespace quic {
+
+namespace test {
+
+class QuicStreamSequencerBufferPeer {
+ public:
+  explicit QuicStreamSequencerBufferPeer(QuicStreamSequencerBuffer* buffer);
+  QuicStreamSequencerBufferPeer(const QuicStreamSequencerBufferPeer&) = delete;
+  QuicStreamSequencerBufferPeer& operator=(
+      const QuicStreamSequencerBufferPeer&) = delete;
+
+  // Read from this buffer_ into the given destination buffer_ up to the
+  // size of the destination. Returns the number of bytes read. Reading from
+  // an empty buffer_->returns 0.
+  size_t Read(char* dest_buffer, size_t size);
+
+  // If buffer is empty, the blocks_ array must be empty, which means all
+  // blocks are deallocated.
+  bool CheckEmptyInvariants();
+
+  bool IsBlockArrayEmpty();
+
+  bool CheckInitialState();
+
+  bool CheckBufferInvariants();
+
+  size_t GetInBlockOffset(QuicStreamOffset offset);
+
+  QuicStreamSequencerBuffer::BufferBlock* GetBlock(size_t index);
+
+  int IntervalSize();
+
+  size_t max_buffer_capacity();
+
+  size_t ReadableBytes();
+
+  void set_total_bytes_read(QuicStreamOffset total_bytes_read);
+
+  void AddBytesReceived(QuicStreamOffset offset, QuicByteCount length);
+
+  bool IsBufferAllocated();
+
+  size_t block_count();
+
+  const QuicIntervalSet<QuicStreamOffset>& bytes_received();
+
+ private:
+  QuicStreamSequencerBuffer* buffer_;
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_BUFFER_PEER_H_
diff --git a/quic/test_tools/quic_stream_sequencer_peer.cc b/quic/test_tools/quic_stream_sequencer_peer.cc
new file mode 100644
index 0000000..05cf35c
--- /dev/null
+++ b/quic/test_tools/quic_stream_sequencer_peer.cc
@@ -0,0 +1,40 @@
+// Copyright 2014 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_stream_sequencer_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_stream_sequencer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_buffer_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+size_t QuicStreamSequencerPeer::GetNumBufferedBytes(
+    QuicStreamSequencer* sequencer) {
+  return sequencer->buffered_frames_.BytesBuffered();
+}
+
+// static
+QuicStreamOffset QuicStreamSequencerPeer::GetCloseOffset(
+    QuicStreamSequencer* sequencer) {
+  return sequencer->close_offset_;
+}
+
+// static
+bool QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(
+    QuicStreamSequencer* sequencer) {
+  QuicStreamSequencerBufferPeer buffer_peer(&(sequencer->buffered_frames_));
+  return buffer_peer.IsBufferAllocated();
+}
+
+// static
+void QuicStreamSequencerPeer::SetFrameBufferTotalBytesRead(
+    QuicStreamSequencer* sequencer,
+    QuicStreamOffset total_bytes_read) {
+  QuicStreamSequencerBufferPeer buffer_peer(&(sequencer->buffered_frames_));
+  buffer_peer.set_total_bytes_read(total_bytes_read);
+}
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_stream_sequencer_peer.h b/quic/test_tools/quic_stream_sequencer_peer.h
new file mode 100644
index 0000000..c317209
--- /dev/null
+++ b/quic/test_tools/quic_stream_sequencer_peer.h
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+
+class QuicStreamSequencer;
+
+namespace test {
+
+class QuicStreamSequencerPeer {
+ public:
+  QuicStreamSequencerPeer() = delete;
+
+  static size_t GetNumBufferedBytes(QuicStreamSequencer* sequencer);
+
+  static QuicStreamOffset GetCloseOffset(QuicStreamSequencer* sequencer);
+
+  static bool IsUnderlyingBufferAllocated(QuicStreamSequencer* sequencer);
+
+  static void SetFrameBufferTotalBytesRead(QuicStreamSequencer* sequencer,
+                                           QuicStreamOffset total_bytes_read);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_PEER_H_
diff --git a/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc b/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc
new file mode 100644
index 0000000..9f08faf
--- /dev/null
+++ b/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 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_sustained_bandwidth_recorder_peer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_sustained_bandwidth_recorder.h"
+
+namespace quic {
+namespace test {
+
+// static
+void QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate(
+    QuicSustainedBandwidthRecorder* bandwidth_recorder,
+    int32_t bandwidth_estimate_kbytes_per_second) {
+  bandwidth_recorder->has_estimate_ = true;
+  bandwidth_recorder->bandwidth_estimate_ =
+      QuicBandwidth::FromKBytesPerSecond(bandwidth_estimate_kbytes_per_second);
+}
+
+// static
+void QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate(
+    QuicSustainedBandwidthRecorder* bandwidth_recorder,
+    int32_t max_bandwidth_estimate_kbytes_per_second,
+    int32_t max_bandwidth_timestamp) {
+  bandwidth_recorder->max_bandwidth_estimate_ =
+      QuicBandwidth::FromKBytesPerSecond(
+          max_bandwidth_estimate_kbytes_per_second);
+  bandwidth_recorder->max_bandwidth_timestamp_ = max_bandwidth_timestamp;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h b/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h
new file mode 100644
index 0000000..f73e00c
--- /dev/null
+++ b/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h
@@ -0,0 +1,36 @@
+// Copyright 2014 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_SUSTAINED_BANDWIDTH_RECORDER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_SUSTAINED_BANDWIDTH_RECORDER_PEER_H_
+
+#include <cstdint>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+
+class QuicSustainedBandwidthRecorder;
+
+namespace test {
+
+class QuicSustainedBandwidthRecorderPeer {
+ public:
+  QuicSustainedBandwidthRecorderPeer() = delete;
+
+  static void SetBandwidthEstimate(
+      QuicSustainedBandwidthRecorder* bandwidth_recorder,
+      int32_t bandwidth_estimate_kbytes_per_second);
+
+  static void SetMaxBandwidthEstimate(
+      QuicSustainedBandwidthRecorder* bandwidth_recorder,
+      int32_t max_bandwidth_estimate_kbytes_per_second,
+      int32_t max_bandwidth_timestamp);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_SUSTAINED_BANDWIDTH_RECORDER_PEER_H_
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
diff --git a/quic/test_tools/quic_test_client.h b/quic/test_tools/quic_test_client.h
new file mode 100644
index 0000000..f9cc532
--- /dev/null
+++ b/quic/test_tools/quic_test_client.h
@@ -0,0 +1,413 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/tools/quic_client.h"
+
+namespace quic {
+
+class ProofVerifier;
+class QuicPacketWriterWrapper;
+
+namespace test {
+
+class MockableQuicClientEpollNetworkHelper;
+
+// A quic client which allows mocking out reads and writes.
+class MockableQuicClient : public QuicClient {
+ public:
+  MockableQuicClient(QuicSocketAddress server_address,
+                     const QuicServerId& server_id,
+                     const ParsedQuicVersionVector& supported_versions,
+                     QuicEpollServer* epoll_server);
+
+  MockableQuicClient(QuicSocketAddress server_address,
+                     const QuicServerId& server_id,
+                     const QuicConfig& config,
+                     const ParsedQuicVersionVector& supported_versions,
+                     QuicEpollServer* epoll_server);
+
+  MockableQuicClient(QuicSocketAddress server_address,
+                     const QuicServerId& server_id,
+                     const QuicConfig& config,
+                     const ParsedQuicVersionVector& supported_versions,
+                     QuicEpollServer* epoll_server,
+                     std::unique_ptr<ProofVerifier> proof_verifier);
+  MockableQuicClient(const MockableQuicClient&) = delete;
+  MockableQuicClient& operator=(const MockableQuicClient&) = delete;
+
+  ~MockableQuicClient() override;
+
+  QuicConnectionId GenerateNewConnectionId() override;
+  void UseConnectionId(QuicConnectionId connection_id);
+
+  void UseWriter(QuicPacketWriterWrapper* writer);
+  void set_peer_address(const QuicSocketAddress& address);
+  // The last incoming packet, iff |track_last_incoming_packet| is true.
+  const QuicReceivedPacket* last_incoming_packet();
+  // If true, copy each packet from ProcessPacket into |last_incoming_packet|
+  void set_track_last_incoming_packet(bool track);
+
+  // Casts the network helper to a MockableQuicClientEpollNetworkHelper.
+  MockableQuicClientEpollNetworkHelper* mockable_network_helper();
+  const MockableQuicClientEpollNetworkHelper* mockable_network_helper() const;
+
+ private:
+  // ConnectionId to use, if connection_id_overridden_
+  QuicConnectionId override_connection_id_;
+  bool connection_id_overridden_;
+  CachedNetworkParameters cached_network_paramaters_;
+};
+
+// A toy QUIC client used for testing.
+class QuicTestClient : public QuicSpdyStream::Visitor,
+                       public QuicClientPushPromiseIndex::Delegate {
+ public:
+  QuicTestClient(QuicSocketAddress server_address,
+                 const QuicString& server_hostname,
+                 const ParsedQuicVersionVector& supported_versions);
+  QuicTestClient(QuicSocketAddress server_address,
+                 const QuicString& server_hostname,
+                 const QuicConfig& config,
+                 const ParsedQuicVersionVector& supported_versions);
+  QuicTestClient(QuicSocketAddress server_address,
+                 const QuicString& server_hostname,
+                 const QuicConfig& config,
+                 const ParsedQuicVersionVector& supported_versions,
+                 std::unique_ptr<ProofVerifier> proof_verifier);
+
+  ~QuicTestClient() override;
+
+  // Sets the |user_agent_id| of the |client_|.
+  void SetUserAgentID(const QuicString& user_agent_id);
+
+  // Wraps data in a quic packet and sends it.
+  ssize_t SendData(const QuicString& data, bool last_data);
+  // As above, but |delegate| will be notified when |data| is ACKed.
+  ssize_t SendData(
+      const QuicString& data,
+      bool last_data,
+      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+
+  // Clears any outstanding state and sends a simple GET of 'uri' to the
+  // server.  Returns 0 if the request failed and no bytes were written.
+  ssize_t SendRequest(const QuicString& uri);
+  // Send a request R and a RST_FRAME which resets R, in the same packet.
+  ssize_t SendRequestAndRstTogether(const QuicString& uri);
+  // Sends requests for all the urls and waits for the responses.  To process
+  // the individual responses as they are returned, the caller should use the
+  // set the response_listener on the client().
+  void SendRequestsAndWaitForResponses(const std::vector<QuicString>& url_list);
+  // Sends a request containing |headers| and |body| and returns the number of
+  // bytes sent (the size of the serialized request headers and body).
+  ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
+                      QuicStringPiece body);
+  // Sends a request containing |headers| and |body| with the fin bit set to
+  // |fin| and returns the number of bytes sent (the size of the serialized
+  // request headers and body).
+  ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
+                      QuicStringPiece body,
+                      bool fin);
+  // Sends a request containing |headers| and |body| with the fin bit set to
+  // |fin| and returns the number of bytes sent (the size of the serialized
+  // request headers and body). If |flush| is true, will wait for the message to
+  // be flushed before returning.
+  ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
+                      QuicStringPiece body,
+                      bool fin,
+                      bool flush);
+  // Sends a request containing |headers| and |body|, waits for the response,
+  // and returns the response body.
+  QuicString SendCustomSynchronousRequest(const spdy::SpdyHeaderBlock& headers,
+                                          const QuicString& body);
+  // Sends a GET request for |uri|, waits for the response, and returns the
+  // response body.
+  QuicString SendSynchronousRequest(const QuicString& uri);
+  void SendConnectivityProbing();
+  void Connect();
+  void ResetConnection();
+  void Disconnect();
+  QuicSocketAddress local_address() const;
+  void ClearPerRequestState();
+  bool WaitUntil(int timeout_ms, std::function<bool()> trigger);
+  ssize_t Send(const void* buffer, size_t size);
+  bool connected() const;
+  bool buffer_body() const;
+  void set_buffer_body(bool buffer_body);
+
+  // Getters for stream state. Please note, these getters are divided into two
+  // groups. 1) returns state which only get updated once a complete response
+  // is received. 2) returns state of the oldest active stream which have
+  // received partial response (if any).
+  // Group 1.
+  const spdy::SpdyHeaderBlock& response_trailers() const;
+  bool response_complete() const;
+  int64_t response_body_size() const;
+  const QuicString& response_body() const;
+  // Group 2.
+  bool response_headers_complete() const;
+  const spdy::SpdyHeaderBlock* response_headers() const;
+  const spdy::SpdyHeaderBlock* preliminary_headers() const;
+  int64_t response_size() const;
+  size_t bytes_read() const;
+  size_t bytes_written() const;
+
+  // Returns once at least one complete response or a connection close has been
+  // received from the server. If responses are received for multiple (say 2)
+  // streams, next WaitForResponse will return immediately.
+  void WaitForResponse() { WaitForResponseForMs(-1); }
+
+  // Returns once some data is received on any open streams or at least one
+  // complete response is received from the server.
+  void WaitForInitialResponse() { WaitForInitialResponseForMs(-1); }
+
+  // Returns once at least one complete response or a connection close has been
+  // received from the server, or once the timeout expires. -1 means no timeout.
+  // If responses are received for multiple (say 2) streams, next
+  // WaitForResponseForMs will return immediately.
+  void WaitForResponseForMs(int timeout_ms) {
+    WaitUntil(timeout_ms, [this]() { return !closed_stream_states_.empty(); });
+    if (response_complete()) {
+      VLOG(1) << "Client received response:"
+              << response_headers()->DebugString() << response_body();
+    }
+  }
+
+  // Returns once some data is received on any open streams or at least one
+  // complete response is received from the server, or once the timeout
+  // expires. -1 means no timeout.
+  void WaitForInitialResponseForMs(int timeout_ms) {
+    WaitUntil(timeout_ms, [this]() { return response_size() != 0; });
+  }
+
+  // Migrate local address to <|new_host|, a random port>.
+  // Return whether the migration succeeded.
+  bool MigrateSocket(const QuicIpAddress& new_host);
+  // Migrate local address to <|new_host|, |port|>.
+  // Return whether the migration succeeded.
+  bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port);
+  QuicIpAddress bind_to_address() const;
+  void set_bind_to_address(QuicIpAddress address);
+  const QuicSocketAddress& address() const;
+
+  // From QuicSpdyStream::Visitor
+  void OnClose(QuicSpdyStream* stream) override;
+
+  // From QuicClientPushPromiseIndex::Delegate
+  bool CheckVary(const spdy::SpdyHeaderBlock& client_request,
+                 const spdy::SpdyHeaderBlock& promise_request,
+                 const spdy::SpdyHeaderBlock& promise_response) override;
+  void OnRendezvousResult(QuicSpdyStream*) override;
+
+  // Configures client_ to take ownership of and use the writer.
+  // Must be called before initial connect.
+  void UseWriter(QuicPacketWriterWrapper* writer);
+  // If the given ConnectionId is nonzero, configures client_ to use a specific
+  // ConnectionId instead of a random one.
+  void UseConnectionId(QuicConnectionId connection_id);
+
+  // Returns nullptr if the maximum number of streams have already been created.
+  QuicSpdyClientStream* GetOrCreateStream();
+
+  // Calls GetOrCreateStream(), sends the request on the stream, and
+  // stores the request in case it needs to be resent.  If |headers| is
+  // null, only the body will be sent on the stream.
+  ssize_t GetOrCreateStreamAndSendRequest(
+      const spdy::SpdyHeaderBlock* headers,
+      QuicStringPiece body,
+      bool fin,
+      QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+
+  QuicRstStreamErrorCode stream_error() { return stream_error_; }
+  QuicErrorCode connection_error();
+
+  MockableQuicClient* client();
+
+  // cert_common_name returns the common name value of the server's certificate,
+  // or the empty QuicString if no certificate was presented.
+  const QuicString& cert_common_name() const;
+
+  // cert_sct returns the signed timestamp of the server's certificate,
+  // or the empty QuicString if no signed timestamp was presented.
+  const QuicString& cert_sct() const;
+
+  // Get the server config map.
+  QuicTagValueMap GetServerConfig() const;
+
+  void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
+
+  void set_priority(spdy::SpdyPriority priority) { priority_ = priority; }
+
+  void WaitForWriteToFlush();
+
+  QuicEpollServer* epoll_server() { return &epoll_server_; }
+
+  size_t num_requests() const { return num_requests_; }
+
+  size_t num_responses() const { return num_responses_; }
+
+  void set_server_address(const QuicSocketAddress& server_address) {
+    client_->set_server_address(server_address);
+  }
+
+  void set_peer_address(const QuicSocketAddress& address) {
+    client_->set_peer_address(address);
+  }
+
+  // Explicitly set the SNI value for this client, overriding the default
+  // behavior which extracts the SNI value from the request URL.
+  void OverrideSni(const QuicString& sni) {
+    override_sni_set_ = true;
+    override_sni_ = sni;
+  }
+
+  void Initialize();
+
+  void set_client(MockableQuicClient* client) { client_.reset(client); }
+
+  // Given |uri|, populates the fields in |headers| for a simple GET
+  // request. If |uri| is a relative URL, the QuicServerId will be
+  // use to specify the authority.
+  bool PopulateHeaderBlockFromUrl(const QuicString& uri,
+                                  spdy::SpdyHeaderBlock* headers);
+
+  // Waits for a period of time that is long enough to receive all delayed acks
+  // sent by peer.
+  void WaitForDelayedAcks();
+
+  QuicSpdyClientStream* latest_created_stream() {
+    return latest_created_stream_;
+  }
+
+ protected:
+  QuicTestClient();
+  QuicTestClient(const QuicTestClient&) = delete;
+  QuicTestClient& operator=(const QuicTestClient&) = delete;
+
+ private:
+  class TestClientDataToResend : public QuicClient::QuicDataToResend {
+   public:
+    TestClientDataToResend(
+        std::unique_ptr<spdy::SpdyHeaderBlock> headers,
+        QuicStringPiece body,
+        bool fin,
+        QuicTestClient* test_client,
+        QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
+
+    ~TestClientDataToResend() override;
+
+    void Resend() override;
+
+   protected:
+    QuicTestClient* test_client_;
+    QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_;
+  };
+
+  // PerStreamState of a stream is updated when it is closed.
+  struct PerStreamState {
+    PerStreamState(const PerStreamState& other);
+    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);
+    ~PerStreamState();
+
+    QuicRstStreamErrorCode stream_error;
+    bool response_complete;
+    bool response_headers_complete;
+    spdy::SpdyHeaderBlock response_headers;
+    spdy::SpdyHeaderBlock preliminary_headers;
+    QuicString response;
+    spdy::SpdyHeaderBlock response_trailers;
+    uint64_t bytes_read;
+    uint64_t bytes_written;
+    int64_t response_body_size;
+  };
+
+  bool HaveActiveStream();
+
+  // Read oldest received response and remove it from closed_stream_states_.
+  void ReadNextResponse();
+
+  // Clear open_streams_, closed_stream_states_ and reset
+  // latest_created_stream_.
+  void ClearPerConnectionState();
+
+  // Update latest_created_stream_, add |stream| to open_streams_ and starts
+  // tracking its state.
+  void SetLatestCreatedStream(QuicSpdyClientStream* stream);
+
+  QuicEpollServer epoll_server_;
+  std::unique_ptr<MockableQuicClient> client_;  // The actual client
+  QuicSpdyClientStream* latest_created_stream_;
+  std::map<QuicStreamId, QuicSpdyClientStream*> open_streams_;
+  // Received responses of closed streams.
+  QuicLinkedHashMap<QuicStreamId, PerStreamState> closed_stream_states_;
+
+  QuicRstStreamErrorCode stream_error_;
+
+  bool response_complete_;
+  bool response_headers_complete_;
+  mutable spdy::SpdyHeaderBlock preliminary_headers_;
+  mutable spdy::SpdyHeaderBlock response_headers_;
+
+  // Parsed response trailers (if present), copied from the stream in OnClose.
+  spdy::SpdyHeaderBlock response_trailers_;
+
+  spdy::SpdyPriority priority_;
+  QuicString response_;
+  // bytes_read_ and bytes_written_ are updated only when stream_ is released;
+  // prefer bytes_read() and bytes_written() member functions.
+  uint64_t bytes_read_;
+  uint64_t bytes_written_;
+  // The number of HTTP body bytes received.
+  int64_t response_body_size_;
+  // True if we tried to connect already since the last call to Disconnect().
+  bool connect_attempted_;
+  // The client will auto-connect exactly once before sending data.  If
+  // something causes a connection reset, it will not automatically reconnect
+  // unless auto_reconnect_ is true.
+  bool auto_reconnect_;
+  // Should we buffer the response body? Defaults to true.
+  bool buffer_body_;
+  // For async push promise rendezvous, validation may fail in which
+  // case the request should be retried.
+  std::unique_ptr<TestClientDataToResend> push_promise_data_to_resend_;
+  // Number of requests/responses this client has sent/received.
+  size_t num_requests_;
+  size_t num_responses_;
+
+  // If set, this value is used for the connection SNI, overriding the usual
+  // logic which extracts the SNI from the request URL.
+  bool override_sni_set_ = false;
+  QuicString override_sni_;
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
diff --git a/quic/test_tools/quic_test_server.cc b/quic/test_tools/quic_test_server.cc
new file mode 100644
index 0000000..bda2148
--- /dev/null
+++ b/quic/test_tools/quic_test_server.cc
@@ -0,0 +1,232 @@
+// Copyright (c) 2015 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_server.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_server_session.h"
+
+namespace quic {
+
+namespace test {
+
+class CustomStreamSession : public QuicSimpleServerSession {
+ public:
+  CustomStreamSession(
+      const QuicConfig& config,
+      const ParsedQuicVersionVector& supported_versions,
+      QuicConnection* connection,
+      QuicSession::Visitor* visitor,
+      QuicCryptoServerStream::Helper* helper,
+      const QuicCryptoServerConfig* crypto_config,
+      QuicCompressedCertsCache* compressed_certs_cache,
+      QuicTestServer::StreamFactory* stream_factory,
+      QuicTestServer::CryptoStreamFactory* crypto_stream_factory,
+      QuicSimpleServerBackend* quic_simple_server_backend)
+      : QuicSimpleServerSession(config,
+                                supported_versions,
+                                connection,
+                                visitor,
+                                helper,
+                                crypto_config,
+                                compressed_certs_cache,
+                                quic_simple_server_backend),
+        stream_factory_(stream_factory),
+        crypto_stream_factory_(crypto_stream_factory) {}
+
+  QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override {
+    if (!ShouldCreateIncomingStream(id)) {
+      return nullptr;
+    }
+    if (stream_factory_) {
+      QuicSpdyStream* stream =
+          stream_factory_->CreateStream(id, this, server_backend());
+      ActivateStream(QuicWrapUnique(stream));
+      return stream;
+    }
+    return QuicSimpleServerSession::CreateIncomingStream(id);
+  }
+
+  QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
+      const QuicCryptoServerConfig* crypto_config,
+      QuicCompressedCertsCache* compressed_certs_cache) override {
+    if (crypto_stream_factory_) {
+      return crypto_stream_factory_->CreateCryptoStream(crypto_config, this);
+    }
+    return QuicSimpleServerSession::CreateQuicCryptoServerStream(
+        crypto_config, compressed_certs_cache);
+  }
+
+ private:
+  QuicTestServer::StreamFactory* stream_factory_;               // Not owned.
+  QuicTestServer::CryptoStreamFactory* crypto_stream_factory_;  // Not owned.
+};
+
+class QuicTestDispatcher : public QuicSimpleDispatcher {
+ public:
+  QuicTestDispatcher(
+      const QuicConfig* config,
+      const QuicCryptoServerConfig* crypto_config,
+      QuicVersionManager* version_manager,
+      std::unique_ptr<QuicConnectionHelperInterface> helper,
+      std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+      std::unique_ptr<QuicAlarmFactory> alarm_factory,
+      QuicSimpleServerBackend* quic_simple_server_backend,
+      uint8_t expected_connection_id_length)
+      : QuicSimpleDispatcher(config,
+                             crypto_config,
+                             version_manager,
+                             std::move(helper),
+                             std::move(session_helper),
+                             std::move(alarm_factory),
+                             quic_simple_server_backend,
+                             expected_connection_id_length),
+        session_factory_(nullptr),
+        stream_factory_(nullptr),
+        crypto_stream_factory_(nullptr) {}
+
+  QuicServerSessionBase* CreateQuicSession(
+      QuicConnectionId id,
+      const QuicSocketAddress& client,
+      QuicStringPiece alpn,
+      const ParsedQuicVersion& version) override {
+    QuicReaderMutexLock lock(&factory_lock_);
+    if (session_factory_ == nullptr && stream_factory_ == nullptr &&
+        crypto_stream_factory_ == nullptr) {
+      return QuicSimpleDispatcher::CreateQuicSession(id, client, alpn, version);
+    }
+    QuicConnection* connection =
+        new QuicConnection(id, client, helper(), alarm_factory(), writer(),
+                           /* owns_writer= */ false, Perspective::IS_SERVER,
+                           ParsedQuicVersionVector{version});
+
+    QuicServerSessionBase* session = nullptr;
+    if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) {
+      session = new CustomStreamSession(
+          config(), GetSupportedVersions(), connection, this, session_helper(),
+          crypto_config(), compressed_certs_cache(), stream_factory_,
+          crypto_stream_factory_, server_backend());
+    } else {
+      session = session_factory_->CreateSession(
+          config(), connection, this, session_helper(), crypto_config(),
+          compressed_certs_cache(), server_backend());
+    }
+    session->Initialize();
+    return session;
+  }
+
+  void SetSessionFactory(QuicTestServer::SessionFactory* factory) {
+    QuicWriterMutexLock lock(&factory_lock_);
+    DCHECK(session_factory_ == nullptr);
+    DCHECK(stream_factory_ == nullptr);
+    DCHECK(crypto_stream_factory_ == nullptr);
+    session_factory_ = factory;
+  }
+
+  void SetStreamFactory(QuicTestServer::StreamFactory* factory) {
+    QuicWriterMutexLock lock(&factory_lock_);
+    DCHECK(session_factory_ == nullptr);
+    DCHECK(stream_factory_ == nullptr);
+    stream_factory_ = factory;
+  }
+
+  void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) {
+    QuicWriterMutexLock lock(&factory_lock_);
+    DCHECK(session_factory_ == nullptr);
+    DCHECK(crypto_stream_factory_ == nullptr);
+    crypto_stream_factory_ = factory;
+  }
+
+ private:
+  QuicMutex factory_lock_;
+  QuicTestServer::SessionFactory* session_factory_;             // Not owned.
+  QuicTestServer::StreamFactory* stream_factory_;               // Not owned.
+  QuicTestServer::CryptoStreamFactory* crypto_stream_factory_;  // Not owned.
+};
+
+QuicTestServer::QuicTestServer(
+    std::unique_ptr<ProofSource> proof_source,
+    QuicSimpleServerBackend* quic_simple_server_backend)
+    : QuicServer(std::move(proof_source), quic_simple_server_backend) {}
+
+QuicTestServer::QuicTestServer(
+    std::unique_ptr<ProofSource> proof_source,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    QuicSimpleServerBackend* quic_simple_server_backend)
+    : QuicTestServer(std::move(proof_source),
+                     config,
+                     supported_versions,
+                     quic_simple_server_backend,
+                     kQuicDefaultConnectionIdLength) {}
+
+QuicTestServer::QuicTestServer(
+    std::unique_ptr<ProofSource> proof_source,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    QuicSimpleServerBackend* quic_simple_server_backend,
+    uint8_t expected_connection_id_length)
+    : QuicServer(std::move(proof_source),
+                 config,
+                 QuicCryptoServerConfig::ConfigOptions(),
+                 supported_versions,
+                 quic_simple_server_backend,
+                 expected_connection_id_length) {}
+
+QuicDispatcher* QuicTestServer::CreateQuicDispatcher() {
+  return new QuicTestDispatcher(
+      &config(), &crypto_config(), version_manager(),
+      QuicMakeUnique<QuicEpollConnectionHelper>(epoll_server(),
+                                                QuicAllocator::BUFFER_POOL),
+      std::unique_ptr<QuicCryptoServerStream::Helper>(
+          new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
+      QuicMakeUnique<QuicEpollAlarmFactory>(epoll_server()), server_backend(),
+      expected_connection_id_length());
+}
+
+void QuicTestServer::SetSessionFactory(SessionFactory* factory) {
+  DCHECK(dispatcher());
+  static_cast<QuicTestDispatcher*>(dispatcher())->SetSessionFactory(factory);
+}
+
+void QuicTestServer::SetSpdyStreamFactory(StreamFactory* factory) {
+  static_cast<QuicTestDispatcher*>(dispatcher())->SetStreamFactory(factory);
+}
+
+void QuicTestServer::SetCryptoStreamFactory(CryptoStreamFactory* factory) {
+  static_cast<QuicTestDispatcher*>(dispatcher())
+      ->SetCryptoStreamFactory(factory);
+}
+
+///////////////////////////   TEST SESSIONS ///////////////////////////////
+
+ImmediateGoAwaySession::ImmediateGoAwaySession(
+    const QuicConfig& config,
+    QuicConnection* connection,
+    QuicSession::Visitor* visitor,
+    QuicCryptoServerStream::Helper* helper,
+    const QuicCryptoServerConfig* crypto_config,
+    QuicCompressedCertsCache* compressed_certs_cache,
+    QuicSimpleServerBackend* quic_simple_server_backend)
+    : QuicSimpleServerSession(config,
+                              CurrentSupportedVersions(),
+                              connection,
+                              visitor,
+                              helper,
+                              crypto_config,
+                              compressed_certs_cache,
+                              quic_simple_server_backend) {}
+
+void ImmediateGoAwaySession::OnStreamFrame(const QuicStreamFrame& frame) {
+  SendGoAway(QUIC_PEER_GOING_AWAY, "");
+  QuicSimpleServerSession::OnStreamFrame(frame);
+}
+
+}  // namespace test
+
+}  // namespace quic
diff --git a/quic/test_tools/quic_test_server.h b/quic/test_tools/quic_test_server.h
new file mode 100644
index 0000000..52fb7c5
--- /dev/null
+++ b/quic/test_tools/quic_test_server.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2015 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_SERVER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_SERVER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/tools/quic_server.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_server_session.h"
+#include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h"
+
+namespace quic {
+
+namespace test {
+
+// A test server which enables easy creation of custom QuicServerSessions
+//
+// Eventually this may be extended to allow custom QuicConnections etc.
+class QuicTestServer : public QuicServer {
+ public:
+  // Factory for creating QuicServerSessions.
+  class SessionFactory {
+   public:
+    virtual ~SessionFactory() {}
+
+    // Returns a new session owned by the caller.
+    virtual QuicServerSessionBase* CreateSession(
+        const QuicConfig& config,
+        QuicConnection* connection,
+        QuicSession::Visitor* visitor,
+        QuicCryptoServerStream::Helper* helper,
+        const QuicCryptoServerConfig* crypto_config,
+        QuicCompressedCertsCache* compressed_certs_cache,
+        QuicSimpleServerBackend* quic_simple_server_backend) = 0;
+  };
+
+  // Factory for creating QuicSimpleServerStreams.
+  class StreamFactory {
+   public:
+    virtual ~StreamFactory() {}
+
+    // Returns a new stream owned by the caller.
+    virtual QuicSimpleServerStream* CreateStream(
+        QuicStreamId id,
+        QuicSpdySession* session,
+        QuicSimpleServerBackend* quic_simple_server_backend) = 0;
+  };
+
+  class CryptoStreamFactory {
+   public:
+    virtual ~CryptoStreamFactory() {}
+
+    // Returns a new QuicCryptoServerStreamBase owned by the caller
+    virtual QuicCryptoServerStreamBase* CreateCryptoStream(
+        const QuicCryptoServerConfig* crypto_config,
+        QuicServerSessionBase* session) = 0;
+  };
+
+  QuicTestServer(std::unique_ptr<ProofSource> proof_source,
+                 QuicSimpleServerBackend* quic_simple_server_backend);
+  QuicTestServer(std::unique_ptr<ProofSource> proof_source,
+                 const QuicConfig& config,
+                 const ParsedQuicVersionVector& supported_versions,
+                 QuicSimpleServerBackend* quic_simple_server_backend);
+  QuicTestServer(std::unique_ptr<ProofSource> proof_source,
+                 const QuicConfig& config,
+                 const ParsedQuicVersionVector& supported_versions,
+                 QuicSimpleServerBackend* quic_simple_server_backend,
+                 uint8_t expected_connection_id_length);
+
+  // Create a custom dispatcher which creates custom sessions.
+  QuicDispatcher* CreateQuicDispatcher() override;
+
+  // Sets a custom session factory, owned by the caller, for easy custom
+  // session logic. This is incompatible with setting a stream factory or a
+  // crypto stream factory.
+  void SetSessionFactory(SessionFactory* factory);
+
+  // Sets a custom stream factory, owned by the caller, for easy custom
+  // stream logic. This is incompatible with setting a session factory.
+  void SetSpdyStreamFactory(StreamFactory* factory);
+
+  // Sets a custom crypto stream factory, owned by the caller, for easy custom
+  // crypto logic.  This is incompatible with setting a session factory.
+  void SetCryptoStreamFactory(CryptoStreamFactory* factory);
+};
+
+// Useful test sessions for the QuicTestServer.
+
+// Test session which sends a GOAWAY immedaitely on creation, before crypto
+// credentials have even been established.
+class ImmediateGoAwaySession : public QuicSimpleServerSession {
+ public:
+  ImmediateGoAwaySession(const QuicConfig& config,
+                         QuicConnection* connection,
+                         QuicSession::Visitor* visitor,
+                         QuicCryptoServerStream::Helper* helper,
+                         const QuicCryptoServerConfig* crypto_config,
+                         QuicCompressedCertsCache* compressed_certs_cache,
+                         QuicSimpleServerBackend* quic_simple_server_backend);
+
+  // Override to send GoAway.
+  void OnStreamFrame(const QuicStreamFrame& frame) override;
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_SERVER_H_
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
new file mode 100644
index 0000000..6e3c2a5
--- /dev/null
+++ b/quic/test_tools/quic_test_utils.cc
@@ -0,0 +1,1177 @@
+// 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_utils.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.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/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
+
+using testing::_;
+using testing::Invoke;
+
+namespace quic {
+namespace test {
+
+QuicConnectionId TestConnectionId() {
+  // Chosen by fair dice roll.
+  // Guaranteed to be random.
+  return TestConnectionId(42);
+}
+
+QuicConnectionId TestConnectionId(uint64_t connection_number) {
+  const uint64_t connection_id64_net =
+      QuicEndian::HostToNet64(connection_number);
+  return QuicConnectionId(reinterpret_cast<const char*>(&connection_id64_net),
+                          sizeof(connection_id64_net));
+}
+
+uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) {
+  DCHECK_EQ(connection_id.length(), kQuicDefaultConnectionIdLength);
+  uint64_t connection_id64_net = 0;
+  memcpy(&connection_id64_net, connection_id.data(),
+         std::min<size_t>(static_cast<size_t>(connection_id.length()),
+                          sizeof(connection_id64_net)));
+  return QuicEndian::NetToHost64(connection_id64_net);
+}
+
+QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) {
+  DCHECK_GT(ack_blocks.size(), 0u);
+
+  QuicAckFrame ack;
+  QuicPacketNumber end_of_previous_block(1);
+  for (const QuicAckBlock& block : ack_blocks) {
+    DCHECK_GE(block.start, end_of_previous_block);
+    DCHECK_GT(block.limit, block.start);
+    ack.packets.AddRange(block.start, block.limit);
+    end_of_previous_block = block.limit;
+  }
+
+  ack.largest_acked = ack.packets.Max();
+
+  return ack;
+}
+
+QuicAckFrame InitAckFrame(uint64_t largest_acked) {
+  return InitAckFrame(QuicPacketNumber(largest_acked));
+}
+
+QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked) {
+  return InitAckFrame({{QuicPacketNumber(1), largest_acked + 1}});
+}
+
+QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks,
+                                       uint64_t least_unacked) {
+  QuicAckFrame ack;
+  ack.largest_acked = QuicPacketNumber(2 * num_ack_blocks + least_unacked);
+  // Add enough received packets to get num_ack_blocks ack blocks.
+  for (QuicPacketNumber i = QuicPacketNumber(2);
+       i < QuicPacketNumber(2 * num_ack_blocks + 1); i += 2) {
+    ack.packets.Add(i + least_unacked);
+  }
+  return ack;
+}
+
+std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
+    QuicFramer* framer,
+    const QuicPacketHeader& header,
+    const QuicFrames& frames) {
+  const size_t max_plaintext_size = framer->GetMaxPlaintextSize(kMaxPacketSize);
+  size_t packet_size = GetPacketHeaderSize(framer->transport_version(), header);
+  for (size_t i = 0; i < frames.size(); ++i) {
+    DCHECK_LE(packet_size, max_plaintext_size);
+    bool first_frame = i == 0;
+    bool last_frame = i == frames.size() - 1;
+    const size_t frame_size = framer->GetSerializedFrameLength(
+        frames[i], max_plaintext_size - packet_size, first_frame, last_frame,
+        header.packet_number_length);
+    DCHECK(frame_size);
+    packet_size += frame_size;
+  }
+  return BuildUnsizedDataPacket(framer, header, frames, packet_size);
+}
+
+std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
+    QuicFramer* framer,
+    const QuicPacketHeader& header,
+    const QuicFrames& frames,
+    size_t packet_size) {
+  char* buffer = new char[packet_size];
+  size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size,
+                                          ENCRYPTION_NONE);
+  DCHECK_NE(0u, length);
+  // Re-construct the data packet with data ownership.
+  return QuicMakeUnique<QuicPacket>(
+      buffer, length, /* owns_buffer */ true,
+      GetIncludedDestinationConnectionIdLength(header),
+      GetIncludedSourceConnectionIdLength(header), header.version_flag,
+      header.nonce != nullptr, header.packet_number_length,
+      header.retry_token_length_length, header.retry_token.length(),
+      header.length_length);
+}
+
+QuicString Sha1Hash(QuicStringPiece data) {
+  char buffer[SHA_DIGEST_LENGTH];
+  SHA1(reinterpret_cast<const uint8_t*>(data.data()), data.size(),
+       reinterpret_cast<uint8_t*>(buffer));
+  return QuicString(buffer, QUIC_ARRAYSIZE(buffer));
+}
+
+uint64_t SimpleRandom::RandUint64() {
+  QuicString hash =
+      Sha1Hash(QuicStringPiece(reinterpret_cast<char*>(&seed_), sizeof(seed_)));
+  DCHECK_EQ(static_cast<size_t>(SHA_DIGEST_LENGTH), hash.length());
+  memcpy(&seed_, hash.data(), sizeof(seed_));
+  return seed_;
+}
+
+void SimpleRandom::RandBytes(void* data, size_t len) {
+  uint8_t* real_data = static_cast<uint8_t*>(data);
+  for (size_t offset = 0; offset < len; offset++) {
+    real_data[offset] = RandUint64() & 0xff;
+  }
+}
+
+MockFramerVisitor::MockFramerVisitor() {
+  // By default, we want to accept packets.
+  ON_CALL(*this, OnProtocolVersionMismatch(_, _))
+      .WillByDefault(testing::Return(false));
+
+  // By default, we want to accept packets.
+  ON_CALL(*this, OnUnauthenticatedHeader(_))
+      .WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnUnauthenticatedPublicHeader(_))
+      .WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnPacketHeader(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnStreamFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnCryptoFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnStopWaitingFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnPaddingFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnPingFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnRstStreamFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnConnectionCloseFrame(_))
+      .WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnApplicationCloseFrame(_))
+      .WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnStopSendingFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnPathChallengeFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnPathResponseFrame(_)).WillByDefault(testing::Return(true));
+
+  ON_CALL(*this, OnGoAwayFrame(_)).WillByDefault(testing::Return(true));
+  ON_CALL(*this, OnMaxStreamIdFrame(_)).WillByDefault(testing::Return(true));
+  ON_CALL(*this, OnStreamIdBlockedFrame(_))
+      .WillByDefault(testing::Return(true));
+}
+
+MockFramerVisitor::~MockFramerVisitor() {}
+
+bool NoOpFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                                  PacketHeaderFormat form) {
+  return false;
+}
+
+bool NoOpFramerVisitor::OnUnauthenticatedPublicHeader(
+    const QuicPacketHeader& header) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnUnauthenticatedHeader(
+    const QuicPacketHeader& header) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) {
+  return true;
+}
+
+void NoOpFramerVisitor::OnCoalescedPacket(const QuicEncryptedPacket& packet) {}
+
+bool NoOpFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnAckFrameStart(QuicPacketNumber largest_acked,
+                                        QuicTime::Delta ack_delay_time) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnAckRange(QuicPacketNumber start,
+                                   QuicPacketNumber end) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnAckTimestamp(QuicPacketNumber packet_number,
+                                       QuicTime timestamp) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnAckFrameEnd(QuicPacketNumber start) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnPingFrame(const QuicPingFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnConnectionCloseFrame(
+    const QuicConnectionCloseFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnApplicationCloseFrame(
+    const QuicApplicationCloseFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnNewConnectionIdFrame(
+    const QuicNewConnectionIdFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnRetireConnectionIdFrame(
+    const QuicRetireConnectionIdFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnPathChallengeFrame(
+    const QuicPathChallengeFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnPathResponseFrame(
+    const QuicPathResponseFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnStreamIdBlockedFrame(
+    const QuicStreamIdBlockedFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnWindowUpdateFrame(
+    const QuicWindowUpdateFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::OnMessageFrame(const QuicMessageFrame& frame) {
+  return true;
+}
+
+bool NoOpFramerVisitor::IsValidStatelessResetToken(QuicUint128 token) const {
+  return false;
+}
+
+MockQuicConnectionVisitor::MockQuicConnectionVisitor() {}
+
+MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {}
+
+MockQuicConnectionHelper::MockQuicConnectionHelper() {}
+
+MockQuicConnectionHelper::~MockQuicConnectionHelper() {}
+
+const QuicClock* MockQuicConnectionHelper::GetClock() const {
+  return &clock_;
+}
+
+QuicRandom* MockQuicConnectionHelper::GetRandomGenerator() {
+  return &random_generator_;
+}
+
+QuicAlarm* MockAlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
+  return new MockAlarmFactory::TestAlarm(
+      QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+}
+
+QuicArenaScopedPtr<QuicAlarm> MockAlarmFactory::CreateAlarm(
+    QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+    QuicConnectionArena* arena) {
+  if (arena != nullptr) {
+    return arena->New<TestAlarm>(std::move(delegate));
+  } else {
+    return QuicArenaScopedPtr<TestAlarm>(new TestAlarm(std::move(delegate)));
+  }
+}
+
+QuicBufferAllocator* MockQuicConnectionHelper::GetStreamSendBufferAllocator() {
+  return &buffer_allocator_;
+}
+
+void MockQuicConnectionHelper::AdvanceTime(QuicTime::Delta delta) {
+  clock_.AdvanceTime(delta);
+}
+
+MockQuicConnection::MockQuicConnection(MockQuicConnectionHelper* helper,
+                                       MockAlarmFactory* alarm_factory,
+                                       Perspective perspective)
+    : MockQuicConnection(TestConnectionId(),
+                         QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+                         helper,
+                         alarm_factory,
+                         perspective,
+                         ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {}
+
+MockQuicConnection::MockQuicConnection(QuicSocketAddress address,
+                                       MockQuicConnectionHelper* helper,
+                                       MockAlarmFactory* alarm_factory,
+                                       Perspective perspective)
+    : MockQuicConnection(TestConnectionId(),
+                         address,
+                         helper,
+                         alarm_factory,
+                         perspective,
+                         ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {}
+
+MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id,
+                                       MockQuicConnectionHelper* helper,
+                                       MockAlarmFactory* alarm_factory,
+                                       Perspective perspective)
+    : MockQuicConnection(connection_id,
+                         QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+                         helper,
+                         alarm_factory,
+                         perspective,
+                         ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {}
+
+MockQuicConnection::MockQuicConnection(
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    Perspective perspective,
+    const ParsedQuicVersionVector& supported_versions)
+    : MockQuicConnection(TestConnectionId(),
+                         QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+                         helper,
+                         alarm_factory,
+                         perspective,
+                         supported_versions) {}
+
+MockQuicConnection::MockQuicConnection(
+    QuicConnectionId connection_id,
+    QuicSocketAddress address,
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    Perspective perspective,
+    const ParsedQuicVersionVector& supported_versions)
+    : QuicConnection(connection_id,
+                     address,
+                     helper,
+                     alarm_factory,
+                     new testing::NiceMock<MockPacketWriter>(),
+                     /* owns_writer= */ true,
+                     perspective,
+                     supported_versions) {
+  ON_CALL(*this, OnError(_))
+      .WillByDefault(
+          Invoke(this, &PacketSavingConnection::QuicConnection_OnError));
+  ON_CALL(*this, SendCryptoData(_, _, _))
+      .WillByDefault(
+          Invoke(this, &MockQuicConnection::QuicConnection_SendCryptoData));
+
+  SetSelfAddress(QuicSocketAddress(QuicIpAddress::Any4(), 5));
+}
+
+MockQuicConnection::~MockQuicConnection() {}
+
+void MockQuicConnection::AdvanceTime(QuicTime::Delta delta) {
+  static_cast<MockQuicConnectionHelper*>(helper())->AdvanceTime(delta);
+}
+
+bool MockQuicConnection::OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                                   PacketHeaderFormat form) {
+  return false;
+}
+
+PacketSavingConnection::PacketSavingConnection(MockQuicConnectionHelper* helper,
+                                               MockAlarmFactory* alarm_factory,
+                                               Perspective perspective)
+    : MockQuicConnection(helper, alarm_factory, perspective) {}
+
+PacketSavingConnection::PacketSavingConnection(
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    Perspective perspective,
+    const ParsedQuicVersionVector& supported_versions)
+    : MockQuicConnection(helper,
+                         alarm_factory,
+                         perspective,
+                         supported_versions) {}
+
+PacketSavingConnection::~PacketSavingConnection() {}
+
+void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) {
+  encrypted_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>(
+      CopyBuffer(*packet), packet->encrypted_length, true));
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+  // Transfer ownership of the packet to the SentPacketManager and the
+  // ack notifier to the AckNotifierManager.
+  QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent(
+      packet, QuicPacketNumber(), clock_.ApproximateNow(), NOT_RETRANSMISSION,
+      HAS_RETRANSMITTABLE_DATA);
+}
+
+MockQuicSession::MockQuicSession(QuicConnection* connection)
+    : MockQuicSession(connection, true) {}
+
+MockQuicSession::MockQuicSession(QuicConnection* connection,
+                                 bool create_mock_crypto_stream)
+    : QuicSession(connection,
+                  nullptr,
+                  DefaultQuicConfig(),
+                  CurrentSupportedVersions()) {
+  if (create_mock_crypto_stream) {
+    crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this);
+  }
+  ON_CALL(*this, WritevData(_, _, _, _, _))
+      .WillByDefault(testing::Return(QuicConsumedData(0, false)));
+}
+
+MockQuicSession::~MockQuicSession() {
+  delete connection();
+}
+
+QuicCryptoStream* MockQuicSession::GetMutableCryptoStream() {
+  return crypto_stream_.get();
+}
+
+const QuicCryptoStream* MockQuicSession::GetCryptoStream() const {
+  return crypto_stream_.get();
+}
+
+void MockQuicSession::SetCryptoStream(QuicCryptoStream* crypto_stream) {
+  crypto_stream_.reset(crypto_stream);
+}
+
+// static
+QuicConsumedData MockQuicSession::ConsumeData(QuicStream* stream,
+                                              QuicStreamId /*id*/,
+                                              size_t write_length,
+                                              QuicStreamOffset offset,
+                                              StreamSendingState state) {
+  if (write_length > 0) {
+    auto buf = QuicMakeUnique<char[]>(write_length);
+    QuicDataWriter writer(write_length, buf.get(), HOST_BYTE_ORDER);
+    stream->WriteStreamData(offset, write_length, &writer);
+  } else {
+    DCHECK(state != NO_FIN);
+  }
+  return QuicConsumedData(write_length, state != NO_FIN);
+}
+
+MockQuicCryptoStream::MockQuicCryptoStream(QuicSession* session)
+    : QuicCryptoStream(session), params_(new QuicCryptoNegotiatedParameters) {}
+
+MockQuicCryptoStream::~MockQuicCryptoStream() {}
+
+bool MockQuicCryptoStream::encryption_established() const {
+  return false;
+}
+
+bool MockQuicCryptoStream::handshake_confirmed() const {
+  return false;
+}
+
+const QuicCryptoNegotiatedParameters&
+MockQuicCryptoStream::crypto_negotiated_params() const {
+  return *params_;
+}
+
+CryptoMessageParser* MockQuicCryptoStream::crypto_message_parser() {
+  return &crypto_framer_;
+}
+
+MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection)
+    : MockQuicSpdySession(connection, true) {}
+
+MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection,
+                                         bool create_mock_crypto_stream)
+    : QuicSpdySession(connection,
+                      nullptr,
+                      DefaultQuicConfig(),
+                      connection->supported_versions()) {
+  if (create_mock_crypto_stream) {
+    crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this);
+  }
+
+  ON_CALL(*this, WritevData(_, _, _, _, _))
+      .WillByDefault(testing::Return(QuicConsumedData(0, false)));
+}
+
+MockQuicSpdySession::~MockQuicSpdySession() {
+  delete connection();
+}
+
+QuicCryptoStream* MockQuicSpdySession::GetMutableCryptoStream() {
+  return crypto_stream_.get();
+}
+
+const QuicCryptoStream* MockQuicSpdySession::GetCryptoStream() const {
+  return crypto_stream_.get();
+}
+
+void MockQuicSpdySession::SetCryptoStream(QuicCryptoStream* crypto_stream) {
+  crypto_stream_.reset(crypto_stream);
+}
+
+TestQuicSpdyServerSession::TestQuicSpdyServerSession(
+    QuicConnection* connection,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    const QuicCryptoServerConfig* crypto_config,
+    QuicCompressedCertsCache* compressed_certs_cache)
+    : QuicServerSessionBase(config,
+                            supported_versions,
+                            connection,
+                            &visitor_,
+                            &helper_,
+                            crypto_config,
+                            compressed_certs_cache) {
+  Initialize();
+  ON_CALL(helper_, GenerateConnectionIdForReject(_, _))
+      .WillByDefault(testing::Return(
+          QuicUtils::CreateRandomConnectionId(connection->random_generator())));
+  ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _))
+      .WillByDefault(testing::Return(true));
+}
+
+TestQuicSpdyServerSession::~TestQuicSpdyServerSession() {
+  delete connection();
+}
+
+QuicCryptoServerStreamBase*
+TestQuicSpdyServerSession::CreateQuicCryptoServerStream(
+    const QuicCryptoServerConfig* crypto_config,
+    QuicCompressedCertsCache* compressed_certs_cache) {
+  return new QuicCryptoServerStream(
+      crypto_config, compressed_certs_cache,
+      GetQuicReloadableFlag(enable_quic_stateless_reject_support), this,
+      &helper_);
+}
+
+void TestQuicSpdyServerSession::OnCryptoHandshakeEvent(
+    CryptoHandshakeEvent event) {
+  QuicSession::OnCryptoHandshakeEvent(event);
+}
+
+QuicCryptoServerStream* TestQuicSpdyServerSession::GetMutableCryptoStream() {
+  return static_cast<QuicCryptoServerStream*>(
+      QuicServerSessionBase::GetMutableCryptoStream());
+}
+
+const QuicCryptoServerStream* TestQuicSpdyServerSession::GetCryptoStream()
+    const {
+  return static_cast<const QuicCryptoServerStream*>(
+      QuicServerSessionBase::GetCryptoStream());
+}
+
+TestQuicSpdyClientSession::TestQuicSpdyClientSession(
+    QuicConnection* connection,
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
+    const QuicServerId& server_id,
+    QuicCryptoClientConfig* crypto_config)
+    : QuicSpdyClientSessionBase(connection,
+                                &push_promise_index_,
+                                config,
+                                supported_versions) {
+  crypto_stream_ = QuicMakeUnique<QuicCryptoClientStream>(
+      server_id, this, crypto_test_utils::ProofVerifyContextForTesting(),
+      crypto_config, this);
+  Initialize();
+}
+
+TestQuicSpdyClientSession::~TestQuicSpdyClientSession() {}
+
+bool TestQuicSpdyClientSession::IsAuthorized(const QuicString& authority) {
+  return true;
+}
+
+void TestQuicSpdyClientSession::OnCryptoHandshakeEvent(
+    CryptoHandshakeEvent event) {
+  QuicSession::OnCryptoHandshakeEvent(event);
+}
+
+QuicCryptoClientStream* TestQuicSpdyClientSession::GetMutableCryptoStream() {
+  return crypto_stream_.get();
+}
+
+const QuicCryptoClientStream* TestQuicSpdyClientSession::GetCryptoStream()
+    const {
+  return crypto_stream_.get();
+}
+
+TestPushPromiseDelegate::TestPushPromiseDelegate(bool match)
+    : match_(match), rendezvous_fired_(false), rendezvous_stream_(nullptr) {}
+
+bool TestPushPromiseDelegate::CheckVary(
+    const spdy::SpdyHeaderBlock& client_request,
+    const spdy::SpdyHeaderBlock& promise_request,
+    const spdy::SpdyHeaderBlock& promise_response) {
+  QUIC_DVLOG(1) << "match " << match_;
+  return match_;
+}
+
+void TestPushPromiseDelegate::OnRendezvousResult(QuicSpdyStream* stream) {
+  rendezvous_fired_ = true;
+  rendezvous_stream_ = stream;
+}
+
+MockPacketWriter::MockPacketWriter() {
+  ON_CALL(*this, GetMaxPacketSize(_))
+      .WillByDefault(testing::Return(kMaxPacketSize));
+  ON_CALL(*this, IsBatchMode()).WillByDefault(testing::Return(false));
+  ON_CALL(*this, GetNextWriteLocation(_, _))
+      .WillByDefault(testing::Return(nullptr));
+  ON_CALL(*this, Flush())
+      .WillByDefault(testing::Return(WriteResult(WRITE_STATUS_OK, 0)));
+}
+
+MockPacketWriter::~MockPacketWriter() {}
+
+MockSendAlgorithm::MockSendAlgorithm() {}
+
+MockSendAlgorithm::~MockSendAlgorithm() {}
+
+MockLossAlgorithm::MockLossAlgorithm() {}
+
+MockLossAlgorithm::~MockLossAlgorithm() {}
+
+MockAckListener::MockAckListener() {}
+
+MockAckListener::~MockAckListener() {}
+
+MockNetworkChangeVisitor::MockNetworkChangeVisitor() {}
+
+MockNetworkChangeVisitor::~MockNetworkChangeVisitor() {}
+
+namespace {
+
+QuicString HexDumpWithMarks(const char* data,
+                            int length,
+                            const bool* marks,
+                            int mark_length) {
+  static const char kHexChars[] = "0123456789abcdef";
+  static const int kColumns = 4;
+
+  const int kSizeLimit = 1024;
+  if (length > kSizeLimit || mark_length > kSizeLimit) {
+    QUIC_LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes.";
+    length = std::min(length, kSizeLimit);
+    mark_length = std::min(mark_length, kSizeLimit);
+  }
+
+  QuicString hex;
+  for (const char* row = data; length > 0;
+       row += kColumns, length -= kColumns) {
+    for (const char* p = row; p < row + 4; ++p) {
+      if (p < row + length) {
+        const bool mark =
+            (marks && (p - data) < mark_length && marks[p - data]);
+        hex += mark ? '*' : ' ';
+        hex += kHexChars[(*p & 0xf0) >> 4];
+        hex += kHexChars[*p & 0x0f];
+        hex += mark ? '*' : ' ';
+      } else {
+        hex += "    ";
+      }
+    }
+    hex = hex + "  ";
+
+    for (const char* p = row; p < row + 4 && p < row + length; ++p) {
+      hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.';
+    }
+
+    hex = hex + '\n';
+  }
+  return hex;
+}
+
+}  // namespace
+
+QuicIpAddress TestPeerIPAddress() {
+  return QuicIpAddress::Loopback4();
+}
+
+ParsedQuicVersion QuicVersionMax() {
+  return AllSupportedVersions().front();
+}
+
+ParsedQuicVersion QuicVersionMin() {
+  return AllSupportedVersions().back();
+}
+
+QuicTransportVersion QuicTransportVersionMax() {
+  return AllSupportedTransportVersions().front();
+}
+
+QuicTransportVersion QuicTransportVersionMin() {
+  return AllSupportedTransportVersions().back();
+}
+
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data) {
+  return ConstructEncryptedPacket(
+      destination_connection_id, source_connection_id, version_flag, reset_flag,
+      packet_number, data, CONNECTION_ID_PRESENT, CONNECTION_ID_ABSENT,
+      PACKET_4BYTE_PACKET_NUMBER);
+}
+
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length) {
+  return ConstructEncryptedPacket(
+      destination_connection_id, source_connection_id, version_flag, reset_flag,
+      packet_number, data, destination_connection_id_included,
+      source_connection_id_included, packet_number_length, nullptr);
+}
+
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length,
+    ParsedQuicVersionVector* versions) {
+  return ConstructEncryptedPacket(
+      destination_connection_id, source_connection_id, version_flag, reset_flag,
+      packet_number, data, destination_connection_id_included,
+      source_connection_id_included, packet_number_length, versions,
+      Perspective::IS_CLIENT);
+}
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length,
+    ParsedQuicVersionVector* versions,
+    Perspective perspective) {
+  QuicPacketHeader header;
+  header.destination_connection_id = destination_connection_id;
+  header.destination_connection_id_included =
+      destination_connection_id_included;
+  header.source_connection_id = source_connection_id;
+  header.source_connection_id_included = source_connection_id_included;
+  header.version_flag = version_flag;
+  header.reset_flag = reset_flag;
+  header.packet_number_length = packet_number_length;
+  header.packet_number = QuicPacketNumber(packet_number);
+  ParsedQuicVersionVector supported_versions = CurrentSupportedVersions();
+  if (!versions) {
+    versions = &supported_versions;
+  }
+  if (QuicVersionHasLongHeaderLengths((*versions)[0].transport_version) &&
+      version_flag) {
+    header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1;
+    header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2;
+  }
+
+  QuicFrames frames;
+  QuicFramer framer(*versions, QuicTime::Zero(), perspective,
+                    kQuicDefaultConnectionIdLength);
+  if ((*versions)[0].transport_version < QUIC_VERSION_47) {
+    QuicFrame frame(QuicStreamFrame(
+        QuicUtils::GetCryptoStreamId((*versions)[0].transport_version), false,
+        0, QuicStringPiece(data)));
+    frames.push_back(frame);
+  } else {
+    QuicFrame frame(new QuicCryptoFrame(ENCRYPTION_NONE, 0, data));
+    frames.push_back(frame);
+  }
+
+  std::unique_ptr<QuicPacket> packet(
+      BuildUnsizedDataPacket(&framer, header, frames));
+  EXPECT_TRUE(packet != nullptr);
+  char* buffer = new char[kMaxPacketSize];
+  size_t encrypted_length =
+      framer.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(packet_number),
+                            *packet, buffer, kMaxPacketSize);
+  EXPECT_NE(0u, encrypted_length);
+  DeleteFrames(&frames);
+  return new QuicEncryptedPacket(buffer, encrypted_length, true);
+}
+
+QuicReceivedPacket* ConstructReceivedPacket(
+    const QuicEncryptedPacket& encrypted_packet,
+    QuicTime receipt_time) {
+  char* buffer = new char[encrypted_packet.length()];
+  memcpy(buffer, encrypted_packet.data(), encrypted_packet.length());
+  return new QuicReceivedPacket(buffer, encrypted_packet.length(), receipt_time,
+                                true);
+}
+
+QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length,
+    ParsedQuicVersionVector* versions,
+    Perspective perspective) {
+  QuicPacketHeader header;
+  header.destination_connection_id = destination_connection_id;
+  header.destination_connection_id_included =
+      destination_connection_id_included;
+  header.source_connection_id = source_connection_id;
+  header.source_connection_id_included = source_connection_id_included;
+  header.version_flag = version_flag;
+  header.reset_flag = reset_flag;
+  header.packet_number_length = packet_number_length;
+  header.packet_number = QuicPacketNumber(packet_number);
+  QuicFrame frame(QuicStreamFrame(1, false, 0, QuicStringPiece(data)));
+  QuicFrames frames;
+  frames.push_back(frame);
+  QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(),
+                    QuicTime::Zero(), perspective,
+                    kQuicDefaultConnectionIdLength);
+
+  std::unique_ptr<QuicPacket> packet(
+      BuildUnsizedDataPacket(&framer, header, frames));
+  EXPECT_TRUE(packet != nullptr);
+
+  // Now set the frame type to 0x1F, which is an invalid frame type.
+  reinterpret_cast<unsigned char*>(
+      packet->mutable_data())[GetStartOfEncryptedData(
+      framer.transport_version(),
+      GetIncludedDestinationConnectionIdLength(header),
+      GetIncludedSourceConnectionIdLength(header), version_flag,
+      false /* no diversification nonce */, packet_number_length,
+      VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)] =
+      0x1F;
+
+  char* buffer = new char[kMaxPacketSize];
+  size_t encrypted_length =
+      framer.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(packet_number),
+                            *packet, buffer, kMaxPacketSize);
+  EXPECT_NE(0u, encrypted_length);
+  return new QuicEncryptedPacket(buffer, encrypted_length, true);
+}
+
+void CompareCharArraysWithHexError(const QuicString& description,
+                                   const char* actual,
+                                   const int actual_len,
+                                   const char* expected,
+                                   const int expected_len) {
+  EXPECT_EQ(actual_len, expected_len);
+  const int min_len = std::min(actual_len, expected_len);
+  const int max_len = std::max(actual_len, expected_len);
+  std::unique_ptr<bool[]> marks(new bool[max_len]);
+  bool identical = (actual_len == expected_len);
+  for (int i = 0; i < min_len; ++i) {
+    if (actual[i] != expected[i]) {
+      marks[i] = true;
+      identical = false;
+    } else {
+      marks[i] = false;
+    }
+  }
+  for (int i = min_len; i < max_len; ++i) {
+    marks[i] = true;
+  }
+  if (identical)
+    return;
+  ADD_FAILURE() << "Description:\n"
+                << description << "\n\nExpected:\n"
+                << HexDumpWithMarks(expected, expected_len, marks.get(),
+                                    max_len)
+                << "\nActual:\n"
+                << HexDumpWithMarks(actual, actual_len, marks.get(), max_len);
+}
+
+size_t GetPacketLengthForOneStream(
+    QuicTransportVersion version,
+    bool include_version,
+    bool include_diversification_nonce,
+    QuicConnectionIdLength destination_connection_id_length,
+    QuicConnectionIdLength source_connection_id_length,
+    QuicPacketNumberLength packet_number_length,
+    QuicVariableLengthIntegerLength retry_token_length_length,
+    QuicVariableLengthIntegerLength length_length,
+    size_t* payload_length) {
+  *payload_length = 1;
+  const size_t stream_length =
+      NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(*payload_length) +
+      QuicPacketCreator::StreamFramePacketOverhead(
+          version, destination_connection_id_length,
+          source_connection_id_length, include_version,
+          include_diversification_nonce, packet_number_length,
+          retry_token_length_length, length_length, 0u);
+  const size_t ack_length =
+      NullEncrypter(Perspective::IS_CLIENT)
+          .GetCiphertextSize(QuicFramer::GetMinAckFrameSize(
+              version, PACKET_1BYTE_PACKET_NUMBER)) +
+      GetPacketHeaderSize(version, destination_connection_id_length,
+                          source_connection_id_length, include_version,
+                          include_diversification_nonce, packet_number_length,
+                          retry_token_length_length, 0, length_length);
+  if (stream_length < ack_length) {
+    *payload_length = 1 + ack_length - stream_length;
+  }
+
+  return NullEncrypter(Perspective::IS_CLIENT)
+             .GetCiphertextSize(*payload_length) +
+         QuicPacketCreator::StreamFramePacketOverhead(
+             version, destination_connection_id_length,
+             source_connection_id_length, include_version,
+             include_diversification_nonce, packet_number_length,
+             retry_token_length_length, length_length, 0u);
+}
+
+QuicConfig DefaultQuicConfig() {
+  QuicConfig config;
+  config.SetInitialStreamFlowControlWindowToSend(
+      kInitialStreamFlowControlWindowForTest);
+  config.SetInitialSessionFlowControlWindowToSend(
+      kInitialSessionFlowControlWindowForTest);
+  QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(
+      &config, kDefaultMaxStreamsPerConnection);
+  // Default enable NSTP.
+  // This is unnecessary for versions > 44
+  if (!config.HasClientSentConnectionOption(quic::kNSTP,
+                                            quic::Perspective::IS_CLIENT)) {
+    quic::QuicTagVector connection_options;
+    connection_options.push_back(quic::kNSTP);
+    config.SetConnectionOptionsToSend(connection_options);
+  }
+  return config;
+}
+
+QuicConfig DefaultQuicConfigStatelessRejects() {
+  QuicConfig config = DefaultQuicConfig();
+  QuicTagVector copt;
+  copt.push_back(kSREJ);
+  config.SetConnectionOptionsToSend(copt);
+  return config;
+}
+
+QuicTransportVersionVector SupportedTransportVersions(
+    QuicTransportVersion version) {
+  QuicTransportVersionVector versions;
+  versions.push_back(version);
+  return versions;
+}
+
+ParsedQuicVersionVector SupportedVersions(ParsedQuicVersion version) {
+  ParsedQuicVersionVector versions;
+  versions.push_back(version);
+  return versions;
+}
+
+MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() {}
+
+MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {}
+
+MockReceivedPacketManager::MockReceivedPacketManager(QuicConnectionStats* stats)
+    : QuicReceivedPacketManager(stats) {}
+
+MockReceivedPacketManager::~MockReceivedPacketManager() {}
+
+MockConnectionCloseDelegate::MockConnectionCloseDelegate() {}
+
+MockConnectionCloseDelegate::~MockConnectionCloseDelegate() {}
+
+MockPacketCreatorDelegate::MockPacketCreatorDelegate() {}
+MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {}
+
+MockSessionNotifier::MockSessionNotifier() {}
+MockSessionNotifier::~MockSessionNotifier() {}
+
+void CreateClientSessionForTest(
+    QuicServerId server_id,
+    bool supports_stateless_rejects,
+    QuicTime::Delta connection_start_time,
+    const ParsedQuicVersionVector& supported_versions,
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    QuicCryptoClientConfig* crypto_client_config,
+    PacketSavingConnection** client_connection,
+    TestQuicSpdyClientSession** client_session) {
+  CHECK(crypto_client_config);
+  CHECK(client_connection);
+  CHECK(client_session);
+  CHECK(!connection_start_time.IsZero())
+      << "Connections must start at non-zero times, otherwise the "
+      << "strike-register will be unhappy.";
+
+  QuicConfig config = supports_stateless_rejects
+                          ? DefaultQuicConfigStatelessRejects()
+                          : DefaultQuicConfig();
+  *client_connection = new PacketSavingConnection(
+      helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
+  *client_session = new TestQuicSpdyClientSession(*client_connection, config,
+                                                  supported_versions, server_id,
+                                                  crypto_client_config);
+  (*client_connection)->AdvanceTime(connection_start_time);
+}
+
+void CreateServerSessionForTest(
+    QuicServerId server_id,
+    QuicTime::Delta connection_start_time,
+    ParsedQuicVersionVector supported_versions,
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    QuicCryptoServerConfig* server_crypto_config,
+    QuicCompressedCertsCache* compressed_certs_cache,
+    PacketSavingConnection** server_connection,
+    TestQuicSpdyServerSession** server_session) {
+  CHECK(server_crypto_config);
+  CHECK(server_connection);
+  CHECK(server_session);
+  CHECK(!connection_start_time.IsZero())
+      << "Connections must start at non-zero times, otherwise the "
+      << "strike-register will be unhappy.";
+
+  *server_connection =
+      new PacketSavingConnection(helper, alarm_factory, Perspective::IS_SERVER,
+                                 ParsedVersionOfIndex(supported_versions, 0));
+  *server_session = new TestQuicSpdyServerSession(
+      *server_connection, DefaultQuicConfig(), supported_versions,
+      server_crypto_config, compressed_certs_cache);
+
+  // We advance the clock initially because the default time is zero and the
+  // strike register worries that we've just overflowed a uint32_t time.
+  (*server_connection)->AdvanceTime(connection_start_time);
+}
+
+QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
+    QuicTransportVersion version,
+    int n) {
+  return QuicUtils::GetFirstBidirectionalStreamId(version,
+                                                  Perspective::IS_CLIENT) +
+         // + 1 because spdy_session contains headers stream.
+         QuicUtils::StreamIdDelta(version) * (n + 1);
+}
+
+QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
+    QuicTransportVersion version,
+    int n) {
+  return QuicUtils::GetFirstBidirectionalStreamId(version,
+                                                  Perspective::IS_SERVER) +
+         QuicUtils::StreamIdDelta(version) * n;
+}
+
+QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
+    QuicTransportVersion version,
+    int n) {
+  return QuicUtils::GetFirstUnidirectionalStreamId(version,
+                                                   Perspective::IS_SERVER) +
+         QuicUtils::StreamIdDelta(version) * n;
+}
+
+StreamType DetermineStreamType(QuicStreamId id,
+                               QuicTransportVersion version,
+                               Perspective perspective,
+                               bool is_incoming,
+                               StreamType default_type) {
+  return version == QUIC_VERSION_99
+             ? QuicUtils::GetStreamType(id, perspective, is_incoming)
+             : default_type;
+}
+
+QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator,
+                          QuicStringPiece message_data,
+                          QuicMemSliceStorage* storage) {
+  if (message_data.length() == 0) {
+    *storage = QuicMemSliceStorage(nullptr, 0, allocator, kMaxPacketSize);
+    return storage->ToSpan();
+  }
+  struct iovec iov = {const_cast<char*>(message_data.data()),
+                      message_data.length()};
+  *storage = QuicMemSliceStorage(&iov, 1, allocator, kMaxPacketSize);
+  return storage->ToSpan();
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
new file mode 100644
index 0000000..2cca768
--- /dev/null
+++ b/quic/test_tools/quic_test_utils.h
@@ -0,0 +1,1201 @@
+// 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.
+
+// Common utilities for Quic tests
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_close_delegate_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
+#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_random.h"
+
+namespace quic {
+
+namespace test {
+
+// A generic predictable connection ID suited for testing.
+QuicConnectionId TestConnectionId();
+
+// A generic predictable connection ID suited for testing, generated from a
+// given number, such as an index.
+QuicConnectionId TestConnectionId(uint64_t connection_number);
+
+// Extracts the connection number passed to TestConnectionId().
+uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id);
+
+static const uint16_t kTestPort = 12345;
+static const uint32_t kInitialStreamFlowControlWindowForTest =
+    1024 * 1024;  // 1 MB
+static const uint32_t kInitialSessionFlowControlWindowForTest =
+    1536 * 1024;  // 1.5 MB
+
+// Returns the test peer IP address.
+QuicIpAddress TestPeerIPAddress();
+
+// Upper limit on versions we support.
+ParsedQuicVersion QuicVersionMax();
+
+// Lower limit on versions we support.
+ParsedQuicVersion QuicVersionMin();
+
+// Upper limit on versions we support.
+// TODO(nharper): Remove this function when it is no longer used.
+QuicTransportVersion QuicTransportVersionMax();
+
+// Lower limit on versions we support.
+// TODO(nharper): Remove this function when it is no longer used.
+QuicTransportVersion QuicTransportVersionMin();
+
+// Create an encrypted packet for testing.
+// If versions == nullptr, uses &AllSupportedVersions().
+// Note that the packet is encrypted with NullEncrypter, so to decrypt the
+// constructed packet, the framer must be set to use NullDecrypter.
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length,
+    ParsedQuicVersionVector* versions,
+    Perspective perspective);
+
+// Create an encrypted packet for testing.
+// If versions == nullptr, uses &AllSupportedVersions().
+// Note that the packet is encrypted with NullEncrypter, so to decrypt the
+// constructed packet, the framer must be set to use NullDecrypter.
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length,
+    ParsedQuicVersionVector* versions);
+
+// This form assumes |versions| == nullptr.
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length);
+
+// This form assumes |connection_id_length| == PACKET_8BYTE_CONNECTION_ID,
+// |packet_number_length| == PACKET_4BYTE_PACKET_NUMBER and
+// |versions| == nullptr.
+QuicEncryptedPacket* ConstructEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data);
+
+// Constructs a received packet for testing. The caller must take ownership of
+// the returned pointer.
+QuicReceivedPacket* ConstructReceivedPacket(
+    const QuicEncryptedPacket& encrypted_packet,
+    QuicTime receipt_time);
+
+// Create an encrypted packet for testing whose data portion erroneous.
+// The specific way the data portion is erroneous is not specified, but
+// it is an error that QuicFramer detects.
+// Note that the packet is encrypted with NullEncrypter, so to decrypt the
+// constructed packet, the framer must be set to use NullDecrypter.
+QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
+    QuicConnectionId destination_connection_id,
+    QuicConnectionId source_connection_id,
+    bool version_flag,
+    bool reset_flag,
+    uint64_t packet_number,
+    const QuicString& data,
+    QuicConnectionIdIncluded destination_connection_id_included,
+    QuicConnectionIdIncluded source_connection_id_included,
+    QuicPacketNumberLength packet_number_length,
+    ParsedQuicVersionVector* versions,
+    Perspective perspective);
+
+void CompareCharArraysWithHexError(const QuicString& description,
+                                   const char* actual,
+                                   const int actual_len,
+                                   const char* expected,
+                                   const int expected_len);
+
+// Returns the length of a QuicPacket that is capable of holding either a
+// stream frame or a minimal ack frame.  Sets |*payload_length| to the number
+// of bytes of stream data that will fit in such a packet.
+size_t GetPacketLengthForOneStream(
+    QuicTransportVersion version,
+    bool include_version,
+    bool include_diversification_nonce,
+    QuicConnectionIdLength destination_connection_id_length,
+    QuicConnectionIdLength source_connection_id_length,
+    QuicPacketNumberLength packet_number_length,
+    QuicVariableLengthIntegerLength retry_token_length_length,
+    QuicVariableLengthIntegerLength length_length,
+    size_t* payload_length);
+
+// Returns QuicConfig set to default values.
+QuicConfig DefaultQuicConfig();
+
+// Returns a QuicConfig set to default values that supports stateless rejects.
+QuicConfig DefaultQuicConfigStatelessRejects();
+
+// Returns a version vector consisting of |version|.
+QuicTransportVersionVector SupportedTransportVersions(
+    QuicTransportVersion version);
+
+ParsedQuicVersionVector SupportedVersions(ParsedQuicVersion version);
+
+struct QuicAckBlock {
+  QuicPacketNumber start;  // Included
+  QuicPacketNumber limit;  // Excluded
+};
+
+// Testing convenience method to construct a QuicAckFrame with arbitrary ack
+// blocks. Each block is given by a (closed-open) range of packet numbers. e.g.:
+// InitAckFrame({{1, 10}})
+//   => 1 ack block acking packet numbers 1 to 9.
+//
+// InitAckFrame({{1, 2}, {3, 4}})
+//   => 2 ack blocks acking packet 1 and 3. Packet 2 is missing.
+QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks);
+
+// Testing convenience method to construct a QuicAckFrame with 1 ack block which
+// covers packet number range [1, |largest_acked| + 1).
+// Equivalent to InitAckFrame({{1, largest_acked + 1}})
+QuicAckFrame InitAckFrame(uint64_t largest_acked);
+QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked);
+
+// Testing convenience method to construct a QuicAckFrame with |num_ack_blocks|
+// ack blocks of width 1 packet, starting from |least_unacked| + 2.
+QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks,
+                                       uint64_t least_unacked);
+
+// Returns a QuicPacket that is owned by the caller, and
+// is populated with the fields in |header| and |frames|, or is nullptr if the
+// packet could not be created.
+std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
+    QuicFramer* framer,
+    const QuicPacketHeader& header,
+    const QuicFrames& frames);
+// Returns a QuicPacket that is owned by the caller, and of size |packet_size|.
+std::unique_ptr<QuicPacket> BuildUnsizedDataPacket(
+    QuicFramer* framer,
+    const QuicPacketHeader& header,
+    const QuicFrames& frames,
+    size_t packet_size);
+
+// Compute SHA-1 hash of the supplied QuicString.
+QuicString Sha1Hash(QuicStringPiece data);
+
+// Simple random number generator used to compute random numbers suitable
+// for pseudo-randomly dropping packets in tests.  It works by computing
+// the sha1 hash of the current seed, and using the first 64 bits as
+// the next random number, and the next seed.
+class SimpleRandom : public QuicRandom {
+ public:
+  SimpleRandom() : seed_(0) {}
+  SimpleRandom(const SimpleRandom&) = delete;
+  SimpleRandom& operator=(const SimpleRandom&) = delete;
+  ~SimpleRandom() override {}
+
+  // Returns a random number in the range [0, kuint64max].
+  uint64_t RandUint64() override;
+
+  void RandBytes(void* data, size_t len) override;
+
+  void set_seed(uint64_t seed) { seed_ = seed; }
+
+ private:
+  uint64_t seed_;
+};
+
+class MockFramerVisitor : public QuicFramerVisitorInterface {
+ public:
+  MockFramerVisitor();
+  MockFramerVisitor(const MockFramerVisitor&) = delete;
+  MockFramerVisitor& operator=(const MockFramerVisitor&) = delete;
+  ~MockFramerVisitor() override;
+
+  MOCK_METHOD1(OnError, void(QuicFramer* framer));
+  // The constructor sets this up to return false by default.
+  MOCK_METHOD2(OnProtocolVersionMismatch,
+               bool(ParsedQuicVersion version, PacketHeaderFormat form));
+  MOCK_METHOD0(OnPacket, void());
+  MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header));
+  MOCK_METHOD1(OnVersionNegotiationPacket,
+               void(const QuicVersionNegotiationPacket& packet));
+  // The constructor sets this up to return true by default.
+  MOCK_METHOD1(OnUnauthenticatedHeader, bool(const QuicPacketHeader& header));
+  // The constructor sets this up to return true by default.
+  MOCK_METHOD1(OnUnauthenticatedPublicHeader,
+               bool(const QuicPacketHeader& header));
+  MOCK_METHOD1(OnDecryptedPacket, void(EncryptionLevel level));
+  MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header));
+  MOCK_METHOD1(OnCoalescedPacket, void(const QuicEncryptedPacket& packet));
+  MOCK_METHOD1(OnStreamFrame, bool(const QuicStreamFrame& frame));
+  MOCK_METHOD1(OnCryptoFrame, bool(const QuicCryptoFrame& frame));
+  MOCK_METHOD2(OnAckFrameStart, bool(QuicPacketNumber, QuicTime::Delta));
+  MOCK_METHOD2(OnAckRange, bool(QuicPacketNumber, QuicPacketNumber));
+  MOCK_METHOD2(OnAckTimestamp, bool(QuicPacketNumber, QuicTime));
+  MOCK_METHOD1(OnAckFrameEnd, bool(QuicPacketNumber));
+  MOCK_METHOD1(OnStopWaitingFrame, bool(const QuicStopWaitingFrame& frame));
+  MOCK_METHOD1(OnPaddingFrame, bool(const QuicPaddingFrame& frame));
+  MOCK_METHOD1(OnPingFrame, bool(const QuicPingFrame& frame));
+  MOCK_METHOD1(OnRstStreamFrame, bool(const QuicRstStreamFrame& frame));
+  MOCK_METHOD1(OnConnectionCloseFrame,
+               bool(const QuicConnectionCloseFrame& frame));
+  MOCK_METHOD1(OnApplicationCloseFrame,
+               bool(const QuicApplicationCloseFrame& frame));
+  MOCK_METHOD1(OnNewConnectionIdFrame,
+               bool(const QuicNewConnectionIdFrame& frame));
+  MOCK_METHOD1(OnRetireConnectionIdFrame,
+               bool(const QuicRetireConnectionIdFrame& frame));
+  MOCK_METHOD1(OnNewTokenFrame, bool(const QuicNewTokenFrame& frame));
+  MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame));
+  MOCK_METHOD1(OnPathChallengeFrame, bool(const QuicPathChallengeFrame& frame));
+  MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame& frame));
+  MOCK_METHOD1(OnGoAwayFrame, bool(const QuicGoAwayFrame& frame));
+  MOCK_METHOD1(OnMaxStreamIdFrame, bool(const QuicMaxStreamIdFrame& frame));
+  MOCK_METHOD1(OnStreamIdBlockedFrame,
+               bool(const QuicStreamIdBlockedFrame& frame));
+  MOCK_METHOD1(OnWindowUpdateFrame, bool(const QuicWindowUpdateFrame& frame));
+  MOCK_METHOD1(OnBlockedFrame, bool(const QuicBlockedFrame& frame));
+  MOCK_METHOD1(OnMessageFrame, bool(const QuicMessageFrame& frame));
+  MOCK_METHOD0(OnPacketComplete, void());
+  MOCK_CONST_METHOD1(IsValidStatelessResetToken, bool(QuicUint128));
+  MOCK_METHOD1(OnAuthenticatedIetfStatelessResetPacket,
+               void(const QuicIetfStatelessResetPacket&));
+};
+
+class NoOpFramerVisitor : public QuicFramerVisitorInterface {
+ public:
+  NoOpFramerVisitor() {}
+  NoOpFramerVisitor(const NoOpFramerVisitor&) = delete;
+  NoOpFramerVisitor& operator=(const NoOpFramerVisitor&) = delete;
+
+  void OnError(QuicFramer* framer) override {}
+  void OnPacket() override {}
+  void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {}
+  void OnVersionNegotiationPacket(
+      const QuicVersionNegotiationPacket& packet) override {}
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override;
+  bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
+  bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
+  void OnDecryptedPacket(EncryptionLevel level) override {}
+  bool OnPacketHeader(const QuicPacketHeader& header) override;
+  void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
+  bool OnStreamFrame(const QuicStreamFrame& frame) override;
+  bool OnCryptoFrame(const QuicCryptoFrame& frame) override;
+  bool OnAckFrameStart(QuicPacketNumber largest_acked,
+                       QuicTime::Delta ack_delay_time) override;
+  bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override;
+  bool OnAckTimestamp(QuicPacketNumber packet_number,
+                      QuicTime timestamp) override;
+  bool OnAckFrameEnd(QuicPacketNumber start) override;
+  bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
+  bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
+  bool OnPingFrame(const QuicPingFrame& frame) override;
+  bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
+  bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
+  bool OnApplicationCloseFrame(const QuicApplicationCloseFrame& frame) override;
+  bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override;
+  bool OnRetireConnectionIdFrame(
+      const QuicRetireConnectionIdFrame& frame) override;
+  bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override;
+  bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override;
+  bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override;
+  bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override;
+  bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
+  bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override;
+  bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override;
+  bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
+  bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
+  bool OnMessageFrame(const QuicMessageFrame& frame) override;
+  void OnPacketComplete() override {}
+  bool IsValidStatelessResetToken(QuicUint128 token) const override;
+  void OnAuthenticatedIetfStatelessResetPacket(
+      const QuicIetfStatelessResetPacket& packet) override {}
+};
+
+class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface {
+ public:
+  MockQuicConnectionVisitor();
+  MockQuicConnectionVisitor(const MockQuicConnectionVisitor&) = delete;
+  MockQuicConnectionVisitor& operator=(const MockQuicConnectionVisitor&) =
+      delete;
+  ~MockQuicConnectionVisitor() override;
+
+  MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame& frame));
+  MOCK_METHOD1(OnCryptoFrame, void(const QuicCryptoFrame& frame));
+  MOCK_METHOD1(OnWindowUpdateFrame, void(const QuicWindowUpdateFrame& frame));
+  MOCK_METHOD1(OnBlockedFrame, void(const QuicBlockedFrame& frame));
+  MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame));
+  MOCK_METHOD1(OnGoAway, void(const QuicGoAwayFrame& frame));
+  MOCK_METHOD1(OnMessageReceived, void(QuicStringPiece message));
+  MOCK_METHOD3(OnConnectionClosed,
+               void(QuicErrorCode error,
+                    const QuicString& error_details,
+                    ConnectionCloseSource source));
+  MOCK_METHOD0(OnWriteBlocked, void());
+  MOCK_METHOD0(OnCanWrite, void());
+  MOCK_METHOD1(OnCongestionWindowChange, void(QuicTime now));
+  MOCK_METHOD1(OnConnectionMigration, void(AddressChangeType type));
+  MOCK_METHOD0(OnPathDegrading, void());
+  MOCK_CONST_METHOD0(WillingAndAbleToWrite, bool());
+  MOCK_CONST_METHOD0(HasPendingHandshake, bool());
+  MOCK_CONST_METHOD0(ShouldKeepConnectionAlive, bool());
+  MOCK_METHOD1(OnSuccessfulVersionNegotiation,
+               void(const ParsedQuicVersion& version));
+  MOCK_METHOD2(OnConnectivityProbeReceived,
+               void(const QuicSocketAddress& self_address,
+                    const QuicSocketAddress& peer_address));
+  MOCK_METHOD0(OnConfigNegotiated, void());
+  MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void());
+  MOCK_METHOD0(SendPing, void());
+  MOCK_CONST_METHOD0(AllowSelfAddressChange, bool());
+  MOCK_METHOD0(OnForwardProgressConfirmed, void());
+  MOCK_METHOD1(OnMaxStreamIdFrame, bool(const QuicMaxStreamIdFrame& frame));
+  MOCK_METHOD1(OnStreamIdBlockedFrame,
+               bool(const QuicStreamIdBlockedFrame& frame));
+  MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame));
+};
+
+class MockQuicConnectionHelper : public QuicConnectionHelperInterface {
+ public:
+  MockQuicConnectionHelper();
+  MockQuicConnectionHelper(const MockQuicConnectionHelper&) = delete;
+  MockQuicConnectionHelper& operator=(const MockQuicConnectionHelper&) = delete;
+  ~MockQuicConnectionHelper() override;
+  const QuicClock* GetClock() const override;
+  QuicRandom* GetRandomGenerator() override;
+  QuicBufferAllocator* GetStreamSendBufferAllocator() override;
+  void AdvanceTime(QuicTime::Delta delta);
+
+ private:
+  MockClock clock_;
+  MockRandom random_generator_;
+  SimpleBufferAllocator buffer_allocator_;
+};
+
+class MockAlarmFactory : public QuicAlarmFactory {
+ public:
+  QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
+  QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+      QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+      QuicConnectionArena* arena) override;
+
+  // No-op alarm implementation
+  class TestAlarm : public QuicAlarm {
+   public:
+    explicit TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+        : QuicAlarm(std::move(delegate)) {}
+
+    void SetImpl() override {}
+    void CancelImpl() override {}
+
+    using QuicAlarm::Fire;
+  };
+
+  void FireAlarm(QuicAlarm* alarm) {
+    reinterpret_cast<TestAlarm*>(alarm)->Fire();
+  }
+};
+
+class MockQuicConnection : public QuicConnection {
+ public:
+  // Uses a ConnectionId of 42 and 127.0.0.1:123.
+  MockQuicConnection(MockQuicConnectionHelper* helper,
+                     MockAlarmFactory* alarm_factory,
+                     Perspective perspective);
+
+  // Uses a ConnectionId of 42.
+  MockQuicConnection(QuicSocketAddress address,
+                     MockQuicConnectionHelper* helper,
+                     MockAlarmFactory* alarm_factory,
+                     Perspective perspective);
+
+  // Uses 127.0.0.1:123.
+  MockQuicConnection(QuicConnectionId connection_id,
+                     MockQuicConnectionHelper* helper,
+                     MockAlarmFactory* alarm_factory,
+                     Perspective perspective);
+
+  // Uses a ConnectionId of 42, and 127.0.0.1:123.
+  MockQuicConnection(MockQuicConnectionHelper* helper,
+                     MockAlarmFactory* alarm_factory,
+                     Perspective perspective,
+                     const ParsedQuicVersionVector& supported_versions);
+
+  MockQuicConnection(QuicConnectionId connection_id,
+                     QuicSocketAddress address,
+                     MockQuicConnectionHelper* helper,
+                     MockAlarmFactory* alarm_factory,
+                     Perspective perspective,
+                     const ParsedQuicVersionVector& supported_versions);
+  MockQuicConnection(const MockQuicConnection&) = delete;
+  MockQuicConnection& operator=(const MockQuicConnection&) = delete;
+
+  ~MockQuicConnection() override;
+
+  // If the constructor that uses a MockQuicConnectionHelper has been used then
+  // this method
+  // will advance the time of the MockClock.
+  void AdvanceTime(QuicTime::Delta delta);
+
+  MOCK_METHOD3(ProcessUdpPacket,
+               void(const QuicSocketAddress& self_address,
+                    const QuicSocketAddress& peer_address,
+                    const QuicReceivedPacket& packet));
+  MOCK_METHOD1(SendConnectionClose, void(QuicErrorCode error));
+  MOCK_METHOD3(CloseConnection,
+               void(QuicErrorCode error,
+                    const QuicString& details,
+                    ConnectionCloseBehavior connection_close_behavior));
+  MOCK_METHOD3(SendConnectionClosePacket,
+               void(QuicErrorCode error,
+                    const QuicString& details,
+                    AckBundling ack_mode));
+  MOCK_METHOD3(SendRstStream,
+               void(QuicStreamId id,
+                    QuicRstStreamErrorCode error,
+                    QuicStreamOffset bytes_written));
+  MOCK_METHOD3(SendGoAway,
+               void(QuicErrorCode error,
+                    QuicStreamId last_good_stream_id,
+                    const QuicString& reason));
+  MOCK_METHOD1(SendBlocked, void(QuicStreamId id));
+  MOCK_METHOD2(SendWindowUpdate,
+               void(QuicStreamId id, QuicStreamOffset byte_offset));
+  MOCK_METHOD0(OnCanWrite, void());
+  MOCK_METHOD1(SendConnectivityProbingResponsePacket,
+               void(const QuicSocketAddress& peer_address));
+  MOCK_METHOD2(SendConnectivityProbingPacket,
+               bool(QuicPacketWriter* probing_writer,
+                    const QuicSocketAddress& peer_address));
+
+  MOCK_METHOD1(OnSendConnectionState, void(const CachedNetworkParameters&));
+  MOCK_METHOD2(ResumeConnectionState,
+               void(const CachedNetworkParameters&, bool));
+  MOCK_METHOD1(SetMaxPacingRate, void(QuicBandwidth));
+
+  MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode));
+  MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame));
+  MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicMemSliceSpan));
+  MOCK_METHOD3(OnConnectionClosed,
+               void(QuicErrorCode error,
+                    const QuicString& error_details,
+                    ConnectionCloseSource source));
+
+  MOCK_METHOD1(OnError, void(QuicFramer* framer));
+  void QuicConnection_OnError(QuicFramer* framer) {
+    QuicConnection::OnError(framer);
+  }
+
+  void ReallyCloseConnection(
+      QuicErrorCode error,
+      const QuicString& details,
+      ConnectionCloseBehavior connection_close_behavior) {
+    QuicConnection::CloseConnection(error, details, connection_close_behavior);
+  }
+
+  void ReallyProcessUdpPacket(const QuicSocketAddress& self_address,
+                              const QuicSocketAddress& peer_address,
+                              const QuicReceivedPacket& packet) {
+    QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
+  }
+
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override;
+
+  bool ReallySendControlFrame(const QuicFrame& frame) {
+    return QuicConnection::SendControlFrame(frame);
+  }
+
+  bool ReallySendConnectivityProbingPacket(
+      QuicPacketWriter* probing_writer,
+      const QuicSocketAddress& peer_address) {
+    return QuicConnection::SendConnectivityProbingPacket(probing_writer,
+                                                         peer_address);
+  }
+
+  void ReallySendConnectivityProbingResponsePacket(
+      const QuicSocketAddress& peer_address) {
+    QuicConnection::SendConnectivityProbingResponsePacket(peer_address);
+  }
+  MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&));
+  MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame));
+  MOCK_METHOD3(SendCryptoData,
+               size_t(EncryptionLevel, size_t, QuicStreamOffset));
+  size_t QuicConnection_SendCryptoData(EncryptionLevel level,
+                                       size_t write_length,
+                                       QuicStreamOffset offset) {
+    return QuicConnection::SendCryptoData(level, write_length, offset);
+  }
+};
+
+class PacketSavingConnection : public MockQuicConnection {
+ public:
+  PacketSavingConnection(MockQuicConnectionHelper* helper,
+                         MockAlarmFactory* alarm_factory,
+                         Perspective perspective);
+
+  PacketSavingConnection(MockQuicConnectionHelper* helper,
+                         MockAlarmFactory* alarm_factory,
+                         Perspective perspective,
+                         const ParsedQuicVersionVector& supported_versions);
+  PacketSavingConnection(const PacketSavingConnection&) = delete;
+  PacketSavingConnection& operator=(const PacketSavingConnection&) = delete;
+
+  ~PacketSavingConnection() override;
+
+  void SendOrQueuePacket(SerializedPacket* packet) override;
+
+  std::vector<std::unique_ptr<QuicEncryptedPacket>> encrypted_packets_;
+  MockClock clock_;
+};
+
+class MockQuicSession : public QuicSession {
+ public:
+  // Takes ownership of |connection|.
+  MockQuicSession(QuicConnection* connection, bool create_mock_crypto_stream);
+
+  // Takes ownership of |connection|.
+  explicit MockQuicSession(QuicConnection* connection);
+  MockQuicSession(const MockQuicSession&) = delete;
+  MockQuicSession& operator=(const MockQuicSession&) = delete;
+  ~MockQuicSession() override;
+
+  QuicCryptoStream* GetMutableCryptoStream() override;
+  const QuicCryptoStream* GetCryptoStream() const override;
+  void SetCryptoStream(QuicCryptoStream* crypto_stream);
+
+  MOCK_METHOD3(OnConnectionClosed,
+               void(QuicErrorCode error,
+                    const QuicString& error_details,
+                    ConnectionCloseSource source));
+  MOCK_METHOD1(CreateIncomingStream, QuicStream*(QuicStreamId id));
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream stream));
+  MOCK_METHOD1(ShouldCreateIncomingStream2, bool(QuicStreamId id));
+  MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool());
+  MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool());
+  MOCK_METHOD5(WritevData,
+               QuicConsumedData(QuicStream* stream,
+                                QuicStreamId id,
+                                size_t write_length,
+                                QuicStreamOffset offset,
+                                StreamSendingState state));
+
+  MOCK_METHOD3(SendRstStream,
+               void(QuicStreamId stream_id,
+                    QuicRstStreamErrorCode error,
+                    QuicStreamOffset bytes_written));
+
+  MOCK_METHOD2(OnStreamHeaders,
+               void(QuicStreamId stream_id, QuicStringPiece headers_data));
+  MOCK_METHOD2(OnStreamHeadersPriority,
+               void(QuicStreamId stream_id, spdy::SpdyPriority priority));
+  MOCK_METHOD3(OnStreamHeadersComplete,
+               void(QuicStreamId stream_id, bool fin, size_t frame_len));
+  MOCK_CONST_METHOD0(IsCryptoHandshakeConfirmed, bool());
+  MOCK_CONST_METHOD0(ShouldKeepConnectionAlive, bool());
+  MOCK_METHOD2(SendStopSending, void(uint16_t code, QuicStreamId stream_id));
+
+  using QuicSession::ActivateStream;
+
+  // Returns a QuicConsumedData that indicates all of |write_length| (and |fin|
+  // if set) has been consumed.
+  static QuicConsumedData ConsumeData(QuicStream* stream,
+                                      QuicStreamId id,
+                                      size_t write_length,
+                                      QuicStreamOffset offset,
+                                      StreamSendingState state);
+
+ private:
+  std::unique_ptr<QuicCryptoStream> crypto_stream_;
+};
+
+class MockQuicCryptoStream : public QuicCryptoStream {
+ public:
+  explicit MockQuicCryptoStream(QuicSession* session);
+
+  ~MockQuicCryptoStream() override;
+
+  bool encryption_established() const override;
+  bool handshake_confirmed() const override;
+  const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
+      const override;
+  CryptoMessageParser* crypto_message_parser() override;
+
+ private:
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
+  CryptoFramer crypto_framer_;
+};
+
+class MockQuicSpdySession : public QuicSpdySession {
+ public:
+  // Takes ownership of |connection|.
+  explicit MockQuicSpdySession(QuicConnection* connection);
+  // Takes ownership of |connection|.
+  MockQuicSpdySession(QuicConnection* connection,
+                      bool create_mock_crypto_stream);
+  MockQuicSpdySession(const MockQuicSpdySession&) = delete;
+  MockQuicSpdySession& operator=(const MockQuicSpdySession&) = delete;
+  ~MockQuicSpdySession() override;
+
+  QuicCryptoStream* GetMutableCryptoStream() override;
+  const QuicCryptoStream* GetCryptoStream() const override;
+  void SetCryptoStream(QuicCryptoStream* crypto_stream);
+
+  // From QuicSession.
+  MOCK_METHOD3(OnConnectionClosed,
+               void(QuicErrorCode error,
+                    const QuicString& error_details,
+                    ConnectionCloseSource source));
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id));
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream stream));
+  MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*());
+  MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*());
+  MOCK_METHOD1(ShouldCreateIncomingStream, bool(QuicStreamId id));
+  MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool());
+  MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool());
+  MOCK_METHOD5(WritevData,
+               QuicConsumedData(QuicStream* stream,
+                                QuicStreamId id,
+                                size_t write_length,
+                                QuicStreamOffset offset,
+                                StreamSendingState state));
+
+  MOCK_METHOD3(SendRstStream,
+               void(QuicStreamId stream_id,
+                    QuicRstStreamErrorCode error,
+                    QuicStreamOffset bytes_written));
+
+  MOCK_METHOD2(OnStreamHeaders,
+               void(QuicStreamId stream_id, QuicStringPiece headers_data));
+  MOCK_METHOD2(OnStreamHeadersPriority,
+               void(QuicStreamId stream_id, spdy::SpdyPriority priority));
+  MOCK_METHOD3(OnStreamHeadersComplete,
+               void(QuicStreamId stream_id, bool fin, size_t frame_len));
+  MOCK_METHOD4(OnStreamHeaderList,
+               void(QuicStreamId stream_id,
+                    bool fin,
+                    size_t frame_len,
+                    const QuicHeaderList& header_list));
+  MOCK_CONST_METHOD0(IsCryptoHandshakeConfirmed, bool());
+  MOCK_METHOD2(OnPromiseHeaders,
+               void(QuicStreamId stream_id, QuicStringPiece headers_data));
+  MOCK_METHOD3(OnPromiseHeadersComplete,
+               void(QuicStreamId stream_id,
+                    QuicStreamId promised_stream_id,
+                    size_t frame_len));
+  MOCK_METHOD4(OnPromiseHeaderList,
+               void(QuicStreamId stream_id,
+                    QuicStreamId promised_stream_id,
+                    size_t frame_len,
+                    const QuicHeaderList& header_list));
+  MOCK_METHOD2(OnPriorityFrame,
+               void(QuicStreamId id, spdy::SpdyPriority priority));
+
+  MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
+  MOCK_METHOD4(
+      OnStreamFrameData,
+      void(QuicStreamId stream_id, const char* data, size_t len, bool fin));
+
+  using QuicSession::ActivateStream;
+
+ private:
+  std::unique_ptr<QuicCryptoStream> crypto_stream_;
+};
+
+class TestQuicSpdyServerSession : public QuicServerSessionBase {
+ public:
+  // Takes ownership of |connection|.
+  TestQuicSpdyServerSession(QuicConnection* connection,
+                            const QuicConfig& config,
+                            const ParsedQuicVersionVector& supported_versions,
+                            const QuicCryptoServerConfig* crypto_config,
+                            QuicCompressedCertsCache* compressed_certs_cache);
+  TestQuicSpdyServerSession(const TestQuicSpdyServerSession&) = delete;
+  TestQuicSpdyServerSession& operator=(const TestQuicSpdyServerSession&) =
+      delete;
+  ~TestQuicSpdyServerSession() override;
+
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id));
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream stream));
+  MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*());
+  MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*());
+  QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
+      const QuicCryptoServerConfig* crypto_config,
+      QuicCompressedCertsCache* compressed_certs_cache) override;
+
+  // Override to not send max header list size.
+  void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
+
+  QuicCryptoServerStream* GetMutableCryptoStream() override;
+
+  const QuicCryptoServerStream* GetCryptoStream() const override;
+
+  MockQuicCryptoServerStreamHelper* helper() { return &helper_; }
+
+ private:
+  MockQuicSessionVisitor visitor_;
+  MockQuicCryptoServerStreamHelper helper_;
+};
+
+// A test implementation of QuicClientPushPromiseIndex::Delegate.
+class TestPushPromiseDelegate : public QuicClientPushPromiseIndex::Delegate {
+ public:
+  // |match| sets the validation result for checking whether designated header
+  // fields match for promise request and client request.
+  explicit TestPushPromiseDelegate(bool match);
+
+  bool CheckVary(const spdy::SpdyHeaderBlock& client_request,
+                 const spdy::SpdyHeaderBlock& promise_request,
+                 const spdy::SpdyHeaderBlock& promise_response) override;
+
+  void OnRendezvousResult(QuicSpdyStream* stream) override;
+
+  QuicSpdyStream* rendezvous_stream() { return rendezvous_stream_; }
+  bool rendezvous_fired() { return rendezvous_fired_; }
+
+ private:
+  bool match_;
+  bool rendezvous_fired_;
+  QuicSpdyStream* rendezvous_stream_;
+};
+
+class TestQuicSpdyClientSession : public QuicSpdyClientSessionBase {
+ public:
+  TestQuicSpdyClientSession(QuicConnection* connection,
+                            const QuicConfig& config,
+                            const ParsedQuicVersionVector& supported_versions,
+                            const QuicServerId& server_id,
+                            QuicCryptoClientConfig* crypto_config);
+  TestQuicSpdyClientSession(const TestQuicSpdyClientSession&) = delete;
+  TestQuicSpdyClientSession& operator=(const TestQuicSpdyClientSession&) =
+      delete;
+  ~TestQuicSpdyClientSession() override;
+
+  bool IsAuthorized(const QuicString& authority) override;
+
+  // QuicSpdyClientSessionBase
+  MOCK_METHOD1(OnProofValid,
+               void(const QuicCryptoClientConfig::CachedState& cached));
+  MOCK_METHOD1(OnProofVerifyDetailsAvailable,
+               void(const ProofVerifyDetails& verify_details));
+
+  // TestQuicSpdyClientSession
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(QuicStreamId id));
+  MOCK_METHOD1(CreateIncomingStream, QuicSpdyStream*(PendingStream stream));
+  MOCK_METHOD0(CreateOutgoingBidirectionalStream, QuicSpdyStream*());
+  MOCK_METHOD0(CreateOutgoingUnidirectionalStream, QuicSpdyStream*());
+  MOCK_METHOD1(ShouldCreateIncomingStream, bool(QuicStreamId id));
+  MOCK_METHOD0(ShouldCreateOutgoingBidirectionalStream, bool());
+  MOCK_METHOD0(ShouldCreateOutgoingUnidirectionalStream, bool());
+
+  // Override to not send max header list size.
+  void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
+  QuicCryptoClientStream* GetMutableCryptoStream() override;
+  const QuicCryptoClientStream* GetCryptoStream() const override;
+
+  // Override to save sent crypto handshake messages.
+  void OnCryptoHandshakeMessageSent(
+      const CryptoHandshakeMessage& message) override {
+    sent_crypto_handshake_messages_.push_back(message);
+  }
+
+  const std::vector<CryptoHandshakeMessage>& sent_crypto_handshake_messages()
+      const {
+    return sent_crypto_handshake_messages_;
+  }
+
+ private:
+  std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
+  QuicClientPushPromiseIndex push_promise_index_;
+  std::vector<CryptoHandshakeMessage> sent_crypto_handshake_messages_;
+};
+
+class MockPacketWriter : public QuicPacketWriter {
+ public:
+  MockPacketWriter();
+  MockPacketWriter(const MockPacketWriter&) = delete;
+  MockPacketWriter& operator=(const MockPacketWriter&) = delete;
+  ~MockPacketWriter() override;
+
+  MOCK_METHOD5(WritePacket,
+               WriteResult(const char* buffer,
+                           size_t buf_len,
+                           const QuicIpAddress& self_address,
+                           const QuicSocketAddress& peer_address,
+                           PerPacketOptions* options));
+  MOCK_CONST_METHOD0(IsWriteBlocked, bool());
+  MOCK_METHOD0(SetWritable, void());
+  MOCK_CONST_METHOD1(GetMaxPacketSize,
+                     QuicByteCount(const QuicSocketAddress& peer_address));
+  MOCK_CONST_METHOD0(SupportsReleaseTime, bool());
+  MOCK_CONST_METHOD0(IsBatchMode, bool());
+  MOCK_METHOD2(GetNextWriteLocation,
+               char*(const QuicIpAddress& self_address,
+                     const QuicSocketAddress& peer_address));
+  MOCK_METHOD0(Flush, WriteResult());
+};
+
+class MockSendAlgorithm : public SendAlgorithmInterface {
+ public:
+  MockSendAlgorithm();
+  MockSendAlgorithm(const MockSendAlgorithm&) = delete;
+  MockSendAlgorithm& operator=(const MockSendAlgorithm&) = delete;
+  ~MockSendAlgorithm() override;
+
+  MOCK_METHOD2(SetFromConfig,
+               void(const QuicConfig& config, Perspective perspective));
+  MOCK_METHOD1(SetNumEmulatedConnections, void(int num_connections));
+  MOCK_METHOD1(SetInitialCongestionWindowInPackets,
+               void(QuicPacketCount packets));
+  MOCK_METHOD1(SetMaxCongestionWindow,
+               void(QuicByteCount max_congestion_window));
+  MOCK_METHOD5(OnCongestionEvent,
+               void(bool rtt_updated,
+                    QuicByteCount bytes_in_flight,
+                    QuicTime event_time,
+                    const AckedPacketVector& acked_packets,
+                    const LostPacketVector& lost_packets));
+  MOCK_METHOD5(OnPacketSent,
+               void(QuicTime,
+                    QuicByteCount,
+                    QuicPacketNumber,
+                    QuicByteCount,
+                    HasRetransmittableData));
+  MOCK_METHOD1(OnRetransmissionTimeout, void(bool));
+  MOCK_METHOD0(OnConnectionMigration, void());
+  MOCK_METHOD0(RevertRetransmissionTimeout, void());
+  MOCK_METHOD1(CanSend, bool(QuicByteCount));
+  MOCK_CONST_METHOD1(PacingRate, QuicBandwidth(QuicByteCount));
+  MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
+  MOCK_CONST_METHOD0(HasReliableBandwidthEstimate, bool());
+  MOCK_METHOD1(OnRttUpdated, void(QuicPacketNumber));
+  MOCK_CONST_METHOD0(GetCongestionWindow, QuicByteCount());
+  MOCK_CONST_METHOD0(GetDebugState, QuicString());
+  MOCK_CONST_METHOD0(InSlowStart, bool());
+  MOCK_CONST_METHOD0(InRecovery, bool());
+  MOCK_CONST_METHOD0(ShouldSendProbingPacket, bool());
+  MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount());
+  MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType());
+  MOCK_METHOD2(AdjustNetworkParameters, void(QuicBandwidth, QuicTime::Delta));
+  MOCK_METHOD1(OnApplicationLimited, void(QuicByteCount));
+};
+
+class MockLossAlgorithm : public LossDetectionInterface {
+ public:
+  MockLossAlgorithm();
+  MockLossAlgorithm(const MockLossAlgorithm&) = delete;
+  MockLossAlgorithm& operator=(const MockLossAlgorithm&) = delete;
+  ~MockLossAlgorithm() override;
+
+  MOCK_CONST_METHOD0(GetLossDetectionType, LossDetectionType());
+  MOCK_METHOD6(DetectLosses,
+               void(const QuicUnackedPacketMap& unacked_packets,
+                    QuicTime time,
+                    const RttStats& rtt_stats,
+                    QuicPacketNumber largest_recently_acked,
+                    const AckedPacketVector& packets_acked,
+                    LostPacketVector* packets_lost));
+  MOCK_CONST_METHOD0(GetLossTimeout, QuicTime());
+  MOCK_METHOD4(SpuriousRetransmitDetected,
+               void(const QuicUnackedPacketMap&,
+                    QuicTime,
+                    const RttStats&,
+                    QuicPacketNumber));
+};
+
+class MockAckListener : public QuicAckListenerInterface {
+ public:
+  MockAckListener();
+  MockAckListener(const MockAckListener&) = delete;
+  MockAckListener& operator=(const MockAckListener&) = delete;
+
+  MOCK_METHOD2(OnPacketAcked,
+               void(int acked_bytes, QuicTime::Delta ack_delay_time));
+
+  MOCK_METHOD1(OnPacketRetransmitted, void(int retransmitted_bytes));
+
+ protected:
+  // Object is ref counted.
+  ~MockAckListener() override;
+};
+
+class MockNetworkChangeVisitor
+    : public QuicSentPacketManager::NetworkChangeVisitor {
+ public:
+  MockNetworkChangeVisitor();
+  MockNetworkChangeVisitor(const MockNetworkChangeVisitor&) = delete;
+  MockNetworkChangeVisitor& operator=(const MockNetworkChangeVisitor&) = delete;
+  ~MockNetworkChangeVisitor() override;
+
+  MOCK_METHOD0(OnCongestionChange, void());
+  MOCK_METHOD1(OnPathMtuIncreased, void(QuicPacketLength));
+};
+
+class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
+ public:
+  MockQuicConnectionDebugVisitor();
+  ~MockQuicConnectionDebugVisitor() override;
+
+  MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&));
+
+  MOCK_METHOD4(OnPacketSent,
+               void(const SerializedPacket&,
+                    QuicPacketNumber,
+                    TransmissionType,
+                    QuicTime));
+
+  MOCK_METHOD0(OnPingSent, void());
+
+  MOCK_METHOD3(OnPacketReceived,
+               void(const QuicSocketAddress&,
+                    const QuicSocketAddress&,
+                    const QuicEncryptedPacket&));
+
+  MOCK_METHOD1(OnIncorrectConnectionId, void(QuicConnectionId));
+
+  MOCK_METHOD1(OnProtocolVersionMismatch, void(ParsedQuicVersion));
+
+  MOCK_METHOD1(OnPacketHeader, void(const QuicPacketHeader& header));
+
+  MOCK_METHOD1(OnSuccessfulVersionNegotiation, void(const ParsedQuicVersion&));
+
+  MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&));
+
+  MOCK_METHOD1(OnStopWaitingFrame, void(const QuicStopWaitingFrame&));
+
+  MOCK_METHOD1(OnRstStreamFrame, void(const QuicRstStreamFrame&));
+
+  MOCK_METHOD1(OnConnectionCloseFrame, void(const QuicConnectionCloseFrame&));
+
+  MOCK_METHOD1(OnApplicationCloseFrame, void(const QuicApplicationCloseFrame&));
+
+  MOCK_METHOD1(OnStopSendingFrame, void(const QuicStopSendingFrame&));
+
+  MOCK_METHOD1(OnPathChallengeFrame, void(const QuicPathChallengeFrame&));
+
+  MOCK_METHOD1(OnPathResponseFrame, void(const QuicPathResponseFrame&));
+
+  MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket&));
+
+  MOCK_METHOD1(OnVersionNegotiationPacket,
+               void(const QuicVersionNegotiationPacket&));
+};
+
+class MockReceivedPacketManager : public QuicReceivedPacketManager {
+ public:
+  explicit MockReceivedPacketManager(QuicConnectionStats* stats);
+  ~MockReceivedPacketManager() override;
+
+  MOCK_METHOD2(RecordPacketReceived,
+               void(const QuicPacketHeader& header, QuicTime receipt_time));
+  MOCK_METHOD1(IsMissing, bool(QuicPacketNumber packet_number));
+  MOCK_METHOD1(IsAwaitingPacket, bool(QuicPacketNumber packet_number));
+  MOCK_METHOD1(UpdatePacketInformationSentByPeer,
+               void(const QuicStopWaitingFrame& stop_waiting));
+  MOCK_CONST_METHOD0(HasNewMissingPackets, bool(void));
+  MOCK_CONST_METHOD0(ack_frame_updated, bool(void));
+};
+
+class MockConnectionCloseDelegate
+    : public QuicConnectionCloseDelegateInterface {
+ public:
+  MockConnectionCloseDelegate();
+  ~MockConnectionCloseDelegate() override;
+
+  MOCK_METHOD3(OnUnrecoverableError,
+               void(QuicErrorCode,
+                    const QuicString&,
+                    ConnectionCloseSource source));
+};
+
+class MockPacketCreatorDelegate : public QuicPacketCreator::DelegateInterface {
+ public:
+  MockPacketCreatorDelegate();
+  MockPacketCreatorDelegate(const MockPacketCreatorDelegate&) = delete;
+  MockPacketCreatorDelegate& operator=(const MockPacketCreatorDelegate&) =
+      delete;
+  ~MockPacketCreatorDelegate() override;
+
+  MOCK_METHOD0(GetPacketBuffer, char*());
+  MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
+  MOCK_METHOD3(OnUnrecoverableError,
+               void(QuicErrorCode,
+                    const QuicString&,
+                    ConnectionCloseSource source));
+};
+
+class MockSessionNotifier : public SessionNotifierInterface {
+ public:
+  MockSessionNotifier();
+  ~MockSessionNotifier() override;
+
+  MOCK_METHOD2(OnFrameAcked, bool(const QuicFrame&, QuicTime::Delta));
+  MOCK_METHOD1(OnStreamFrameRetransmitted, void(const QuicStreamFrame&));
+  MOCK_METHOD1(OnFrameLost, void(const QuicFrame&));
+  MOCK_METHOD2(RetransmitFrames,
+               void(const QuicFrames&, TransmissionType type));
+  MOCK_CONST_METHOD1(IsFrameOutstanding, bool(const QuicFrame&));
+  MOCK_CONST_METHOD0(HasUnackedCryptoData, bool());
+};
+
+// Creates a client session for testing.
+//
+// server_id: The server id associated with this stream.
+// supports_stateless_rejects:  Does this client support stateless rejects.
+// connection_start_time: The time to set for the connection clock.
+//   Needed for strike-register nonce verification.  The client
+//   connection_start_time should be synchronized witht the server
+//   start time, otherwise nonce verification will fail.
+// supported_versions: Set of QUIC versions this client supports.
+// helper: Pointer to the MockQuicConnectionHelper to use for the session.
+// crypto_client_config: Pointer to the crypto client config.
+// client_connection: Pointer reference for newly created
+//   connection.  This object will be owned by the
+//   client_session.
+// client_session: Pointer reference for the newly created client
+//   session.  The new object will be owned by the caller.
+void CreateClientSessionForTest(
+    QuicServerId server_id,
+    bool supports_stateless_rejects,
+    QuicTime::Delta connection_start_time,
+    const ParsedQuicVersionVector& supported_versions,
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    QuicCryptoClientConfig* crypto_client_config,
+    PacketSavingConnection** client_connection,
+    TestQuicSpdyClientSession** client_session);
+
+// Creates a server session for testing.
+//
+// server_id: The server id associated with this stream.
+// connection_start_time: The time to set for the connection clock.
+//   Needed for strike-register nonce verification.  The server
+//   connection_start_time should be synchronized witht the client
+//   start time, otherwise nonce verification will fail.
+// supported_versions: Set of QUIC versions this server supports.
+// helper: Pointer to the MockQuicConnectionHelper to use for the session.
+// crypto_server_config: Pointer to the crypto server config.
+// server_connection: Pointer reference for newly created
+//   connection.  This object will be owned by the
+//   server_session.
+// server_session: Pointer reference for the newly created server
+//   session.  The new object will be owned by the caller.
+void CreateServerSessionForTest(
+    QuicServerId server_id,
+    QuicTime::Delta connection_start_time,
+    ParsedQuicVersionVector supported_versions,
+    MockQuicConnectionHelper* helper,
+    MockAlarmFactory* alarm_factory,
+    QuicCryptoServerConfig* crypto_server_config,
+    QuicCompressedCertsCache* compressed_certs_cache,
+    PacketSavingConnection** server_connection,
+    TestQuicSpdyServerSession** server_session);
+
+// Verifies that the relative error of |actual| with respect to |expected| is
+// no more than |margin|.
+
+template <typename T>
+void ExpectApproxEq(T expected, T actual, float relative_margin) {
+  // If |relative_margin| > 1 and T is an unsigned type, the comparison will
+  // underflow.
+  ASSERT_LE(relative_margin, 1);
+  ASSERT_GE(relative_margin, 0);
+
+  T absolute_margin = expected * relative_margin;
+
+  EXPECT_GE(expected + absolute_margin, actual);
+  EXPECT_LE(expected - absolute_margin, actual);
+}
+
+template <typename T>
+QuicHeaderList AsHeaderList(const T& container) {
+  QuicHeaderList l;
+  // No need to enforce header list size limits again in this handler.
+  l.set_max_header_list_size(UINT_MAX);
+  l.OnHeaderBlockStart();
+  size_t total_size = 0;
+  for (auto p : container) {
+    total_size += p.first.size() + p.second.size();
+    l.OnHeader(p.first, p.second);
+  }
+  l.OnHeaderBlockEnd(total_size, total_size);
+  return l;
+}
+
+// Utility function that stores |str|'s data in |iov|.
+inline void MakeIOVector(QuicStringPiece str, struct iovec* iov) {
+  iov->iov_base = const_cast<char*>(str.data());
+  iov->iov_len = static_cast<size_t>(str.size());
+}
+
+// Helper functions for stream ids, to allow test logic to abstract over the
+// HTTP stream numbering scheme (i.e. whether one or two QUIC streams are used
+// per HTTP transaction).
+QuicStreamId GetNthClientInitiatedBidirectionalStreamId(
+    QuicTransportVersion version,
+    int n);
+QuicStreamId GetNthServerInitiatedBidirectionalStreamId(
+    QuicTransportVersion version,
+    int n);
+QuicStreamId GetNthServerInitiatedUnidirectionalStreamId(
+    QuicTransportVersion version,
+    int n);
+
+StreamType DetermineStreamType(QuicStreamId id,
+                               QuicTransportVersion version,
+                               Perspective perspective,
+                               bool is_incoming,
+                               StreamType default_type);
+
+// Utility function that stores message_data in |storage| and returns a
+// QuicMemSliceSpan.
+QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator,
+                          QuicStringPiece message_data,
+                          QuicMemSliceStorage* storage);
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_UTILS_H_
diff --git a/quic/test_tools/quic_test_utils_test.cc b/quic/test_tools/quic_test_utils_test.cc
new file mode 100644
index 0000000..79d2af8
--- /dev/null
+++ b/quic/test_tools/quic_test_utils_test.cc
@@ -0,0 +1,61 @@
+// Copyright 2016 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_utils.h"
+
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+
+namespace quic {
+namespace test {
+
+class QuicTestUtilsTest : public QuicTest {};
+
+TEST_F(QuicTestUtilsTest, ConnectionId) {
+  EXPECT_NE(EmptyQuicConnectionId(), TestConnectionId());
+  EXPECT_NE(EmptyQuicConnectionId(), TestConnectionId(1));
+  EXPECT_EQ(TestConnectionId(), TestConnectionId());
+  EXPECT_EQ(TestConnectionId(33), TestConnectionId(33));
+  EXPECT_NE(TestConnectionId(0xdead), TestConnectionId(0xbeef));
+  EXPECT_EQ(0x1337u, TestConnectionIdToUInt64(TestConnectionId(0x1337)));
+  EXPECT_NE(0xdeadu, TestConnectionIdToUInt64(TestConnectionId(0xbeef)));
+}
+
+TEST_F(QuicTestUtilsTest, BasicApproxEq) {
+  ExpectApproxEq(10, 10, 1e-6f);
+  ExpectApproxEq(1000, 1001, 0.01f);
+  EXPECT_NONFATAL_FAILURE(ExpectApproxEq(1000, 1100, 0.01f), "");
+
+  ExpectApproxEq(64, 31, 0.55f);
+  EXPECT_NONFATAL_FAILURE(ExpectApproxEq(31, 64, 0.55f), "");
+}
+
+TEST_F(QuicTestUtilsTest, QuicTimeDelta) {
+  ExpectApproxEq(QuicTime::Delta::FromMicroseconds(1000),
+                 QuicTime::Delta::FromMicroseconds(1003), 0.01f);
+  EXPECT_NONFATAL_FAILURE(
+      ExpectApproxEq(QuicTime::Delta::FromMicroseconds(1000),
+                     QuicTime::Delta::FromMicroseconds(1200), 0.01f),
+      "");
+}
+
+TEST_F(QuicTestUtilsTest, QuicBandwidth) {
+  ExpectApproxEq(QuicBandwidth::FromBytesPerSecond(1000),
+                 QuicBandwidth::FromBitsPerSecond(8005), 0.01f);
+  EXPECT_NONFATAL_FAILURE(
+      ExpectApproxEq(QuicBandwidth::FromBytesPerSecond(1000),
+                     QuicBandwidth::FromBitsPerSecond(9005), 0.01f),
+      "");
+}
+
+// Ensure that SimpleRandom does not change its output for a fixed seed.
+TEST_F(QuicTestUtilsTest, SimpleRandomStability) {
+  SimpleRandom rng;
+  rng.set_seed(UINT64_C(0x1234567800010001));
+  EXPECT_EQ(UINT64_C(14865409841904857791), rng.RandUint64());
+  EXPECT_EQ(UINT64_C(12139094019410129741), rng.RandUint64());
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_time_wait_list_manager_peer.cc b/quic/test_tools/quic_time_wait_list_manager_peer.cc
new file mode 100644
index 0000000..7c90321
--- /dev/null
+++ b/quic/test_tools/quic_time_wait_list_manager_peer.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2016 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_time_wait_list_manager_peer.h"
+
+namespace quic {
+namespace test {
+
+bool QuicTimeWaitListManagerPeer::ShouldSendResponse(
+    QuicTimeWaitListManager* manager,
+    int received_packet_count) {
+  return manager->ShouldSendResponse(received_packet_count);
+}
+
+QuicTime::Delta QuicTimeWaitListManagerPeer::time_wait_period(
+    QuicTimeWaitListManager* manager) {
+  return manager->time_wait_period_;
+}
+
+QuicAlarm* QuicTimeWaitListManagerPeer::expiration_alarm(
+    QuicTimeWaitListManager* manager) {
+  return manager->connection_id_clean_up_alarm_.get();
+}
+
+void QuicTimeWaitListManagerPeer::set_clock(QuicTimeWaitListManager* manager,
+                                            const QuicClock* clock) {
+  manager->clock_ = clock;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_time_wait_list_manager_peer.h b/quic/test_tools/quic_time_wait_list_manager_peer.h
new file mode 100644
index 0000000..0fdf976
--- /dev/null
+++ b/quic/test_tools/quic_time_wait_list_manager_peer.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_TIME_WAIT_LIST_MANAGER_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_TIME_WAIT_LIST_MANAGER_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
+
+namespace quic {
+namespace test {
+
+class QuicTimeWaitListManagerPeer {
+ public:
+  static bool ShouldSendResponse(QuicTimeWaitListManager* manager,
+                                 int received_packet_count);
+
+  static QuicTime::Delta time_wait_period(QuicTimeWaitListManager* manager);
+
+  static QuicAlarm* expiration_alarm(QuicTimeWaitListManager* manager);
+
+  static void set_clock(QuicTimeWaitListManager* manager,
+                        const QuicClock* clock);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_TIME_WAIT_LIST_MANAGER_PEER_H_
diff --git a/quic/test_tools/quic_unacked_packet_map_peer.cc b/quic/test_tools/quic_unacked_packet_map_peer.cc
new file mode 100644
index 0000000..1ecc65f
--- /dev/null
+++ b/quic/test_tools/quic_unacked_packet_map_peer.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2019 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_unacked_packet_map_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+const QuicStreamFrame& QuicUnackedPacketMapPeer::GetAggregatedStreamFrame(
+    const QuicUnackedPacketMap& unacked_packets) {
+  return unacked_packets.aggregated_stream_frame_;
+}
+
+// static
+void QuicUnackedPacketMapPeer::SetPerspective(
+    QuicUnackedPacketMap* unacked_packets,
+    Perspective perspective) {
+  *const_cast<Perspective*>(&unacked_packets->perspective_) = perspective;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/quic_unacked_packet_map_peer.h b/quic/test_tools/quic_unacked_packet_map_peer.h
new file mode 100644
index 0000000..3bba0b6
--- /dev/null
+++ b/quic/test_tools/quic_unacked_packet_map_peer.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2019 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h"
+
+namespace quic {
+namespace test {
+
+class QuicUnackedPacketMapPeer {
+ public:
+  static const QuicStreamFrame& GetAggregatedStreamFrame(
+      const QuicUnackedPacketMap& unacked_packets);
+
+  static void SetPerspective(QuicUnackedPacketMap* unacked_packets,
+                             Perspective perspective);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
diff --git a/quic/test_tools/rtt_stats_peer.cc b/quic/test_tools/rtt_stats_peer.cc
new file mode 100644
index 0000000..e8c6810
--- /dev/null
+++ b/quic/test_tools/rtt_stats_peer.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 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/rtt_stats_peer.h"
+
+namespace quic {
+namespace test {
+
+// static
+void RttStatsPeer::SetSmoothedRtt(RttStats* rtt_stats, QuicTime::Delta rtt_ms) {
+  rtt_stats->smoothed_rtt_ = rtt_ms;
+}
+
+// static
+void RttStatsPeer::SetMinRtt(RttStats* rtt_stats, QuicTime::Delta rtt_ms) {
+  rtt_stats->min_rtt_ = rtt_ms;
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/rtt_stats_peer.h b/quic/test_tools/rtt_stats_peer.h
new file mode 100644
index 0000000..4ea7ad0
--- /dev/null
+++ b/quic/test_tools/rtt_stats_peer.h
@@ -0,0 +1,27 @@
+// Copyright 2015 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_RTT_STATS_PEER_H_
+#define QUICHE_QUIC_TEST_TOOLS_RTT_STATS_PEER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+
+namespace quic {
+namespace test {
+
+class RttStatsPeer {
+ public:
+  RttStatsPeer() = delete;
+
+  static void SetSmoothedRtt(RttStats* rtt_stats, QuicTime::Delta rtt_ms);
+
+  static void SetMinRtt(RttStats* rtt_stats, QuicTime::Delta rtt_ms);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_RTT_STATS_PEER_H_
diff --git a/quic/test_tools/server_thread.cc b/quic/test_tools/server_thread.cc
new file mode 100644
index 0000000..ca15913
--- /dev/null
+++ b/quic/test_tools/server_thread.cc
@@ -0,0 +1,121 @@
+// Copyright 2013 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/server_thread.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_server_peer.h"
+
+namespace quic {
+namespace test {
+
+ServerThread::ServerThread(QuicServer* server, const QuicSocketAddress& address)
+    : QuicThread("server_thread"),
+      server_(server),
+      address_(address),
+      port_(0),
+      initialized_(false) {}
+
+ServerThread::~ServerThread() = default;
+
+void ServerThread::Initialize() {
+  if (initialized_) {
+    return;
+  }
+
+  server_->CreateUDPSocketAndListen(address_);
+
+  QuicWriterMutexLock lock(&port_lock_);
+  port_ = server_->port();
+
+  initialized_ = true;
+}
+
+void ServerThread::Run() {
+  if (!initialized_) {
+    Initialize();
+  }
+
+  while (!quit_.HasBeenNotified()) {
+    if (pause_.HasBeenNotified() && !resume_.HasBeenNotified()) {
+      paused_.Notify();
+      resume_.WaitForNotification();
+    }
+    server_->WaitForEvents();
+    ExecuteScheduledActions();
+    MaybeNotifyOfHandshakeConfirmation();
+  }
+
+  server_->Shutdown();
+}
+
+int ServerThread::GetPort() {
+  QuicReaderMutexLock lock(&port_lock_);
+  int rc = port_;
+  return rc;
+}
+
+void ServerThread::Schedule(std::function<void()> action) {
+  DCHECK(!quit_.HasBeenNotified());
+  QuicWriterMutexLock lock(&scheduled_actions_lock_);
+  scheduled_actions_.push_back(std::move(action));
+}
+
+void ServerThread::WaitForCryptoHandshakeConfirmed() {
+  confirmed_.WaitForNotification();
+}
+
+void ServerThread::Pause() {
+  DCHECK(!pause_.HasBeenNotified());
+  pause_.Notify();
+  paused_.WaitForNotification();
+}
+
+void ServerThread::Resume() {
+  DCHECK(!resume_.HasBeenNotified());
+  DCHECK(pause_.HasBeenNotified());
+  resume_.Notify();
+}
+
+void ServerThread::Quit() {
+  if (pause_.HasBeenNotified() && !resume_.HasBeenNotified()) {
+    resume_.Notify();
+  }
+  if (!quit_.HasBeenNotified()) {
+    quit_.Notify();
+  }
+}
+
+void ServerThread::MaybeNotifyOfHandshakeConfirmation() {
+  if (confirmed_.HasBeenNotified()) {
+    // Only notify once.
+    return;
+  }
+  QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server());
+  if (dispatcher->session_map().empty()) {
+    // Wait for a session to be created.
+    return;
+  }
+  QuicSession* session = dispatcher->session_map().begin()->second.get();
+  if (session->IsCryptoHandshakeConfirmed()) {
+    confirmed_.Notify();
+  }
+}
+
+void ServerThread::ExecuteScheduledActions() {
+  QuicDeque<std::function<void()>> actions;
+  {
+    QuicWriterMutexLock lock(&scheduled_actions_lock_);
+    actions.swap(scheduled_actions_);
+  }
+  while (!actions.empty()) {
+    actions.front()();
+    actions.pop_front();
+  }
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/server_thread.h b/quic/test_tools/server_thread.h
new file mode 100644
index 0000000..ffbce7f
--- /dev/null
+++ b/quic/test_tools/server_thread.h
@@ -0,0 +1,88 @@
+// Copyright 2013 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SERVER_THREAD_H_
+#define QUICHE_QUIC_TEST_TOOLS_SERVER_THREAD_H_
+
+#include <memory>
+
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_thread.h"
+#include "net/third_party/quiche/src/quic/tools/quic_server.h"
+
+namespace quic {
+namespace test {
+
+// Simple wrapper class to run QuicServer in a dedicated thread.
+class ServerThread : public QuicThread {
+ public:
+  ServerThread(QuicServer* server, const QuicSocketAddress& address);
+  ServerThread(const ServerThread&) = delete;
+  ServerThread& operator=(const ServerThread&) = delete;
+
+  ~ServerThread() override;
+
+  // Prepares the server, but does not start accepting connections. Useful for
+  // injecting mocks.
+  void Initialize();
+
+  // Runs the event loop. Will initialize if necessary.
+  void Run() override;
+
+  // Schedules the given action for execution in the event loop.
+  void Schedule(std::function<void()> action);
+
+  // Waits for the handshake to be confirmed for the first session created.
+  void WaitForCryptoHandshakeConfirmed();
+
+  // Pauses execution of the server until Resume() is called.  May only be
+  // called once.
+  void Pause();
+
+  // Resumes execution of the server after Pause() has been called.  May only
+  // be called once.
+  void Resume();
+
+  // Stops the server from executing and shuts it down, destroying all
+  // server objects.
+  void Quit();
+
+  // Returns the underlying server.  Care must be taken to avoid data races
+  // when accessing the server.  It is always safe to access the server
+  // after calling Pause() and before calling Resume().
+  QuicServer* server() { return server_.get(); }
+
+  // Returns the port that the server is listening on.
+  int GetPort();
+
+ private:
+  void MaybeNotifyOfHandshakeConfirmation();
+  void ExecuteScheduledActions();
+
+  QuicNotification
+      confirmed_;            // Notified when the first handshake is confirmed.
+  QuicNotification pause_;   // Notified when the server should pause.
+  QuicNotification paused_;  // Notitied when the server has paused
+  QuicNotification resume_;  // Notified when the server should resume.
+  QuicNotification quit_;    // Notified when the server should quit.
+
+  std::unique_ptr<QuicServer> server_;
+  QuicSocketAddress address_;
+  mutable QuicMutex port_lock_;
+  int port_ GUARDED_BY(port_lock_);
+
+  bool initialized_;
+
+  QuicMutex scheduled_actions_lock_;
+  QuicDeque<std::function<void()>> scheduled_actions_
+      GUARDED_BY(scheduled_actions_lock_);
+};
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SERVER_THREAD_H_
diff --git a/quic/test_tools/simple_data_producer.cc b/quic/test_tools/simple_data_producer.cc
new file mode 100644
index 0000000..ab98fd1
--- /dev/null
+++ b/quic/test_tools/simple_data_producer.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2017 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/simple_data_producer.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+namespace test {
+
+SimpleDataProducer::SimpleDataProducer() {}
+
+SimpleDataProducer::~SimpleDataProducer() {}
+
+void SimpleDataProducer::SaveStreamData(QuicStreamId id,
+                                        const struct iovec* iov,
+                                        int iov_count,
+                                        size_t iov_offset,
+                                        QuicByteCount data_length) {
+  if (data_length == 0) {
+    return;
+  }
+  if (!QuicContainsKey(send_buffer_map_, id)) {
+    send_buffer_map_[id] = QuicMakeUnique<QuicStreamSendBuffer>(&allocator_);
+  }
+  send_buffer_map_[id]->SaveStreamData(iov, iov_count, iov_offset, data_length);
+}
+
+void SimpleDataProducer::SaveCryptoData(EncryptionLevel level,
+                                        QuicStreamOffset offset,
+                                        QuicStringPiece data) {
+  auto key = std::make_pair(level, offset);
+  crypto_buffer_map_[key] = data;
+}
+
+WriteStreamDataResult SimpleDataProducer::WriteStreamData(
+    QuicStreamId id,
+    QuicStreamOffset offset,
+    QuicByteCount data_length,
+    QuicDataWriter* writer) {
+  auto iter = send_buffer_map_.find(id);
+  if (iter == send_buffer_map_.end()) {
+    return STREAM_MISSING;
+  }
+  if (iter->second->WriteStreamData(offset, data_length, writer)) {
+    return WRITE_SUCCESS;
+  }
+  return WRITE_FAILED;
+}
+
+bool SimpleDataProducer::WriteCryptoData(EncryptionLevel level,
+                                         QuicStreamOffset offset,
+                                         QuicByteCount data_length,
+                                         QuicDataWriter* writer) {
+  auto it = crypto_buffer_map_.find(std::make_pair(level, offset));
+  if (it == crypto_buffer_map_.end() || it->second.length() != data_length) {
+    return false;
+  }
+  return writer->WriteStringPiece(it->second);
+}
+
+}  // namespace test
+
+}  // namespace quic
diff --git a/quic/test_tools/simple_data_producer.h b/quic/test_tools/simple_data_producer.h
new file mode 100644
index 0000000..d51ec69
--- /dev/null
+++ b/quic/test_tools/simple_data_producer.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2017 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_DATA_PRODUCER_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMPLE_DATA_PRODUCER_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+
+namespace quic {
+
+namespace test {
+
+// A simple data producer which copies stream data into a map from stream
+// id to send buffer.
+class SimpleDataProducer : public QuicStreamFrameDataProducer {
+ public:
+  SimpleDataProducer();
+  ~SimpleDataProducer() override;
+
+  // Saves data to be provided when WriteStreamData is called. Data of length
+  // |data_length| is buffered to be provided for stream |id|. Multiple calls to
+  // SaveStreamData for the same stream ID append to the buffer for that stream.
+  // The data to be buffered is provided in |iov_count| iovec structs, with
+  // |iov| pointing to the first, and |iov_offset| indicating how many bytes
+  // into the iovec structs the data starts.
+  void SaveStreamData(QuicStreamId id,
+                      const struct iovec* iov,
+                      int iov_count,
+                      size_t iov_offset,
+                      QuicByteCount data_length);
+
+  void SaveCryptoData(EncryptionLevel level,
+                      QuicStreamOffset offset,
+                      QuicStringPiece data);
+
+  // QuicStreamFrameDataProducer
+  WriteStreamDataResult WriteStreamData(QuicStreamId id,
+                                        QuicStreamOffset offset,
+                                        QuicByteCount data_length,
+                                        QuicDataWriter* writer) override;
+  bool WriteCryptoData(EncryptionLevel level,
+                       QuicStreamOffset offset,
+                       QuicByteCount data_length,
+                       QuicDataWriter* writer) override;
+
+  // TODO(wub): Allow QuicDefaultHasher to accept a pair. Then remove this.
+  class PairHash {
+   public:
+    template <class T1, class T2>
+    size_t operator()(const std::pair<T1, T2>& pair) const {
+      return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
+    }
+  };
+
+ private:
+  using SendBufferMap =
+      QuicUnorderedMap<QuicStreamId, std::unique_ptr<QuicStreamSendBuffer>>;
+
+  using CryptoBufferMap =
+      QuicUnorderedMap<std::pair<EncryptionLevel, QuicStreamOffset>,
+                       QuicStringPiece,
+                       PairHash>;
+
+  SimpleBufferAllocator allocator_;
+
+  SendBufferMap send_buffer_map_;
+
+  // |crypto_buffer_map_| stores data provided by SaveCryptoData to later write
+  // in WriteCryptoData. The level and data passed into SaveCryptoData are used
+  // as the key to identify the data when WriteCryptoData is called.
+  // WriteCryptoData will only succeed if there is data in the map for the
+  // provided level and offset, and the data in the map matches the data_length
+  // passed into WriteCryptoData.
+  //
+  // Unlike SaveStreamData/WriteStreamData which uses a map of
+  // QuicStreamSendBuffers (for each stream ID), this map provides data for
+  // specific offsets. Using a QuicStreamSendBuffer requires that all data
+  // before an offset exist, whereas this allows providing data that exists at
+  // arbitrary offsets for testing.
+  CryptoBufferMap crypto_buffer_map_;
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMPLE_DATA_PRODUCER_H_
diff --git a/quic/test_tools/simple_quic_framer.cc b/quic/test_tools/simple_quic_framer.cc
new file mode 100644
index 0000000..bf7184e
--- /dev/null
+++ b/quic/test_tools/simple_quic_framer.cc
@@ -0,0 +1,411 @@
+// 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/simple_quic_framer.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+namespace test {
+
+class SimpleFramerVisitor : public QuicFramerVisitorInterface {
+ public:
+  SimpleFramerVisitor() : error_(QUIC_NO_ERROR) {}
+  SimpleFramerVisitor(const SimpleFramerVisitor&) = delete;
+  SimpleFramerVisitor& operator=(const SimpleFramerVisitor&) = delete;
+
+  ~SimpleFramerVisitor() override {}
+
+  void OnError(QuicFramer* framer) override { error_ = framer->error(); }
+
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override {
+    return false;
+  }
+
+  void OnPacket() override {}
+  void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {
+    public_reset_packet_ = QuicMakeUnique<QuicPublicResetPacket>((packet));
+  }
+  void OnVersionNegotiationPacket(
+      const QuicVersionNegotiationPacket& packet) override {
+    version_negotiation_packet_ =
+        QuicMakeUnique<QuicVersionNegotiationPacket>((packet));
+  }
+
+  bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override {
+    return true;
+  }
+  bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override {
+    return true;
+  }
+  void OnDecryptedPacket(EncryptionLevel level) override {
+    last_decrypted_level_ = level;
+  }
+  bool OnPacketHeader(const QuicPacketHeader& header) override {
+    has_header_ = true;
+    header_ = header;
+    return true;
+  }
+
+  void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {}
+
+  bool OnStreamFrame(const QuicStreamFrame& frame) override {
+    // Save a copy of the data so it is valid after the packet is processed.
+    QuicString* string_data =
+        new QuicString(frame.data_buffer, frame.data_length);
+    stream_data_.push_back(QuicWrapUnique(string_data));
+    // TODO(ianswett): A pointer isn't necessary with emplace_back.
+    stream_frames_.push_back(QuicMakeUnique<QuicStreamFrame>(
+        frame.stream_id, frame.fin, frame.offset,
+        QuicStringPiece(*string_data)));
+    return true;
+  }
+
+  bool OnCryptoFrame(const QuicCryptoFrame& frame) override {
+    // Save a copy of the data so it is valid after the packet is processed.
+    QuicString* string_data =
+        new QuicString(frame.data_buffer, frame.data_length);
+    crypto_data_.push_back(QuicWrapUnique(string_data));
+    crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>(
+        frame.level, frame.offset, QuicStringPiece(*string_data)));
+    return true;
+  }
+
+  bool OnAckFrameStart(QuicPacketNumber largest_acked,
+                       QuicTime::Delta ack_delay_time) override {
+    QuicAckFrame ack_frame;
+    ack_frame.largest_acked = largest_acked;
+    ack_frame.ack_delay_time = ack_delay_time;
+    ack_frames_.push_back(ack_frame);
+    return true;
+  }
+
+  bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override {
+    DCHECK(!ack_frames_.empty());
+    ack_frames_[ack_frames_.size() - 1].packets.AddRange(start, end);
+    return true;
+  }
+
+  bool OnAckTimestamp(QuicPacketNumber packet_number,
+                      QuicTime timestamp) override {
+    return true;
+  }
+
+  bool OnAckFrameEnd(QuicPacketNumber /*start*/) override { return true; }
+
+  bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override {
+    stop_waiting_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnPaddingFrame(const QuicPaddingFrame& frame) override {
+    padding_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnPingFrame(const QuicPingFrame& frame) override {
+    ping_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
+    rst_stream_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override {
+    connection_close_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnApplicationCloseFrame(
+      const QuicApplicationCloseFrame& frame) override {
+    application_close_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override {
+    new_connection_id_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnRetireConnectionIdFrame(
+      const QuicRetireConnectionIdFrame& frame) override {
+    retire_connection_id_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override {
+    new_token_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override {
+    stop_sending_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override {
+    path_challenge_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override {
+    path_response_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override {
+    goaway_frames_.push_back(frame);
+    return true;
+  }
+  bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override {
+    max_stream_id_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override {
+    stream_id_blocked_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {
+    window_update_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
+    blocked_frames_.push_back(frame);
+    return true;
+  }
+
+  bool OnMessageFrame(const QuicMessageFrame& frame) override {
+    message_frames_.emplace_back(frame.data, frame.message_length);
+    return true;
+  }
+
+  void OnPacketComplete() override {}
+
+  bool IsValidStatelessResetToken(QuicUint128 token) const override {
+    return false;
+  }
+
+  void OnAuthenticatedIetfStatelessResetPacket(
+      const QuicIetfStatelessResetPacket& packet) override {
+    stateless_reset_packet_ =
+        QuicMakeUnique<QuicIetfStatelessResetPacket>(packet);
+  }
+
+  const QuicPacketHeader& header() const { return header_; }
+  const std::vector<QuicAckFrame>& ack_frames() const { return ack_frames_; }
+  const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const {
+    return connection_close_frames_;
+  }
+  const std::vector<QuicApplicationCloseFrame>& application_close_frames()
+      const {
+    return application_close_frames_;
+  }
+  const std::vector<QuicGoAwayFrame>& goaway_frames() const {
+    return goaway_frames_;
+  }
+  const std::vector<QuicMaxStreamIdFrame>& max_stream_id_frames() const {
+    return max_stream_id_frames_;
+  }
+  const std::vector<QuicStreamIdBlockedFrame>& stream_id_blocked_frames()
+      const {
+    return stream_id_blocked_frames_;
+  }
+  const std::vector<QuicRstStreamFrame>& rst_stream_frames() const {
+    return rst_stream_frames_;
+  }
+  const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const {
+    return stream_frames_;
+  }
+  const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const {
+    return crypto_frames_;
+  }
+  const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
+    return stop_waiting_frames_;
+  }
+  const std::vector<QuicPingFrame>& ping_frames() const { return ping_frames_; }
+  const std::vector<QuicMessageFrame>& message_frames() const {
+    return message_frames_;
+  }
+  const std::vector<QuicWindowUpdateFrame>& window_update_frames() const {
+    return window_update_frames_;
+  }
+  const std::vector<QuicPaddingFrame>& padding_frames() const {
+    return padding_frames_;
+  }
+  const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const {
+    return path_challenge_frames_;
+  }
+  const std::vector<QuicPathResponseFrame>& path_response_frames() const {
+    return path_response_frames_;
+  }
+  const QuicVersionNegotiationPacket* version_negotiation_packet() const {
+    return version_negotiation_packet_.get();
+  }
+  EncryptionLevel last_decrypted_level() const { return last_decrypted_level_; }
+
+ private:
+  QuicErrorCode error_;
+  bool has_header_;
+  QuicPacketHeader header_;
+  std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
+  std::unique_ptr<QuicPublicResetPacket> public_reset_packet_;
+  std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_;
+  std::vector<QuicAckFrame> ack_frames_;
+  std::vector<QuicStopWaitingFrame> stop_waiting_frames_;
+  std::vector<QuicPaddingFrame> padding_frames_;
+  std::vector<QuicPingFrame> ping_frames_;
+  std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_;
+  std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_;
+  std::vector<QuicRstStreamFrame> rst_stream_frames_;
+  std::vector<QuicGoAwayFrame> goaway_frames_;
+  std::vector<QuicStreamIdBlockedFrame> stream_id_blocked_frames_;
+  std::vector<QuicMaxStreamIdFrame> max_stream_id_frames_;
+  std::vector<QuicConnectionCloseFrame> connection_close_frames_;
+  std::vector<QuicApplicationCloseFrame> application_close_frames_;
+  std::vector<QuicStopSendingFrame> stop_sending_frames_;
+  std::vector<QuicPathChallengeFrame> path_challenge_frames_;
+  std::vector<QuicPathResponseFrame> path_response_frames_;
+  std::vector<QuicWindowUpdateFrame> window_update_frames_;
+  std::vector<QuicBlockedFrame> blocked_frames_;
+  std::vector<QuicNewConnectionIdFrame> new_connection_id_frames_;
+  std::vector<QuicRetireConnectionIdFrame> retire_connection_id_frames_;
+  std::vector<QuicNewTokenFrame> new_token_frames_;
+  std::vector<QuicMessageFrame> message_frames_;
+  std::vector<std::unique_ptr<QuicString>> stream_data_;
+  std::vector<std::unique_ptr<QuicString>> crypto_data_;
+  EncryptionLevel last_decrypted_level_;
+};
+
+SimpleQuicFramer::SimpleQuicFramer()
+    : framer_(AllSupportedVersions(),
+              QuicTime::Zero(),
+              Perspective::IS_SERVER,
+              kQuicDefaultConnectionIdLength) {}
+
+SimpleQuicFramer::SimpleQuicFramer(
+    const ParsedQuicVersionVector& supported_versions)
+    : framer_(supported_versions,
+              QuicTime::Zero(),
+              Perspective::IS_SERVER,
+              kQuicDefaultConnectionIdLength) {}
+
+SimpleQuicFramer::SimpleQuicFramer(
+    const ParsedQuicVersionVector& supported_versions,
+    Perspective perspective)
+    : framer_(supported_versions,
+              QuicTime::Zero(),
+              perspective,
+              kQuicDefaultConnectionIdLength) {}
+
+SimpleQuicFramer::~SimpleQuicFramer() {}
+
+bool SimpleQuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
+  visitor_ = QuicMakeUnique<SimpleFramerVisitor>();
+  framer_.set_visitor(visitor_.get());
+  return framer_.ProcessPacket(packet);
+}
+
+void SimpleQuicFramer::Reset() {
+  visitor_ = QuicMakeUnique<SimpleFramerVisitor>();
+}
+
+const QuicPacketHeader& SimpleQuicFramer::header() const {
+  return visitor_->header();
+}
+
+const QuicVersionNegotiationPacket*
+SimpleQuicFramer::version_negotiation_packet() const {
+  return visitor_->version_negotiation_packet();
+}
+
+EncryptionLevel SimpleQuicFramer::last_decrypted_level() const {
+  return visitor_->last_decrypted_level();
+}
+
+QuicFramer* SimpleQuicFramer::framer() {
+  return &framer_;
+}
+
+size_t SimpleQuicFramer::num_frames() const {
+  return ack_frames().size() + goaway_frames().size() +
+         rst_stream_frames().size() + stop_waiting_frames().size() +
+         path_challenge_frames().size() + path_response_frames().size() +
+         stream_frames().size() + ping_frames().size() +
+         connection_close_frames().size() + padding_frames().size() +
+         crypto_frames().size();
+}
+
+const std::vector<QuicAckFrame>& SimpleQuicFramer::ack_frames() const {
+  return visitor_->ack_frames();
+}
+
+const std::vector<QuicStopWaitingFrame>& SimpleQuicFramer::stop_waiting_frames()
+    const {
+  return visitor_->stop_waiting_frames();
+}
+
+const std::vector<QuicPathChallengeFrame>&
+SimpleQuicFramer::path_challenge_frames() const {
+  return visitor_->path_challenge_frames();
+}
+const std::vector<QuicPathResponseFrame>&
+SimpleQuicFramer::path_response_frames() const {
+  return visitor_->path_response_frames();
+}
+
+const std::vector<QuicPingFrame>& SimpleQuicFramer::ping_frames() const {
+  return visitor_->ping_frames();
+}
+
+const std::vector<QuicMessageFrame>& SimpleQuicFramer::message_frames() const {
+  return visitor_->message_frames();
+}
+
+const std::vector<QuicWindowUpdateFrame>&
+SimpleQuicFramer::window_update_frames() const {
+  return visitor_->window_update_frames();
+}
+
+const std::vector<std::unique_ptr<QuicStreamFrame>>&
+SimpleQuicFramer::stream_frames() const {
+  return visitor_->stream_frames();
+}
+
+const std::vector<std::unique_ptr<QuicCryptoFrame>>&
+SimpleQuicFramer::crypto_frames() const {
+  return visitor_->crypto_frames();
+}
+
+const std::vector<QuicRstStreamFrame>& SimpleQuicFramer::rst_stream_frames()
+    const {
+  return visitor_->rst_stream_frames();
+}
+
+const std::vector<QuicGoAwayFrame>& SimpleQuicFramer::goaway_frames() const {
+  return visitor_->goaway_frames();
+}
+
+const std::vector<QuicConnectionCloseFrame>&
+SimpleQuicFramer::connection_close_frames() const {
+  return visitor_->connection_close_frames();
+}
+
+const std::vector<QuicPaddingFrame>& SimpleQuicFramer::padding_frames() const {
+  return visitor_->padding_frames();
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/simple_quic_framer.h b/quic/test_tools/simple_quic_framer.h
new file mode 100644
index 0000000..2edf9d3
--- /dev/null
+++ b/quic/test_tools/simple_quic_framer.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_QUIC_FRAMER_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMPLE_QUIC_FRAMER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/quic_framer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+
+namespace quic {
+
+struct QuicAckFrame;
+
+namespace test {
+
+class SimpleFramerVisitor;
+
+// Peer to make public a number of otherwise private QuicFramer methods.
+class SimpleQuicFramer {
+ public:
+  SimpleQuicFramer();
+  explicit SimpleQuicFramer(const ParsedQuicVersionVector& supported_versions);
+  SimpleQuicFramer(const ParsedQuicVersionVector& supported_versions,
+                   Perspective perspective);
+  SimpleQuicFramer(const SimpleQuicFramer&) = delete;
+  SimpleQuicFramer& operator=(const SimpleQuicFramer&) = delete;
+  ~SimpleQuicFramer();
+
+  bool ProcessPacket(const QuicEncryptedPacket& packet);
+  void Reset();
+
+  const QuicPacketHeader& header() const;
+  size_t num_frames() const;
+  const std::vector<QuicAckFrame>& ack_frames() const;
+  const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const;
+  const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const;
+  const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const;
+  const std::vector<QuicPathResponseFrame>& path_response_frames() const;
+  const std::vector<QuicPingFrame>& ping_frames() const;
+  const std::vector<QuicMessageFrame>& message_frames() const;
+  const std::vector<QuicWindowUpdateFrame>& window_update_frames() const;
+  const std::vector<QuicGoAwayFrame>& goaway_frames() const;
+  const std::vector<QuicRstStreamFrame>& rst_stream_frames() const;
+  const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const;
+  const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const;
+  const std::vector<QuicPaddingFrame>& padding_frames() const;
+  const QuicVersionNegotiationPacket* version_negotiation_packet() const;
+  EncryptionLevel last_decrypted_level() const;
+
+  QuicFramer* framer();
+
+  void SetSupportedVersions(const ParsedQuicVersionVector& versions) {
+    framer_.SetSupportedVersions(versions);
+  }
+
+ private:
+  QuicFramer framer_;
+  std::unique_ptr<SimpleFramerVisitor> visitor_;
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMPLE_QUIC_FRAMER_H_
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc
new file mode 100644
index 0000000..c56831e
--- /dev/null
+++ b/quic/test_tools/simple_session_notifier.cc
@@ -0,0 +1,633 @@
+// Copyright (c) 2018 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/simple_session_notifier.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+
+namespace test {
+
+SimpleSessionNotifier::SimpleSessionNotifier(QuicConnection* connection)
+    : last_control_frame_id_(kInvalidControlFrameId),
+      least_unacked_(1),
+      least_unsent_(1),
+      connection_(connection) {}
+
+SimpleSessionNotifier::~SimpleSessionNotifier() {
+  while (!control_frames_.empty()) {
+    DeleteFrame(&control_frames_.front());
+    control_frames_.pop_front();
+  }
+}
+
+SimpleSessionNotifier::StreamState::StreamState()
+    : bytes_total(0),
+      bytes_sent(0),
+      fin_buffered(false),
+      fin_sent(false),
+      fin_outstanding(false),
+      fin_lost(false) {}
+
+SimpleSessionNotifier::StreamState::~StreamState() {}
+
+QuicConsumedData SimpleSessionNotifier::WriteOrBufferData(
+    QuicStreamId id,
+    QuicByteCount data_length,
+    StreamSendingState state) {
+  if (!QuicContainsKey(stream_map_, id)) {
+    stream_map_[id] = StreamState();
+  }
+  StreamState& stream_state = stream_map_.find(id)->second;
+  const bool had_buffered_data =
+      HasBufferedStreamData() || HasBufferedControlFrames();
+  QuicConsumedData total_consumed(0, false);
+  QuicStreamOffset offset = stream_state.bytes_sent;
+  QUIC_DVLOG(1) << "WriteOrBuffer stream_id: " << id << " [" << offset << ", "
+                << offset + data_length << "), fin: " << (state != NO_FIN);
+  stream_state.bytes_total += data_length;
+  stream_state.fin_buffered = state != NO_FIN;
+  if (had_buffered_data) {
+    QUIC_DLOG(WARNING) << "Connection is write blocked";
+    return {0, false};
+  }
+  const size_t length = stream_state.bytes_total - stream_state.bytes_sent;
+  connection_->SetTransmissionType(NOT_RETRANSMISSION);
+  QuicConsumedData consumed =
+      connection_->SendStreamData(id, length, stream_state.bytes_sent,
+                                  stream_state.fin_buffered ? FIN : NO_FIN);
+  QUIC_DVLOG(1) << "consumed: " << consumed;
+  OnStreamDataConsumed(id, stream_state.bytes_sent, consumed.bytes_consumed,
+                       consumed.fin_consumed);
+  return consumed;
+}
+
+void SimpleSessionNotifier::OnStreamDataConsumed(QuicStreamId id,
+                                                 QuicStreamOffset offset,
+                                                 QuicByteCount data_length,
+                                                 bool fin) {
+  StreamState& state = stream_map_.find(id)->second;
+  if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) &&
+      data_length > 0) {
+    crypto_bytes_transferred_[connection_->encryption_level()].Add(
+        offset, offset + data_length);
+  }
+  state.bytes_sent += data_length;
+  state.fin_sent = fin;
+  state.fin_outstanding = fin;
+}
+
+size_t SimpleSessionNotifier::WriteCryptoData(EncryptionLevel level,
+                                              QuicByteCount data_length,
+                                              QuicStreamOffset offset) {
+  crypto_state_[level].bytes_total += data_length;
+  size_t bytes_written =
+      connection_->SendCryptoData(level, data_length, offset);
+  crypto_state_[level].bytes_sent += bytes_written;
+  crypto_bytes_transferred_[level].Add(offset, offset + bytes_written);
+  return bytes_written;
+}
+
+void SimpleSessionNotifier::WriteOrBufferRstStream(
+    QuicStreamId id,
+    QuicRstStreamErrorCode error,
+    QuicStreamOffset bytes_written) {
+  QUIC_DVLOG(1) << "Writing RST_STREAM_FRAME";
+  const bool had_buffered_data =
+      HasBufferedStreamData() || HasBufferedControlFrames();
+  control_frames_.emplace_back((QuicFrame(new QuicRstStreamFrame(
+      ++last_control_frame_id_, id, error, bytes_written))));
+  if (error != QUIC_STREAM_NO_ERROR) {
+    // Delete stream to avoid retransmissions.
+    stream_map_.erase(id);
+  }
+  if (had_buffered_data) {
+    QUIC_DLOG(WARNING) << "Connection is write blocked";
+    return;
+  }
+  WriteBufferedControlFrames();
+}
+
+void SimpleSessionNotifier::NeuterUnencryptedData() {
+  for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_NONE]) {
+    // TODO(nharper): Handle CRYPTO frame case.
+    QuicStreamFrame stream_frame(
+        QuicUtils::GetCryptoStreamId(connection_->transport_version()), false,
+        interval.min(), interval.max() - interval.min());
+    OnFrameAcked(QuicFrame(stream_frame), QuicTime::Delta::Zero());
+  }
+}
+
+void SimpleSessionNotifier::OnCanWrite() {
+  if (!RetransmitLostCryptoData() || !RetransmitLostControlFrames() ||
+      !RetransmitLostStreamData()) {
+    return;
+  }
+  // Write buffered control frames.
+  if (!WriteBufferedControlFrames()) {
+    return;
+  }
+  // Write new data.
+  // TODO(nharper): Write CRYPTO frames.
+  for (const auto& pair : stream_map_) {
+    const auto& state = pair.second;
+    if (!StreamHasBufferedData(pair.first)) {
+      continue;
+    }
+
+    const size_t length = state.bytes_total - state.bytes_sent;
+    const bool can_bundle_fin =
+        state.fin_buffered && (state.bytes_sent + length == state.bytes_total);
+    connection_->SetTransmissionType(NOT_RETRANSMISSION);
+    QuicConsumedData consumed = connection_->SendStreamData(
+        pair.first, length, state.bytes_sent, can_bundle_fin ? FIN : NO_FIN);
+    QUIC_DVLOG(1) << "Tries to write stream_id: " << pair.first << " ["
+                  << state.bytes_sent << ", " << state.bytes_sent + length
+                  << "), fin: " << can_bundle_fin
+                  << ", and consumed: " << consumed;
+    OnStreamDataConsumed(pair.first, state.bytes_sent, consumed.bytes_consumed,
+                         consumed.fin_consumed);
+    if (length != consumed.bytes_consumed ||
+        (can_bundle_fin && !consumed.fin_consumed)) {
+      break;
+    }
+  }
+}
+
+bool SimpleSessionNotifier::WillingToWrite() const {
+  QUIC_DVLOG(1) << "has_buffered_control_frames: " << HasBufferedControlFrames()
+                << " as_lost_control_frames: " << !lost_control_frames_.empty()
+                << " has_buffered_stream_data: " << HasBufferedStreamData()
+                << " has_lost_stream_data: " << HasLostStreamData();
+  return HasBufferedControlFrames() || !lost_control_frames_.empty() ||
+         HasBufferedStreamData() || HasLostStreamData();
+}
+
+QuicByteCount SimpleSessionNotifier::StreamBytesSent() const {
+  QuicByteCount bytes_sent = 0;
+  for (const auto& pair : stream_map_) {
+    const auto& state = pair.second;
+    bytes_sent += state.bytes_sent;
+  }
+  return bytes_sent;
+}
+
+QuicByteCount SimpleSessionNotifier::StreamBytesToSend() const {
+  QuicByteCount bytes_to_send = 0;
+  for (const auto& pair : stream_map_) {
+    const auto& state = pair.second;
+    bytes_to_send += (state.bytes_total - state.bytes_sent);
+  }
+  return bytes_to_send;
+}
+
+bool SimpleSessionNotifier::OnFrameAcked(const QuicFrame& frame,
+                                         QuicTime::Delta /*ack_delay_time*/) {
+  QUIC_DVLOG(1) << "Acking " << frame;
+  if (frame.type == CRYPTO_FRAME) {
+    StreamState* state = &crypto_state_[frame.crypto_frame->level];
+    QuicStreamOffset offset = frame.crypto_frame->offset;
+    QuicByteCount data_length = frame.crypto_frame->data_length;
+    QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
+    newly_acked.Difference(state->bytes_acked);
+    if (newly_acked.Empty()) {
+      return false;
+    }
+    state->bytes_acked.Add(offset, offset + data_length);
+    state->pending_retransmissions.Difference(offset, offset + data_length);
+    return true;
+  }
+  if (frame.type != STREAM_FRAME) {
+    return OnControlFrameAcked(frame);
+  }
+  if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
+    return false;
+  }
+  auto* state = &stream_map_.find(frame.stream_frame.stream_id)->second;
+  QuicStreamOffset offset = frame.stream_frame.offset;
+  QuicByteCount data_length = frame.stream_frame.data_length;
+  QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
+  newly_acked.Difference(state->bytes_acked);
+  const bool fin_newly_acked = frame.stream_frame.fin && state->fin_outstanding;
+  if (newly_acked.Empty() && !fin_newly_acked) {
+    return false;
+  }
+  state->bytes_acked.Add(offset, offset + data_length);
+  if (fin_newly_acked) {
+    state->fin_outstanding = false;
+    state->fin_lost = false;
+  }
+  state->pending_retransmissions.Difference(offset, offset + data_length);
+  return true;
+}
+
+void SimpleSessionNotifier::OnFrameLost(const QuicFrame& frame) {
+  QUIC_DVLOG(1) << "Losting " << frame;
+  if (frame.type == CRYPTO_FRAME) {
+    StreamState* state = &crypto_state_[frame.crypto_frame->level];
+    QuicStreamOffset offset = frame.crypto_frame->offset;
+    QuicByteCount data_length = frame.crypto_frame->data_length;
+    QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
+    bytes_lost.Difference(state->bytes_acked);
+    if (bytes_lost.Empty()) {
+      return;
+    }
+    for (const auto& lost : bytes_lost) {
+      state->pending_retransmissions.Add(lost.min(), lost.max());
+    }
+    return;
+  }
+  if (frame.type != STREAM_FRAME) {
+    OnControlFrameLost(frame);
+    return;
+  }
+  if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
+    return;
+  }
+  auto* state = &stream_map_.find(frame.stream_frame.stream_id)->second;
+  QuicStreamOffset offset = frame.stream_frame.offset;
+  QuicByteCount data_length = frame.stream_frame.data_length;
+  QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length);
+  bytes_lost.Difference(state->bytes_acked);
+  const bool fin_lost = state->fin_outstanding && frame.stream_frame.fin;
+  if (bytes_lost.Empty() && !fin_lost) {
+    return;
+  }
+  for (const auto& lost : bytes_lost) {
+    state->pending_retransmissions.Add(lost.min(), lost.max());
+  }
+  state->fin_lost = fin_lost;
+}
+
+void SimpleSessionNotifier::RetransmitFrames(const QuicFrames& frames,
+                                             TransmissionType type) {
+  QuicConnection::ScopedPacketFlusher retransmission_flusher(
+      connection_, QuicConnection::SEND_ACK_IF_QUEUED);
+  connection_->SetTransmissionType(type);
+  for (const QuicFrame& frame : frames) {
+    if (frame.type == CRYPTO_FRAME) {
+      const StreamState& state = crypto_state_[frame.crypto_frame->level];
+      QuicIntervalSet<QuicStreamOffset> retransmission(
+          frame.crypto_frame->offset,
+          frame.crypto_frame->offset + frame.crypto_frame->data_length);
+      retransmission.Difference(state.bytes_acked);
+      for (const auto& interval : retransmission) {
+        QuicStreamOffset offset = interval.min();
+        QuicByteCount length = interval.max() - interval.min();
+        size_t consumed = connection_->SendCryptoData(frame.crypto_frame->level,
+                                                      length, offset);
+        // CRYPTO frames should never be write blocked.
+        DCHECK_EQ(consumed, length);
+      }
+    }
+    if (frame.type != STREAM_FRAME) {
+      if (GetControlFrameId(frame) == kInvalidControlFrameId) {
+        continue;
+      }
+      QuicFrame copy = CopyRetransmittableControlFrame(frame);
+      if (!connection_->SendControlFrame(copy)) {
+        // Connection is write blocked.
+        DeleteFrame(&copy);
+        return;
+      }
+      continue;
+    }
+    if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
+      continue;
+    }
+    const auto& state = stream_map_.find(frame.stream_frame.stream_id)->second;
+    QuicIntervalSet<QuicStreamOffset> retransmission(
+        frame.stream_frame.offset,
+        frame.stream_frame.offset + frame.stream_frame.data_length);
+    EncryptionLevel retransmission_encryption_level =
+        connection_->encryption_level();
+    EncryptionLevel current_encryption_level = connection_->encryption_level();
+    if (frame.stream_frame.stream_id ==
+        QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
+      for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+        if (retransmission.Intersects(crypto_bytes_transferred_[i])) {
+          retransmission_encryption_level = static_cast<EncryptionLevel>(i);
+          retransmission.Intersection(crypto_bytes_transferred_[i]);
+          break;
+        }
+      }
+    }
+    retransmission.Difference(state.bytes_acked);
+    bool retransmit_fin = frame.stream_frame.fin && state.fin_outstanding;
+    QuicConsumedData consumed(0, false);
+    for (const auto& interval : retransmission) {
+      QuicStreamOffset retransmission_offset = interval.min();
+      QuicByteCount retransmission_length = interval.max() - interval.min();
+      const bool can_bundle_fin =
+          retransmit_fin &&
+          (retransmission_offset + retransmission_length == state.bytes_sent);
+      if (frame.stream_frame.stream_id ==
+          QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
+        // Set appropriate encryption level for crypto stream.
+        connection_->SetDefaultEncryptionLevel(retransmission_encryption_level);
+      }
+      consumed = connection_->SendStreamData(
+          frame.stream_frame.stream_id, retransmission_length,
+          retransmission_offset, can_bundle_fin ? FIN : NO_FIN);
+      QUIC_DVLOG(1) << "stream " << frame.stream_frame.stream_id
+                    << " is forced to retransmit stream data ["
+                    << retransmission_offset << ", "
+                    << retransmission_offset + retransmission_length
+                    << ") and fin: " << can_bundle_fin
+                    << ", consumed: " << consumed;
+      if (can_bundle_fin) {
+        retransmit_fin = !consumed.fin_consumed;
+      }
+      if (frame.stream_frame.stream_id ==
+          QuicUtils::GetCryptoStreamId(connection_->transport_version())) {
+        // Restore encryption level.
+        connection_->SetDefaultEncryptionLevel(current_encryption_level);
+      }
+      if (consumed.bytes_consumed < retransmission_length ||
+          (can_bundle_fin && !consumed.fin_consumed)) {
+        // Connection is write blocked.
+        return;
+      }
+    }
+    if (retransmit_fin) {
+      QUIC_DVLOG(1) << "stream " << frame.stream_frame.stream_id
+                    << " retransmits fin only frame.";
+      consumed = connection_->SendStreamData(frame.stream_frame.stream_id, 0,
+                                             state.bytes_sent, FIN);
+    }
+  }
+}
+
+bool SimpleSessionNotifier::IsFrameOutstanding(const QuicFrame& frame) const {
+  if (frame.type == CRYPTO_FRAME) {
+    QuicStreamOffset offset = frame.crypto_frame->offset;
+    QuicByteCount data_length = frame.crypto_frame->data_length;
+    bool ret = data_length > 0 &&
+               !crypto_state_[frame.crypto_frame->level].bytes_acked.Contains(
+                   offset, offset + data_length);
+    return ret;
+  }
+  if (frame.type != STREAM_FRAME) {
+    return IsControlFrameOutstanding(frame);
+  }
+  if (!QuicContainsKey(stream_map_, frame.stream_frame.stream_id)) {
+    return false;
+  }
+  const auto& state = stream_map_.find(frame.stream_frame.stream_id)->second;
+  QuicStreamOffset offset = frame.stream_frame.offset;
+  QuicByteCount data_length = frame.stream_frame.data_length;
+  return (data_length > 0 &&
+          !state.bytes_acked.Contains(offset, offset + data_length)) ||
+         (frame.stream_frame.fin && state.fin_outstanding);
+}
+
+bool SimpleSessionNotifier::HasUnackedCryptoData() const {
+  if (connection_->transport_version() >= QUIC_VERSION_47) {
+    for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+      const StreamState& state = crypto_state_[i];
+      if (state.bytes_total > state.bytes_sent) {
+        return true;
+      }
+      QuicIntervalSet<QuicStreamOffset> bytes_to_ack(0, state.bytes_total);
+      bytes_to_ack.Difference(state.bytes_acked);
+      if (!bytes_to_ack.Empty()) {
+        return true;
+      }
+    }
+    return false;
+  }
+  if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
+                                        connection_->transport_version()))) {
+    return false;
+  }
+  const auto& state =
+      stream_map_
+          .find(QuicUtils::GetCryptoStreamId(connection_->transport_version()))
+          ->second;
+  if (state.bytes_total > state.bytes_sent) {
+    return true;
+  }
+  QuicIntervalSet<QuicStreamOffset> bytes_to_ack(0, state.bytes_total);
+  bytes_to_ack.Difference(state.bytes_acked);
+  return !bytes_to_ack.Empty();
+}
+
+bool SimpleSessionNotifier::OnControlFrameAcked(const QuicFrame& frame) {
+  QuicControlFrameId id = GetControlFrameId(frame);
+  if (id == kInvalidControlFrameId) {
+    return false;
+  }
+  DCHECK(id < least_unacked_ + control_frames_.size());
+  if (id < least_unacked_ ||
+      GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
+          kInvalidControlFrameId) {
+    return false;
+  }
+  SetControlFrameId(kInvalidControlFrameId,
+                    &control_frames_.at(id - least_unacked_));
+  lost_control_frames_.erase(id);
+  while (!control_frames_.empty() &&
+         GetControlFrameId(control_frames_.front()) == kInvalidControlFrameId) {
+    DeleteFrame(&control_frames_.front());
+    control_frames_.pop_front();
+    ++least_unacked_;
+  }
+  return true;
+}
+
+void SimpleSessionNotifier::OnControlFrameLost(const QuicFrame& frame) {
+  QuicControlFrameId id = GetControlFrameId(frame);
+  if (id == kInvalidControlFrameId) {
+    return;
+  }
+  DCHECK(id < least_unacked_ + control_frames_.size());
+  if (id < least_unacked_ ||
+      GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
+          kInvalidControlFrameId) {
+    return;
+  }
+  if (!QuicContainsKey(lost_control_frames_, id)) {
+    lost_control_frames_[id] = true;
+  }
+}
+
+bool SimpleSessionNotifier::IsControlFrameOutstanding(
+    const QuicFrame& frame) const {
+  QuicControlFrameId id = GetControlFrameId(frame);
+  if (id == kInvalidControlFrameId) {
+    return false;
+  }
+  return id < least_unacked_ + control_frames_.size() && id >= least_unacked_ &&
+         GetControlFrameId(control_frames_.at(id - least_unacked_)) !=
+             kInvalidControlFrameId;
+}
+
+bool SimpleSessionNotifier::RetransmitLostControlFrames() {
+  while (!lost_control_frames_.empty()) {
+    QuicFrame pending = control_frames_.at(lost_control_frames_.begin()->first -
+                                           least_unacked_);
+    QuicFrame copy = CopyRetransmittableControlFrame(pending);
+    connection_->SetTransmissionType(LOSS_RETRANSMISSION);
+    if (!connection_->SendControlFrame(copy)) {
+      // Connection is write blocked.
+      DeleteFrame(&copy);
+      break;
+    }
+    lost_control_frames_.pop_front();
+  }
+  return lost_control_frames_.empty();
+}
+
+bool SimpleSessionNotifier::RetransmitLostCryptoData() {
+  // TODO(nharper): Handle CRYPTO frame case.
+  if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId(
+                                        connection_->transport_version()))) {
+    return true;
+  }
+  auto& state =
+      stream_map_
+          .find(QuicUtils::GetCryptoStreamId(connection_->transport_version()))
+          ->second;
+  while (!state.pending_retransmissions.Empty()) {
+    connection_->SetTransmissionType(HANDSHAKE_RETRANSMISSION);
+    QuicIntervalSet<QuicStreamOffset> retransmission(
+        state.pending_retransmissions.begin()->min(),
+        state.pending_retransmissions.begin()->max());
+    EncryptionLevel retransmission_encryption_level = ENCRYPTION_NONE;
+    for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) {
+      if (retransmission.Intersects(crypto_bytes_transferred_[i])) {
+        retransmission_encryption_level = static_cast<EncryptionLevel>(i);
+        retransmission.Intersection(crypto_bytes_transferred_[i]);
+        break;
+      }
+    }
+    QuicStreamOffset retransmission_offset = retransmission.begin()->min();
+    QuicByteCount retransmission_length =
+        retransmission.begin()->max() - retransmission.begin()->min();
+    EncryptionLevel current_encryption_level = connection_->encryption_level();
+    // Set appropriate encryption level.
+    connection_->SetDefaultEncryptionLevel(retransmission_encryption_level);
+    QuicConsumedData consumed = connection_->SendStreamData(
+        QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+        retransmission_length, retransmission_offset, NO_FIN);
+    // Restore encryption level.
+    connection_->SetDefaultEncryptionLevel(current_encryption_level);
+    state.pending_retransmissions.Difference(
+        retransmission_offset, retransmission_offset + consumed.bytes_consumed);
+    if (consumed.bytes_consumed < retransmission_length) {
+      break;
+    }
+  }
+  return state.pending_retransmissions.Empty();
+}
+
+bool SimpleSessionNotifier::RetransmitLostStreamData() {
+  for (auto& pair : stream_map_) {
+    StreamState& state = pair.second;
+    QuicConsumedData consumed(0, false);
+    while (!state.pending_retransmissions.Empty() || state.fin_lost) {
+      connection_->SetTransmissionType(LOSS_RETRANSMISSION);
+      if (state.pending_retransmissions.Empty()) {
+        QUIC_DVLOG(1) << "stream " << pair.first
+                      << " retransmits fin only frame.";
+        consumed =
+            connection_->SendStreamData(pair.first, 0, state.bytes_sent, FIN);
+        state.fin_lost = !consumed.fin_consumed;
+        if (state.fin_lost) {
+          DLOG(INFO) << "Connection is write blocked";
+          return false;
+        }
+      } else {
+        QuicStreamOffset offset = state.pending_retransmissions.begin()->min();
+        QuicByteCount length = state.pending_retransmissions.begin()->max() -
+                               state.pending_retransmissions.begin()->min();
+        const bool can_bundle_fin =
+            state.fin_lost && (offset + length == state.bytes_sent);
+        consumed = connection_->SendStreamData(pair.first, length, offset,
+                                               can_bundle_fin ? FIN : NO_FIN);
+        QUIC_DVLOG(1) << "stream " << pair.first
+                      << " tries to retransmit stream data [" << offset << ", "
+                      << offset + length << ") and fin: " << can_bundle_fin
+                      << ", consumed: " << consumed;
+        state.pending_retransmissions.Difference(
+            offset, offset + consumed.bytes_consumed);
+        if (consumed.fin_consumed) {
+          state.fin_lost = false;
+        }
+        if (length > consumed.bytes_consumed ||
+            (can_bundle_fin && !consumed.fin_consumed)) {
+          DVLOG(1) << "Connection is write blocked";
+          break;
+        }
+      }
+    }
+  }
+  return !HasLostStreamData();
+}
+
+bool SimpleSessionNotifier::WriteBufferedControlFrames() {
+  while (HasBufferedControlFrames()) {
+    QuicFrame frame_to_send =
+        control_frames_.at(least_unsent_ - least_unacked_);
+    QuicFrame copy = CopyRetransmittableControlFrame(frame_to_send);
+    connection_->SetTransmissionType(NOT_RETRANSMISSION);
+    if (!connection_->SendControlFrame(copy)) {
+      // Connection is write blocked.
+      DeleteFrame(&copy);
+      break;
+    }
+    ++least_unsent_;
+  }
+  return !HasBufferedControlFrames();
+}
+
+bool SimpleSessionNotifier::HasBufferedControlFrames() const {
+  return least_unsent_ < least_unacked_ + control_frames_.size();
+}
+
+bool SimpleSessionNotifier::HasBufferedStreamData() const {
+  for (const auto& pair : stream_map_) {
+    const auto& state = pair.second;
+    if (state.bytes_total > state.bytes_sent ||
+        (state.fin_buffered && !state.fin_sent)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool SimpleSessionNotifier::StreamIsWaitingForAcks(QuicStreamId id) const {
+  if (!QuicContainsKey(stream_map_, id)) {
+    return false;
+  }
+  const StreamState& state = stream_map_.find(id)->second;
+  return !state.bytes_acked.Contains(0, state.bytes_sent) ||
+         state.fin_outstanding;
+}
+
+bool SimpleSessionNotifier::StreamHasBufferedData(QuicStreamId id) const {
+  if (!QuicContainsKey(stream_map_, id)) {
+    return false;
+  }
+  const StreamState& state = stream_map_.find(id)->second;
+  return state.bytes_total > state.bytes_sent ||
+         (state.fin_buffered && !state.fin_sent);
+}
+
+bool SimpleSessionNotifier::HasLostStreamData() const {
+  for (const auto& pair : stream_map_) {
+    const auto& state = pair.second;
+    if (!state.pending_retransmissions.Empty() || state.fin_lost) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace test
+
+}  // namespace quic
diff --git a/quic/test_tools/simple_session_notifier.h b/quic/test_tools/simple_session_notifier.h
new file mode 100644
index 0000000..f7982d2
--- /dev/null
+++ b/quic/test_tools/simple_session_notifier.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2018 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
+#include "net/third_party/quiche/src/quic/core/session_notifier_interface.h"
+
+namespace quic {
+
+class QuicConnection;
+
+namespace test {
+
+// SimpleSessionNotifier implements the basic functionalities of a session, and
+// it manages stream data and control frames.
+class SimpleSessionNotifier : public SessionNotifierInterface {
+ public:
+  explicit SimpleSessionNotifier(QuicConnection* connection);
+  ~SimpleSessionNotifier() override;
+
+  // Tries to write stream data and returns data consumed.
+  QuicConsumedData WriteOrBufferData(QuicStreamId id,
+                                     QuicByteCount data_length,
+                                     StreamSendingState state);
+
+  // Tries to write RST_STREAM_FRAME.
+  void WriteOrBufferRstStream(QuicStreamId id,
+                              QuicRstStreamErrorCode error,
+                              QuicStreamOffset bytes_written);
+
+  // Tries to write CRYPTO data and returns the number of bytes written.
+  size_t WriteCryptoData(EncryptionLevel level,
+                         QuicByteCount data_length,
+                         QuicStreamOffset offset);
+
+  // Neuters unencrypted data of crypto stream.
+  void NeuterUnencryptedData();
+
+  // Called when connection_ becomes writable.
+  void OnCanWrite();
+
+  // Returns true if there are 1) unsent control frames and stream data, or 2)
+  // lost control frames and stream data.
+  bool WillingToWrite() const;
+
+  // Number of sent stream bytes. Please note, this does not count
+  // retransmissions.
+  QuicByteCount StreamBytesSent() const;
+
+  // Number of stream bytes waiting to be sent for the first time.
+  QuicByteCount StreamBytesToSend() const;
+
+  // Returns true if there is any stream data waiting to be sent for the first
+  // time.
+  bool HasBufferedStreamData() const;
+
+  // Returns true if stream |id| has any outstanding data.
+  bool StreamIsWaitingForAcks(QuicStreamId id) const;
+
+  // SessionNotifierInterface methods:
+  bool OnFrameAcked(const QuicFrame& frame,
+                    QuicTime::Delta ack_delay_time) override;
+  void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override {}
+  void OnFrameLost(const QuicFrame& frame) override;
+  void RetransmitFrames(const QuicFrames& frames,
+                        TransmissionType type) override;
+  bool IsFrameOutstanding(const QuicFrame& frame) const override;
+  bool HasUnackedCryptoData() const override;
+
+ private:
+  struct StreamState {
+    StreamState();
+    ~StreamState();
+
+    // Total number of bytes.
+    QuicByteCount bytes_total;
+    // Number of sent bytes.
+    QuicByteCount bytes_sent;
+    // Record of acked offsets.
+    QuicIntervalSet<QuicStreamOffset> bytes_acked;
+    // Data considered as lost and needs to be retransmitted.
+    QuicIntervalSet<QuicStreamOffset> pending_retransmissions;
+
+    bool fin_buffered;
+    bool fin_sent;
+    bool fin_outstanding;
+    bool fin_lost;
+  };
+
+  friend std::ostream& operator<<(std::ostream& os, const StreamState& s);
+
+  using StreamMap = QuicUnorderedMap<QuicStreamId, StreamState>;
+
+  void OnStreamDataConsumed(QuicStreamId id,
+                            QuicStreamOffset offset,
+                            QuicByteCount data_length,
+                            bool fin);
+
+  bool OnControlFrameAcked(const QuicFrame& frame);
+
+  void OnControlFrameLost(const QuicFrame& frame);
+
+  bool RetransmitLostControlFrames();
+
+  bool RetransmitLostCryptoData();
+
+  bool RetransmitLostStreamData();
+
+  bool WriteBufferedControlFrames();
+
+  bool IsControlFrameOutstanding(const QuicFrame& frame) const;
+
+  bool HasBufferedControlFrames() const;
+
+  bool HasLostStreamData() const;
+
+  bool StreamHasBufferedData(QuicStreamId id) const;
+
+  QuicDeque<QuicFrame> control_frames_;
+
+  QuicLinkedHashMap<QuicControlFrameId, bool> lost_control_frames_;
+
+  // Id of latest saved control frame. 0 if no control frame has been saved.
+  QuicControlFrameId last_control_frame_id_;
+
+  // The control frame at the 0th index of control_frames_.
+  QuicControlFrameId least_unacked_;
+
+  // ID of the least unsent control frame.
+  QuicControlFrameId least_unsent_;
+
+  StreamMap stream_map_;
+
+  // Transferred crypto bytes according to encryption levels.
+  QuicIntervalSet<QuicStreamOffset>
+      crypto_bytes_transferred_[NUM_ENCRYPTION_LEVELS];
+
+  StreamState crypto_state_[NUM_ENCRYPTION_LEVELS];
+
+  QuicConnection* connection_;
+};
+
+}  // namespace test
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_
diff --git a/quic/test_tools/simple_session_notifier_test.cc b/quic/test_tools/simple_session_notifier_test.cc
new file mode 100644
index 0000000..b20fee6
--- /dev/null
+++ b/quic/test_tools/simple_session_notifier_test.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2018 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/simple_session_notifier.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+using testing::_;
+using testing::InSequence;
+using testing::Return;
+using testing::StrictMock;
+
+namespace quic {
+namespace test {
+namespace {
+
+class MockQuicConnectionWithSendStreamData : public MockQuicConnection {
+ public:
+  MockQuicConnectionWithSendStreamData(MockQuicConnectionHelper* helper,
+                                       MockAlarmFactory* alarm_factory,
+                                       Perspective perspective)
+      : MockQuicConnection(helper, alarm_factory, perspective) {}
+
+  MOCK_METHOD4(SendStreamData,
+               QuicConsumedData(QuicStreamId id,
+                                size_t write_length,
+                                QuicStreamOffset offset,
+                                StreamSendingState state));
+};
+
+class SimpleSessionNotifierTest : public QuicTest {
+ public:
+  SimpleSessionNotifierTest()
+      : connection_(&helper_, &alarm_factory_, Perspective::IS_CLIENT),
+        notifier_(&connection_) {
+    connection_.set_visitor(&visitor_);
+    QuicConnectionPeer::SetSessionDecidesWhatToWrite(&connection_);
+    EXPECT_FALSE(notifier_.WillingToWrite());
+    EXPECT_EQ(0u, notifier_.StreamBytesSent());
+    EXPECT_FALSE(notifier_.HasBufferedStreamData());
+  }
+
+  bool ControlFrameConsumed(const QuicFrame& frame) {
+    DeleteFrame(&const_cast<QuicFrame&>(frame));
+    return true;
+  }
+
+  MockQuicConnectionHelper helper_;
+  MockAlarmFactory alarm_factory_;
+  MockQuicConnectionVisitor visitor_;
+  StrictMock<MockQuicConnectionWithSendStreamData> connection_;
+  SimpleSessionNotifier notifier_;
+};
+
+TEST_F(SimpleSessionNotifierTest, WriteOrBufferData) {
+  InSequence s;
+  EXPECT_CALL(connection_, SendStreamData(3, 1024, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(1024, false)));
+  notifier_.WriteOrBufferData(3, 1024, NO_FIN);
+  EXPECT_EQ(0u, notifier_.StreamBytesToSend());
+  EXPECT_CALL(connection_, SendStreamData(5, 512, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(512, false)));
+  notifier_.WriteOrBufferData(5, 512, NO_FIN);
+  EXPECT_FALSE(notifier_.WillingToWrite());
+  // Connection is blocked.
+  EXPECT_CALL(connection_, SendStreamData(5, 512, 512, FIN))
+      .WillOnce(Return(QuicConsumedData(256, false)));
+  notifier_.WriteOrBufferData(5, 512, FIN);
+  EXPECT_TRUE(notifier_.WillingToWrite());
+  EXPECT_EQ(1792u, notifier_.StreamBytesSent());
+  EXPECT_EQ(256u, notifier_.StreamBytesToSend());
+  EXPECT_TRUE(notifier_.HasBufferedStreamData());
+
+  // New data cannot be sent as connection is blocked.
+  EXPECT_CALL(connection_, SendStreamData(7, 1024, 0, FIN)).Times(0);
+  notifier_.WriteOrBufferData(7, 1024, FIN);
+  EXPECT_EQ(1792u, notifier_.StreamBytesSent());
+}
+
+TEST_F(SimpleSessionNotifierTest, WriteOrBufferRstStream) {
+  InSequence s;
+  EXPECT_CALL(connection_, SendStreamData(5, 1024, 0, FIN))
+      .WillOnce(Return(QuicConsumedData(1024, true)));
+  notifier_.WriteOrBufferData(5, 1024, FIN);
+
+  // Reset stream 5 with no error.
+  EXPECT_CALL(connection_, SendControlFrame(_))
+      .WillRepeatedly(
+          Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed));
+  notifier_.WriteOrBufferRstStream(5, QUIC_STREAM_NO_ERROR, 1024);
+  // Verify stream 5 is waiting for acks.
+  EXPECT_TRUE(notifier_.StreamIsWaitingForAcks(5));
+
+  // Reset stream 5 with error.
+  notifier_.WriteOrBufferRstStream(5, QUIC_ERROR_PROCESSING_STREAM, 1024);
+  EXPECT_FALSE(notifier_.StreamIsWaitingForAcks(5));
+}
+
+TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) {
+  InSequence s;
+  // Send crypto data [0, 1024) in ENCRYPTION_NONE.
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+  EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
+                                              connection_.transport_version()),
+                                          1024, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(1024, false)));
+  notifier_.WriteOrBufferData(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
+      NO_FIN);
+  // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
+                                              connection_.transport_version()),
+                                          1024, 1024, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(1024, false)));
+  notifier_.WriteOrBufferData(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
+      NO_FIN);
+  // Ack [1024, 2048).
+  QuicStreamFrame stream_frame(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
+      1024, 1024);
+  notifier_.OnFrameAcked(QuicFrame(stream_frame), QuicTime::Delta::Zero());
+  EXPECT_TRUE(notifier_.StreamIsWaitingForAcks(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version())));
+  // Neuters unencrypted data.
+  notifier_.NeuterUnencryptedData();
+  EXPECT_FALSE(notifier_.StreamIsWaitingForAcks(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version())));
+}
+
+TEST_F(SimpleSessionNotifierTest, OnCanWrite) {
+  InSequence s;
+  // Send crypto data [0, 1024) in ENCRYPTION_NONE.
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+  EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
+                                              connection_.transport_version()),
+                                          1024, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(1024, false)));
+  notifier_.WriteOrBufferData(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
+      NO_FIN);
+  // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
+                                              connection_.transport_version()),
+                                          1024, 1024, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(1024, false)));
+  notifier_.WriteOrBufferData(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
+      NO_FIN);
+  // Send stream 3 [0, 1024) and connection is blocked.
+  EXPECT_CALL(connection_, SendStreamData(3, 1024, 0, FIN))
+      .WillOnce(Return(QuicConsumedData(512, false)));
+  notifier_.WriteOrBufferData(3, 1024, FIN);
+  // Send stream 5 [0, 1024).
+  EXPECT_CALL(connection_, SendStreamData(5, _, _, _)).Times(0);
+  notifier_.WriteOrBufferData(5, 1024, NO_FIN);
+  // Reset stream 5 with error.
+  EXPECT_CALL(connection_, SendControlFrame(_)).Times(0);
+  notifier_.WriteOrBufferRstStream(5, QUIC_ERROR_PROCESSING_STREAM, 1024);
+
+  // Lost crypto data [500, 1500) and stream 3 [0, 512).
+  QuicStreamFrame frame1(
+      QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 500,
+      1000);
+  QuicStreamFrame frame2(3, false, 0, 512);
+  notifier_.OnFrameLost(QuicFrame(frame1));
+  notifier_.OnFrameLost(QuicFrame(frame2));
+
+  // Connection becomes writable.
+  // Lost crypto data gets retransmitted as [500, 1024) and [1024, 1500), as
+  // they are in different encryption levels.
+  EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
+                                              connection_.transport_version()),
+                                          524, 500, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(524, false)));
+  EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
+                                              connection_.transport_version()),
+                                          476, 1024, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(476, false)));
+  // Lost stream 3 data gets retransmitted.
+  EXPECT_CALL(connection_, SendStreamData(3, 512, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(512, false)));
+  // Buffered control frames get sent.
+  EXPECT_CALL(connection_, SendControlFrame(_))
+      .WillOnce(Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed));
+  // Buffered stream 3 data [512, 1024) gets sent.
+  EXPECT_CALL(connection_, SendStreamData(3, 512, 512, FIN))
+      .WillOnce(Return(QuicConsumedData(512, true)));
+  notifier_.OnCanWrite();
+  EXPECT_FALSE(notifier_.WillingToWrite());
+}
+
+TEST_F(SimpleSessionNotifierTest, RetransmitFrames) {
+  InSequence s;
+  // Send stream 3 data [0, 10) and fin.
+  EXPECT_CALL(connection_, SendStreamData(3, 10, 0, FIN))
+      .WillOnce(Return(QuicConsumedData(10, true)));
+  notifier_.WriteOrBufferData(3, 10, FIN);
+  QuicStreamFrame frame1(3, true, 0, 10);
+  // Send stream 5 [0, 10) and fin.
+  EXPECT_CALL(connection_, SendStreamData(5, 10, 0, FIN))
+      .WillOnce(Return(QuicConsumedData(10, true)));
+  notifier_.WriteOrBufferData(5, 10, FIN);
+  QuicStreamFrame frame2(5, true, 0, 10);
+  // Reset stream 5 with no error.
+  EXPECT_CALL(connection_, SendControlFrame(_))
+      .WillOnce(Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed));
+  notifier_.WriteOrBufferRstStream(5, QUIC_STREAM_NO_ERROR, 10);
+
+  // Ack stream 3 [3, 7), and stream 5 [8, 10).
+  QuicStreamFrame ack_frame1(3, false, 3, 4);
+  QuicStreamFrame ack_frame2(5, false, 8, 2);
+  notifier_.OnFrameAcked(QuicFrame(ack_frame1), QuicTime::Delta::Zero());
+  notifier_.OnFrameAcked(QuicFrame(ack_frame2), QuicTime::Delta::Zero());
+  EXPECT_FALSE(notifier_.WillingToWrite());
+
+  // Force to send.
+  QuicRstStreamFrame rst_stream(1, 5, QUIC_STREAM_NO_ERROR, 10);
+  QuicFrames frames;
+  frames.push_back(QuicFrame(frame2));
+  frames.push_back(QuicFrame(&rst_stream));
+  frames.push_back(QuicFrame(frame1));
+  // stream 5 data [0, 8), fin only are retransmitted.
+  EXPECT_CALL(connection_, SendStreamData(5, 8, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(8, false)));
+  EXPECT_CALL(connection_, SendStreamData(5, 0, 10, FIN))
+      .WillOnce(Return(QuicConsumedData(0, true)));
+  // rst_stream is retransmitted.
+  EXPECT_CALL(connection_, SendControlFrame(_))
+      .WillOnce(Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed));
+  // stream 3 data [0, 3) is retransmitted and connection is blocked.
+  EXPECT_CALL(connection_, SendStreamData(3, 3, 0, NO_FIN))
+      .WillOnce(Return(QuicConsumedData(2, false)));
+  notifier_.RetransmitFrames(frames, RTO_RETRANSMISSION);
+  EXPECT_FALSE(notifier_.WillingToWrite());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/simulator/actor.cc b/quic/test_tools/simulator/actor.cc
new file mode 100644
index 0000000..546875d
--- /dev/null
+++ b/quic/test_tools/simulator/actor.cc
@@ -0,0 +1,31 @@
+// 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/simulator/actor.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+
+namespace quic {
+namespace simulator {
+
+Actor::Actor(Simulator* simulator, QuicString name)
+    : simulator_(simulator),
+      clock_(simulator->GetClock()),
+      name_(std::move(name)) {
+  simulator_->AddActor(this);
+}
+
+Actor::~Actor() {
+  simulator_->RemoveActor(this);
+}
+
+void Actor::Schedule(QuicTime next_tick) {
+  simulator_->Schedule(this, next_tick);
+}
+
+void Actor::Unschedule() {
+  simulator_->Unschedule(this);
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/actor.h b/quic/test_tools/simulator/actor.h
new file mode 100644
index 0000000..0c24913
--- /dev/null
+++ b/quic/test_tools/simulator/actor.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
+
+#include <string>
+
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+
+namespace quic {
+namespace simulator {
+
+class Simulator;
+
+// Actor is the base class for all participants of the simulation which can
+// schedule events to be triggered at the specified time.  Every actor has a
+// name assigned to it, which can be used for debugging and addressing purposes.
+//
+// The Actor object is scheduled as follows:
+// 1. Every Actor object appears at most once in the event queue, for one
+//    specific time.
+// 2. Actor is scheduled by calling Schedule() method.
+// 3. If Schedule() method is called with multiple different times specified,
+//    Act() method will be called at the earliest time specified.
+// 4. Before Act() is called, the Actor is removed from the event queue.  Act()
+//    will not be called again unless Schedule() is called.
+class Actor {
+ public:
+  Actor(Simulator* simulator, QuicString name);
+  virtual ~Actor();
+
+  // Trigger all the events the actor can potentially handle at this point.
+  // Before Act() is called, the actor is removed from the event queue, and has
+  // to schedule the next call manually.
+  virtual void Act() = 0;
+
+  inline QuicString name() const { return name_; }
+  inline Simulator* simulator() const { return simulator_; }
+
+ protected:
+  // Calls Schedule() on the associated simulator.
+  void Schedule(QuicTime next_tick);
+
+  // Calls Unschedule() on the associated simulator.
+  void Unschedule();
+
+  Simulator* simulator_;
+  const QuicClock* clock_;
+  QuicString name_;
+
+ private:
+  // Since the Actor object registers itself with a simulator using a pointer to
+  // itself, do not allow it to be moved.
+  Actor(Actor&&) = delete;
+  Actor(const Actor&) = delete;
+  Actor& operator=(const Actor&) = delete;
+  Actor& operator=(Actor&&) = delete;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
diff --git a/quic/test_tools/simulator/alarm_factory.cc b/quic/test_tools/simulator/alarm_factory.cc
new file mode 100644
index 0000000..736f9ea
--- /dev/null
+++ b/quic/test_tools/simulator/alarm_factory.cc
@@ -0,0 +1,81 @@
+// 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/simulator/alarm_factory.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
+namespace quic {
+namespace simulator {
+
+// Alarm is an implementation of QuicAlarm which can schedule alarms in the
+// simulation timeline.
+class Alarm : public QuicAlarm {
+ public:
+  Alarm(Simulator* simulator,
+        QuicString name,
+        QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+      : QuicAlarm(std::move(delegate)), adapter_(simulator, name, this) {}
+  ~Alarm() override {}
+
+  void SetImpl() override {
+    DCHECK(deadline().IsInitialized());
+    adapter_.Set(deadline());
+  }
+
+  void CancelImpl() override { adapter_.Cancel(); }
+
+ private:
+  // An adapter class triggering a QuicAlarm using a simulation time system.
+  // An adapter is required here because neither Actor nor QuicAlarm are pure
+  // interfaces.
+  class Adapter : public Actor {
+   public:
+    Adapter(Simulator* simulator, QuicString name, Alarm* parent)
+        : Actor(simulator, name), parent_(parent) {}
+    ~Adapter() override {}
+
+    void Set(QuicTime time) { Schedule(std::max(time, clock_->Now())); }
+    void Cancel() { Unschedule(); }
+
+    void Act() override {
+      DCHECK(clock_->Now() >= parent_->deadline());
+      parent_->Fire();
+    }
+
+   private:
+    Alarm* parent_;
+  };
+  Adapter adapter_;
+};
+
+AlarmFactory::AlarmFactory(Simulator* simulator, QuicString name)
+    : simulator_(simulator), name_(std::move(name)), counter_(0) {}
+
+AlarmFactory::~AlarmFactory() {}
+
+QuicString AlarmFactory::GetNewAlarmName() {
+  ++counter_;
+  return QuicStringPrintf("%s (alarm %i)", name_.c_str(), counter_);
+}
+
+QuicAlarm* AlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
+  return new Alarm(simulator_, GetNewAlarmName(),
+                   QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+}
+
+QuicArenaScopedPtr<QuicAlarm> AlarmFactory::CreateAlarm(
+    QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+    QuicConnectionArena* arena) {
+  if (arena != nullptr) {
+    return arena->New<Alarm>(simulator_, GetNewAlarmName(),
+                             std::move(delegate));
+  }
+  return QuicArenaScopedPtr<QuicAlarm>(
+      new Alarm(simulator_, GetNewAlarmName(), std::move(delegate)));
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/alarm_factory.h b/quic/test_tools/simulator/alarm_factory.h
new file mode 100644
index 0000000..535095a
--- /dev/null
+++ b/quic/test_tools/simulator/alarm_factory.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/actor.h"
+
+namespace quic {
+namespace simulator {
+
+// AlarmFactory allows to schedule QuicAlarms using the simulation event queue.
+class AlarmFactory : public QuicAlarmFactory {
+ public:
+  AlarmFactory(Simulator* simulator, QuicString name);
+  AlarmFactory(const AlarmFactory&) = delete;
+  AlarmFactory& operator=(const AlarmFactory&) = delete;
+  ~AlarmFactory() override;
+
+  QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
+  QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+      QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+      QuicConnectionArena* arena) override;
+
+ private:
+  // Automatically generate a name for a new alarm.
+  QuicString GetNewAlarmName();
+
+  Simulator* simulator_;
+  QuicString name_;
+  int counter_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
diff --git a/quic/test_tools/simulator/link.cc b/quic/test_tools/simulator/link.cc
new file mode 100644
index 0000000..879de26
--- /dev/null
+++ b/quic/test_tools/simulator/link.cc
@@ -0,0 +1,121 @@
+// 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/simulator/link.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+
+namespace quic {
+namespace simulator {
+
+// Parameters for random noise delay.
+const uint64_t kMaxRandomDelayUs = 10;
+
+OneWayLink::OneWayLink(Simulator* simulator,
+                       QuicString name,
+                       UnconstrainedPortInterface* sink,
+                       QuicBandwidth bandwidth,
+                       QuicTime::Delta propagation_delay)
+    : Actor(simulator, name),
+      sink_(sink),
+      bandwidth_(bandwidth),
+      propagation_delay_(propagation_delay),
+      next_write_at_(QuicTime::Zero()) {}
+
+OneWayLink::~OneWayLink() {}
+
+OneWayLink::QueuedPacket::QueuedPacket(std::unique_ptr<Packet> packet,
+                                       QuicTime dequeue_time)
+    : packet(std::move(packet)), dequeue_time(dequeue_time) {}
+
+OneWayLink::QueuedPacket::QueuedPacket(QueuedPacket&& other) = default;
+
+OneWayLink::QueuedPacket::~QueuedPacket() {}
+
+void OneWayLink::AcceptPacket(std::unique_ptr<Packet> packet) {
+  DCHECK(TimeUntilAvailable().IsZero());
+  QuicTime::Delta transfer_time = bandwidth_.TransferTime(packet->size);
+  next_write_at_ = clock_->Now() + transfer_time;
+
+  packets_in_transit_.emplace(
+      std::move(packet),
+      next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_time));
+  ScheduleNextPacketDeparture();
+}
+
+QuicTime::Delta OneWayLink::TimeUntilAvailable() {
+  const QuicTime now = clock_->Now();
+  if (next_write_at_ <= now) {
+    return QuicTime::Delta::Zero();
+  }
+
+  return next_write_at_ - now;
+}
+
+void OneWayLink::Act() {
+  DCHECK(!packets_in_transit_.empty());
+  DCHECK(packets_in_transit_.front().dequeue_time >= clock_->Now());
+
+  sink_->AcceptPacket(std::move(packets_in_transit_.front().packet));
+  packets_in_transit_.pop();
+
+  ScheduleNextPacketDeparture();
+}
+
+void OneWayLink::ScheduleNextPacketDeparture() {
+  if (packets_in_transit_.empty()) {
+    return;
+  }
+
+  Schedule(packets_in_transit_.front().dequeue_time);
+}
+
+QuicTime::Delta OneWayLink::GetRandomDelay(QuicTime::Delta transfer_time) {
+  if (!simulator_->enable_random_delays()) {
+    return QuicTime::Delta::Zero();
+  }
+
+  QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(
+      simulator_->GetRandomGenerator()->RandUint64() % (kMaxRandomDelayUs + 1));
+  // Have an upper bound on the delay to ensure packets do not go out of order.
+  delta = std::min(delta, transfer_time * 0.5);
+  return delta;
+}
+
+SymmetricLink::SymmetricLink(Simulator* simulator,
+                             QuicString name,
+                             UnconstrainedPortInterface* sink_a,
+                             UnconstrainedPortInterface* sink_b,
+                             QuicBandwidth bandwidth,
+                             QuicTime::Delta propagation_delay)
+    : a_to_b_link_(simulator,
+                   QuicStringPrintf("%s (A-to-B)", name.c_str()),
+                   sink_b,
+                   bandwidth,
+                   propagation_delay),
+      b_to_a_link_(simulator,
+                   QuicStringPrintf("%s (B-to-A)", name.c_str()),
+                   sink_a,
+                   bandwidth,
+                   propagation_delay) {}
+
+SymmetricLink::SymmetricLink(Endpoint* endpoint_a,
+                             Endpoint* endpoint_b,
+                             QuicBandwidth bandwidth,
+                             QuicTime::Delta propagation_delay)
+    : SymmetricLink(endpoint_a->simulator(),
+                    QuicStringPrintf("Link [%s]<->[%s]",
+                                     endpoint_a->name().c_str(),
+                                     endpoint_b->name().c_str()),
+                    endpoint_a->GetRxPort(),
+                    endpoint_b->GetRxPort(),
+                    bandwidth,
+                    propagation_delay) {
+  endpoint_a->SetTxPort(&a_to_b_link_);
+  endpoint_b->SetTxPort(&b_to_a_link_);
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/link.h b/quic/test_tools/simulator/link.h
new file mode 100644
index 0000000..4553324
--- /dev/null
+++ b/quic/test_tools/simulator/link.h
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
+
+#include <utility>
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/actor.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h"
+
+namespace quic {
+namespace simulator {
+
+// A reliable simplex link between two endpoints with constrained bandwidth.  A
+// few microseconds of random delay are added for every packet to avoid
+// synchronization issues.
+class OneWayLink : public Actor, public ConstrainedPortInterface {
+ public:
+  OneWayLink(Simulator* simulator,
+             QuicString name,
+             UnconstrainedPortInterface* sink,
+             QuicBandwidth bandwidth,
+             QuicTime::Delta propagation_delay);
+  OneWayLink(const OneWayLink&) = delete;
+  OneWayLink& operator=(const OneWayLink&) = delete;
+  ~OneWayLink() override;
+
+  void AcceptPacket(std::unique_ptr<Packet> packet) override;
+  QuicTime::Delta TimeUntilAvailable() override;
+  void Act() override;
+
+  inline QuicBandwidth bandwidth() const { return bandwidth_; }
+
+ private:
+  struct QueuedPacket {
+    std::unique_ptr<Packet> packet;
+    QuicTime dequeue_time;
+
+    QueuedPacket(std::unique_ptr<Packet> packet, QuicTime dequeue_time);
+    QueuedPacket(QueuedPacket&& other);
+    ~QueuedPacket();
+  };
+
+  // Schedule the next packet to be egressed out of the link if there are
+  // packets on the link.
+  void ScheduleNextPacketDeparture();
+
+  // Get the value of a random delay imposed on each packet in order to avoid
+  // artifical synchronization artifacts during the simulation.
+  QuicTime::Delta GetRandomDelay(QuicTime::Delta transfer_time);
+
+  UnconstrainedPortInterface* sink_;
+  QuicQueue<QueuedPacket> packets_in_transit_;
+
+  const QuicBandwidth bandwidth_;
+  const QuicTime::Delta propagation_delay_;
+
+  QuicTime next_write_at_;
+};
+
+// A full-duplex link between two endpoints, functionally equivalent to two
+// OneWayLink objects tied together.
+class SymmetricLink {
+ public:
+  SymmetricLink(Simulator* simulator,
+                QuicString name,
+                UnconstrainedPortInterface* sink_a,
+                UnconstrainedPortInterface* sink_b,
+                QuicBandwidth bandwidth,
+                QuicTime::Delta propagation_delay);
+  SymmetricLink(Endpoint* endpoint_a,
+                Endpoint* endpoint_b,
+                QuicBandwidth bandwidth,
+                QuicTime::Delta propagation_delay);
+  SymmetricLink(const SymmetricLink&) = delete;
+  SymmetricLink& operator=(const SymmetricLink&) = delete;
+
+  inline QuicBandwidth bandwidth() { return a_to_b_link_.bandwidth(); }
+
+ private:
+  OneWayLink a_to_b_link_;
+  OneWayLink b_to_a_link_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
diff --git a/quic/test_tools/simulator/packet_filter.cc b/quic/test_tools/simulator/packet_filter.cc
new file mode 100644
index 0000000..8ee038a
--- /dev/null
+++ b/quic/test_tools/simulator/packet_filter.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2016 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/simulator/packet_filter.h"
+
+namespace quic {
+namespace simulator {
+
+PacketFilter::PacketFilter(Simulator* simulator,
+                           QuicString name,
+                           Endpoint* input)
+    : Endpoint(simulator, name), input_(input) {
+  input_->SetTxPort(this);
+}
+
+PacketFilter::~PacketFilter() {}
+
+void PacketFilter::AcceptPacket(std::unique_ptr<Packet> packet) {
+  if (FilterPacket(*packet)) {
+    output_tx_port_->AcceptPacket(std::move(packet));
+  }
+}
+
+QuicTime::Delta PacketFilter::TimeUntilAvailable() {
+  return output_tx_port_->TimeUntilAvailable();
+}
+
+void PacketFilter::Act() {}
+
+UnconstrainedPortInterface* PacketFilter::GetRxPort() {
+  return input_->GetRxPort();
+}
+
+void PacketFilter::SetTxPort(ConstrainedPortInterface* port) {
+  output_tx_port_ = port;
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/packet_filter.h b/quic/test_tools/simulator/packet_filter.h
new file mode 100644
index 0000000..e79b2cb
--- /dev/null
+++ b/quic/test_tools/simulator/packet_filter.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_PACKET_FILTER_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_PACKET_FILTER_H_
+
+#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h"
+
+namespace quic {
+namespace simulator {
+
+// Packet filter allows subclasses to filter out the packets that enter the
+// input port and exit the output port.  Packets in the other direction are
+// always passed through.
+//
+// The filter wraps around the input endpoint, and exposes the resulting
+// filtered endpoint via the output() method.  For example, if initially there
+// are two endpoints, A and B, connected via a symmetric link:
+//
+//   QuicEndpoint endpoint_a;
+//   QuicEndpoint endpoint_b;
+//
+//   [...]
+//
+//   SymmetricLink a_b_link(&endpoint_a, &endpoint_b, ...);
+//
+// and the goal is to filter the traffic from A to B, then the new invocation
+// would be as follows:
+//
+//   PacketFilter filter(&simulator, "A-to-B packet filter", endpoint_a);
+//   SymmetricLink a_b_link(&filter, &endpoint_b, ...);
+//
+// Note that the filter drops the packet instanteneously, without it ever
+// reaching the output wire.  This means that in a direct endpoint-to-endpoint
+// scenario, whenever the packet is dropped, the link would become immediately
+// available for the next packet.
+class PacketFilter : public Endpoint, public ConstrainedPortInterface {
+ public:
+  // Initialize the filter by wrapping around |input|.  Does not take the
+  // ownership of |input|.
+  PacketFilter(Simulator* simulator, QuicString name, Endpoint* input);
+  PacketFilter(const PacketFilter&) = delete;
+  PacketFilter& operator=(const PacketFilter&) = delete;
+  ~PacketFilter() override;
+
+  // Implementation of ConstrainedPortInterface.
+  void AcceptPacket(std::unique_ptr<Packet> packet) override;
+  QuicTime::Delta TimeUntilAvailable() override;
+
+  // Implementation of Endpoint interface methods.
+  UnconstrainedPortInterface* GetRxPort() override;
+  void SetTxPort(ConstrainedPortInterface* port) override;
+
+  // Implementation of Actor interface methods.
+  void Act() override;
+
+ protected:
+  // Returns true if the packet should be passed through, and false if it should
+  // be dropped.  The function is called once per packet, in the order that the
+  // packets arrive, so it is safe for the function to alter the internal state
+  // of the filter.
+  virtual bool FilterPacket(const Packet& packet) = 0;
+
+ private:
+  // The port onto which the filtered packets are egressed.
+  ConstrainedPortInterface* output_tx_port_;
+
+  // The original network endpoint wrapped by the class.
+  Endpoint* input_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_PACKET_FILTER_H_
diff --git a/quic/test_tools/simulator/port.cc b/quic/test_tools/simulator/port.cc
new file mode 100644
index 0000000..3db8888
--- /dev/null
+++ b/quic/test_tools/simulator/port.cc
@@ -0,0 +1,21 @@
+// 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/simulator/port.h"
+
+namespace quic {
+namespace simulator {
+
+Packet::Packet()
+    : source(), destination(), tx_timestamp(QuicTime::Zero()), size(0) {}
+
+Packet::~Packet() {}
+
+Packet::Packet(const Packet& packet) = default;
+
+Endpoint::Endpoint(Simulator* simulator, QuicString name)
+    : Actor(simulator, name) {}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/port.h b/quic/test_tools/simulator/port.h
new file mode 100644
index 0000000..5cd4a7f
--- /dev/null
+++ b/quic/test_tools/simulator/port.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
+
+#include <string>
+#include <utility>
+
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/actor.h"
+
+namespace quic {
+namespace simulator {
+
+struct Packet {
+  Packet();
+  ~Packet();
+  Packet(const Packet& packet);
+
+  QuicString source;
+  QuicString destination;
+  QuicTime tx_timestamp;
+
+  QuicString contents;
+  QuicByteCount size;
+};
+
+// An interface for anything that accepts packets at arbitrary rate.
+class UnconstrainedPortInterface {
+ public:
+  virtual ~UnconstrainedPortInterface() {}
+  virtual void AcceptPacket(std::unique_ptr<Packet> packet) = 0;
+};
+
+// An interface for any device that accepts packets at a specific rate.
+// Typically one would use a Queue object in order to write into a constrained
+// port.
+class ConstrainedPortInterface {
+ public:
+  virtual ~ConstrainedPortInterface() {}
+
+  // Accept a packet for a port.  TimeUntilAvailable() must be zero before this
+  // method is called.
+  virtual void AcceptPacket(std::unique_ptr<Packet> packet) = 0;
+
+  // Time until write for the next port is available.  Cannot be infinite.
+  virtual QuicTime::Delta TimeUntilAvailable() = 0;
+};
+
+// A convenience class for any network endpoints, i.e. the objects which can
+// both accept and send packets.
+class Endpoint : public Actor {
+ public:
+  virtual UnconstrainedPortInterface* GetRxPort() = 0;
+  virtual void SetTxPort(ConstrainedPortInterface* port) = 0;
+
+ protected:
+  Endpoint(Simulator* simulator, QuicString name);
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
diff --git a/quic/test_tools/simulator/queue.cc b/quic/test_tools/simulator/queue.cc
new file mode 100644
index 0000000..4236481
--- /dev/null
+++ b/quic/test_tools/simulator/queue.cc
@@ -0,0 +1,123 @@
+// 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/simulator/queue.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+
+namespace quic {
+namespace simulator {
+
+Queue::ListenerInterface::~ListenerInterface() {}
+
+Queue::Queue(Simulator* simulator, QuicString name, QuicByteCount capacity)
+    : Actor(simulator, name),
+      capacity_(capacity),
+      bytes_queued_(0),
+      aggregation_threshold_(0),
+      aggregation_timeout_(QuicTime::Delta::Infinite()),
+      current_bundle_(0),
+      current_bundle_bytes_(0),
+      listener_(nullptr) {
+  aggregation_timeout_alarm_.reset(simulator_->GetAlarmFactory()->CreateAlarm(
+      new AggregationAlarmDelegate(this)));
+}
+
+Queue::~Queue() {}
+
+void Queue::set_tx_port(ConstrainedPortInterface* port) {
+  tx_port_ = port;
+}
+
+void Queue::AcceptPacket(std::unique_ptr<Packet> packet) {
+  if (packet->size + bytes_queued_ > capacity_) {
+    QUIC_DVLOG(1) << "Queue [" << name() << "] has received a packet from ["
+                  << packet->source << "] to [" << packet->destination
+                  << "] which is over capacity.  Dropping it.";
+    QUIC_DVLOG(1) << "Queue size: " << bytes_queued_ << " out of " << capacity_
+                  << ".  Packet size: " << packet->size;
+    return;
+  }
+
+  bytes_queued_ += packet->size;
+  queue_.emplace(std::move(packet), current_bundle_);
+
+  if (IsAggregationEnabled()) {
+    current_bundle_bytes_ += queue_.front().packet->size;
+    if (!aggregation_timeout_alarm_->IsSet()) {
+      aggregation_timeout_alarm_->Set(clock_->Now() + aggregation_timeout_);
+    }
+    if (current_bundle_bytes_ >= aggregation_threshold_) {
+      NextBundle();
+    }
+  }
+
+  ScheduleNextPacketDequeue();
+}
+
+void Queue::Act() {
+  DCHECK(!queue_.empty());
+  if (tx_port_->TimeUntilAvailable().IsZero()) {
+    DCHECK(bytes_queued_ >= queue_.front().packet->size);
+    bytes_queued_ -= queue_.front().packet->size;
+
+    tx_port_->AcceptPacket(std::move(queue_.front().packet));
+    queue_.pop();
+    if (listener_ != nullptr) {
+      listener_->OnPacketDequeued();
+    }
+  }
+
+  ScheduleNextPacketDequeue();
+}
+
+void Queue::EnableAggregation(QuicByteCount aggregation_threshold,
+                              QuicTime::Delta aggregation_timeout) {
+  DCHECK_EQ(bytes_queued_, 0u);
+  DCHECK_GT(aggregation_threshold, 0u);
+  DCHECK(!aggregation_timeout.IsZero());
+  DCHECK(!aggregation_timeout.IsInfinite());
+
+  aggregation_threshold_ = aggregation_threshold;
+  aggregation_timeout_ = aggregation_timeout;
+}
+
+Queue::AggregationAlarmDelegate::AggregationAlarmDelegate(Queue* queue)
+    : queue_(queue) {}
+
+void Queue::AggregationAlarmDelegate::OnAlarm() {
+  queue_->NextBundle();
+  queue_->ScheduleNextPacketDequeue();
+}
+
+Queue::EnqueuedPacket::EnqueuedPacket(std::unique_ptr<Packet> packet,
+                                      AggregationBundleNumber bundle)
+    : packet(std::move(packet)), bundle(bundle) {}
+
+Queue::EnqueuedPacket::EnqueuedPacket(EnqueuedPacket&& other) = default;
+
+Queue::EnqueuedPacket::~EnqueuedPacket() = default;
+
+void Queue::NextBundle() {
+  current_bundle_++;
+  current_bundle_bytes_ = 0;
+  aggregation_timeout_alarm_->Cancel();
+}
+
+void Queue::ScheduleNextPacketDequeue() {
+  if (queue_.empty()) {
+    DCHECK_EQ(bytes_queued_, 0u);
+    return;
+  }
+
+  if (IsAggregationEnabled() && queue_.front().bundle == current_bundle_) {
+    return;
+  }
+
+  Schedule(clock_->Now() + tx_port_->TimeUntilAvailable());
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/queue.h b/quic/test_tools/simulator/queue.h
new file mode 100644
index 0000000..f9fa483
--- /dev/null
+++ b/quic/test_tools/simulator/queue.h
@@ -0,0 +1,120 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
+
+namespace quic {
+namespace simulator {
+
+// A finitely sized queue which egresses packets onto a constrained link.  The
+// capacity of the queue is measured in bytes as opposed to packets.
+class Queue : public Actor, public UnconstrainedPortInterface {
+ public:
+  class ListenerInterface {
+   public:
+    virtual ~ListenerInterface();
+
+    // Called whenever a packet is removed from the queue.
+    virtual void OnPacketDequeued() = 0;
+  };
+
+  Queue(Simulator* simulator, QuicString name, QuicByteCount capacity);
+  Queue(const Queue&) = delete;
+  Queue& operator=(const Queue&) = delete;
+  ~Queue() override;
+
+  void set_tx_port(ConstrainedPortInterface* port);
+
+  void AcceptPacket(std::unique_ptr<Packet> packet) override;
+
+  void Act() override;
+
+  inline QuicByteCount capacity() const { return capacity_; }
+  inline QuicByteCount bytes_queued() const { return bytes_queued_; }
+  inline QuicPacketCount packets_queued() const { return queue_.size(); }
+
+  inline void set_listener_interface(ListenerInterface* listener) {
+    listener_ = listener;
+  }
+
+  // Enables packet aggregation on the queue.  Packet aggregation makes the
+  // queue bundle packets up until they reach certain size.  When the
+  // aggregation is enabled, the packets are not dequeued until the total size
+  // of packets in the queue reaches |aggregation_threshold|.  The packets are
+  // automatically flushed from the queue if the oldest packet has been in it
+  // for |aggregation_timeout|.
+  //
+  // This method may only be called when the queue is empty.  Once enabled,
+  // aggregation cannot be disabled.
+  void EnableAggregation(QuicByteCount aggregation_threshold,
+                         QuicTime::Delta aggregation_timeout);
+
+ private:
+  typedef uint64_t AggregationBundleNumber;
+
+  // In order to implement packet aggregation, each packet is tagged with a
+  // bundle number.  The queue keeps a bundle counter, and whenever a bundle is
+  // ready, it increments the number of the current bundle.  Only the packets
+  // outside of the current bundle are allowed to leave the queue.
+  struct EnqueuedPacket {
+    EnqueuedPacket(std::unique_ptr<Packet> packet,
+                   AggregationBundleNumber bundle);
+    EnqueuedPacket(EnqueuedPacket&& other);
+    ~EnqueuedPacket();
+
+    std::unique_ptr<Packet> packet;
+    AggregationBundleNumber bundle;
+  };
+
+  // Alarm handler for aggregation timeout.
+  class AggregationAlarmDelegate : public QuicAlarm::Delegate {
+   public:
+    explicit AggregationAlarmDelegate(Queue* queue);
+
+    void OnAlarm() override;
+
+   private:
+    Queue* queue_;
+  };
+
+  inline bool IsAggregationEnabled() const {
+    return aggregation_threshold_ > 0;
+  }
+
+  // Increment the bundle counter and reset the bundle state.  This causes all
+  // packets currently in the bundle to be flushed onto the link.
+  void NextBundle();
+
+  void ScheduleNextPacketDequeue();
+
+  const QuicByteCount capacity_;
+  QuicByteCount bytes_queued_;
+
+  QuicByteCount aggregation_threshold_;
+  QuicTime::Delta aggregation_timeout_;
+  // The number of the current aggregation bundle.  Monotonically increasing.
+  // All packets in the previous bundles are allowed to leave the queue, and
+  // none of the packets in the current one are.
+  AggregationBundleNumber current_bundle_;
+  // Size of the current bundle.  Whenever it exceeds |aggregation_threshold_|,
+  // the next bundle is created.
+  QuicByteCount current_bundle_bytes_;
+  // Alarm responsible for flushing the current bundle upon timeout.  Set when
+  // the first packet in the bundle is enqueued.
+  std::unique_ptr<QuicAlarm> aggregation_timeout_alarm_;
+
+  ConstrainedPortInterface* tx_port_;
+  QuicQueue<EnqueuedPacket> queue_;
+
+  ListenerInterface* listener_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc
new file mode 100644
index 0000000..1bacdf2
--- /dev/null
+++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -0,0 +1,415 @@
+// 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/simulator/quic_endpoint.h"
+
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test_output.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+
+namespace quic {
+namespace simulator {
+
+const QuicStreamId kDataStream = 3;
+const QuicByteCount kWriteChunkSize = 128 * 1024;
+const char kStreamDataContents = 'Q';
+
+// Takes a SHA-1 hash of the name and converts it into five 32-bit integers.
+static std::vector<uint32_t> HashNameIntoFive32BitIntegers(QuicString name) {
+  const QuicString hash = test::Sha1Hash(name);
+
+  std::vector<uint32_t> output;
+  uint32_t current_number = 0;
+  for (size_t i = 0; i < hash.size(); i++) {
+    current_number = (current_number << 8) + hash[i];
+    if (i % 4 == 3) {
+      output.push_back(i);
+      current_number = 0;
+    }
+  }
+
+  return output;
+}
+
+QuicSocketAddress GetAddressFromName(QuicString name) {
+  const std::vector<uint32_t> hash = HashNameIntoFive32BitIntegers(name);
+
+  // Generate a random port between 1025 and 65535.
+  const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1);
+
+  // Generate a random 10.x.x.x address, where x is between 1 and 254.
+  QuicString ip_address{"\xa\0\0\0", 4};
+  for (size_t i = 1; i < 4; i++) {
+    ip_address[i] = 1 + hash[i] % 254;
+  }
+  QuicIpAddress host;
+  host.FromPackedString(ip_address.c_str(), ip_address.length());
+  return QuicSocketAddress(host, port);
+}
+
+QuicEndpoint::QuicEndpoint(Simulator* simulator,
+                           QuicString name,
+                           QuicString peer_name,
+                           Perspective perspective,
+                           QuicConnectionId connection_id)
+    : Endpoint(simulator, name),
+      peer_name_(peer_name),
+      writer_(this),
+      nic_tx_queue_(simulator,
+                    QuicStringPrintf("%s (TX Queue)", name.c_str()),
+                    kMaxPacketSize * kTxQueueSize),
+      connection_(connection_id,
+                  GetAddressFromName(peer_name),
+                  simulator,
+                  simulator->GetAlarmFactory(),
+                  &writer_,
+                  false,
+                  perspective,
+                  ParsedVersionOfIndex(CurrentSupportedVersions(), 0)),
+      bytes_to_transfer_(0),
+      bytes_transferred_(0),
+      write_blocked_count_(0),
+      wrong_data_received_(false),
+      drop_next_packet_(false),
+      notifier_(nullptr) {
+  nic_tx_queue_.set_listener_interface(this);
+
+  connection_.SetSelfAddress(GetAddressFromName(name));
+  connection_.set_visitor(this);
+  connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+                           QuicMakeUnique<NullEncrypter>(perspective));
+  connection_.SetDecrypter(ENCRYPTION_FORWARD_SECURE,
+                           QuicMakeUnique<NullDecrypter>(perspective));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  if (perspective == Perspective::IS_SERVER) {
+    // Skip version negotiation.
+    test::QuicConnectionPeer::SetNegotiatedVersion(&connection_);
+  }
+  connection_.SetDataProducer(&producer_);
+  connection_.SetSessionNotifier(this);
+  if (connection_.session_decides_what_to_write()) {
+    notifier_ = QuicMakeUnique<test::SimpleSessionNotifier>(&connection_);
+  }
+
+  // Configure the connection as if it received a handshake.  This is important
+  // primarily because
+  //  - this enables pacing, and
+  //  - this sets the non-handshake timeouts.
+  QuicString error;
+  CryptoHandshakeMessage peer_hello;
+  peer_hello.SetValue(kICSL,
+                      static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1));
+  peer_hello.SetValue(kMIDS,
+                      static_cast<uint32_t>(kDefaultMaxStreamsPerConnection));
+  QuicConfig config;
+  QuicErrorCode error_code = config.ProcessPeerHello(
+      peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT,
+      &error);
+  DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error;
+  connection_.SetFromConfig(config);
+}
+
+QuicEndpoint::~QuicEndpoint() {
+  if (trace_visitor_ != nullptr) {
+    const char* perspective_prefix =
+        connection_.perspective() == Perspective::IS_CLIENT ? "C" : "S";
+
+    QuicString identifier =
+        QuicStrCat(perspective_prefix, connection_.connection_id().ToString());
+    QuicRecordTestOutput(identifier,
+                         trace_visitor_->trace()->SerializeAsString());
+  }
+}
+
+QuicByteCount QuicEndpoint::bytes_received() const {
+  QuicByteCount total = 0;
+  for (auto& interval : offsets_received_) {
+    total += interval.max() - interval.min();
+  }
+  return total;
+}
+
+QuicByteCount QuicEndpoint::bytes_to_transfer() const {
+  if (notifier_ != nullptr) {
+    return notifier_->StreamBytesToSend();
+  }
+  return bytes_to_transfer_;
+}
+
+QuicByteCount QuicEndpoint::bytes_transferred() const {
+  if (notifier_ != nullptr) {
+    return notifier_->StreamBytesSent();
+  }
+  return bytes_transferred_;
+}
+
+void QuicEndpoint::AddBytesToTransfer(QuicByteCount bytes) {
+  if (notifier_ != nullptr) {
+    if (notifier_->HasBufferedStreamData()) {
+      Schedule(clock_->Now());
+    }
+    notifier_->WriteOrBufferData(kDataStream, bytes, NO_FIN);
+    return;
+  }
+
+  if (bytes_to_transfer_ > 0) {
+    Schedule(clock_->Now());
+  }
+
+  bytes_to_transfer_ += bytes;
+  WriteStreamData();
+}
+
+void QuicEndpoint::DropNextIncomingPacket() {
+  drop_next_packet_ = true;
+}
+
+void QuicEndpoint::RecordTrace() {
+  trace_visitor_ = QuicMakeUnique<QuicTraceVisitor>(&connection_);
+  connection_.set_debug_visitor(trace_visitor_.get());
+}
+
+void QuicEndpoint::AcceptPacket(std::unique_ptr<Packet> packet) {
+  if (packet->destination != name_) {
+    return;
+  }
+  if (drop_next_packet_) {
+    drop_next_packet_ = false;
+    return;
+  }
+
+  QuicReceivedPacket received_packet(packet->contents.data(),
+                                     packet->contents.size(), clock_->Now());
+  connection_.ProcessUdpPacket(connection_.self_address(),
+                               connection_.peer_address(), received_packet);
+}
+
+UnconstrainedPortInterface* QuicEndpoint::GetRxPort() {
+  return this;
+}
+
+void QuicEndpoint::SetTxPort(ConstrainedPortInterface* port) {
+  // Any egress done by the endpoint is actually handled by a queue on an NIC.
+  nic_tx_queue_.set_tx_port(port);
+}
+
+void QuicEndpoint::OnPacketDequeued() {
+  if (writer_.IsWriteBlocked() &&
+      (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >=
+          kMaxPacketSize) {
+    writer_.SetWritable();
+    connection_.OnCanWrite();
+  }
+}
+
+void QuicEndpoint::OnStreamFrame(const QuicStreamFrame& frame) {
+  // Verify that the data received always matches the expected.
+  DCHECK(frame.stream_id == kDataStream);
+  for (size_t i = 0; i < frame.data_length; i++) {
+    if (frame.data_buffer[i] != kStreamDataContents) {
+      wrong_data_received_ = true;
+    }
+  }
+  offsets_received_.Add(frame.offset, frame.offset + frame.data_length);
+  // Sanity check against very pathological connections.
+  DCHECK_LE(offsets_received_.Size(), 1000u);
+}
+
+void QuicEndpoint::OnCryptoFrame(const QuicCryptoFrame& frame) {}
+
+void QuicEndpoint::OnCanWrite() {
+  if (notifier_ != nullptr) {
+    notifier_->OnCanWrite();
+    return;
+  }
+  WriteStreamData();
+}
+bool QuicEndpoint::WillingAndAbleToWrite() const {
+  if (notifier_ != nullptr) {
+    return notifier_->WillingToWrite();
+  }
+  return bytes_to_transfer_ != 0;
+}
+bool QuicEndpoint::HasPendingHandshake() const {
+  return false;
+}
+bool QuicEndpoint::ShouldKeepConnectionAlive() const {
+  return true;
+}
+
+bool QuicEndpoint::AllowSelfAddressChange() const {
+  return false;
+}
+
+bool QuicEndpoint::OnFrameAcked(const QuicFrame& frame,
+                                QuicTime::Delta ack_delay_time) {
+  if (notifier_ != nullptr) {
+    return notifier_->OnFrameAcked(frame, ack_delay_time);
+  }
+  return false;
+}
+
+void QuicEndpoint::OnFrameLost(const QuicFrame& frame) {
+  DCHECK(notifier_);
+  notifier_->OnFrameLost(frame);
+}
+
+void QuicEndpoint::RetransmitFrames(const QuicFrames& frames,
+                                    TransmissionType type) {
+  DCHECK(notifier_);
+  notifier_->RetransmitFrames(frames, type);
+}
+
+bool QuicEndpoint::IsFrameOutstanding(const QuicFrame& frame) const {
+  DCHECK(notifier_);
+  return notifier_->IsFrameOutstanding(frame);
+}
+
+bool QuicEndpoint::HasUnackedCryptoData() const {
+  return false;
+}
+
+QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
+    : endpoint_(endpoint), is_blocked_(false) {}
+
+QuicEndpoint::Writer::~Writer() {}
+
+WriteResult QuicEndpoint::Writer::WritePacket(
+    const char* buffer,
+    size_t buf_len,
+    const QuicIpAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    PerPacketOptions* options) {
+  DCHECK(!IsWriteBlocked());
+  DCHECK(options == nullptr);
+  DCHECK(buf_len <= kMaxPacketSize);
+
+  // Instead of losing a packet, become write-blocked when the egress queue is
+  // full.
+  if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
+    is_blocked_ = true;
+    endpoint_->write_blocked_count_++;
+    return WriteResult(WRITE_STATUS_BLOCKED, 0);
+  }
+
+  auto packet = QuicMakeUnique<Packet>();
+  packet->source = endpoint_->name();
+  packet->destination = endpoint_->peer_name_;
+  packet->tx_timestamp = endpoint_->clock_->Now();
+
+  packet->contents = QuicString(buffer, buf_len);
+  packet->size = buf_len;
+
+  endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet));
+
+  return WriteResult(WRITE_STATUS_OK, buf_len);
+}
+
+bool QuicEndpoint::Writer::IsWriteBlocked() const {
+  return is_blocked_;
+}
+
+void QuicEndpoint::Writer::SetWritable() {
+  is_blocked_ = false;
+}
+
+QuicByteCount QuicEndpoint::Writer::GetMaxPacketSize(
+    const QuicSocketAddress& /*peer_address*/) const {
+  return kMaxPacketSize;
+}
+
+bool QuicEndpoint::Writer::SupportsReleaseTime() const {
+  return false;
+}
+
+bool QuicEndpoint::Writer::IsBatchMode() const {
+  return false;
+}
+
+char* QuicEndpoint::Writer::GetNextWriteLocation(
+    const QuicIpAddress& self_address,
+    const QuicSocketAddress& peer_address) {
+  return nullptr;
+}
+
+WriteResult QuicEndpoint::Writer::Flush() {
+  return WriteResult(WRITE_STATUS_OK, 0);
+}
+
+WriteStreamDataResult QuicEndpoint::DataProducer::WriteStreamData(
+    QuicStreamId id,
+    QuicStreamOffset offset,
+    QuicByteCount data_length,
+    QuicDataWriter* writer) {
+  writer->WriteRepeatedByte(kStreamDataContents, data_length);
+  return WRITE_SUCCESS;
+}
+
+bool QuicEndpoint::DataProducer::WriteCryptoData(EncryptionLevel leve,
+                                                 QuicStreamOffset offset,
+                                                 QuicByteCount data_length,
+                                                 QuicDataWriter* writer) {
+  QUIC_BUG << "QuicEndpoint::DataProducer::WriteCryptoData is unimplemented";
+  return false;
+}
+
+void QuicEndpoint::WriteStreamData() {
+  // Instantiate a flusher which would normally be here due to QuicSession.
+  QuicConnection::ScopedPacketFlusher flusher(
+      &connection_, QuicConnection::SEND_ACK_IF_QUEUED);
+
+  while (bytes_to_transfer_ > 0) {
+    // Transfer data in chunks of size at most |kWriteChunkSize|.
+    const size_t transmission_size =
+        std::min(kWriteChunkSize, bytes_to_transfer_);
+
+    QuicConsumedData consumed_data = connection_.SendStreamData(
+        kDataStream, transmission_size, bytes_transferred_, NO_FIN);
+
+    DCHECK(consumed_data.bytes_consumed <= transmission_size);
+    bytes_transferred_ += consumed_data.bytes_consumed;
+    bytes_to_transfer_ -= consumed_data.bytes_consumed;
+    if (consumed_data.bytes_consumed != transmission_size) {
+      return;
+    }
+  }
+}
+
+QuicEndpointMultiplexer::QuicEndpointMultiplexer(
+    QuicString name,
+    std::initializer_list<QuicEndpoint*> endpoints)
+    : Endpoint((*endpoints.begin())->simulator(), name) {
+  for (QuicEndpoint* endpoint : endpoints) {
+    mapping_.insert(std::make_pair(endpoint->name(), endpoint));
+  }
+}
+
+QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {}
+
+void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr<Packet> packet) {
+  auto key_value_pair_it = mapping_.find(packet->destination);
+  if (key_value_pair_it == mapping_.end()) {
+    return;
+  }
+
+  key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet));
+}
+UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() {
+  return this;
+}
+void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) {
+  for (auto& key_value_pair : mapping_) {
+    key_value_pair.second->SetTxPort(port);
+  }
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
new file mode 100644
index 0000000..ab4ee4b
--- /dev/null
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -0,0 +1,234 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_default_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_stream_frame_data_producer.h"
+#include "net/third_party/quiche/src/quic/core/quic_trace_visitor.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h"
+
+namespace quic {
+namespace simulator {
+
+// Size of the TX queue used by the kernel/NIC.  1000 is the Linux
+// kernel default.
+const QuicByteCount kTxQueueSize = 1000;
+
+// Generate a random local network host-port tuple based on the name of the
+// endpoint.
+QuicSocketAddress GetAddressFromName(QuicString name);
+
+// A QUIC connection endpoint.  Wraps around QuicConnection.  In order to
+// initiate a transfer, the caller has to call AddBytesToTransfer().  The data
+// transferred is always the same and is always transferred on a single stream.
+// The endpoint receives all packets addressed to it, and verifies that the data
+// received is what it's supposed to be.
+class QuicEndpoint : public Endpoint,
+                     public UnconstrainedPortInterface,
+                     public Queue::ListenerInterface,
+                     public QuicConnectionVisitorInterface,
+                     public SessionNotifierInterface {
+ public:
+  QuicEndpoint(Simulator* simulator,
+               QuicString name,
+               QuicString peer_name,
+               Perspective perspective,
+               QuicConnectionId connection_id);
+  ~QuicEndpoint() override;
+
+  inline QuicConnection* connection() { return &connection_; }
+  QuicByteCount bytes_to_transfer() const;
+  QuicByteCount bytes_transferred() const;
+  QuicByteCount bytes_received() const;
+  inline size_t write_blocked_count() { return write_blocked_count_; }
+  inline bool wrong_data_received() const { return wrong_data_received_; }
+
+  // Send |bytes| bytes.  Initiates the transfer if one is not already in
+  // progress.
+  void AddBytesToTransfer(QuicByteCount bytes);
+
+  // Drop the next packet upon receipt.
+  void DropNextIncomingPacket();
+
+  // UnconstrainedPortInterface method.  Called whenever the endpoint receives a
+  // packet.
+  void AcceptPacket(std::unique_ptr<Packet> packet) override;
+
+  // Enables logging of the connection trace at the end of the unit test.
+  void RecordTrace();
+
+  // Begin Endpoint implementation.
+  UnconstrainedPortInterface* GetRxPort() override;
+  void SetTxPort(ConstrainedPortInterface* port) override;
+  // End Endpoint implementation.
+
+  // Actor method.
+  void Act() override {}
+
+  // Queue::ListenerInterface method.
+  void OnPacketDequeued() override;
+
+  // Begin QuicConnectionVisitorInterface implementation.
+  void OnStreamFrame(const QuicStreamFrame& frame) override;
+  void OnCryptoFrame(const QuicCryptoFrame& frame) override;
+  void OnCanWrite() override;
+  bool WillingAndAbleToWrite() const override;
+  bool HasPendingHandshake() const override;
+  bool ShouldKeepConnectionAlive() const override;
+
+  void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {}
+  void OnBlockedFrame(const QuicBlockedFrame& frame) override {}
+  void OnRstStream(const QuicRstStreamFrame& frame) override {}
+  void OnGoAway(const QuicGoAwayFrame& frame) override {}
+  void OnMessageReceived(QuicStringPiece message) override {}
+  void OnConnectionClosed(QuicErrorCode error,
+                          const QuicString& error_details,
+                          ConnectionCloseSource source) override {}
+  void OnWriteBlocked() override {}
+  void OnSuccessfulVersionNegotiation(
+      const ParsedQuicVersion& version) override {}
+  void OnConnectivityProbeReceived(
+      const QuicSocketAddress& self_address,
+      const QuicSocketAddress& peer_address) override {}
+  void OnCongestionWindowChange(QuicTime now) override {}
+  void OnConnectionMigration(AddressChangeType type) override {}
+  void OnPathDegrading() override {}
+  void OnAckNeedsRetransmittableFrame() override {}
+  void SendPing() override {}
+  bool AllowSelfAddressChange() const override;
+  void OnForwardProgressConfirmed() override {}
+  bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override {
+    return true;
+  }
+  bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override {
+    return true;
+  }
+  bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override {
+    return true;
+  }
+
+  // End QuicConnectionVisitorInterface implementation.
+
+  // Begin SessionNotifierInterface methods:
+  bool OnFrameAcked(const QuicFrame& frame,
+                    QuicTime::Delta ack_delay_time) override;
+  void OnStreamFrameRetransmitted(const QuicStreamFrame& frame) override {}
+  void OnFrameLost(const QuicFrame& frame) override;
+  void RetransmitFrames(const QuicFrames& frames,
+                        TransmissionType type) override;
+  bool IsFrameOutstanding(const QuicFrame& frame) const override;
+  bool HasUnackedCryptoData() const override;
+  // End SessionNotifierInterface implementation.
+
+ private:
+  // A Writer object that writes into the |nic_tx_queue_|.
+  class Writer : public QuicPacketWriter {
+   public:
+    explicit Writer(QuicEndpoint* endpoint);
+    ~Writer() override;
+
+    WriteResult WritePacket(const char* buffer,
+                            size_t buf_len,
+                            const QuicIpAddress& self_address,
+                            const QuicSocketAddress& peer_address,
+                            PerPacketOptions* options) override;
+    bool IsWriteBlocked() const override;
+    void SetWritable() override;
+    QuicByteCount GetMaxPacketSize(
+        const QuicSocketAddress& peer_address) const override;
+    bool SupportsReleaseTime() const override;
+    bool IsBatchMode() const override;
+    char* GetNextWriteLocation(const QuicIpAddress& self_address,
+                               const QuicSocketAddress& peer_address) override;
+    WriteResult Flush() override;
+
+   private:
+    QuicEndpoint* endpoint_;
+
+    bool is_blocked_;
+  };
+
+  // The producer outputs the repetition of the same byte.  That sequence is
+  // verified by the receiver.
+  class DataProducer : public QuicStreamFrameDataProducer {
+   public:
+    WriteStreamDataResult WriteStreamData(QuicStreamId id,
+                                          QuicStreamOffset offset,
+                                          QuicByteCount data_length,
+                                          QuicDataWriter* writer) override;
+    bool WriteCryptoData(EncryptionLevel level,
+                         QuicStreamOffset offset,
+                         QuicByteCount data_length,
+                         QuicDataWriter* writer) override;
+  };
+
+  // Write stream data until |bytes_to_transfer_| is zero or the connection is
+  // write-blocked.
+  void WriteStreamData();
+
+  QuicString peer_name_;
+
+  Writer writer_;
+  DataProducer producer_;
+  // The queue for the outgoing packets.  In reality, this might be either on
+  // the network card, or in the kernel, but for concreteness we assume it's on
+  // the network card.
+  Queue nic_tx_queue_;
+  QuicConnection connection_;
+
+  QuicByteCount bytes_to_transfer_;
+  QuicByteCount bytes_transferred_;
+
+  // Counts the number of times the writer became write-blocked.
+  size_t write_blocked_count_;
+
+  // Set to true if the endpoint receives stream data different from what it
+  // expects.
+  bool wrong_data_received_;
+
+  // If true, drop the next packet when receiving it.
+  bool drop_next_packet_;
+
+  // Record of received offsets in the data stream.
+  QuicIntervalSet<QuicStreamOffset> offsets_received_;
+
+  std::unique_ptr<test::SimpleSessionNotifier> notifier_;
+  std::unique_ptr<QuicTraceVisitor> trace_visitor_;
+};
+
+// Multiplexes multiple connections at the same host on the network.
+class QuicEndpointMultiplexer : public Endpoint,
+                                public UnconstrainedPortInterface {
+ public:
+  QuicEndpointMultiplexer(QuicString name,
+                          std::initializer_list<QuicEndpoint*> endpoints);
+  ~QuicEndpointMultiplexer() override;
+
+  // Receives a packet and passes it to the specified endpoint if that endpoint
+  // is one of the endpoints being multiplexed, otherwise ignores the packet.
+  void AcceptPacket(std::unique_ptr<Packet> packet) override;
+  UnconstrainedPortInterface* GetRxPort() override;
+
+  // Sets the egress port for all the endpoints being multiplexed.
+  void SetTxPort(ConstrainedPortInterface* port) override;
+
+  void Act() override {}
+
+ private:
+  QuicUnorderedMap<QuicString, QuicEndpoint*> mapping_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
diff --git a/quic/test_tools/simulator/quic_endpoint_test.cc b/quic/test_tools/simulator/quic_endpoint_test.cc
new file mode 100644
index 0000000..0b25096
--- /dev/null
+++ b/quic/test_tools/simulator/quic_endpoint_test.cc
@@ -0,0 +1,209 @@
+// 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/simulator/quic_endpoint.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
+
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+namespace quic {
+namespace simulator {
+
+const QuicBandwidth kDefaultBandwidth =
+    QuicBandwidth::FromKBitsPerSecond(10 * 1000);
+const QuicTime::Delta kDefaultPropagationDelay =
+    QuicTime::Delta::FromMilliseconds(20);
+const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay;
+
+// A simple test harness where all hosts are connected to a switch with
+// identical links.
+class QuicEndpointTest : public QuicTest {
+ public:
+  QuicEndpointTest()
+      : simulator_(), switch_(&simulator_, "Switch", 8, kDefaultBdp * 2) {}
+
+ protected:
+  Simulator simulator_;
+  Switch switch_;
+
+  std::unique_ptr<SymmetricLink> Link(Endpoint* a, Endpoint* b) {
+    return QuicMakeUnique<SymmetricLink>(a, b, kDefaultBandwidth,
+                                         kDefaultPropagationDelay);
+  }
+
+  std::unique_ptr<SymmetricLink> CustomLink(Endpoint* a,
+                                            Endpoint* b,
+                                            uint64_t extra_rtt_ms) {
+    return QuicMakeUnique<SymmetricLink>(
+        a, b, kDefaultBandwidth,
+        kDefaultPropagationDelay +
+            QuicTime::Delta::FromMilliseconds(extra_rtt_ms));
+  }
+};
+
+// Test transmission from one host to another.
+TEST_F(QuicEndpointTest, OneWayTransmission) {
+  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+                          Perspective::IS_CLIENT, test::TestConnectionId(42));
+  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+                          Perspective::IS_SERVER, test::TestConnectionId(42));
+  auto link_a = Link(&endpoint_a, switch_.port(1));
+  auto link_b = Link(&endpoint_b, switch_.port(2));
+
+  // First transmit a small, packet-size chunk of data.
+  endpoint_a.AddBytesToTransfer(600);
+  QuicTime end_time =
+      simulator_.GetClock()->Now() + QuicTime::Delta::FromMilliseconds(1000);
+  simulator_.RunUntil(
+      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+  EXPECT_EQ(600u, endpoint_a.bytes_transferred());
+  ASSERT_EQ(600u, endpoint_b.bytes_received());
+  EXPECT_FALSE(endpoint_a.wrong_data_received());
+  EXPECT_FALSE(endpoint_b.wrong_data_received());
+
+  // After a small chunk succeeds, try to transfer 2 MiB.
+  endpoint_a.AddBytesToTransfer(2 * 1024 * 1024);
+  end_time = simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
+  simulator_.RunUntil(
+      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+  const QuicByteCount total_bytes_transferred = 600 + 2 * 1024 * 1024;
+  EXPECT_EQ(total_bytes_transferred, endpoint_a.bytes_transferred());
+  EXPECT_EQ(total_bytes_transferred, endpoint_b.bytes_received());
+  EXPECT_EQ(0u, endpoint_a.write_blocked_count());
+  EXPECT_FALSE(endpoint_a.wrong_data_received());
+  EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Test the situation in which the writer becomes write-blocked.
+TEST_F(QuicEndpointTest, WriteBlocked) {
+  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+                          Perspective::IS_CLIENT, test::TestConnectionId(42));
+  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+                          Perspective::IS_SERVER, test::TestConnectionId(42));
+  auto link_a = Link(&endpoint_a, switch_.port(1));
+  auto link_b = Link(&endpoint_b, switch_.port(2));
+
+  // Will be owned by the sent packet manager.
+  auto* sender = new NiceMock<test::MockSendAlgorithm>();
+  EXPECT_CALL(*sender, CanSend(_)).WillRepeatedly(Return(true));
+  EXPECT_CALL(*sender, PacingRate(_))
+      .WillRepeatedly(Return(10 * kDefaultBandwidth));
+  EXPECT_CALL(*sender, BandwidthEstimate())
+      .WillRepeatedly(Return(10 * kDefaultBandwidth));
+  EXPECT_CALL(*sender, GetCongestionWindow())
+      .WillRepeatedly(
+          Return(kMaxPacketSize * kDefaultMaxCongestionWindowPackets));
+  test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(), sender);
+
+  // First transmit a small, packet-size chunk of data.
+  QuicByteCount bytes_to_transfer = 3 * 1024 * 1024;
+  endpoint_a.AddBytesToTransfer(bytes_to_transfer);
+  QuicTime end_time =
+      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(30);
+  simulator_.RunUntil([this, &endpoint_b, bytes_to_transfer, end_time]() {
+    return endpoint_b.bytes_received() == bytes_to_transfer ||
+           simulator_.GetClock()->Now() >= end_time;
+  });
+
+  EXPECT_EQ(bytes_to_transfer, endpoint_a.bytes_transferred());
+  EXPECT_EQ(bytes_to_transfer, endpoint_b.bytes_received());
+  EXPECT_GT(endpoint_a.write_blocked_count(), 0u);
+  EXPECT_FALSE(endpoint_a.wrong_data_received());
+  EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Test transmission of 1 MiB of data between two hosts simultaneously in both
+// directions.
+TEST_F(QuicEndpointTest, TwoWayTransmission) {
+  QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+                          Perspective::IS_CLIENT, test::TestConnectionId(42));
+  QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+                          Perspective::IS_SERVER, test::TestConnectionId(42));
+  auto link_a = Link(&endpoint_a, switch_.port(1));
+  auto link_b = Link(&endpoint_b, switch_.port(2));
+
+  endpoint_a.RecordTrace();
+  endpoint_b.RecordTrace();
+
+  endpoint_a.AddBytesToTransfer(1024 * 1024);
+  endpoint_b.AddBytesToTransfer(1024 * 1024);
+  QuicTime end_time =
+      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
+  simulator_.RunUntil(
+      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+  EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_transferred());
+  EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_transferred());
+  EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_received());
+  EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_received());
+  EXPECT_FALSE(endpoint_a.wrong_data_received());
+  EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Simulate three hosts trying to send data to a fourth one simultaneously.
+TEST_F(QuicEndpointTest, Competition) {
+  // TODO(63765788): Turn back on this flag when the issue if fixed.
+  SetQuicReloadableFlag(quic_bbr_one_mss_conservation, false);
+  auto endpoint_a = QuicMakeUnique<QuicEndpoint>(
+      &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT,
+      test::TestConnectionId(42));
+  auto endpoint_b = QuicMakeUnique<QuicEndpoint>(
+      &simulator_, "Endpoint B", "Endpoint D (B)", Perspective::IS_CLIENT,
+      test::TestConnectionId(43));
+  auto endpoint_c = QuicMakeUnique<QuicEndpoint>(
+      &simulator_, "Endpoint C", "Endpoint D (C)", Perspective::IS_CLIENT,
+      test::TestConnectionId(44));
+  auto endpoint_d_a = QuicMakeUnique<QuicEndpoint>(
+      &simulator_, "Endpoint D (A)", "Endpoint A", Perspective::IS_SERVER,
+      test::TestConnectionId(42));
+  auto endpoint_d_b = QuicMakeUnique<QuicEndpoint>(
+      &simulator_, "Endpoint D (B)", "Endpoint B", Perspective::IS_SERVER,
+      test::TestConnectionId(43));
+  auto endpoint_d_c = QuicMakeUnique<QuicEndpoint>(
+      &simulator_, "Endpoint D (C)", "Endpoint C", Perspective::IS_SERVER,
+      test::TestConnectionId(44));
+  QuicEndpointMultiplexer endpoint_d(
+      "Endpoint D",
+      {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()});
+
+  // Create links with slightly different RTTs in order to avoid pathological
+  // side-effects of packets entering the queue at the exactly same time.
+  auto link_a = CustomLink(endpoint_a.get(), switch_.port(1), 0);
+  auto link_b = CustomLink(endpoint_b.get(), switch_.port(2), 1);
+  auto link_c = CustomLink(endpoint_c.get(), switch_.port(3), 2);
+  auto link_d = Link(&endpoint_d, switch_.port(4));
+
+  endpoint_a->AddBytesToTransfer(2 * 1024 * 1024);
+  endpoint_b->AddBytesToTransfer(2 * 1024 * 1024);
+  endpoint_c->AddBytesToTransfer(2 * 1024 * 1024);
+  QuicTime end_time =
+      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(10);
+  simulator_.RunUntil(
+      [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+  for (QuicEndpoint* endpoint :
+       {endpoint_a.get(), endpoint_b.get(), endpoint_c.get()}) {
+    EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_transferred());
+    EXPECT_GE(endpoint->connection()->GetStats().packets_lost, 0u);
+  }
+  for (QuicEndpoint* endpoint :
+       {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()}) {
+    EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_received());
+    EXPECT_FALSE(endpoint->wrong_data_received());
+  }
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/simulator.cc b/quic/test_tools/simulator/simulator.cc
new file mode 100644
index 0000000..fdb59db
--- /dev/null
+++ b/quic/test_tools/simulator/simulator.cc
@@ -0,0 +1,167 @@
+// 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/simulator/simulator.h"
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+
+namespace quic {
+namespace simulator {
+
+Simulator::Simulator()
+    : random_generator_(nullptr),
+      alarm_factory_(this, "Default Alarm Manager"),
+      run_for_should_stop_(false),
+      enable_random_delays_(false) {
+  run_for_alarm_.reset(
+      alarm_factory_.CreateAlarm(new RunForDelegate(&run_for_should_stop_)));
+}
+
+Simulator::~Simulator() {
+  // Ensure that Actor under run_for_alarm_ is removed before Simulator data
+  // structures are destructed.
+  run_for_alarm_.reset();
+}
+
+Simulator::Clock::Clock() : now_(kStartTime) {}
+
+QuicTime Simulator::Clock::ApproximateNow() const {
+  return now_;
+}
+
+QuicTime Simulator::Clock::Now() const {
+  return now_;
+}
+
+QuicWallTime Simulator::Clock::WallNow() const {
+  return QuicWallTime::FromUNIXMicroseconds(
+      (now_ - QuicTime::Zero()).ToMicroseconds());
+}
+
+void Simulator::AddActor(Actor* actor) {
+  auto emplace_times_result =
+      scheduled_times_.insert(std::make_pair(actor, QuicTime::Infinite()));
+  auto emplace_names_result = actor_names_.insert(actor->name());
+
+  // Ensure that the object was actually placed into the map.
+  DCHECK(emplace_times_result.second);
+  DCHECK(emplace_names_result.second);
+}
+
+void Simulator::RemoveActor(Actor* actor) {
+  auto scheduled_time_it = scheduled_times_.find(actor);
+  auto actor_names_it = actor_names_.find(actor->name());
+  DCHECK(scheduled_time_it != scheduled_times_.end());
+  DCHECK(actor_names_it != actor_names_.end());
+
+  QuicTime scheduled_time = scheduled_time_it->second;
+  if (scheduled_time != QuicTime::Infinite()) {
+    Unschedule(actor);
+  }
+
+  scheduled_times_.erase(scheduled_time_it);
+  actor_names_.erase(actor_names_it);
+}
+
+void Simulator::Schedule(Actor* actor, QuicTime new_time) {
+  auto scheduled_time_it = scheduled_times_.find(actor);
+  DCHECK(scheduled_time_it != scheduled_times_.end());
+  QuicTime scheduled_time = scheduled_time_it->second;
+
+  if (scheduled_time <= new_time) {
+    return;
+  }
+
+  if (scheduled_time != QuicTime::Infinite()) {
+    Unschedule(actor);
+  }
+
+  scheduled_time_it->second = new_time;
+  schedule_.insert(std::make_pair(new_time, actor));
+}
+
+void Simulator::Unschedule(Actor* actor) {
+  auto scheduled_time_it = scheduled_times_.find(actor);
+  DCHECK(scheduled_time_it != scheduled_times_.end());
+  QuicTime scheduled_time = scheduled_time_it->second;
+
+  DCHECK(scheduled_time != QuicTime::Infinite());
+  auto range = schedule_.equal_range(scheduled_time);
+  for (auto it = range.first; it != range.second; ++it) {
+    if (it->second == actor) {
+      schedule_.erase(it);
+      scheduled_time_it->second = QuicTime::Infinite();
+      return;
+    }
+  }
+  DCHECK(false);
+}
+
+const QuicClock* Simulator::GetClock() const {
+  return &clock_;
+}
+
+QuicRandom* Simulator::GetRandomGenerator() {
+  if (random_generator_ == nullptr) {
+    random_generator_ = QuicRandom::GetInstance();
+  }
+
+  return random_generator_;
+}
+
+QuicBufferAllocator* Simulator::GetStreamSendBufferAllocator() {
+  return &buffer_allocator_;
+}
+
+QuicAlarmFactory* Simulator::GetAlarmFactory() {
+  return &alarm_factory_;
+}
+
+Simulator::RunForDelegate::RunForDelegate(bool* run_for_should_stop)
+    : run_for_should_stop_(run_for_should_stop) {}
+
+void Simulator::RunForDelegate::OnAlarm() {
+  *run_for_should_stop_ = true;
+}
+
+void Simulator::RunFor(QuicTime::Delta time_span) {
+  DCHECK(!run_for_alarm_->IsSet());
+
+  // RunFor() ensures that the simulation stops at the exact time specified by
+  // scheduling an alarm at that point and using that alarm to abort the
+  // simulation.  An alarm is necessary because otherwise it is possible that
+  // nothing is scheduled at |end_time|, so the simulation will either go
+  // further than requested or stop before reaching |end_time|.
+  const QuicTime end_time = clock_.Now() + time_span;
+  run_for_alarm_->Set(end_time);
+  run_for_should_stop_ = false;
+  bool simulation_result = RunUntil([this]() { return run_for_should_stop_; });
+
+  DCHECK(simulation_result);
+  DCHECK(clock_.Now() == end_time);
+}
+
+void Simulator::HandleNextScheduledActor() {
+  const auto current_event_it = schedule_.begin();
+  QuicTime event_time = current_event_it->first;
+  Actor* actor = current_event_it->second;
+  QUIC_DVLOG(3) << "At t = " << event_time.ToDebuggingValue() << ", calling "
+                << actor->name();
+
+  Unschedule(actor);
+
+  if (clock_.Now() > event_time) {
+    QUIC_BUG << "Error: event registered by [" << actor->name()
+             << "] requires travelling back in time.  Current time: "
+             << clock_.Now().ToDebuggingValue()
+             << ", scheduled time: " << event_time.ToDebuggingValue();
+  }
+  clock_.now_ = event_time;
+
+  actor->Act();
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/simulator.h b/quic/test_tools/simulator/simulator.h
new file mode 100644
index 0000000..0180dcb
--- /dev/null
+++ b/quic/test_tools/simulator/simulator.h
@@ -0,0 +1,166 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
+
+#include <map>
+
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/actor.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/alarm_factory.h"
+
+namespace quic {
+namespace simulator {
+
+// Simulator is responsible for scheduling actors in the simulation and
+// providing basic utility interfaces (clock, alarms, RNG and others).
+class Simulator : public QuicConnectionHelperInterface {
+ public:
+  Simulator();
+  Simulator(const Simulator&) = delete;
+  Simulator& operator=(const Simulator&) = delete;
+  ~Simulator() override;
+
+  // Schedule the specified actor.  This method will ensure that |actor| is
+  // called at |new_time| at latest.  If Schedule() is called multiple times
+  // before the Actor is called, Act() is called exactly once, at the earliest
+  // time requested, and the Actor has to reschedule itself manually for the
+  // subsequent times if they are still necessary.
+  void Schedule(Actor* actor, QuicTime new_time);
+
+  // Remove the specified actor from the schedule.
+  void Unschedule(Actor* actor);
+
+  // Begin QuicConnectionHelperInterface implementation.
+  const QuicClock* GetClock() const override;
+  QuicRandom* GetRandomGenerator() override;
+  QuicBufferAllocator* GetStreamSendBufferAllocator() override;
+  // End QuicConnectionHelperInterface implementation.
+
+  QuicAlarmFactory* GetAlarmFactory();
+
+  inline void set_random_generator(QuicRandom* random) {
+    random_generator_ = random;
+  }
+
+  inline bool enable_random_delays() const { return enable_random_delays_; }
+
+  // Run the simulation until either no actors are scheduled or
+  // |termination_predicate| returns true.  Returns true if terminated due to
+  // predicate, and false otherwise.
+  template <class TerminationPredicate>
+  bool RunUntil(TerminationPredicate termination_predicate);
+
+  // Same as RunUntil, except this function also accepts a |deadline|, and will
+  // return false if the deadline is exceeded.
+  template <class TerminationPredicate>
+  bool RunUntilOrTimeout(TerminationPredicate termination_predicate,
+                         QuicTime::Delta deadline);
+
+  // Runs the simulation for exactly the specified |time_span|.
+  void RunFor(QuicTime::Delta time_span);
+
+ private:
+  friend class Actor;
+
+  class Clock : public QuicClock {
+   public:
+    // Do not start at zero as certain code can treat zero as an invalid
+    // timestamp.
+    const QuicTime kStartTime =
+        QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1);
+
+    Clock();
+
+    QuicTime ApproximateNow() const override;
+    QuicTime Now() const override;
+    QuicWallTime WallNow() const override;
+
+    QuicTime now_;
+  };
+
+  // The delegate used for RunFor().
+  class RunForDelegate : public QuicAlarm::Delegate {
+   public:
+    explicit RunForDelegate(bool* run_for_should_stop);
+    void OnAlarm() override;
+
+   private:
+    // Pointer to |run_for_should_stop_| in the parent simulator.
+    bool* run_for_should_stop_;
+  };
+
+  // Register an actor with the simulator. Invoked by Actor constructor.
+  void AddActor(Actor* actor);
+
+  // Unregister an actor with the simulator. Invoked by Actor destructor.
+  void RemoveActor(Actor* actor);
+
+  // Finds the next scheduled actor, advances time to the schedule time and
+  // notifies the actor.
+  void HandleNextScheduledActor();
+
+  Clock clock_;
+  QuicRandom* random_generator_;
+  SimpleBufferAllocator buffer_allocator_;
+  AlarmFactory alarm_factory_;
+
+  // Alarm for RunFor() method.
+  std::unique_ptr<QuicAlarm> run_for_alarm_;
+  // Flag used to stop simulations ran via RunFor().
+  bool run_for_should_stop_;
+
+  // Indicates whether the simulator should add random delays on the links in
+  // order to avoid synchronization issues.
+  bool enable_random_delays_;
+
+  // Schedule of when the actors will be executed via an Act() call.  The
+  // schedule is subject to the following invariants:
+  // - An actor cannot be scheduled for a later time than it's currently in the
+  //   schedule.
+  // - An actor is removed from schedule either immediately before Act() is
+  //   called or by explicitly calling Unschedule().
+  // - Each Actor appears in the map at most once.
+  std::multimap<QuicTime, Actor*> schedule_;
+  // For each actor, maintain the time it is scheduled at.  The value for
+  // unscheduled actors is QuicTime::Infinite().
+  QuicUnorderedMap<Actor*, QuicTime> scheduled_times_;
+  QuicUnorderedSet<QuicString> actor_names_;
+};
+
+template <class TerminationPredicate>
+bool Simulator::RunUntil(TerminationPredicate termination_predicate) {
+  bool predicate_value = false;
+  while (true) {
+    predicate_value = termination_predicate();
+    if (predicate_value || schedule_.empty()) {
+      break;
+    }
+    HandleNextScheduledActor();
+  }
+  return predicate_value;
+}
+
+template <class TerminationPredicate>
+bool Simulator::RunUntilOrTimeout(TerminationPredicate termination_predicate,
+                                  QuicTime::Delta timeout) {
+  QuicTime end_time = clock_.Now() + timeout;
+  bool return_value = RunUntil([end_time, &termination_predicate, this]() {
+    return termination_predicate() || clock_.Now() >= end_time;
+  });
+
+  if (clock_.Now() >= end_time) {
+    return false;
+  }
+  return return_value;
+}
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
diff --git a/quic/test_tools/simulator/simulator_test.cc b/quic/test_tools/simulator/simulator_test.cc
new file mode 100644
index 0000000..d9986ad
--- /dev/null
+++ b/quic/test_tools/simulator/simulator_test.cc
@@ -0,0 +1,829 @@
+// 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/simulator/simulator.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.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_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/alarm_factory.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/traffic_policer.h"
+
+using testing::_;
+using testing::Return;
+using testing::StrictMock;
+
+namespace quic {
+namespace simulator {
+
+// A simple counter that increments its value by 1 every specified period.
+class Counter : public Actor {
+ public:
+  Counter(Simulator* simulator, QuicString name, QuicTime::Delta period)
+      : Actor(simulator, name), value_(-1), period_(period) {
+    Schedule(clock_->Now());
+  }
+  ~Counter() override {}
+
+  inline int get_value() const { return value_; }
+
+  void Act() override {
+    ++value_;
+    QUIC_DVLOG(1) << name_ << " has value " << value_ << " at time "
+                  << clock_->Now().ToDebuggingValue();
+    Schedule(clock_->Now() + period_);
+  }
+
+ private:
+  int value_;
+  QuicTime::Delta period_;
+};
+
+class SimulatorTest : public QuicTest {};
+
+// Test that the basic event handling works, and that Actors can be created and
+// destroyed mid-simulation.
+TEST_F(SimulatorTest, Counters) {
+  Simulator simulator;
+  for (int i = 0; i < 2; ++i) {
+    Counter fast_counter(&simulator, "fast_counter",
+                         QuicTime::Delta::FromSeconds(3));
+    Counter slow_counter(&simulator, "slow_counter",
+                         QuicTime::Delta::FromSeconds(10));
+
+    simulator.RunUntil(
+        [&slow_counter]() { return slow_counter.get_value() >= 10; });
+
+    EXPECT_EQ(10, slow_counter.get_value());
+    EXPECT_EQ(10 * 10 / 3, fast_counter.get_value());
+  }
+}
+
+// A port which counts the number of packets received on it, both total and
+// per-destination.
+class CounterPort : public UnconstrainedPortInterface {
+ public:
+  CounterPort() { Reset(); }
+  ~CounterPort() override {}
+
+  inline QuicByteCount bytes() const { return bytes_; }
+  inline QuicPacketCount packets() const { return packets_; }
+
+  void AcceptPacket(std::unique_ptr<Packet> packet) override {
+    bytes_ += packet->size;
+    packets_ += 1;
+
+    per_destination_packet_counter_[packet->destination] += 1;
+  }
+
+  void Reset() {
+    bytes_ = 0;
+    packets_ = 0;
+    per_destination_packet_counter_.clear();
+  }
+
+  QuicPacketCount CountPacketsForDestination(QuicString destination) const {
+    auto result_it = per_destination_packet_counter_.find(destination);
+    if (result_it == per_destination_packet_counter_.cend()) {
+      return 0;
+    }
+    return result_it->second;
+  }
+
+ private:
+  QuicByteCount bytes_;
+  QuicPacketCount packets_;
+
+  QuicUnorderedMap<QuicString, QuicPacketCount> per_destination_packet_counter_;
+};
+
+// Sends the packet to the specified destination at the uplink rate.  Provides a
+// CounterPort as an Rx interface.
+class LinkSaturator : public Endpoint {
+ public:
+  LinkSaturator(Simulator* simulator,
+                QuicString name,
+                QuicByteCount packet_size,
+                QuicString destination)
+      : Endpoint(simulator, name),
+        packet_size_(packet_size),
+        destination_(std::move(destination)),
+        bytes_transmitted_(0),
+        packets_transmitted_(0) {
+    Schedule(clock_->Now());
+  }
+
+  void Act() override {
+    if (tx_port_->TimeUntilAvailable().IsZero()) {
+      auto packet = QuicMakeUnique<Packet>();
+      packet->source = name_;
+      packet->destination = destination_;
+      packet->tx_timestamp = clock_->Now();
+      packet->size = packet_size_;
+
+      tx_port_->AcceptPacket(std::move(packet));
+
+      bytes_transmitted_ += packet_size_;
+      packets_transmitted_ += 1;
+    }
+
+    Schedule(clock_->Now() + tx_port_->TimeUntilAvailable());
+  }
+
+  UnconstrainedPortInterface* GetRxPort() override {
+    return static_cast<UnconstrainedPortInterface*>(&rx_port_);
+  }
+
+  void SetTxPort(ConstrainedPortInterface* port) override { tx_port_ = port; }
+
+  CounterPort* counter() { return &rx_port_; }
+
+  inline QuicByteCount bytes_transmitted() const { return bytes_transmitted_; }
+  inline QuicPacketCount packets_transmitted() const {
+    return packets_transmitted_;
+  }
+
+  void Pause() { Unschedule(); }
+  void Resume() { Schedule(clock_->Now()); }
+
+ private:
+  QuicByteCount packet_size_;
+  QuicString destination_;
+
+  ConstrainedPortInterface* tx_port_;
+  CounterPort rx_port_;
+
+  QuicByteCount bytes_transmitted_;
+  QuicPacketCount packets_transmitted_;
+};
+
+// Saturate a symmetric link and verify that the number of packets sent and
+// received is correct.
+TEST_F(SimulatorTest, DirectLinkSaturation) {
+  Simulator simulator;
+  LinkSaturator saturator_a(&simulator, "Saturator A", 1000, "Saturator B");
+  LinkSaturator saturator_b(&simulator, "Saturator B", 100, "Saturator A");
+  SymmetricLink link(&saturator_a, &saturator_b,
+                     QuicBandwidth::FromKBytesPerSecond(1000),
+                     QuicTime::Delta::FromMilliseconds(100) +
+                         QuicTime::Delta::FromMicroseconds(1));
+
+  const QuicTime start_time = simulator.GetClock()->Now();
+  const QuicTime after_first_50_ms =
+      start_time + QuicTime::Delta::FromMilliseconds(50);
+  simulator.RunUntil([&simulator, after_first_50_ms]() {
+    return simulator.GetClock()->Now() >= after_first_50_ms;
+  });
+  EXPECT_LE(1000u * 50u, saturator_a.bytes_transmitted());
+  EXPECT_GE(1000u * 51u, saturator_a.bytes_transmitted());
+  EXPECT_LE(1000u * 50u, saturator_b.bytes_transmitted());
+  EXPECT_GE(1000u * 51u, saturator_b.bytes_transmitted());
+  EXPECT_LE(50u, saturator_a.packets_transmitted());
+  EXPECT_GE(51u, saturator_a.packets_transmitted());
+  EXPECT_LE(500u, saturator_b.packets_transmitted());
+  EXPECT_GE(501u, saturator_b.packets_transmitted());
+  EXPECT_EQ(0u, saturator_a.counter()->bytes());
+  EXPECT_EQ(0u, saturator_b.counter()->bytes());
+
+  simulator.RunUntil([&saturator_a, &saturator_b]() {
+    if (saturator_a.counter()->packets() > 1000 ||
+        saturator_b.counter()->packets() > 100) {
+      ADD_FAILURE() << "The simulation did not arrive at the expected "
+                       "termination contidition. Saturator A counter: "
+                    << saturator_a.counter()->packets()
+                    << ", saturator B counter: "
+                    << saturator_b.counter()->packets();
+      return true;
+    }
+
+    return saturator_a.counter()->packets() == 1000 &&
+           saturator_b.counter()->packets() == 100;
+  });
+  EXPECT_EQ(201u, saturator_a.packets_transmitted());
+  EXPECT_EQ(2001u, saturator_b.packets_transmitted());
+  EXPECT_EQ(201u * 1000, saturator_a.bytes_transmitted());
+  EXPECT_EQ(2001u * 100, saturator_b.bytes_transmitted());
+
+  EXPECT_EQ(1000u,
+            saturator_a.counter()->CountPacketsForDestination("Saturator A"));
+  EXPECT_EQ(100u,
+            saturator_b.counter()->CountPacketsForDestination("Saturator B"));
+  EXPECT_EQ(0u,
+            saturator_a.counter()->CountPacketsForDestination("Saturator B"));
+  EXPECT_EQ(0u,
+            saturator_b.counter()->CountPacketsForDestination("Saturator A"));
+
+  const QuicTime end_time = simulator.GetClock()->Now();
+  const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
+      saturator_a.bytes_transmitted(), end_time - start_time);
+  test::ExpectApproxEq(link.bandwidth(), observed_bandwidth, 0.01f);
+}
+
+// Accepts packets and stores them internally.
+class PacketAcceptor : public ConstrainedPortInterface {
+ public:
+  void AcceptPacket(std::unique_ptr<Packet> packet) override {
+    packets_.emplace_back(std::move(packet));
+  }
+
+  QuicTime::Delta TimeUntilAvailable() override {
+    return QuicTime::Delta::Zero();
+  }
+
+  std::vector<std::unique_ptr<Packet>>* packets() { return &packets_; }
+
+ private:
+  std::vector<std::unique_ptr<Packet>> packets_;
+};
+
+// Ensure the queue behaves correctly with accepting packets.
+TEST_F(SimulatorTest, Queue) {
+  Simulator simulator;
+  Queue queue(&simulator, "Queue", 1000);
+  PacketAcceptor acceptor;
+  queue.set_tx_port(&acceptor);
+
+  EXPECT_EQ(0u, queue.bytes_queued());
+  EXPECT_EQ(0u, queue.packets_queued());
+  EXPECT_EQ(0u, acceptor.packets()->size());
+
+  auto first_packet = QuicMakeUnique<Packet>();
+  first_packet->size = 600;
+  queue.AcceptPacket(std::move(first_packet));
+  EXPECT_EQ(600u, queue.bytes_queued());
+  EXPECT_EQ(1u, queue.packets_queued());
+  EXPECT_EQ(0u, acceptor.packets()->size());
+
+  // The second packet does not fit and is dropped.
+  auto second_packet = QuicMakeUnique<Packet>();
+  second_packet->size = 500;
+  queue.AcceptPacket(std::move(second_packet));
+  EXPECT_EQ(600u, queue.bytes_queued());
+  EXPECT_EQ(1u, queue.packets_queued());
+  EXPECT_EQ(0u, acceptor.packets()->size());
+
+  auto third_packet = QuicMakeUnique<Packet>();
+  third_packet->size = 400;
+  queue.AcceptPacket(std::move(third_packet));
+  EXPECT_EQ(1000u, queue.bytes_queued());
+  EXPECT_EQ(2u, queue.packets_queued());
+  EXPECT_EQ(0u, acceptor.packets()->size());
+
+  // Run until there is nothing scheduled, so that the queue can deplete.
+  simulator.RunUntil([]() { return false; });
+  EXPECT_EQ(0u, queue.bytes_queued());
+  EXPECT_EQ(0u, queue.packets_queued());
+  ASSERT_EQ(2u, acceptor.packets()->size());
+  EXPECT_EQ(600u, acceptor.packets()->at(0)->size);
+  EXPECT_EQ(400u, acceptor.packets()->at(1)->size);
+}
+
+// Simulate a situation where the bottleneck link is 10 times slower than the
+// uplink, and they are separated by a queue.
+TEST_F(SimulatorTest, QueueBottleneck) {
+  const QuicBandwidth local_bandwidth =
+      QuicBandwidth::FromKBytesPerSecond(1000);
+  const QuicBandwidth bottleneck_bandwidth = 0.1f * local_bandwidth;
+  const QuicTime::Delta local_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(1);
+  const QuicTime::Delta bottleneck_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(20);
+  const QuicByteCount bdp =
+      bottleneck_bandwidth *
+      (local_propagation_delay + bottleneck_propagation_delay);
+
+  Simulator simulator;
+  LinkSaturator saturator(&simulator, "Saturator", 1000, "Counter");
+  ASSERT_GE(bdp, 1000u);
+  Queue queue(&simulator, "Queue", bdp);
+  CounterPort counter;
+
+  OneWayLink local_link(&simulator, "Local link", &queue, local_bandwidth,
+                        local_propagation_delay);
+  OneWayLink bottleneck_link(&simulator, "Bottleneck link", &counter,
+                             bottleneck_bandwidth,
+                             bottleneck_propagation_delay);
+  saturator.SetTxPort(&local_link);
+  queue.set_tx_port(&bottleneck_link);
+
+  static const QuicPacketCount packets_received = 1000;
+  simulator.RunUntil(
+      [&counter]() { return counter.packets() == packets_received; });
+  const double loss_ratio = 1 - static_cast<double>(packets_received) /
+                                    saturator.packets_transmitted();
+  EXPECT_NEAR(loss_ratio, 0.9, 0.001);
+}
+
+// Verify that the queue of exactly one packet allows the transmission to
+// actually go through.
+TEST_F(SimulatorTest, OnePacketQueue) {
+  const QuicBandwidth local_bandwidth =
+      QuicBandwidth::FromKBytesPerSecond(1000);
+  const QuicBandwidth bottleneck_bandwidth = 0.1f * local_bandwidth;
+  const QuicTime::Delta local_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(1);
+  const QuicTime::Delta bottleneck_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(20);
+
+  Simulator simulator;
+  LinkSaturator saturator(&simulator, "Saturator", 1000, "Counter");
+  Queue queue(&simulator, "Queue", 1000);
+  CounterPort counter;
+
+  OneWayLink local_link(&simulator, "Local link", &queue, local_bandwidth,
+                        local_propagation_delay);
+  OneWayLink bottleneck_link(&simulator, "Bottleneck link", &counter,
+                             bottleneck_bandwidth,
+                             bottleneck_propagation_delay);
+  saturator.SetTxPort(&local_link);
+  queue.set_tx_port(&bottleneck_link);
+
+  static const QuicPacketCount packets_received = 10;
+  // The deadline here is to prevent this tests from looping infinitely in case
+  // the packets never reach the receiver.
+  const QuicTime deadline =
+      simulator.GetClock()->Now() + QuicTime::Delta::FromSeconds(10);
+  simulator.RunUntil([&simulator, &counter, deadline]() {
+    return counter.packets() == packets_received ||
+           simulator.GetClock()->Now() > deadline;
+  });
+  ASSERT_EQ(packets_received, counter.packets());
+}
+
+// Simulate a network where three endpoints are connected to a switch and they
+// are sending traffic in circle (1 -> 2, 2 -> 3, 3 -> 1).
+TEST_F(SimulatorTest, SwitchedNetwork) {
+  const QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(10000);
+  const QuicTime::Delta base_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(50);
+
+  Simulator simulator;
+  LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2");
+  LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 3");
+  LinkSaturator saturator3(&simulator, "Saturator 3", 1000, "Saturator 1");
+  Switch network_switch(&simulator, "Switch", 8,
+                        bandwidth * base_propagation_delay * 10);
+
+  // For determinicity, make it so that the first packet will arrive from
+  // Saturator 1, then from Saturator 2, and then from Saturator 3.
+  SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth,
+                      base_propagation_delay);
+  SymmetricLink link2(&saturator2, network_switch.port(2), bandwidth,
+                      base_propagation_delay * 2);
+  SymmetricLink link3(&saturator3, network_switch.port(3), bandwidth,
+                      base_propagation_delay * 3);
+
+  const QuicTime start_time = simulator.GetClock()->Now();
+  static const QuicPacketCount bytes_received = 64 * 1000;
+  simulator.RunUntil([&saturator1]() {
+    return saturator1.counter()->bytes() >= bytes_received;
+  });
+  const QuicTime end_time = simulator.GetClock()->Now();
+
+  const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
+      bytes_received, end_time - start_time);
+  const double bandwidth_ratio =
+      static_cast<double>(observed_bandwidth.ToBitsPerSecond()) /
+      bandwidth.ToBitsPerSecond();
+  EXPECT_NEAR(1, bandwidth_ratio, 0.1);
+
+  const double normalized_received_packets_for_saturator_2 =
+      static_cast<double>(saturator2.counter()->packets()) /
+      saturator1.counter()->packets();
+  const double normalized_received_packets_for_saturator_3 =
+      static_cast<double>(saturator3.counter()->packets()) /
+      saturator1.counter()->packets();
+  EXPECT_NEAR(1, normalized_received_packets_for_saturator_2, 0.1);
+  EXPECT_NEAR(1, normalized_received_packets_for_saturator_3, 0.1);
+
+  // Since Saturator 1 has its packet arrive first into the switch, switch will
+  // always know how to route traffic to it.
+  EXPECT_EQ(0u,
+            saturator2.counter()->CountPacketsForDestination("Saturator 1"));
+  EXPECT_EQ(0u,
+            saturator3.counter()->CountPacketsForDestination("Saturator 1"));
+
+  // Packets from the other saturators will be broadcast at least once.
+  EXPECT_EQ(1u,
+            saturator1.counter()->CountPacketsForDestination("Saturator 2"));
+  EXPECT_EQ(1u,
+            saturator3.counter()->CountPacketsForDestination("Saturator 2"));
+  EXPECT_EQ(1u,
+            saturator1.counter()->CountPacketsForDestination("Saturator 3"));
+  EXPECT_EQ(1u,
+            saturator2.counter()->CountPacketsForDestination("Saturator 3"));
+}
+
+// Toggle an alarm on and off at the specified interval.  Assumes that alarm is
+// initially set and unsets it almost immediately after the object is
+// instantiated.
+class AlarmToggler : public Actor {
+ public:
+  AlarmToggler(Simulator* simulator,
+               QuicString name,
+               QuicAlarm* alarm,
+               QuicTime::Delta interval)
+      : Actor(simulator, name),
+        alarm_(alarm),
+        interval_(interval),
+        deadline_(alarm->deadline()),
+        times_set_(0),
+        times_cancelled_(0) {
+    EXPECT_TRUE(alarm->IsSet());
+    EXPECT_GE(alarm->deadline(), clock_->Now());
+    Schedule(clock_->Now());
+  }
+
+  void Act() override {
+    if (deadline_ <= clock_->Now()) {
+      return;
+    }
+
+    if (alarm_->IsSet()) {
+      alarm_->Cancel();
+      times_cancelled_++;
+    } else {
+      alarm_->Set(deadline_);
+      times_set_++;
+    }
+
+    Schedule(clock_->Now() + interval_);
+  }
+
+  inline int times_set() { return times_set_; }
+  inline int times_cancelled() { return times_cancelled_; }
+
+ private:
+  QuicAlarm* alarm_;
+  QuicTime::Delta interval_;
+  QuicTime deadline_;
+
+  // Counts the number of times the alarm was set.
+  int times_set_;
+  // Counts the number of times the alarm was cancelled.
+  int times_cancelled_;
+};
+
+// Counts the number of times an alarm has fired.
+class CounterDelegate : public QuicAlarm::Delegate {
+ public:
+  explicit CounterDelegate(size_t* counter) : counter_(counter) {}
+
+  void OnAlarm() override { *counter_ += 1; }
+
+ private:
+  size_t* counter_;
+};
+
+// Verifies that the alarms work correctly, even when they are repeatedly
+// toggled.
+TEST_F(SimulatorTest, Alarms) {
+  Simulator simulator;
+  QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory();
+
+  size_t fast_alarm_counter = 0;
+  size_t slow_alarm_counter = 0;
+  std::unique_ptr<QuicAlarm> alarm_fast(
+      alarm_factory->CreateAlarm(new CounterDelegate(&fast_alarm_counter)));
+  std::unique_ptr<QuicAlarm> alarm_slow(
+      alarm_factory->CreateAlarm(new CounterDelegate(&slow_alarm_counter)));
+
+  const QuicTime start_time = simulator.GetClock()->Now();
+  alarm_fast->Set(start_time + QuicTime::Delta::FromMilliseconds(100));
+  alarm_slow->Set(start_time + QuicTime::Delta::FromMilliseconds(750));
+  AlarmToggler toggler(&simulator, "Toggler", alarm_slow.get(),
+                       QuicTime::Delta::FromMilliseconds(100));
+
+  const QuicTime end_time =
+      start_time + QuicTime::Delta::FromMilliseconds(1000);
+  EXPECT_FALSE(simulator.RunUntil([&simulator, end_time]() {
+    return simulator.GetClock()->Now() >= end_time;
+  }));
+  EXPECT_EQ(1u, slow_alarm_counter);
+  EXPECT_EQ(1u, fast_alarm_counter);
+
+  EXPECT_EQ(4, toggler.times_set());
+  EXPECT_EQ(4, toggler.times_cancelled());
+}
+
+// Verifies that a cancelled alarm is never fired.
+TEST_F(SimulatorTest, AlarmCancelling) {
+  Simulator simulator;
+  QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory();
+
+  size_t alarm_counter = 0;
+  std::unique_ptr<QuicAlarm> alarm(
+      alarm_factory->CreateAlarm(new CounterDelegate(&alarm_counter)));
+
+  const QuicTime start_time = simulator.GetClock()->Now();
+  const QuicTime alarm_at = start_time + QuicTime::Delta::FromMilliseconds(300);
+  const QuicTime end_time = start_time + QuicTime::Delta::FromMilliseconds(400);
+
+  alarm->Set(alarm_at);
+  alarm->Cancel();
+  EXPECT_FALSE(alarm->IsSet());
+
+  EXPECT_FALSE(simulator.RunUntil([&simulator, end_time]() {
+    return simulator.GetClock()->Now() >= end_time;
+  }));
+
+  EXPECT_FALSE(alarm->IsSet());
+  EXPECT_EQ(0u, alarm_counter);
+}
+
+// Verifies that alarms can be scheduled into the past.
+TEST_F(SimulatorTest, AlarmInPast) {
+  Simulator simulator;
+  QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory();
+
+  size_t alarm_counter = 0;
+  std::unique_ptr<QuicAlarm> alarm(
+      alarm_factory->CreateAlarm(new CounterDelegate(&alarm_counter)));
+
+  const QuicTime start_time = simulator.GetClock()->Now();
+  simulator.RunFor(QuicTime::Delta::FromMilliseconds(400));
+
+  alarm->Set(start_time);
+  simulator.RunFor(QuicTime::Delta::FromMilliseconds(1));
+  EXPECT_FALSE(alarm->IsSet());
+  EXPECT_EQ(1u, alarm_counter);
+}
+
+// Tests Simulator::RunUntilOrTimeout() interface.
+TEST_F(SimulatorTest, RunUntilOrTimeout) {
+  Simulator simulator;
+  bool simulation_result;
+
+  // Count the number of seconds since the beginning of the simulation.
+  Counter counter(&simulator, "counter", QuicTime::Delta::FromSeconds(1));
+
+  // Ensure that the counter reaches the value of 10 given a 20 second deadline.
+  simulation_result = simulator.RunUntilOrTimeout(
+      [&counter]() { return counter.get_value() == 10; },
+      QuicTime::Delta::FromSeconds(20));
+  ASSERT_TRUE(simulation_result);
+
+  // Ensure that the counter will not reach the value of 100 given that the
+  // starting value is 10 and the deadline is 20 seconds.
+  simulation_result = simulator.RunUntilOrTimeout(
+      [&counter]() { return counter.get_value() == 100; },
+      QuicTime::Delta::FromSeconds(20));
+  ASSERT_FALSE(simulation_result);
+}
+
+// Tests Simulator::RunFor() interface.
+TEST_F(SimulatorTest, RunFor) {
+  Simulator simulator;
+
+  Counter counter(&simulator, "counter", QuicTime::Delta::FromSeconds(3));
+
+  simulator.RunFor(QuicTime::Delta::FromSeconds(100));
+
+  EXPECT_EQ(33, counter.get_value());
+}
+
+class MockPacketFilter : public PacketFilter {
+ public:
+  MockPacketFilter(Simulator* simulator, QuicString name, Endpoint* endpoint)
+      : PacketFilter(simulator, name, endpoint) {}
+  MOCK_METHOD1(FilterPacket, bool(const Packet&));
+};
+
+// Set up two trivial packet filters, one allowing any packets, and one dropping
+// all of them.
+TEST_F(SimulatorTest, PacketFilter) {
+  const QuicBandwidth bandwidth =
+      QuicBandwidth::FromBytesPerSecond(1024 * 1024);
+  const QuicTime::Delta base_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(5);
+
+  Simulator simulator;
+  LinkSaturator saturator_a(&simulator, "Saturator A", 1000, "Saturator B");
+  LinkSaturator saturator_b(&simulator, "Saturator B", 1000, "Saturator A");
+
+  // Attach packets to the switch to create a delay between the point at which
+  // the packet is generated and the point at which it is filtered.  Note that
+  // if the saturators were connected directly, the link would be always
+  // available for the endpoint which has all of its packets dropped, resulting
+  // in saturator looping infinitely.
+  Switch network_switch(&simulator, "Switch", 8,
+                        bandwidth * base_propagation_delay * 10);
+  StrictMock<MockPacketFilter> a_to_b_filter(&simulator, "A -> B filter",
+                                             network_switch.port(1));
+  StrictMock<MockPacketFilter> b_to_a_filter(&simulator, "B -> A filter",
+                                             network_switch.port(2));
+  SymmetricLink link_a(&a_to_b_filter, &saturator_b, bandwidth,
+                       base_propagation_delay);
+  SymmetricLink link_b(&b_to_a_filter, &saturator_a, bandwidth,
+                       base_propagation_delay);
+
+  // Allow packets from A to B, but not from B to A.
+  EXPECT_CALL(a_to_b_filter, FilterPacket(_)).WillRepeatedly(Return(true));
+  EXPECT_CALL(b_to_a_filter, FilterPacket(_)).WillRepeatedly(Return(false));
+
+  // Run the simulation for a while, and expect that only B will receive any
+  // packets.
+  simulator.RunFor(QuicTime::Delta::FromSeconds(10));
+  EXPECT_GE(saturator_b.counter()->packets(), 1u);
+  EXPECT_EQ(saturator_a.counter()->packets(), 0u);
+}
+
+// Set up a traffic policer in one direction that throttles at 25% of link
+// bandwidth, and put two link saturators at each endpoint.
+TEST_F(SimulatorTest, TrafficPolicer) {
+  const QuicBandwidth bandwidth =
+      QuicBandwidth::FromBytesPerSecond(1024 * 1024);
+  const QuicTime::Delta base_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(5);
+  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
+
+  Simulator simulator;
+  LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2");
+  LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 1");
+  Switch network_switch(&simulator, "Switch", 8,
+                        bandwidth * base_propagation_delay * 10);
+
+  static const QuicByteCount initial_burst = 1000 * 10;
+  static const QuicByteCount max_bucket_size = 1000 * 100;
+  static const QuicBandwidth target_bandwidth = bandwidth * 0.25;
+  TrafficPolicer policer(&simulator, "Policer", initial_burst, max_bucket_size,
+                         target_bandwidth, network_switch.port(2));
+
+  SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth,
+                      base_propagation_delay);
+  SymmetricLink link2(&saturator2, &policer, bandwidth, base_propagation_delay);
+
+  // Ensure the initial burst passes without being dropped at all.
+  bool simulator_result = simulator.RunUntilOrTimeout(
+      [&saturator1]() {
+        return saturator1.bytes_transmitted() == initial_burst;
+      },
+      timeout);
+  ASSERT_TRUE(simulator_result);
+  saturator1.Pause();
+  simulator_result = simulator.RunUntilOrTimeout(
+      [&saturator2]() {
+        return saturator2.counter()->bytes() == initial_burst;
+      },
+      timeout);
+  ASSERT_TRUE(simulator_result);
+  saturator1.Resume();
+
+  // Run for some time so that the initial burst is not visible.
+  const QuicTime::Delta simulation_time = QuicTime::Delta::FromSeconds(10);
+  simulator.RunFor(simulation_time);
+
+  // Ensure we've transmitted the amount of data we expected.
+  for (auto* saturator : {&saturator1, &saturator2}) {
+    test::ExpectApproxEq(bandwidth * simulation_time,
+                         saturator->bytes_transmitted(), 0.01f);
+  }
+
+  // Check that only one direction is throttled.
+  test::ExpectApproxEq(saturator1.bytes_transmitted() / 4,
+                       saturator2.counter()->bytes(), 0.1f);
+  test::ExpectApproxEq(saturator2.bytes_transmitted(),
+                       saturator1.counter()->bytes(), 0.1f);
+}
+
+// Ensure that a larger burst is allowed when the policed saturator exits
+// quiescence.
+TEST_F(SimulatorTest, TrafficPolicerBurst) {
+  const QuicBandwidth bandwidth =
+      QuicBandwidth::FromBytesPerSecond(1024 * 1024);
+  const QuicTime::Delta base_propagation_delay =
+      QuicTime::Delta::FromMilliseconds(5);
+  const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
+
+  Simulator simulator;
+  LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2");
+  LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 1");
+  Switch network_switch(&simulator, "Switch", 8,
+                        bandwidth * base_propagation_delay * 10);
+
+  const QuicByteCount initial_burst = 1000 * 10;
+  const QuicByteCount max_bucket_size = 1000 * 100;
+  const QuicBandwidth target_bandwidth = bandwidth * 0.25;
+  TrafficPolicer policer(&simulator, "Policer", initial_burst, max_bucket_size,
+                         target_bandwidth, network_switch.port(2));
+
+  SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth,
+                      base_propagation_delay);
+  SymmetricLink link2(&saturator2, &policer, bandwidth, base_propagation_delay);
+
+  // Ensure at least one packet is sent on each side.
+  bool simulator_result = simulator.RunUntilOrTimeout(
+      [&saturator1, &saturator2]() {
+        return saturator1.packets_transmitted() > 0 &&
+               saturator2.packets_transmitted() > 0;
+      },
+      timeout);
+  ASSERT_TRUE(simulator_result);
+
+  // Wait until the bucket fills up.
+  saturator1.Pause();
+  saturator2.Pause();
+  simulator.RunFor(1.5f * target_bandwidth.TransferTime(max_bucket_size));
+
+  // Send a burst.
+  saturator1.Resume();
+  simulator.RunFor(bandwidth.TransferTime(max_bucket_size));
+  saturator1.Pause();
+  simulator.RunFor(2 * base_propagation_delay);
+
+  // Expect the burst to pass without losses.
+  test::ExpectApproxEq(saturator1.bytes_transmitted(),
+                       saturator2.counter()->bytes(), 0.1f);
+
+  // Expect subsequent traffic to be policed.
+  saturator1.Resume();
+  simulator.RunFor(QuicTime::Delta::FromSeconds(10));
+  test::ExpectApproxEq(saturator1.bytes_transmitted() / 4,
+                       saturator2.counter()->bytes(), 0.1f);
+}
+
+// Test that the packet aggregation support in queues work.
+TEST_F(SimulatorTest, PacketAggregation) {
+  // Model network where the delays are dominated by transfer delay.
+  const QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(1000);
+  const QuicTime::Delta base_propagation_delay =
+      QuicTime::Delta::FromMicroseconds(1);
+  const QuicByteCount aggregation_threshold = 1000;
+  const QuicTime::Delta aggregation_timeout = QuicTime::Delta::FromSeconds(30);
+
+  Simulator simulator;
+  LinkSaturator saturator1(&simulator, "Saturator 1", 10, "Saturator 2");
+  LinkSaturator saturator2(&simulator, "Saturator 2", 10, "Saturator 1");
+  Switch network_switch(&simulator, "Switch", 8, 10 * aggregation_threshold);
+
+  // Make links with asymmetric propagation delay so that Saturator 2 only
+  // receives packets addressed to it.
+  SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth,
+                      base_propagation_delay);
+  SymmetricLink link2(&saturator2, network_switch.port(2), bandwidth,
+                      2 * base_propagation_delay);
+
+  // Enable aggregation in 1 -> 2 direction.
+  Queue* queue = network_switch.port_queue(2);
+  queue->EnableAggregation(aggregation_threshold, aggregation_timeout);
+
+  // Enable aggregation in 2 -> 1 direction in a way that all packets are larger
+  // than the threshold, so that aggregation is effectively a no-op.
+  network_switch.port_queue(1)->EnableAggregation(5, aggregation_timeout);
+
+  // Fill up the aggregation buffer up to 90% (900 bytes).
+  simulator.RunFor(0.9 * bandwidth.TransferTime(aggregation_threshold));
+  EXPECT_EQ(0u, saturator2.counter()->bytes());
+
+  // Stop sending, ensure that given a timespan much shorter than timeout, the
+  // packets remain in the queue.
+  saturator1.Pause();
+  saturator2.Pause();
+  simulator.RunFor(QuicTime::Delta::FromSeconds(10));
+  EXPECT_EQ(0u, saturator2.counter()->bytes());
+  EXPECT_EQ(900u, queue->bytes_queued());
+
+  // Ensure that all packets have reached the saturator not affected by
+  // aggregation.  Here, 10 extra bytes account for a misrouted packet in the
+  // beginning.
+  EXPECT_EQ(910u, saturator1.counter()->bytes());
+
+  // Send 500 more bytes.  Since the aggregation threshold is 1000 bytes, and
+  // queue already has 900 bytes, 1000 bytes will be send and 400 will be in the
+  // queue.
+  saturator1.Resume();
+  simulator.RunFor(0.5 * bandwidth.TransferTime(aggregation_threshold));
+  saturator1.Pause();
+  simulator.RunFor(QuicTime::Delta::FromSeconds(10));
+  EXPECT_EQ(1000u, saturator2.counter()->bytes());
+  EXPECT_EQ(400u, queue->bytes_queued());
+
+  // Actually time out, and cause all of the data to be received.
+  simulator.RunFor(aggregation_timeout);
+  EXPECT_EQ(1400u, saturator2.counter()->bytes());
+  EXPECT_EQ(0u, queue->bytes_queued());
+
+  // Run saturator for a longer time, to ensure that the logic to cancel and
+  // reset alarms works correctly.
+  saturator1.Resume();
+  simulator.RunFor(5.5 * bandwidth.TransferTime(aggregation_threshold));
+  saturator1.Pause();
+  simulator.RunFor(QuicTime::Delta::FromSeconds(10));
+  EXPECT_EQ(6400u, saturator2.counter()->bytes());
+  EXPECT_EQ(500u, queue->bytes_queued());
+
+  // Time out again.
+  simulator.RunFor(aggregation_timeout);
+  EXPECT_EQ(6900u, saturator2.counter()->bytes());
+  EXPECT_EQ(0u, queue->bytes_queued());
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/switch.cc b/quic/test_tools/simulator/switch.cc
new file mode 100644
index 0000000..638fa20
--- /dev/null
+++ b/quic/test_tools/simulator/switch.cc
@@ -0,0 +1,85 @@
+// 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 <cinttypes>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
+
+namespace quic {
+namespace simulator {
+
+Switch::Switch(Simulator* simulator,
+               QuicString name,
+               SwitchPortNumber port_count,
+               QuicByteCount queue_capacity) {
+  for (size_t port_number = 1; port_number <= port_count; port_number++) {
+    ports_.emplace_back(simulator,
+                        QuicStrCat(name, " (port ", port_number, ")"), this,
+                        port_number, queue_capacity);
+  }
+}
+
+Switch::~Switch() {}
+
+Switch::Port::Port(Simulator* simulator,
+                   QuicString name,
+                   Switch* parent,
+                   SwitchPortNumber port_number,
+                   QuicByteCount queue_capacity)
+    : Endpoint(simulator, name),
+      parent_(parent),
+      port_number_(port_number),
+      connected_(false),
+      queue_(simulator,
+             QuicStringPrintf("%s (queue)", name.c_str()),
+             queue_capacity) {}
+
+void Switch::Port::AcceptPacket(std::unique_ptr<Packet> packet) {
+  parent_->DispatchPacket(port_number_, std::move(packet));
+}
+
+void Switch::Port::EnqueuePacket(std::unique_ptr<Packet> packet) {
+  queue_.AcceptPacket(std::move(packet));
+}
+
+UnconstrainedPortInterface* Switch::Port::GetRxPort() {
+  return this;
+}
+
+void Switch::Port::SetTxPort(ConstrainedPortInterface* port) {
+  queue_.set_tx_port(port);
+  connected_ = true;
+}
+
+void Switch::Port::Act() {}
+
+void Switch::DispatchPacket(SwitchPortNumber port_number,
+                            std::unique_ptr<Packet> packet) {
+  Port* source_port = &ports_[port_number - 1];
+  const auto source_mapping_it = switching_table_.find(packet->source);
+  if (source_mapping_it == switching_table_.end()) {
+    switching_table_.insert(std::make_pair(packet->source, source_port));
+  }
+
+  const auto destination_mapping_it =
+      switching_table_.find(packet->destination);
+  if (destination_mapping_it != switching_table_.end()) {
+    destination_mapping_it->second->EnqueuePacket(std::move(packet));
+    return;
+  }
+
+  // If no mapping is available yet, broadcast the packet to all ports
+  // different from the source.
+  for (Port& egress_port : ports_) {
+    if (!egress_port.connected()) {
+      continue;
+    }
+    egress_port.EnqueuePacket(QuicMakeUnique<Packet>(*packet));
+  }
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/switch.h b/quic/test_tools/simulator/switch.h
new file mode 100644
index 0000000..4956c01
--- /dev/null
+++ b/quic/test_tools/simulator/switch.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
+
+#include <deque>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/queue.h"
+
+namespace quic {
+namespace simulator {
+
+typedef size_t SwitchPortNumber;
+
+// Simulates a network switch with simple persistent learning scheme and queues
+// on every output port.
+class Switch {
+ public:
+  Switch(Simulator* simulator,
+         QuicString name,
+         SwitchPortNumber port_count,
+         QuicByteCount queue_capacity);
+  Switch(const Switch&) = delete;
+  Switch& operator=(const Switch&) = delete;
+  ~Switch();
+
+  // Returns Endpoint associated with the port under number |port_number|.  Just
+  // like on most real switches, port numbering starts with 1.
+  inline Endpoint* port(SwitchPortNumber port_number) {
+    DCHECK_NE(port_number, 0u);
+    return &ports_[port_number - 1];
+  }
+
+  inline Queue* port_queue(SwitchPortNumber port_number) {
+    return ports_[port_number - 1].queue();
+  }
+
+ private:
+  class Port : public Endpoint, public UnconstrainedPortInterface {
+   public:
+    Port(Simulator* simulator,
+         QuicString name,
+         Switch* parent,
+         SwitchPortNumber port_number,
+         QuicByteCount queue_capacity);
+    Port(Port&&) = delete;
+    Port(const Port&) = delete;
+    Port& operator=(const Port&) = delete;
+    ~Port() override {}
+
+    // Accepts packet to be routed into the switch.
+    void AcceptPacket(std::unique_ptr<Packet> packet) override;
+    // Enqueue packet to be routed out of the switch.
+    void EnqueuePacket(std::unique_ptr<Packet> packet);
+
+    UnconstrainedPortInterface* GetRxPort() override;
+    void SetTxPort(ConstrainedPortInterface* port) override;
+
+    void Act() override;
+
+    inline bool connected() const { return connected_; }
+    inline Queue* queue() { return &queue_; }
+
+   private:
+    Switch* parent_;
+    SwitchPortNumber port_number_;
+    bool connected_;
+
+    Queue queue_;
+  };
+
+  // Sends the packet to the appropriate port, or to all ports if the
+  // appropriate port is not known.
+  void DispatchPacket(SwitchPortNumber port_number,
+                      std::unique_ptr<Packet> packet);
+
+  // This can not be a QuicDeque since pointers into this are
+  // assumed to be stable.
+  std::deque<Port> ports_;
+  QuicUnorderedMap<QuicString, Port*> switching_table_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
diff --git a/quic/test_tools/simulator/traffic_policer.cc b/quic/test_tools/simulator/traffic_policer.cc
new file mode 100644
index 0000000..e416a7d
--- /dev/null
+++ b/quic/test_tools/simulator/traffic_policer.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2016 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/simulator/traffic_policer.h"
+
+#include <algorithm>
+
+namespace quic {
+namespace simulator {
+
+TrafficPolicer::TrafficPolicer(Simulator* simulator,
+                               QuicString name,
+                               QuicByteCount initial_bucket_size,
+                               QuicByteCount max_bucket_size,
+                               QuicBandwidth target_bandwidth,
+                               Endpoint* input)
+    : PacketFilter(simulator, name, input),
+      initial_bucket_size_(initial_bucket_size),
+      max_bucket_size_(max_bucket_size),
+      target_bandwidth_(target_bandwidth),
+      last_refill_time_(clock_->Now()) {}
+
+TrafficPolicer::~TrafficPolicer() {}
+
+void TrafficPolicer::Refill() {
+  QuicTime::Delta time_passed = clock_->Now() - last_refill_time_;
+  QuicByteCount refill_size = time_passed * target_bandwidth_;
+
+  for (auto& bucket : token_buckets_) {
+    bucket.second = std::min(bucket.second + refill_size, max_bucket_size_);
+  }
+
+  last_refill_time_ = clock_->Now();
+}
+
+bool TrafficPolicer::FilterPacket(const Packet& packet) {
+  // Refill existing buckets.
+  Refill();
+
+  // Create a new bucket if one does not exist.
+  if (token_buckets_.count(packet.destination) == 0) {
+    token_buckets_.insert(
+        std::make_pair(packet.destination, initial_bucket_size_));
+  }
+
+  auto bucket = token_buckets_.find(packet.destination);
+  DCHECK(bucket != token_buckets_.end());
+
+  // Silently drop the packet on the floor if out of tokens
+  if (bucket->second < packet.size) {
+    return false;
+  }
+
+  bucket->second -= packet.size;
+  return true;
+}
+
+}  // namespace simulator
+}  // namespace quic
diff --git a/quic/test_tools/simulator/traffic_policer.h b/quic/test_tools/simulator/traffic_policer.h
new file mode 100644
index 0000000..ee77576
--- /dev/null
+++ b/quic/test_tools/simulator/traffic_policer.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2016 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.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_TRAFFIC_POLICER_H_
+#define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_TRAFFIC_POLICER_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h"
+
+namespace quic {
+namespace simulator {
+
+// Traffic policer uses a token bucket to limit the bandwidth of the traffic
+// passing through.  It wraps around an input port and exposes an output port.
+// Only the traffic from input to the output is policed, so in case when
+// bidirectional policing is desired, two policers have to be used.  The flows
+// are hashed by the destination only.
+class TrafficPolicer : public PacketFilter {
+ public:
+  TrafficPolicer(Simulator* simulator,
+                 QuicString name,
+                 QuicByteCount initial_bucket_size,
+                 QuicByteCount max_bucket_size,
+                 QuicBandwidth target_bandwidth,
+                 Endpoint* input);
+  TrafficPolicer(const TrafficPolicer&) = delete;
+  TrafficPolicer& operator=(const TrafficPolicer&) = delete;
+  ~TrafficPolicer() override;
+
+ protected:
+  bool FilterPacket(const Packet& packet) override;
+
+ private:
+  // Refill the token buckets with all the tokens that have been granted since
+  // |last_refill_time_|.
+  void Refill();
+
+  QuicByteCount initial_bucket_size_;
+  QuicByteCount max_bucket_size_;
+  QuicBandwidth target_bandwidth_;
+
+  // The time at which the token buckets were last refilled.
+  QuicTime last_refill_time_;
+
+  // Maps each destination to the number of tokens it has left.
+  QuicUnorderedMap<QuicString, QuicByteCount> token_buckets_;
+};
+
+}  // namespace simulator
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_TRAFFIC_POLICER_H_