Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / tools / quic / end_to_end_test.cc
index a21dc40..0c86d03 100644 (file)
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_sent_packet_manager.h"
 #include "net/quic/quic_server_id.h"
+#include "net/quic/quic_utils.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/quic/test_tools/quic_flow_controller_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
 #include "net/quic/test_tools/quic_session_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
@@ -52,6 +54,7 @@ using net::EpollServer;
 using net::test::GenerateBody;
 using net::test::QuicConnectionPeer;
 using net::test::QuicFlowControllerPeer;
+using net::test::QuicSentPacketManagerPeer;
 using net::test::QuicSessionPeer;
 using net::test::ReliableQuicStreamPeer;
 using net::test::ValueRestore;
@@ -76,11 +79,15 @@ struct TestParams {
   TestParams(const QuicVersionVector& client_supported_versions,
              const QuicVersionVector& server_supported_versions,
              QuicVersion negotiated_version,
-             bool use_pacing)
+             bool use_pacing,
+             bool use_fec,
+             QuicTag congestion_control_tag)
       : client_supported_versions(client_supported_versions),
         server_supported_versions(server_supported_versions),
         negotiated_version(negotiated_version),
-        use_pacing(use_pacing) {
+        use_pacing(use_pacing),
+        use_fec(use_fec),
+        congestion_control_tag(congestion_control_tag) {
   }
 
   friend ostream& operator<<(ostream& os, const TestParams& p) {
@@ -89,7 +96,10 @@ struct TestParams {
     os << " client_supported_versions: "
        << QuicVersionVectorToString(p.client_supported_versions);
     os << " negotiated_version: " << QuicVersionToString(p.negotiated_version);
-    os << " use_pacing: " << p.use_pacing << " }";
+    os << " use_pacing: " << p.use_pacing;
+    os << " use_fec: " << p.use_fec;
+    os << " congestion_control_tag: "
+       << QuicUtils::TagToString(p.congestion_control_tag) << " }";
     return os;
   }
 
@@ -97,36 +107,53 @@ struct TestParams {
   QuicVersionVector server_supported_versions;
   QuicVersion negotiated_version;
   bool use_pacing;
+  bool use_fec;
+  QuicTag congestion_control_tag;
 };
 
 // Constructs various test permutations.
 vector<TestParams> GetTestParams() {
   vector<TestParams> params;
   QuicVersionVector all_supported_versions = QuicSupportedVersions();
-  for (int use_pacing = 0; use_pacing < 2; ++use_pacing) {
-    // Add an entry for server and client supporting all versions.
-    params.push_back(TestParams(all_supported_versions,
-                                all_supported_versions,
-                                all_supported_versions[0],
-                                use_pacing != 0));
-
-    // Test client supporting all versions and server supporting 1 version.
-    // Simulate an old server and exercise version downgrade in the client.
-    // Protocol negotiation should occur. Skip the i = 0 case because it is
-    // essentially the same as the default case.
-    for (size_t i = 1; i < all_supported_versions.size(); ++i) {
-      QuicVersionVector server_supported_versions;
-      server_supported_versions.push_back(all_supported_versions[i]);
-      if (all_supported_versions[i] >= QUIC_VERSION_17) {
-        // Until flow control is globally rolled out and we remove
-        // QUIC_VERSION_16, the server MUST support at least one QUIC version
-        // that does not use flow control.
-        server_supported_versions.push_back(QUIC_VERSION_16);
+  // TODO(rtenneti): Add kTBBR after BBR code is checked in.
+  // QuicTag congestion_control_tags[] = {kRENO, kTBBR, kQBIC};
+  QuicTag congestion_control_tags[] = {kRENO, kQBIC};
+  for (size_t congestion_control_index = 0;
+       congestion_control_index < arraysize(congestion_control_tags);
+       congestion_control_index++) {
+    QuicTag congestion_control_tag =
+        congestion_control_tags[congestion_control_index];
+    for (int use_fec = 0; use_fec < 2; ++use_fec) {
+      for (int use_pacing = 0; use_pacing < 2; ++use_pacing) {
+        // Add an entry for server and client supporting all versions.
+        params.push_back(TestParams(all_supported_versions,
+                                    all_supported_versions,
+                                    all_supported_versions[0],
+                                    use_pacing != 0,
+                                    use_fec != 0,
+                                    congestion_control_tag));
+
+        // Test client supporting all versions and server supporting 1 version.
+        // Simulate an old server and exercise version downgrade in the client.
+        // Protocol negotiation should occur. Skip the i = 0 case because it is
+        // essentially the same as the default case.
+        for (size_t i = 1; i < all_supported_versions.size(); ++i) {
+          QuicVersionVector server_supported_versions;
+          server_supported_versions.push_back(all_supported_versions[i]);
+          if (all_supported_versions[i] >= QUIC_VERSION_18) {
+            // Until flow control is globally rolled out and we remove
+            // QUIC_VERSION_16, the server MUST support at least one QUIC
+            // version that does not use flow control.
+            server_supported_versions.push_back(QUIC_VERSION_16);
+          }
+          params.push_back(TestParams(all_supported_versions,
+                                      server_supported_versions,
+                                      server_supported_versions[0],
+                                      use_pacing != 0,
+                                      use_fec != 0,
+                                      congestion_control_tag));
+        }
       }
-      params.push_back(TestParams(all_supported_versions,
-                                  server_supported_versions,
-                                  server_supported_versions[0],
-                                  use_pacing != 0));
     }
   }
   return params;
@@ -168,13 +195,8 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
     server_supported_versions_ = GetParam().server_supported_versions;
     negotiated_version_ = GetParam().negotiated_version;
     FLAGS_enable_quic_pacing = GetParam().use_pacing;
+    FLAGS_enable_quic_fec = GetParam().use_fec;
 
-    if (negotiated_version_ >= QUIC_VERSION_17) {
-      FLAGS_enable_quic_stream_flow_control_2 = true;
-    }
-    if (negotiated_version_ >= QUIC_VERSION_19) {
-      FLAGS_enable_quic_connection_flow_control_2 = true;
-    }
     VLOG(1) << "Using Configuration: " << GetParam();
 
     client_config_.SetDefaults();
@@ -259,11 +281,41 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
     server_config_.SetInitialSessionFlowControlWindowToSend(window);
   }
 
+  const QuicSentPacketManager *
+  GetSentPacketManagerFromFirstServerSession() const {
+    QuicDispatcher* dispatcher =
+        QuicServerPeer::GetDispatcher(server_thread_->server());
+    QuicSession* session = dispatcher->session_map().begin()->second;
+    return &session->connection()->sent_packet_manager();
+  }
+
   bool Initialize() {
+    QuicTagVector copt;
+
+    if (GetParam().use_pacing) {
+      copt.push_back(kPACE);
+    }
+    server_config_.SetConnectionOptionsToSend(copt);
+
+    // TODO(nimia): Consider setting the congestion control algorithm for the
+    // client as well according to the test parameter.
+    copt.push_back(GetParam().congestion_control_tag);
+
+    if (GetParam().use_fec) {
+      // Set FEC config in client's connection options and in client session.
+      copt.push_back(kFHDR);
+    }
+
+    client_config_.SetConnectionOptionsToSend(copt);
+
     // Start the server first, because CreateQuicClient() attempts
     // to connect to the server.
     StartServer();
     client_.reset(CreateQuicClient(client_writer_));
+    if (GetParam().use_fec) {
+      // Set FecPolicy to always protect data on all streams.
+      client_->SetFecPolicy(FEC_PROTECT_ALWAYS);
+    }
     static EpollEvent event(EPOLLOUT, false);
     client_writer_->Initialize(
         reinterpret_cast<QuicEpollConnectionHelper*>(
@@ -636,11 +688,11 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
 
   // The 0-RTT handshake should succeed.
   client_->Connect();
-  if (client_supported_versions_[0] >= QUIC_VERSION_17 &&
-      negotiated_version_ < QUIC_VERSION_17) {
+  if (client_supported_versions_[0] >= QUIC_VERSION_18 &&
+      negotiated_version_ <= QUIC_VERSION_16) {
     // If the version negotiation has resulted in a downgrade, then the client
     // must wait for the handshake to complete before sending any data.
-    // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a
+    // Otherwise it may have queued frames which will trigger a
     // DFATAL when they are serialized after the downgrade.
     client_->client()->WaitForCryptoHandshakeConfirmed();
   }
@@ -657,11 +709,11 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
   StartServer();
 
   client_->Connect();
-  if (client_supported_versions_[0] >= QUIC_VERSION_17 &&
-      negotiated_version_ < QUIC_VERSION_17) {
+  if (client_supported_versions_[0] >= QUIC_VERSION_18 &&
+      negotiated_version_ <= QUIC_VERSION_16) {
     // If the version negotiation has resulted in a downgrade, then the client
     // must wait for the handshake to complete before sending any data.
-    // Otherwise it may have queued QUIC_VERSION_17 frames which will trigger a
+    // Otherwise it may have queued frames which will trigger a
     // DFATAL when they are serialized after the downgrade.
     client_->client()->WaitForCryptoHandshakeConfirmed();
   }
@@ -671,30 +723,30 @@ TEST_P(EndToEndTest, DISABLED_LargePostZeroRTTFailure) {
   VerifyCleanConnection(false);
 }
 
-TEST_P(EndToEndTest, LargePostFEC) {
-  // Connect without packet loss to avoid issues with losing handshake packets,
-  // and then up the packet loss rate (b/10126687).
+TEST_P(EndToEndTest, CorrectlyConfiguredFec) {
   ASSERT_TRUE(Initialize());
-
-  // Wait for the server SHLO before upping the packet loss.
   client_->client()->WaitForCryptoHandshakeConfirmed();
-  SetPacketLossPercentage(30);
+  server_thread_->WaitForCryptoHandshakeConfirmed();
 
-  // Enable FEC protection.
-  QuicPacketCreator* creator = QuicConnectionPeer::GetPacketCreator(
-      client_->client()->session()->connection());
-  creator->set_max_packets_per_fec_group(3);
-  // Set FecPolicy to always protect data on all streams.
-  client_->SetFecPolicy(FEC_PROTECT_ALWAYS);
+  FecPolicy expected_policy =
+      GetParam().use_fec ? FEC_PROTECT_ALWAYS : FEC_PROTECT_OPTIONAL;
 
-  string body;
-  GenerateBody(&body, 10240);
+  // Verify that server's FEC configuration is correct.
+  server_thread_->Pause();
+  QuicDispatcher* dispatcher =
+      QuicServerPeer::GetDispatcher(server_thread_->server());
+  ASSERT_EQ(1u, dispatcher->session_map().size());
+  QuicSession* session = dispatcher->session_map().begin()->second;
+  EXPECT_EQ(expected_policy,
+            QuicSessionPeer::GetHeadersStream(session)->fec_policy());
+  server_thread_->Resume();
 
-  HTTPMessage request(HttpConstants::HTTP_1_1,
-                      HttpConstants::POST, "/foo");
-  request.AddBody(body, true);
-  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
-  VerifyCleanConnection(true);
+  // Verify that client's FEC configuration is correct.
+  EXPECT_EQ(expected_policy,
+            QuicSessionPeer::GetHeadersStream(
+                client_->client()->session())->fec_policy());
+  EXPECT_EQ(expected_policy,
+            client_->GetOrCreateStream()->fec_policy());
 }
 
 // TODO(shess): This is flaky on ChromiumOS bots.
@@ -848,6 +900,31 @@ TEST_P(EndToEndTest, NegotiateMaxOpenStreams) {
   EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
 }
 
+TEST_P(EndToEndTest, NegotiateCongestionControl) {
+  ASSERT_TRUE(Initialize());
+  client_->client()->WaitForCryptoHandshakeConfirmed();
+
+  CongestionControlType expected_congestion_control_type;
+  switch (GetParam().congestion_control_tag) {
+    case kRENO:
+      expected_congestion_control_type = kReno;
+      break;
+    case kTBBR:
+      expected_congestion_control_type = kBBR;
+      break;
+    case kQBIC:
+      expected_congestion_control_type = kCubic;
+      break;
+    default:
+      DLOG(FATAL) << "Unexpected congestion control tag";
+  }
+
+  EXPECT_EQ(expected_congestion_control_type,
+            QuicSentPacketManagerPeer::GetCongestionControlAlgorithm(
+                *GetSentPacketManagerFromFirstServerSession())
+            ->GetCongestionControlType());
+}
+
 TEST_P(EndToEndTest, LimitMaxOpenStreams) {
   // Server limits the number of max streams to 2.
   server_config_.set_max_streams_per_connection(2, 2);
@@ -877,11 +954,10 @@ TEST_P(EndToEndTest, DISABLED_LimitCongestionWindowAndRTT) {
   QuicDispatcher* dispatcher =
       QuicServerPeer::GetDispatcher(server_thread_->server());
   ASSERT_EQ(1u, dispatcher->session_map().size());
-  QuicSession* session = dispatcher->session_map().begin()->second;
   const QuicSentPacketManager& client_sent_packet_manager =
       client_->client()->session()->connection()->sent_packet_manager();
   const QuicSentPacketManager& server_sent_packet_manager =
-      session->connection()->sent_packet_manager();
+      *GetSentPacketManagerFromFirstServerSession();
 
   // The client shouldn't set it's initial window based on the negotiated value.
   EXPECT_EQ(kDefaultInitialWindow * kDefaultTCPMSS,
@@ -1074,11 +1150,12 @@ TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) {
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
 
-  scoped_ptr<WrongAddressWriter> writer(new WrongAddressWriter());
+  WrongAddressWriter* writer = new WrongAddressWriter();
 
   writer->set_writer(new QuicDefaultPacketWriter(client_->client()->fd()));
   QuicConnectionPeer::SetWriter(client_->client()->session()->connection(),
-                                writer.get());
+                                writer,
+                                true  /* owns_writer */);
 
   client_->SendSynchronousRequest("/bar");
 
@@ -1090,8 +1167,6 @@ TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) {
   // Tests that the client's port can change during an established QUIC
   // connection, and that doing so does not result in the connection being
   // closed by the server.
-  FLAGS_quic_allow_port_migration = true;
-
   ASSERT_TRUE(Initialize());
 
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
@@ -1237,6 +1312,81 @@ TEST_P(EndToEndTest, DifferentFlowControlWindowsQ020) {
   server_thread_->Resume();
 }
 
+TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
+  // The special headers and crypto streams should be subject to per-stream flow
+  // control limits, but should not be subject to connection level flow control.
+  const uint32 kStreamIFCW = 123456;
+  const uint32 kSessionIFCW = 234567;
+  set_client_initial_stream_flow_control_receive_window(kStreamIFCW);
+  set_client_initial_session_flow_control_receive_window(kSessionIFCW);
+  set_server_initial_stream_flow_control_receive_window(kStreamIFCW);
+  set_server_initial_session_flow_control_receive_window(kSessionIFCW);
+
+  ASSERT_TRUE(Initialize());
+  if (negotiated_version_ <= QUIC_VERSION_20) {
+    return;
+  }
+
+  // Wait for crypto handshake to finish. This should have contributed to the
+  // crypto stream flow control window, but not affected the session flow
+  // control window.
+  client_->client()->WaitForCryptoHandshakeConfirmed();
+  server_thread_->WaitForCryptoHandshakeConfirmed();
+
+  QuicCryptoStream* crypto_stream =
+      QuicSessionPeer::GetCryptoStream(client_->client()->session());
+  EXPECT_LT(
+      QuicFlowControllerPeer::SendWindowSize(crypto_stream->flow_controller()),
+      kStreamIFCW);
+  EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::SendWindowSize(
+                              client_->client()->session()->flow_controller()));
+
+  // Send a request with no body, and verify that the connection level window
+  // has not been affected.
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+
+  QuicHeadersStream* headers_stream =
+      QuicSessionPeer::GetHeadersStream(client_->client()->session());
+  EXPECT_LT(
+      QuicFlowControllerPeer::SendWindowSize(headers_stream->flow_controller()),
+      kStreamIFCW);
+  EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::SendWindowSize(
+                              client_->client()->session()->flow_controller()));
+
+  // Server should be in a similar state: connection flow control window should
+  // not have any bytes marked as received.
+  server_thread_->Pause();
+  QuicDispatcher* dispatcher =
+      QuicServerPeer::GetDispatcher(server_thread_->server());
+  QuicSession* session = dispatcher->session_map().begin()->second;
+  QuicFlowController* server_connection_flow_controller =
+      session->flow_controller();
+  EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::ReceiveWindowSize(
+      server_connection_flow_controller));
+  server_thread_->Resume();
+}
+
+TEST_P(EndToEndTest, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) {
+  // Regression test for b/16010251.
+  // A stream created on receipt of a simple request with no body will never get
+  // a stream frame with a FIN. Verify that we don't keep track of the stream in
+  // the locally closed streams map: it will never be removed if so.
+  ASSERT_TRUE(Initialize());
+
+  // Send a simple headers only request, and receive response.
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+  EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+
+  // Now verify that the server is not waiting for a final FIN or RST.
+  server_thread_->Pause();
+  QuicDispatcher* dispatcher =
+      QuicServerPeer::GetDispatcher(server_thread_->server());
+  QuicSession* session = dispatcher->session_map().begin()->second;
+  EXPECT_EQ(0u, QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(
+      session).size());
+  server_thread_->Resume();
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace tools