src/net/quic/quic_network_transaction_unittest.cc
// This test verifies that a new QUIC connection will be attempted on the
// alternate network if the original QUIC connection fails with idle timeout
// before handshake is confirmed.  If TCP succeeds and QUIC fails on the
// alternate network as well, QUIC is marked as broken and the brokenness will
// not expire when default network changes.
This test verifies that a new QUIC connection will be attempted on the
alternate network if the original QUIC connection fails with idle timeout
before handshake is confirmed.  If TCP succeeds and QUIC fails on the
alternate network as well, QUIC is marked as broken and the brokenness will
not expire when default network changes.
This test verifies that a new QUIC connection will be attempted on the alternate network if the original QUIC connection fails with idle timeout before handshake is confirmed . If TCP succeeds and QUIC fails on the alternate network as well QUIC is marked as broken and the brokenness will not expire when default network changes .
TEST_P(QuicNetworkTransactionTest, QuicFailsOnBothNetworksWhileTCPSucceeds) {
  if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) {
    return;
  }
  SetUpTestForRetryConnectionOnAlternateNetwork();
  client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
  MockQuicData quic_data(version_);
  quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  
  int packet_num = 1;
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));  
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeConnectionClosePacket(
                         packet_num++, true, quic::QUIC_NETWORK_IDLE_TIMEOUT,
                         "No recent network activity after 4s. Timeout:4s"));
  quic_data.AddSocketDataToFactory(&socket_factory_);
  MockWrite http_writes[] = {
      MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
      MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"),
      MockWrite(SYNCHRONOUS, 2, "Connection: keep-alive\r\n\r\n")};
  MockRead http_reads[] = {
      MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"),
      MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader),
      MockRead(SYNCHRONOUS, 5, "TCP succeeds"), MockRead(SYNCHRONOUS, OK, 6)};
  SequencedSocketData http_data(http_reads, http_writes);
  socket_factory_.AddSocketDataProvider(&http_data);
  socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
  MockQuicData quic_data2(version_);
  quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
  quic_data2.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE);  
  quic_data2.AddSocketDataToFactory(&socket_factory_);
  host_resolver_.set_synchronous_mode(true);
  host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
                                           "");
  CreateSession();
  session_->quic_stream_factory()->set_is_quic_known_to_work_on_current_network(
      false);
  QuicStreamFactoryPeer::SetAlarmFactory(
      session_->quic_stream_factory(),
      std::make_unique<QuicChromiumAlarmFactory>(quic_task_runner_.get(),
                                                 context_.clock()));
  AddQuicAlternateProtocolMapping(
      MockCryptoClientStream::COLD_START_WITH_CHLO_SENT);
  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback callback;
  int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
  base::RunLoop().RunUntilIdle();
  EXPECT_THAT(callback.WaitForResult(), IsOk());
  CheckResponseData(&trans, "TCP succeeds");
  quic_task_runner_->FastForwardBy(quic::QuicTime::Delta::FromSeconds(4));
  ASSERT_TRUE(quic_data.AllReadDataConsumed());
  ASSERT_TRUE(quic_data.AllWriteDataConsumed());
  base::RunLoop().RunUntilIdle();
  ExpectBrokenAlternateProtocolMapping();
  scoped_mock_change_notifier_->mock_network_change_notifier()
      ->NotifyNetworkMadeDefault(kNewNetworkForTests);
  ExpectBrokenAlternateProtocolMapping();
  ASSERT_TRUE(quic_data2.AllReadDataConsumed());
  ASSERT_TRUE(quic_data2.AllWriteDataConsumed());
}
TEST_P ( QuicNetworkTransactionTest , QuicFailsOnBothNetworksWhileTCPSucceeds ) { if ( version_ . handshake_protocol == quic :: PROTOCOL_TLS1_3 ) { return ; } SetUpTestForRetryConnectionOnAlternateNetwork ( ) ; client_maker_ -> SetEncryptionLevel ( quic :: ENCRYPTION_ZERO_RTT ) ; MockQuicData quic_data ( version_ ) ; quic_data . AddRead ( SYNCHRONOUS , ERR_IO_PENDING ) ; int packet_num = 1 ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeConnectionClosePacket ( packet_num ++ , true , quic :: QUIC_NETWORK_IDLE_TIMEOUT , " " ) ) ; quic_data . AddSocketDataToFactory ( & socket_factory_ ) ; MockWrite http_writes [ ] = { MockWrite ( SYNCHRONOUS , 0 , " \r \n " ) , MockWrite ( SYNCHRONOUS , 1 , " \r \n " ) , MockWrite ( SYNCHRONOUS , 2 , " \r \n \r \n " ) } ; MockRead http_reads [ ] = { MockRead ( SYNCHRONOUS , 3 , " \r \n " ) , MockRead ( SYNCHRONOUS , 4 , kQuicAlternativeServiceHeader ) , MockRead ( SYNCHRONOUS , 5 , " " ) , MockRead ( SYNCHRONOUS , OK , 6 ) } ; SequencedSocketData http_data ( http_reads , http_writes ) ; socket_factory_ . AddSocketDataProvider ( & http_data ) ; socket_factory_ . AddSSLSocketDataProvider ( & ssl_data_ ) ; MockQuicData quic_data2 ( version_ ) ; quic_data2 . AddRead ( SYNCHRONOUS , ERR_IO_PENDING ) ; quic_data2 . AddWrite ( SYNCHRONOUS , ERR_ADDRESS_UNREACHABLE ) ; quic_data2 . AddSocketDataToFactory ( & socket_factory_ ) ; host_resolver_ . set_synchronous_mode ( true ) ; host_resolver_ . rules ( ) -> AddIPLiteralRule ( " " , " " , " " ) ; CreateSession ( ) ; session_ -> quic_stream_factory ( ) -> set_is_quic_known_to_work_on_current_network ( false ) ; QuicStreamFactoryPeer :: SetAlarmFactory ( session_ -> quic_stream_factory ( ) , std :: make_unique < QuicChromiumAlarmFactory > ( quic_task_runner_ . get ( ) , context_ . clock ( ) ) ) ; AddQuicAlternateProtocolMapping ( MockCryptoClientStream :: COLD_START_WITH_CHLO_SENT ) ; HttpNetworkTransaction trans ( DEFAULT_PRIORITY , session_ . get ( ) ) ; TestCompletionCallback callback ; int rv = trans . Start ( & request_ , callback . callback ( ) , net_log_ . bound ( ) ) ; EXPECT_THAT ( rv , IsError ( ERR_IO_PENDING ) ) ; base :: RunLoop ( ) . RunUntilIdle ( ) ; EXPECT_THAT ( callback . WaitForResult ( ) , IsOk ( ) ) ; CheckResponseData ( & trans , " " ) ; quic_task_runner_ -> FastForwardBy ( quic :: QuicTime :: Delta :: FromSeconds ( 4 ) ) ; ASSERT_TRUE ( quic_data . AllReadDataConsumed ( ) ) ; ASSERT_TRUE ( quic_data . AllWriteDataConsumed ( ) ) ; base :: RunLoop ( ) . RunUntilIdle ( ) ; ExpectBrokenAlternateProtocolMapping ( ) ; scoped_mock_change_notifier_ -> mock_network_change_notifier ( ) -> NotifyNetworkMadeDefault ( kNewNetworkForTests ) ; ExpectBrokenAlternateProtocolMapping ( ) ; ASSERT_TRUE ( quic_data2 . AllReadDataConsumed ( ) ) ; ASSERT_TRUE ( quic_data2 . AllWriteDataConsumed ( ) ) ; }
This test verifies that a new QUIC connection will be attempted on the
alternate network if the original QUIC connection fails with idle timeout
before handshake is confirmed.
This test verifies that a new QUIC connection will be attempted on the alternate network if the original QUIC connection fails with idle timeout before handshake is confirmed .
// QUIC with TLS1.3 handshake doesn't support 0-rtt. // The request will initially go out over QUIC. // Hanging read // CHLO // Retranmit the handshake messages. // After timeout, connection will be closed with QUIC_NETWORK_IDLE_TIMEOUT. // Add successful TCP data so that TCP job will succeed. // Add data for the second QUIC connection to fail. // Write error. // Resolve the host resolution synchronously. // Use a TestTaskRunner to avoid waiting in real time for timeouts. // Add alternate protocol mapping to race QUIC and TCP. // QUIC connection requires handshake to be confirmed and sends CHLO to the // peer. // Pump the message loop to get the request started. // Request will be served with TCP job. // Fast forward to idle timeout the original connection. A new connection will // be kicked off on the alternate network. // Run the message loop to execute posted tasks, which will report job status. // Verify that QUIC is marked as broken. // Deliver a message to notify the new network becomes default, the brokenness // will not expire as QUIC is broken on both networks.