Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc
new file mode 100644
index 0000000..26ed335
--- /dev/null
+++ b/quic/core/quic_crypto_stream_test.cc
@@ -0,0 +1,518 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+using testing::_;
+using testing::InSequence;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+
+namespace quic {
+namespace test {
+namespace {
+
+class MockQuicCryptoStream : public QuicCryptoStream,
+                             public QuicCryptoHandshaker {
+ public:
+  explicit MockQuicCryptoStream(QuicSession* session)
+      : QuicCryptoStream(session),
+        QuicCryptoHandshaker(this, session),
+        params_(new QuicCryptoNegotiatedParameters) {}
+  MockQuicCryptoStream(const MockQuicCryptoStream&) = delete;
+  MockQuicCryptoStream& operator=(const MockQuicCryptoStream&) = delete;
+
+  void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
+    messages_.push_back(message);
+  }
+
+  std::vector<CryptoHandshakeMessage>* messages() { return &messages_; }
+
+  bool encryption_established() const override { return false; }
+  bool handshake_confirmed() const override { return false; }
+
+  const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
+      const override {
+    return *params_;
+  }
+  CryptoMessageParser* crypto_message_parser() override {
+    return QuicCryptoHandshaker::crypto_message_parser();
+  }
+
+ private:
+  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
+  std::vector<CryptoHandshakeMessage> messages_;
+};
+
+class QuicCryptoStreamTest : public QuicTest {
+ public:
+  QuicCryptoStreamTest()
+      : connection_(new MockQuicConnection(&helper_,
+                                           &alarm_factory_,
+                                           Perspective::IS_CLIENT)),
+        session_(connection_, /*create_mock_crypto_stream=*/false) {
+    stream_ = new MockQuicCryptoStream(&session_);
+    session_.SetCryptoStream(stream_);
+    session_.Initialize();
+    message_.set_tag(kSHLO);
+    message_.SetStringPiece(1, "abc");
+    message_.SetStringPiece(2, "def");
+    ConstructHandshakeMessage();
+  }
+  QuicCryptoStreamTest(const QuicCryptoStreamTest&) = delete;
+  QuicCryptoStreamTest& operator=(const QuicCryptoStreamTest&) = delete;
+
+  void ConstructHandshakeMessage() {
+    CryptoFramer framer;
+    message_data_.reset(framer.ConstructHandshakeMessage(message_));
+  }
+
+ protected:
+  MockQuicConnectionHelper helper_;
+  MockAlarmFactory alarm_factory_;
+  MockQuicConnection* connection_;
+  MockQuicSpdySession session_;
+  MockQuicCryptoStream* stream_;
+  CryptoHandshakeMessage message_;
+  std::unique_ptr<QuicData> message_data_;
+};
+
+TEST_F(QuicCryptoStreamTest, NotInitiallyConected) {
+  EXPECT_FALSE(stream_->encryption_established());
+  EXPECT_FALSE(stream_->handshake_confirmed());
+}
+
+TEST_F(QuicCryptoStreamTest, ProcessRawData) {
+  if (connection_->transport_version() < QUIC_VERSION_47) {
+    stream_->OnStreamFrame(QuicStreamFrame(
+        QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+        /*fin=*/false,
+        /*offset=*/0, message_data_->AsStringPiece()));
+  } else {
+    stream_->OnCryptoFrame(QuicCryptoFrame(ENCRYPTION_NONE, /*offset*/ 0,
+                                           message_data_->AsStringPiece()));
+  }
+  ASSERT_EQ(1u, stream_->messages()->size());
+  const CryptoHandshakeMessage& message = (*stream_->messages())[0];
+  EXPECT_EQ(kSHLO, message.tag());
+  EXPECT_EQ(2u, message.tag_value_map().size());
+  EXPECT_EQ("abc", crypto_test_utils::GetValueForTag(message, 1));
+  EXPECT_EQ("def", crypto_test_utils::GetValueForTag(message, 2));
+}
+
+TEST_F(QuicCryptoStreamTest, ProcessBadData) {
+  QuicString bad(message_data_->data(), message_data_->length());
+  const int kFirstTagIndex = sizeof(uint32_t) +  // message tag
+                             sizeof(uint16_t) +  // number of tag-value pairs
+                             sizeof(uint16_t);   // padding
+  EXPECT_EQ(1, bad[kFirstTagIndex]);
+  bad[kFirstTagIndex] = 0x7F;  // out of order tag
+
+  EXPECT_CALL(*connection_, CloseConnection(QUIC_CRYPTO_TAGS_OUT_OF_ORDER,
+                                            testing::_, testing::_));
+  if (connection_->transport_version() < QUIC_VERSION_47) {
+    stream_->OnStreamFrame(QuicStreamFrame(
+        QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+        /*fin=*/false, /*offset=*/0, bad));
+  } else {
+    stream_->OnCryptoFrame(QuicCryptoFrame(ENCRYPTION_NONE, /*offset*/ 0, bad));
+  }
+}
+
+TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) {
+  EXPECT_FALSE(
+      QuicStreamPeer::StreamContributesToConnectionFlowControl(stream_));
+}
+
+TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) {
+  if (connection_->transport_version() >= QUIC_VERSION_47) {
+    return;
+  }
+  InSequence s;
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 0, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->WriteOrBufferData(data, false, nullptr);
+  // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 1350, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->WriteOrBufferData(data, false, nullptr);
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  // Lost [0, 1000).
+  stream_->OnStreamFrameLost(0, 1000, false);
+  EXPECT_TRUE(stream_->HasPendingRetransmission());
+  // Lost [1200, 2000).
+  stream_->OnStreamFrameLost(1200, 800, false);
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1000, 0, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of
+  // they are in different encryption levels.
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 150, 1200, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 650, 1350, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->OnCanWrite();
+  EXPECT_FALSE(stream_->HasPendingRetransmission());
+  // Verify connection's encryption level has restored.
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+}
+
+TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) {
+  if (connection_->transport_version() < QUIC_VERSION_47) {
+    return;
+  }
+  EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+  InSequence s;
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+  // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  std::unique_ptr<NullEncrypter> encrypter =
+      QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT);
+  connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+  EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  // Lost [0, 1000).
+  QuicCryptoFrame lost_frame(ENCRYPTION_NONE, 0, 1000);
+  stream_->OnCryptoFrameLost(&lost_frame);
+  EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+  // Lost [1200, 2000).
+  lost_frame = QuicCryptoFrame(ENCRYPTION_NONE, 1200, 150);
+  stream_->OnCryptoFrameLost(&lost_frame);
+  lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650);
+  stream_->OnCryptoFrameLost(&lost_frame);
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1000, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of
+  // they are in different encryption levels.
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 150, 1200))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WritePendingCryptoRetransmission();
+  EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+  // Verify connection's encryption level has restored.
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+}
+
+TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) {
+  if (connection_->transport_version() >= QUIC_VERSION_47) {
+    return;
+  }
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 0, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->WriteOrBufferData(data, false, nullptr);
+  // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 1350, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->WriteOrBufferData(data, false, nullptr);
+
+  // Lost [0, 1350).
+  stream_->OnStreamFrameLost(0, 1350, false);
+  EXPECT_TRUE(stream_->HasPendingRetransmission());
+  // Neuters [0, 1350).
+  stream_->NeuterUnencryptedStreamData();
+  EXPECT_FALSE(stream_->HasPendingRetransmission());
+  // Lost [0, 1350) again.
+  stream_->OnStreamFrameLost(0, 1350, false);
+  EXPECT_FALSE(stream_->HasPendingRetransmission());
+
+  // Lost [1350, 2000).
+  stream_->OnStreamFrameLost(1350, 650, false);
+  EXPECT_TRUE(stream_->HasPendingRetransmission());
+  stream_->NeuterUnencryptedStreamData();
+  EXPECT_TRUE(stream_->HasPendingRetransmission());
+}
+
+TEST_F(QuicCryptoStreamTest, NeuterUnencryptedCryptoData) {
+  if (connection_->transport_version() < QUIC_VERSION_47) {
+    return;
+  }
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+  // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  std::unique_ptr<NullEncrypter> encrypter =
+      QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT);
+  connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+  EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+  EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+
+  // Lost [0, 1350).
+  QuicCryptoFrame lost_frame(ENCRYPTION_NONE, 0, 1350);
+  stream_->OnCryptoFrameLost(&lost_frame);
+  EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+  // Neuters [0, 1350).
+  stream_->NeuterUnencryptedStreamData();
+  EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+  // Lost [0, 1350) again.
+  stream_->OnCryptoFrameLost(&lost_frame);
+  EXPECT_FALSE(stream_->HasPendingCryptoRetransmission());
+
+  // Lost [1350, 2000), which starts at offset 0 at the ENCRYPTION_ZERO_RTT
+  // level.
+  lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650);
+  stream_->OnCryptoFrameLost(&lost_frame);
+  EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+  stream_->NeuterUnencryptedStreamData();
+  EXPECT_TRUE(stream_->HasPendingCryptoRetransmission());
+}
+
+TEST_F(QuicCryptoStreamTest, RetransmitStreamData) {
+  if (connection_->transport_version() >= QUIC_VERSION_47) {
+    return;
+  }
+  InSequence s;
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 0, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->WriteOrBufferData(data, false, nullptr);
+  // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 1350, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->WriteOrBufferData(data, false, nullptr);
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  // Ack [2000, 2500).
+  QuicByteCount newly_acked_length = 0;
+  stream_->OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero(),
+                              &newly_acked_length);
+  EXPECT_EQ(500u, newly_acked_length);
+
+  // Force crypto stream to send [1350, 2700) and only [1350, 1500) is consumed.
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 650, 1350, _))
+      .WillOnce(InvokeWithoutArgs([this]() {
+        return MockQuicSession::ConsumeData(
+            stream_,
+            QuicUtils::GetCryptoStreamId(connection_->transport_version()), 150,
+            1350, NO_FIN);
+      }));
+
+  EXPECT_FALSE(stream_->RetransmitStreamData(1350, 1350, false));
+  // Verify connection's encryption level has restored.
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  // Force session to send [1350, 1500) again and all data is consumed.
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 650, 1350, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 200, 2500, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  EXPECT_TRUE(stream_->RetransmitStreamData(1350, 1350, false));
+  // Verify connection's encryption level has restored.
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  EXPECT_CALL(session_, WritevData(_, _, _, _, _)).Times(0);
+  // Force to send an empty frame.
+  EXPECT_TRUE(stream_->RetransmitStreamData(0, 0, false));
+}
+
+TEST_F(QuicCryptoStreamTest, RetransmitStreamDataWithCryptoFrames) {
+  if (connection_->transport_version() < QUIC_VERSION_47) {
+    return;
+  }
+  InSequence s;
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+  // Send [1350, 2700) in ENCRYPTION_ZERO_RTT.
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT);
+  std::unique_ptr<NullEncrypter> encrypter =
+      QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT);
+  connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter));
+  EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level());
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data);
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  // Ack [2000, 2500).
+  QuicCryptoFrame acked_frame(ENCRYPTION_ZERO_RTT, 650, 500);
+  EXPECT_TRUE(
+      stream_->OnCryptoFrameAcked(acked_frame, QuicTime::Delta::Zero()));
+
+  // Retransmit only [1350, 1500).
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 150, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  QuicCryptoFrame frame_to_retransmit(ENCRYPTION_ZERO_RTT, 0, 150);
+  stream_->RetransmitData(&frame_to_retransmit);
+
+  // Verify connection's encryption level has restored.
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  // Retransmit [1350, 2700) again and all data is sent.
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 200, 1150))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  frame_to_retransmit = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 1350);
+  stream_->RetransmitData(&frame_to_retransmit);
+  // Verify connection's encryption level has restored.
+  EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level());
+
+  EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0);
+  // Force to send an empty frame.
+  QuicCryptoFrame empty_frame(ENCRYPTION_FORWARD_SECURE, 0, 0);
+  stream_->RetransmitData(&empty_frame);
+}
+
+// Regression test for b/115926584.
+TEST_F(QuicCryptoStreamTest, HasUnackedCryptoData) {
+  if (connection_->transport_version() >= QUIC_VERSION_47) {
+    return;
+  }
+  QuicString data(1350, 'a');
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 0, _))
+      .WillOnce(testing::Return(QuicConsumedData(0, false)));
+  stream_->WriteOrBufferData(data, false, nullptr);
+  EXPECT_FALSE(stream_->IsWaitingForAcks());
+  // Although there is no outstanding data, verify session has pending crypto
+  // data.
+  EXPECT_EQ(GetQuicReloadableFlag(quic_fix_has_pending_crypto_data),
+            session_.HasUnackedCryptoData());
+
+  EXPECT_CALL(
+      session_,
+      WritevData(_,
+                 QuicUtils::GetCryptoStreamId(connection_->transport_version()),
+                 1350, 0, _))
+      .WillOnce(Invoke(MockQuicSession::ConsumeData));
+  stream_->OnCanWrite();
+  EXPECT_TRUE(stream_->IsWaitingForAcks());
+  EXPECT_TRUE(session_.HasUnackedCryptoData());
+}
+
+TEST_F(QuicCryptoStreamTest, HasUnackedCryptoDataWithCryptoFrames) {
+  if (connection_->transport_version() < QUIC_VERSION_47) {
+    return;
+  }
+  // Send [0, 1350) in ENCRYPTION_NONE.
+  EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+  QuicString data(1350, 'a');
+  EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0))
+      .WillOnce(Invoke(connection_,
+                       &MockQuicConnection::QuicConnection_SendCryptoData));
+  stream_->WriteCryptoData(ENCRYPTION_NONE, data);
+  EXPECT_TRUE(stream_->IsWaitingForAcks());
+  EXPECT_TRUE(session_.HasUnackedCryptoData());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace quic