gfe-relnote: only respect TLPR when there is pending non-crypto stream data. Flag protected by quic_ignore_tlpr_if_no_pending_stream_data and session_decides_what_to_write.

When calculating the tail loss probe delay and TLPR option is enabled, only use half tail loss probe when session has pending stream data. Otherwise, ignore TLPR.

PiperOrigin-RevId: 253286073
Change-Id: I9321c9d0608f68bb4ec0f7f4fbba1e470e4a0a3c
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index cb51a3b..82bdd20 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -1061,6 +1061,7 @@
                void(const QuicFrames&, TransmissionType type));
   MOCK_CONST_METHOD1(IsFrameOutstanding, bool(const QuicFrame&));
   MOCK_CONST_METHOD0(HasUnackedCryptoData, bool());
+  MOCK_CONST_METHOD0(HasUnackedStreamData, bool());
 };
 
 // Creates a client session for testing.
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc
index c6e3801..624e4f7 100644
--- a/quic/test_tools/simple_session_notifier.cc
+++ b/quic/test_tools/simple_session_notifier.cc
@@ -434,6 +434,14 @@
   return !bytes_to_ack.Empty();
 }
 
+bool SimpleSessionNotifier::HasUnackedStreamData() const {
+  for (auto it : stream_map_) {
+    if (StreamIsWaitingForAcks(it.first))
+      return true;
+  }
+  return false;
+}
+
 bool SimpleSessionNotifier::OnControlFrameAcked(const QuicFrame& frame) {
   QuicControlFrameId id = GetControlFrameId(frame);
   if (id == kInvalidControlFrameId) {
diff --git a/quic/test_tools/simple_session_notifier.h b/quic/test_tools/simple_session_notifier.h
index 25c9941..aab3769 100644
--- a/quic/test_tools/simple_session_notifier.h
+++ b/quic/test_tools/simple_session_notifier.h
@@ -73,6 +73,7 @@
                         TransmissionType type) override;
   bool IsFrameOutstanding(const QuicFrame& frame) const override;
   bool HasUnackedCryptoData() const override;
+  bool HasUnackedStreamData() const override;
 
  private:
   struct StreamState {
diff --git a/quic/test_tools/simple_session_notifier_test.cc b/quic/test_tools/simple_session_notifier_test.cc
index d9958c8..8b931fe 100644
--- a/quic/test_tools/simple_session_notifier_test.cc
+++ b/quic/test_tools/simple_session_notifier_test.cc
@@ -88,6 +88,8 @@
   EXPECT_CALL(connection_, SendStreamData(5, 1024, 0, FIN))
       .WillOnce(Return(QuicConsumedData(1024, true)));
   notifier_.WriteOrBufferData(5, 1024, FIN);
+  EXPECT_TRUE(notifier_.StreamIsWaitingForAcks(5));
+  EXPECT_TRUE(notifier_.HasUnackedStreamData());
 
   // Reset stream 5 with no error.
   EXPECT_CALL(connection_, SendControlFrame(_))
@@ -96,10 +98,12 @@
   notifier_.WriteOrBufferRstStream(5, QUIC_STREAM_NO_ERROR, 1024);
   // Verify stream 5 is waiting for acks.
   EXPECT_TRUE(notifier_.StreamIsWaitingForAcks(5));
+  EXPECT_TRUE(notifier_.HasUnackedStreamData());
 
   // Reset stream 5 with error.
   notifier_.WriteOrBufferRstStream(5, QUIC_ERROR_PROCESSING_STREAM, 1024);
   EXPECT_FALSE(notifier_.StreamIsWaitingForAcks(5));
+  EXPECT_FALSE(notifier_.HasUnackedStreamData());
 }
 
 TEST_F(SimpleSessionNotifierTest, WriteOrBufferPing) {
@@ -158,10 +162,13 @@
                          QuicTime::Zero());
   EXPECT_TRUE(notifier_.StreamIsWaitingForAcks(
       QuicUtils::GetCryptoStreamId(connection_.transport_version())));
+  EXPECT_TRUE(notifier_.HasUnackedStreamData());
+
   // Neuters unencrypted data.
   notifier_.NeuterUnencryptedData();
   EXPECT_FALSE(notifier_.StreamIsWaitingForAcks(
       QuicUtils::GetCryptoStreamId(connection_.transport_version())));
+  EXPECT_FALSE(notifier_.HasUnackedStreamData());
 }
 
 TEST_F(SimpleSessionNotifierTest, OnCanWrite) {
@@ -178,6 +185,7 @@
   notifier_.WriteOrBufferData(
       QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024,
       NO_FIN);
+
   // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT.
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
   EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId(
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc
index ba9d206..872a9b2 100644
--- a/quic/test_tools/simulator/quic_endpoint.cc
+++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -293,6 +293,13 @@
   return false;
 }
 
+bool QuicEndpoint::HasUnackedStreamData() const {
+  if (notifier_ != nullptr) {
+    return notifier_->HasUnackedStreamData();
+  }
+  return false;
+}
+
 QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
     : endpoint_(endpoint), is_blocked_(false) {}
 
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
index 53bff3a..c547551 100644
--- a/quic/test_tools/simulator/quic_endpoint.h
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -130,6 +130,7 @@
                         TransmissionType type) override;
   bool IsFrameOutstanding(const QuicFrame& frame) const override;
   bool HasUnackedCryptoData() const override;
+  bool HasUnackedStreamData() const override;
   // End SessionNotifierInterface implementation.
 
  private: