While sending PATH_CHALLENGE, make sure QuicConnection flushes probing packet on alternative path before bundling ACK.

Protected by quic_reloadable_flag_quic_not_bundle_ack_on_alternative_path.

PiperOrigin-RevId: 442816394
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 522c78e..ac4ad7c 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -14037,6 +14037,123 @@
   EXPECT_EQ(1u, connection_.GetStats().num_validated_peer_migration);
 }
 
+// Regression test of b/228645208.
+TEST_P(QuicConnectionTest, NoNonProbingFrameOnAlternativePath) {
+  if (!connection_.connection_migration_use_new_cid()) {
+    return;
+  }
+
+  PathProbeTestInit(Perspective::IS_SERVER);
+  SetClientConnectionId(TestConnectionId(1));
+  connection_.CreateConnectionIdManager();
+
+  QuicConnectionId server_cid0 = connection_.connection_id();
+  QuicConnectionId client_cid0 = connection_.client_connection_id();
+  QuicConnectionId client_cid1 = TestConnectionId(2);
+  QuicConnectionId server_cid1;
+  // Sends new server CID to client.
+  EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+      .WillOnce(
+          Invoke([&](const QuicConnectionId& cid) { server_cid1 = cid; }));
+  EXPECT_CALL(visitor_, SendNewConnectionId(_));
+  connection_.MaybeSendConnectionIdToClient();
+  // Receives new client CID from client.
+  QuicNewConnectionIdFrame new_cid_frame;
+  new_cid_frame.connection_id = client_cid1;
+  new_cid_frame.sequence_number = 1u;
+  new_cid_frame.retire_prior_to = 0u;
+  connection_.OnNewConnectionIdFrame(new_cid_frame);
+  auto* packet_creator = QuicConnectionPeer::GetPacketCreator(&connection_);
+  ASSERT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+  ASSERT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
+
+  peer_creator_.SetServerConnectionId(server_cid1);
+  const QuicSocketAddress kNewPeerAddress =
+      QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
+  QuicPathFrameBuffer path_challenge_payload{0, 1, 2, 3, 4, 5, 6, 7};
+  QuicFrames frames1;
+  frames1.push_back(
+      QuicFrame(QuicPathChallengeFrame(0, path_challenge_payload)));
+  QuicPathFrameBuffer payload;
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, NO_RETRANSMITTABLE_DATA))
+      .Times(AtLeast(1))
+      .WillOnce(Invoke([&]() {
+        EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+        EXPECT_EQ(kPeerAddress, connection_.peer_address());
+        EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+        EXPECT_FALSE(writer_->path_response_frames().empty());
+        EXPECT_FALSE(writer_->path_challenge_frames().empty());
+        payload = writer_->path_challenge_frames().front().data_buffer;
+      }));
+  ProcessFramesPacketWithAddresses(frames1, kSelfAddress, kNewPeerAddress,
+                                   ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(kPeerAddress, connection_.peer_address());
+  EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+  EXPECT_TRUE(connection_.HasPendingPathValidation());
+  const auto* default_path = QuicConnectionPeer::GetDefaultPath(&connection_);
+  const auto* alternative_path =
+      QuicConnectionPeer::GetAlternativePath(&connection_);
+  EXPECT_EQ(default_path->client_connection_id, client_cid0);
+  EXPECT_EQ(default_path->server_connection_id, server_cid0);
+  EXPECT_EQ(alternative_path->client_connection_id, client_cid1);
+  EXPECT_EQ(alternative_path->server_connection_id, server_cid1);
+  EXPECT_EQ(packet_creator->GetDestinationConnectionId(), client_cid0);
+  EXPECT_EQ(packet_creator->GetSourceConnectionId(), server_cid0);
+
+  // Process non-probing packets on the default path.
+  peer_creator_.SetServerConnectionId(server_cid0);
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).WillRepeatedly(Invoke([=]() {
+    EXPECT_EQ(kPeerAddress, connection_.peer_address());
+  }));
+  // Receives packets 3 - 39 to send 19 ACK-only packets, which will force the
+  // connection to reach |kMaxConsecutiveNonRetransmittablePackets| while
+  // sending the next ACK.
+  for (size_t i = 3; i <= 39; ++i) {
+    ProcessDataPacket(i);
+  }
+  EXPECT_EQ(kPeerAddress, connection_.peer_address());
+  EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+  EXPECT_TRUE(connection_.HasPendingAcks());
+  QuicTime ack_time = connection_.GetAckAlarm()->deadline();
+  QuicTime path_validation_retry_time =
+      connection_.GetRetryTimeout(kNewPeerAddress, writer_.get());
+  // Advance time to simultaneously fire path validation retry and ACK alarms.
+  clock_.AdvanceTime(std::max(ack_time, path_validation_retry_time) -
+                     clock_.ApproximateNow());
+
+  // The 20th ACK should bundle with a WINDOW_UPDATE frame.
+  EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame())
+      .WillOnce(Invoke([this]() {
+        connection_.SendControlFrame(QuicFrame(QuicWindowUpdateFrame(1, 0, 0)));
+      }));
+  if (GetQuicReloadableFlag(quic_not_bundle_ack_on_alternative_path)) {
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+        .WillOnce(Invoke([&]() {
+          EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address());
+          EXPECT_FALSE(writer_->path_challenge_frames().empty());
+          // Retry path validation shouldn't bundle ACK.
+          EXPECT_TRUE(writer_->ack_frames().empty());
+        }))
+        .WillOnce(Invoke([&]() {
+          EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address());
+          EXPECT_FALSE(writer_->ack_frames().empty());
+          EXPECT_FALSE(writer_->window_update_frames().empty());
+        }));
+    static_cast<TestAlarmFactory::TestAlarm*>(
+        QuicPathValidatorPeer::retry_timer(
+            QuicConnectionPeer::path_validator(&connection_)))
+        ->Fire();
+  } else {
+    EXPECT_QUIC_BUG(static_cast<TestAlarmFactory::TestAlarm*>(
+                        QuicPathValidatorPeer::retry_timer(
+                            QuicConnectionPeer::path_validator(&connection_)))
+                        ->Fire(),
+                    "quic_bug_12645_2");
+  }
+}
+
 TEST_P(QuicConnectionTest,
        ProbedOnAnotherPathAfterPeerIpAddressChangeAtServer) {
   PathProbeTestInit(Perspective::IS_SERVER);