Add a simple integration test for QuicTransport.

gfe-relnote: n/a (not used in production)
PiperOrigin-RevId: 276340873
Change-Id: Ie2caa7e6d5389f9170d79f0b2e471c36dbfbcbc2
diff --git a/quic/quic_transport/quic_transport_client_session.h b/quic/quic_transport/quic_transport_client_session.h
index a39f112..2e575e1 100644
--- a/quic/quic_transport/quic_transport_client_session.h
+++ b/quic/quic_transport/quic_transport_client_session.h
@@ -53,6 +53,10 @@
     return crypto_stream_.get();
   }
 
+  // Returns true once the encryption has been established and the client
+  // indication has been sent.  No application data will be read or written
+  // before the connection is ready.  Once the connection becomes ready, this
+  // method will never return false.
   bool IsSessionReady() const override { return ready_; }
 
   QuicStream* CreateIncomingStream(QuicStreamId id) override;
diff --git a/quic/quic_transport/quic_transport_integration_test.cc b/quic/quic_transport/quic_transport_integration_test.cc
new file mode 100644
index 0000000..f4c6a2a
--- /dev/null
+++ b/quic/quic_transport/quic_transport_integration_test.cc
@@ -0,0 +1,227 @@
+// 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.
+
+// An integration test that covers interactions between QuicTransport client and
+// server sessions.
+
+#include <memory>
+
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h"
+#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.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"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.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"
+
+namespace quic {
+namespace test {
+namespace {
+
+using simulator::QuicEndpointBase;
+using simulator::Simulator;
+using testing::_;
+using testing::Return;
+
+url::Origin GetTestOrigin() {
+  constexpr char kTestOrigin[] = "https://test-origin.test";
+  GURL origin_url(kTestOrigin);
+  return url::Origin::Create(origin_url);
+}
+
+ParsedQuicVersionVector GetVersions() {
+  return {ParsedQuicVersion{PROTOCOL_TLS1_3, QUIC_VERSION_99}};
+}
+
+class QuicTransportEndpointBase : public QuicEndpointBase {
+ public:
+  QuicTransportEndpointBase(Simulator* simulator,
+                            const std::string& name,
+                            const std::string& peer_name,
+                            Perspective perspective)
+      : QuicEndpointBase(simulator, name, peer_name) {
+    connection_ = std::make_unique<QuicConnection>(
+        TestConnectionId(0x10), simulator::GetAddressFromName(peer_name),
+        simulator, simulator->GetAlarmFactory(), &writer_,
+        /*owns_writer=*/false, perspective, GetVersions());
+    connection_->SetSelfAddress(simulator::GetAddressFromName(name));
+
+    SetQuicReloadableFlag(quic_supports_tls_handshake, true);
+  }
+};
+
+class QuicTransportClientEndpoint : public QuicTransportEndpointBase {
+ public:
+  QuicTransportClientEndpoint(Simulator* simulator,
+                              const std::string& name,
+                              const std::string& peer_name,
+                              url::Origin origin)
+      : QuicTransportEndpointBase(simulator,
+                                  name,
+                                  peer_name,
+                                  Perspective::IS_CLIENT),
+        crypto_config_(crypto_test_utils::ProofVerifierForTesting()),
+        session_(connection_.get(),
+                 nullptr,
+                 DefaultQuicConfig(),
+                 GetVersions(),
+                 QuicServerId("test.example.com", 443),
+                 &crypto_config_,
+                 origin) {
+    session_.Initialize();
+  }
+
+  QuicTransportClientSession* session() { return &session_; }
+
+ private:
+  QuicCryptoClientConfig crypto_config_;
+  QuicTransportClientSession session_;
+};
+
+class MockServerVisitor : public QuicTransportServerSession::ServerVisitor {
+ public:
+  MOCK_METHOD1(CheckOrigin, bool(url::Origin));
+};
+
+class QuicTransportServerEndpoint : public QuicTransportEndpointBase {
+ public:
+  QuicTransportServerEndpoint(Simulator* simulator,
+                              const std::string& name,
+                              const std::string& peer_name)
+      : QuicTransportEndpointBase(simulator,
+                                  name,
+                                  peer_name,
+                                  Perspective::IS_SERVER),
+        crypto_config_(QuicCryptoServerConfig::TESTING,
+                       QuicRandom::GetInstance(),
+                       crypto_test_utils::ProofSourceForTesting(),
+                       KeyExchangeSource::Default()),
+        compressed_certs_cache_(
+            QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
+        session_(connection_.get(),
+                 nullptr,
+                 DefaultQuicConfig(),
+                 GetVersions(),
+                 &crypto_config_,
+                 &compressed_certs_cache_,
+                 &visitor_) {
+    session_.Initialize();
+  }
+
+  QuicTransportServerSession* session() { return &session_; }
+  MockServerVisitor* visitor() { return &visitor_; }
+
+ private:
+  QuicCryptoServerConfig crypto_config_;
+  QuicCompressedCertsCache compressed_certs_cache_;
+  QuicTransportServerSession session_;
+  MockServerVisitor visitor_;
+};
+
+constexpr QuicBandwidth kClientBandwidth =
+    QuicBandwidth::FromKBitsPerSecond(10000);
+constexpr QuicTime::Delta kClientPropagationDelay =
+    QuicTime::Delta::FromMilliseconds(2);
+constexpr QuicBandwidth kServerBandwidth =
+    QuicBandwidth::FromKBitsPerSecond(4000);
+constexpr QuicTime::Delta kServerPropagationDelay =
+    QuicTime::Delta::FromMilliseconds(50);
+const QuicTime::Delta kTransferTime =
+    kClientBandwidth.TransferTime(kMaxOutgoingPacketSize) +
+    kServerBandwidth.TransferTime(kMaxOutgoingPacketSize);
+const QuicTime::Delta kRtt =
+    (kClientPropagationDelay + kServerPropagationDelay + kTransferTime) * 2;
+const QuicByteCount kBdp = kRtt * kServerBandwidth;
+
+constexpr QuicTime::Delta kHandshakeTimeout = QuicTime::Delta::FromSeconds(3);
+
+class QuicTransportIntegrationTest : public QuicTest {
+ public:
+  QuicTransportIntegrationTest()
+      : switch_(&simulator_, "Switch", 8, 2 * kBdp) {}
+
+  void CreateDefaultEndpoints() {
+    client_ = std::make_unique<QuicTransportClientEndpoint>(
+        &simulator_, "Client", "Server", GetTestOrigin());
+    server_ = std::make_unique<QuicTransportServerEndpoint>(&simulator_,
+                                                            "Server", "Client");
+    ON_CALL(*server_->visitor(), CheckOrigin(_)).WillByDefault(Return(true));
+  }
+
+  void WireUpEndpoints() {
+    client_link_ = std::make_unique<simulator::SymmetricLink>(
+        client_.get(), switch_.port(1), kClientBandwidth,
+        kClientPropagationDelay);
+    server_link_ = std::make_unique<simulator::SymmetricLink>(
+        server_.get(), switch_.port(2), kServerBandwidth,
+        kServerPropagationDelay);
+  }
+
+  void RunHandshake() {
+    client_->session()->CryptoConnect();
+    bool result = simulator_.RunUntilOrTimeout(
+        [this]() {
+          return IsHandshakeDone(client_->session()) &&
+                 IsHandshakeDone(server_->session());
+        },
+        kHandshakeTimeout);
+    EXPECT_TRUE(result);
+  }
+
+ protected:
+  template <class Session>
+  static bool IsHandshakeDone(const Session* session) {
+    return session->IsSessionReady() || session->error() != QUIC_NO_ERROR;
+  }
+
+  Simulator simulator_;
+  simulator::Switch switch_;
+  std::unique_ptr<simulator::SymmetricLink> client_link_;
+  std::unique_ptr<simulator::SymmetricLink> server_link_;
+
+  std::unique_ptr<QuicTransportClientEndpoint> client_;
+  std::unique_ptr<QuicTransportServerEndpoint> server_;
+};
+
+TEST_F(QuicTransportIntegrationTest, SuccessfulHandshake) {
+  CreateDefaultEndpoints();
+  WireUpEndpoints();
+  RunHandshake();
+  EXPECT_TRUE(client_->session()->IsSessionReady());
+  EXPECT_TRUE(server_->session()->IsSessionReady());
+}
+
+TEST_F(QuicTransportIntegrationTest, OriginMismatch) {
+  CreateDefaultEndpoints();
+  WireUpEndpoints();
+  EXPECT_CALL(*server_->visitor(), CheckOrigin(_))
+      .WillRepeatedly(Return(false));
+  RunHandshake();
+  // Wait until the client receives CONNECTION_CLOSE.
+  simulator_.RunUntilOrTimeout(
+      [this]() { return !client_->session()->connection()->connected(); },
+      kHandshakeTimeout);
+  EXPECT_TRUE(client_->session()->IsSessionReady());
+  EXPECT_FALSE(server_->session()->IsSessionReady());
+  EXPECT_FALSE(client_->session()->connection()->connected());
+  EXPECT_FALSE(server_->session()->connection()->connected());
+  EXPECT_EQ(client_->session()->error(),
+            QUIC_TRANSPORT_INVALID_CLIENT_INDICATION);
+  EXPECT_EQ(server_->session()->error(),
+            QUIC_TRANSPORT_INVALID_CLIENT_INDICATION);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace quic
diff --git a/quic/quic_transport/quic_transport_server_session.h b/quic/quic_transport/quic_transport_server_session.h
index b1a9043..c488775 100644
--- a/quic/quic_transport/quic_transport_server_session.h
+++ b/quic/quic_transport/quic_transport_server_session.h
@@ -49,6 +49,10 @@
     return crypto_stream_.get();
   }
 
+  // Returns true once the encryption has been established, the client
+  // indication has been received and the origin has been verified.  No
+  // application data will be read or written before the connection is ready.
+  // Once the connection becomes ready, this method will never return false.
   bool IsSessionReady() const override { return ready_; }
 
   QuicStream* CreateIncomingStream(QuicStreamId id) override;