Add quic::test::GetFirstFlightOfPackets()

This CL adds GetFirstFlightOfPackets, a mechanism to extract
the first flight of packets from a QUIC connection. This will be
used to test code that parses the CHLO. This CL also adds various
test classes and methods that are used by GetFirstFlightOfPackets.

gfe-relnote: n/a, test-only
PiperOrigin-RevId: 307703986
Change-Id: Iedd17f41f1120d2be2188694710dcd698d61efc8
diff --git a/quic/test_tools/first_flight.cc b/quic/test_tools/first_flight.cc
new file mode 100644
index 0000000..e4d2816
--- /dev/null
+++ b/quic/test_tools/first_flight.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2020 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/first_flight.h"
+
+#include <memory>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.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_spdy_client_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+
+// Utility class that creates a custom HTTP/3 session and QUIC connection in
+// order to extract the first flight of packets it sends. This is meant to only
+// be used by GetFirstFlightOfPackets() below.
+class FirstFlightExtractor : public DelegatedPacketWriter::Delegate {
+ public:
+  FirstFlightExtractor(const ParsedQuicVersion& version,
+                       const QuicConfig& config,
+                       const QuicConnectionId& server_connection_id,
+                       const QuicConnectionId& client_connection_id)
+      : version_(version),
+        server_connection_id_(server_connection_id),
+        client_connection_id_(client_connection_id),
+        writer_(this),
+        config_(config),
+        crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {
+    EXPECT_NE(version_, UnsupportedQuicVersion());
+  }
+
+  void GenerateFirstFlight() {
+    crypto_config_.set_alpn(AlpnForVersion(version_));
+    connection_ =
+        new QuicConnection(server_connection_id_,
+                           QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+                           &connection_helper_, &alarm_factory_, &writer_,
+                           /*owns_writer=*/false, Perspective::IS_CLIENT,
+                           ParsedQuicVersionVector{version_});
+    connection_->set_client_connection_id(client_connection_id_);
+    session_ = std::make_unique<QuicSpdyClientSession>(
+        config_, ParsedQuicVersionVector{version_},
+        connection_,  // session_ takes ownership of connection_ here.
+        TestServerId(), &crypto_config_, &push_promise_index_);
+    session_->Initialize();
+    session_->CryptoConnect();
+  }
+
+  void OnDelegatedPacket(const char* buffer,
+                         size_t buf_len,
+                         const QuicIpAddress& /*self_client_address*/,
+                         const QuicSocketAddress& /*peer_client_address*/,
+                         PerPacketOptions* /*options*/) override {
+    packets_.emplace_back(
+        QuicReceivedPacket(buffer, buf_len,
+                           connection_helper_.GetClock()->ApproximateNow(),
+                           /*owns_buffer=*/false)
+            .Clone());
+  }
+
+  std::vector<std::unique_ptr<QuicReceivedPacket>>&& ConsumePackets() {
+    return std::move(packets_);
+  }
+
+ private:
+  ParsedQuicVersion version_;
+  QuicConnectionId server_connection_id_;
+  QuicConnectionId client_connection_id_;
+  MockQuicConnectionHelper connection_helper_;
+  MockAlarmFactory alarm_factory_;
+  DelegatedPacketWriter writer_;
+  QuicConfig config_;
+  QuicCryptoClientConfig crypto_config_;
+  QuicClientPushPromiseIndex push_promise_index_;
+  QuicConnection* connection_;  // Owned by session_.
+  std::unique_ptr<QuicSpdyClientSession> session_;
+  std::vector<std::unique_ptr<QuicReceivedPacket>> packets_;
+};
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConfig& config,
+    const QuicConnectionId& server_connection_id,
+    const QuicConnectionId& client_connection_id) {
+  FirstFlightExtractor first_flight_extractor(
+      version, config, server_connection_id, client_connection_id);
+  first_flight_extractor.GenerateFirstFlight();
+  return first_flight_extractor.ConsumePackets();
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConfig& config,
+    const QuicConnectionId& server_connection_id) {
+  return GetFirstFlightOfPackets(version, config, server_connection_id,
+                                 EmptyQuicConnectionId());
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConfig& config) {
+  return GetFirstFlightOfPackets(version, config, TestConnectionId());
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConnectionId& server_connection_id,
+    const QuicConnectionId& client_connection_id) {
+  return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
+                                 server_connection_id, client_connection_id);
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConnectionId& server_connection_id) {
+  return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
+                                 server_connection_id, EmptyQuicConnectionId());
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version) {
+  return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
+                                 TestConnectionId());
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/test_tools/first_flight.h b/quic/test_tools/first_flight.h
new file mode 100644
index 0000000..b2a4ebd
--- /dev/null
+++ b/quic/test_tools/first_flight.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2020 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_FIRST_FLIGHT_H_
+#define QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_
+
+#include <memory>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+
+namespace quic {
+namespace test {
+
+// Implementation of QuicPacketWriter that sends all packets to a delegate.
+class QUIC_NO_EXPORT DelegatedPacketWriter : public QuicPacketWriter {
+ public:
+  class QUIC_NO_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+    // Note that |buffer| may be released after this call completes so overrides
+    // that want to use the data after the call is complete MUST copy it.
+    virtual void OnDelegatedPacket(const char* buffer,
+                                   size_t buf_len,
+                                   const QuicIpAddress& self_client_address,
+                                   const QuicSocketAddress& peer_client_address,
+                                   PerPacketOptions* options) = 0;
+  };
+
+  // |delegate| MUST be valid for the duration of the DelegatedPacketWriter's
+  // lifetime.
+  explicit DelegatedPacketWriter(Delegate* delegate) : delegate_(delegate) {
+    CHECK_NE(delegate_, nullptr);
+  }
+
+  // Overrides for QuicPacketWriter.
+  bool IsWriteBlocked() const override { return false; }
+  void SetWritable() override {}
+  QuicByteCount GetMaxPacketSize(
+      const QuicSocketAddress& /*peer_address*/) const override {
+    return kMaxOutgoingPacketSize;
+  }
+  bool SupportsReleaseTime() const override { return false; }
+  bool IsBatchMode() const override { return false; }
+  char* GetNextWriteLocation(
+      const QuicIpAddress& /*self_address*/,
+      const QuicSocketAddress& /*peer_address*/) override {
+    return nullptr;
+  }
+  WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
+
+  WriteResult WritePacket(const char* buffer,
+                          size_t buf_len,
+                          const QuicIpAddress& self_client_address,
+                          const QuicSocketAddress& peer_client_address,
+                          PerPacketOptions* options) override {
+    delegate_->OnDelegatedPacket(buffer, buf_len, self_client_address,
+                                 peer_client_address, options);
+    return WriteResult(WRITE_STATUS_OK, buf_len);
+  }
+
+ private:
+  Delegate* delegate_;  // Unowned.
+};
+
+// Returns an array of packets that represent the first flight of a real
+// HTTP/3 connection. In most cases, this array will only contain one packet
+// that carries the CHLO.
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConfig& config,
+    const QuicConnectionId& server_connection_id,
+    const QuicConnectionId& client_connection_id);
+
+// Below are various convenience overloads that use default values for the
+// omitted parameters:
+// |config| = DefaultQuicConfig(),
+// |server_connection_id| = TestConnectionId(),
+// |client_connection_id| = EmptyQuicConnectionId().
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConfig& config,
+    const QuicConnectionId& server_connection_id);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConnectionId& server_connection_id,
+    const QuicConnectionId& client_connection_id);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConnectionId& server_connection_id);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version,
+    const QuicConfig& config);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+    const ParsedQuicVersion& version);
+
+}  // namespace test
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index 47fd05f..bb45ae3 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -17,13 +17,16 @@
 #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/http/quic_spdy_client_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.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_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.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/test_tools/crypto_test_utils.h"
@@ -74,6 +77,14 @@
   return quiche::QuicheEndian::NetToHost64(connection_id64_net);
 }
 
+std::string TestHostname() {
+  return "test.example.org";
+}
+
+QuicServerId TestServerId() {
+  return QuicServerId(TestHostname(), kTestPort);
+}
+
 QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) {
   DCHECK_GT(ack_blocks.size(), 0u);
 
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index b8e0eae..d70cbef 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -19,9 +19,11 @@
 #include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h"
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.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_server_id.h"
 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
@@ -56,6 +58,12 @@
   kInitialSessionFlowControlWindowForTest = 1536 * 1024,  // 1.5 MB
 };
 
+// A hostname useful for testing, returns "test.example.org".
+std::string TestHostname();
+
+// A server ID useful for testing, returns test.example.org:12345.
+QuicServerId TestServerId();
+
 // Returns the test peer IP address.
 QuicIpAddress TestPeerIPAddress();