gfe-relnote: If batch writer is used in a QuicConneciton, flush it right after a MTU probe is sent. Protected by --gfe2_reloadable_flag_quic_batch_writer_flush_after_mtu_probe.

PiperOrigin-RevId: 292547985
Change-Id: I14c3eab267c5d2a78c0fa742285910c7b1281161
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 7809cc5..8f02bbb 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -340,24 +340,7 @@
   TestPacketWriter(ParsedQuicVersion version, MockClock* clock)
       : version_(version),
         framer_(SupportedVersions(version_), Perspective::IS_SERVER),
-        last_packet_size_(0),
-        write_blocked_(false),
-        write_should_fail_(false),
-        block_on_next_flush_(false),
-        block_on_next_write_(false),
-        next_packet_too_large_(false),
-        always_get_packet_too_large_(false),
-        is_write_blocked_data_buffered_(false),
-        is_batch_mode_(false),
-        final_bytes_of_last_packet_(0),
-        final_bytes_of_previous_packet_(0),
-        use_tagging_decrypter_(false),
-        packets_write_attempts_(0),
-        connection_close_packets_(0),
-        clock_(clock),
-        write_pause_time_delta_(QuicTime::Delta::Zero()),
-        max_packet_size_(kMaxOutgoingPacketSize),
-        supports_release_time_(false) {
+        clock_(clock) {
     QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
                                                         TestConnectionId());
     framer_.framer()->SetInitialObfuscators(TestConnectionId());
@@ -430,6 +413,10 @@
     if (!write_pause_time_delta_.IsZero()) {
       clock_->AdvanceTime(write_pause_time_delta_);
     }
+    if (is_batch_mode_) {
+      bytes_buffered_ += last_packet_size_;
+      return WriteResult(WRITE_STATUS_OK, 0);
+    }
     return WriteResult(WRITE_STATUS_OK, last_packet_size_);
   }
 
@@ -459,12 +446,15 @@
   }
 
   WriteResult Flush() override {
+    flush_attempts_++;
     if (block_on_next_flush_) {
       block_on_next_flush_ = false;
       SetWriteBlocked();
       return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1);
     }
-    return WriteResult(WRITE_STATUS_OK, 0);
+    int bytes_flushed = bytes_buffered_;
+    bytes_buffered_ = 0;
+    return WriteResult(WRITE_STATUS_OK, bytes_flushed);
   }
 
   void BlockOnNextFlush() { block_on_next_flush_ = true; }
@@ -572,7 +562,9 @@
 
   void use_tagging_decrypter() { use_tagging_decrypter_ = true; }
 
-  uint32_t packets_write_attempts() { return packets_write_attempts_; }
+  uint32_t packets_write_attempts() const { return packets_write_attempts_; }
+
+  uint32_t flush_attempts() const { return flush_attempts_; }
 
   uint32_t connection_close_packets() const {
     return connection_close_packets_;
@@ -597,27 +589,32 @@
  private:
   ParsedQuicVersion version_;
   SimpleQuicFramer framer_;
-  size_t last_packet_size_;
+  size_t last_packet_size_ = 0;
   QuicPacketHeader last_packet_header_;
-  bool write_blocked_;
-  bool write_should_fail_;
-  bool block_on_next_flush_;
-  bool block_on_next_write_;
-  bool next_packet_too_large_;
-  bool always_get_packet_too_large_;
-  bool is_write_blocked_data_buffered_;
-  bool is_batch_mode_;
-  uint32_t final_bytes_of_last_packet_;
-  uint32_t final_bytes_of_previous_packet_;
-  bool use_tagging_decrypter_;
-  uint32_t packets_write_attempts_;
-  uint32_t connection_close_packets_;
-  MockClock* clock_;
+  bool write_blocked_ = false;
+  bool write_should_fail_ = false;
+  bool block_on_next_flush_ = false;
+  bool block_on_next_write_ = false;
+  bool next_packet_too_large_ = false;
+  bool always_get_packet_too_large_ = false;
+  bool is_write_blocked_data_buffered_ = false;
+  bool is_batch_mode_ = false;
+  // Number of times Flush() was called.
+  uint32_t flush_attempts_ = 0;
+  // (Batch mode only) Number of bytes buffered in writer. It is used as the
+  // return value of a successful Flush().
+  uint32_t bytes_buffered_ = 0;
+  uint32_t final_bytes_of_last_packet_ = 0;
+  uint32_t final_bytes_of_previous_packet_ = 0;
+  bool use_tagging_decrypter_ = false;
+  uint32_t packets_write_attempts_ = 0;
+  uint32_t connection_close_packets_ = 0;
+  MockClock* clock_ = nullptr;
   // If non-zero, the clock will pause during WritePacket for this amount of
   // time.
-  QuicTime::Delta write_pause_time_delta_;
-  QuicByteCount max_packet_size_;
-  bool supports_release_time_;
+  QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero();
+  QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize;
+  bool supports_release_time_ = false;
 };
 
 class TestConnection : public QuicConnection {
@@ -4836,6 +4833,25 @@
   EXPECT_EQ(QuicPacketNumber(4u), creator_->packet_number());
 }
 
+// Verifies that when a MTU probe packet is sent and buffered in a batch writer,
+// the writer is flushed immediately.
+TEST_P(QuicConnectionTest, BatchWriterFlushedAfterMtuDiscoveryPacket) {
+  writer_->SetBatchMode(true);
+  MtuDiscoveryTestInit();
+
+  // Send an MTU probe.
+  const size_t target_mtu = kDefaultMaxPacketSize + 100;
+  QuicByteCount mtu_probe_size;
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(SaveArg<3>(&mtu_probe_size));
+  const uint32_t prior_flush_attempts = writer_->flush_attempts();
+  connection_.SendMtuDiscoveryPacket(target_mtu);
+  EXPECT_EQ(target_mtu, mtu_probe_size);
+  if (GetQuicReloadableFlag(quic_batch_writer_flush_after_mtu_probe)) {
+    EXPECT_EQ(writer_->flush_attempts(), prior_flush_attempts + 1);
+  }
+}
+
 // Tests whether MTU discovery does not happen when it is not explicitly enabled
 // by the connection options.
 TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) {