Make sure there is pending timer credit when trying to retransmit packets in PTO mode.

Protected by FLAGS_quic_reloadable_flag_quic_fix_pto_pending_timer_count.

PiperOrigin-RevId: 331227032
Change-Id: Id7e072c9d9e8e40b7da935c879d69c6e05c3c852
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 7de6702..c5a4b9d 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -865,6 +865,8 @@
   void set_perspective(Perspective perspective) {
     writer()->set_perspective(perspective);
     QuicConnectionPeer::SetPerspective(this, perspective);
+    QuicSentPacketManagerPeer::SetPerspective(
+        QuicConnectionPeer::GetSentPacketManager(this), perspective);
   }
 
   // Enable path MTU discovery.  Assumes that the test is performed from the
@@ -1371,7 +1373,9 @@
     } else {
       frames.push_back(QuicFrame(frame1_));
     }
-    frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
+    if (level == ENCRYPTION_INITIAL) {
+      frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
+    }
     std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames);
     char buffer[kMaxOutgoingPacketSize];
     peer_creator_.set_encryption_level(level);
@@ -11857,6 +11861,90 @@
                   .empty());
 }
 
+// Regression test for b/168101557.
+TEST_P(QuicConnectionTest, HandshakeDataDoesNotGetPtoed) {
+  if (!connection_.SupportsMultiplePacketNumberSpaces() ||
+      !GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) {
+    return;
+  }
+  set_perspective(Perspective::IS_SERVER);
+  if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+    EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+  }
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+  use_tagging_decrypter();
+  ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+  EXPECT_TRUE(connection_.HasPendingAcks());
+
+  connection_.SetEncrypter(ENCRYPTION_INITIAL,
+                           std::make_unique<TaggingEncrypter>(0x01));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+  // Send INITIAL 1.
+  connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL);
+
+  connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+                           std::make_unique<TaggingEncrypter>(0x02));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+  SetDecrypter(ENCRYPTION_HANDSHAKE,
+               std::make_unique<StrictTaggingDecrypter>(0x02));
+  // Send HANDSHAKE packets.
+  EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+  connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE);
+
+  connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+                           std::make_unique<TaggingEncrypter>(0x03));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  // Send half RTT packet.
+  connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN);
+
+  // Receives HANDSHAKE 1.
+  peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+                            std::make_unique<TaggingEncrypter>(0x02));
+  ProcessCryptoPacketAtLevel(1, ENCRYPTION_HANDSHAKE);
+  // Discard INITIAL key.
+  connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+  connection_.NeuterUnencryptedPackets();
+  // Verify there is pending ACK.
+  ASSERT_TRUE(connection_.HasPendingAcks());
+  // Set the send alarm.
+  connection_.GetSendAlarm()->Set(clock_.ApproximateNow());
+
+  // Fire ACK alarm.
+  EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+  connection_.GetAckAlarm()->Fire();
+  if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) {
+    // Verify 1-RTT packet is coalesced with handshake packet.
+    EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+  } else {
+    // Verify handshake crypto frame is not bundled.
+    EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+    EXPECT_FALSE(writer_->ack_frames().empty());
+    EXPECT_TRUE(writer_->crypto_frames().empty());
+  }
+  connection_.GetSendAlarm()->Fire();
+
+  ASSERT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+  if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) {
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+  } else {
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(0);
+    EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() {
+      SendPing();
+    }));
+  }
+  connection_.GetRetransmissionAlarm()->Fire();
+  if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) {
+    // Verify a handshake packet gets PTOed and 1-RTT packet gets coalesced.
+    EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+  } else {
+    // Verify an 1-RTT PING gets sent because there is nothing to PTO, bummer,
+    // since this 1-RTT PING cannot be processed by peer and there is a
+    // deadlock.
+    EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
+    EXPECT_FALSE(writer_->ping_frames().empty());
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic