Re-land cl/443493674 by fixing build error.
Original description: When retransmittable-on-wire timeout, re-send 1st 1-RTT packet or random bytes (which are behind client connection options ROWF and ROWR, respectively).
PiperOrigin-RevId: 443532932
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 97f69f3..b77cc15 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -1285,6 +1285,10 @@
void SimulateNextPacketTooLarge() { writer_->SimulateNextPacketTooLarge(); }
+ void ExpectNextPacketUnprocessable() {
+ writer_->ExpectNextPacketUnprocessable();
+ }
+
void AlwaysGetPacketTooLarge() { writer_->AlwaysGetPacketTooLarge(); }
void SetWritePauseTimeDelta(QuicTime::Delta delta) {
@@ -7646,6 +7650,150 @@
connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
}
+TEST_P(QuicConnectionTest, RetransmittableOnWireSendFirstPacket) {
+ if (!GetQuicReloadableFlag(quic_use_ping_manager) ||
+ !VersionHasIetfQuicFrames(connection_.version().transport_version)) {
+ return;
+ }
+ EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ const QuicTime::Delta kRetransmittableOnWireTimeout =
+ QuicTime::Delta::FromMilliseconds(200);
+ const QuicTime::Delta kTestRtt = QuicTime::Delta::FromMilliseconds(100);
+
+ connection_.set_initial_retransmittable_on_wire_timeout(
+ kRetransmittableOnWireTimeout);
+
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kROWF);
+ config.SetClientConnectionOptions(connection_options);
+ connection_.SetFromConfig(config);
+
+ // Send a request.
+ connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN);
+ // Receive an ACK after 1-RTT.
+ clock_.AdvanceTime(kTestRtt);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+ QuicAckFrame frame =
+ InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
+ ProcessAckPacket(&frame);
+ ASSERT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(kRetransmittableOnWireTimeout,
+ connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+ // Fire retransmittable-on-wire alarm.
+ clock_.AdvanceTime(kRetransmittableOnWireTimeout);
+ connection_.GetPingAlarm()->Fire();
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+ // Verify alarm is set in keep-alive mode.
+ ASSERT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
+ connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
+}
+
+TEST_P(QuicConnectionTest, RetransmittableOnWireSendRandomBytes) {
+ if (!GetQuicReloadableFlag(quic_use_ping_manager) ||
+ !VersionHasIetfQuicFrames(connection_.version().transport_version)) {
+ return;
+ }
+ EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ const QuicTime::Delta kRetransmittableOnWireTimeout =
+ QuicTime::Delta::FromMilliseconds(200);
+ const QuicTime::Delta kTestRtt = QuicTime::Delta::FromMilliseconds(100);
+
+ connection_.set_initial_retransmittable_on_wire_timeout(
+ kRetransmittableOnWireTimeout);
+
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kROWR);
+ config.SetClientConnectionOptions(connection_options);
+ connection_.SetFromConfig(config);
+
+ // Send a request.
+ connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN);
+ // Receive an ACK after 1-RTT.
+ clock_.AdvanceTime(kTestRtt);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+ QuicAckFrame frame =
+ InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
+ ProcessAckPacket(&frame);
+ ASSERT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(kRetransmittableOnWireTimeout,
+ connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+ // Fire retransmittable-on-wire alarm.
+ clock_.AdvanceTime(kRetransmittableOnWireTimeout);
+ // Next packet is not processable by the framer in the test writer.
+ ExpectNextPacketUnprocessable();
+ connection_.GetPingAlarm()->Fire();
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+ // Verify alarm is set in keep-alive mode.
+ ASSERT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
+ connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
+}
+
+TEST_P(QuicConnectionTest,
+ RetransmittableOnWireSendRandomBytesWithWriterBlocked) {
+ if (!GetQuicReloadableFlag(quic_use_ping_manager) ||
+ !VersionHasIetfQuicFrames(connection_.version().transport_version)) {
+ return;
+ }
+ EXPECT_CALL(visitor_, ShouldKeepConnectionAlive())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+
+ const QuicTime::Delta kRetransmittableOnWireTimeout =
+ QuicTime::Delta::FromMilliseconds(200);
+ const QuicTime::Delta kTestRtt = QuicTime::Delta::FromMilliseconds(100);
+
+ connection_.set_initial_retransmittable_on_wire_timeout(
+ kRetransmittableOnWireTimeout);
+
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kROWR);
+ config.SetClientConnectionOptions(connection_options);
+ connection_.SetFromConfig(config);
+
+ // Send a request.
+ connection_.SendStreamDataWithString(3, "foo", 0, NO_FIN);
+ // Receive an ACK after 1-RTT.
+ clock_.AdvanceTime(kTestRtt);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+ QuicAckFrame frame =
+ InitAckFrame({{QuicPacketNumber(1), QuicPacketNumber(2)}});
+ ProcessAckPacket(&frame);
+ ASSERT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(kRetransmittableOnWireTimeout,
+ connection_.GetPingAlarm()->deadline() - clock_.ApproximateNow());
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ // Receive an out of order data packet and block the ACK packet.
+ BlockOnNextWrite();
+ ProcessDataPacket(3);
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+
+ // Fire retransmittable-on-wire alarm.
+ clock_.AdvanceTime(kRetransmittableOnWireTimeout);
+ connection_.GetPingAlarm()->Fire();
+ // Verify the random bytes packet gets queued.
+ EXPECT_EQ(2u, connection_.NumQueuedPackets());
+}
+
// This test verifies that the connection marks path as degrading and does not
// spin timer to detect path degrading when a new packet is sent on the
// degraded path.