Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/quartc/quartc_stream_test.cc b/quic/quartc/quartc_stream_test.cc
new file mode 100644
index 0000000..edb0ee0
--- /dev/null
+++ b/quic/quartc/quartc_stream_test.cc
@@ -0,0 +1,640 @@
+// Copyright (c) 2017 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/quartc/quartc_stream.h"
+
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
+#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.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/platform/api/quic_test_mem_slice_vector.h"
+#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
+
+namespace quic {
+
+namespace {
+
+static const QuicStreamId kStreamId = 5;
+
+// MockQuicSession that does not create streams and writes data from
+// QuicStream to a string.
+class MockQuicSession : public QuicSession {
+ public:
+  MockQuicSession(QuicConnection* connection,
+                  const QuicConfig& config,
+                  QuicString* write_buffer)
+      : QuicSession(connection,
+                    nullptr /*visitor*/,
+                    config,
+                    CurrentSupportedVersions()),
+        write_buffer_(write_buffer) {}
+
+  ~MockQuicSession() override {}
+
+  // Writes outgoing data from QuicStream to a string.
+  QuicConsumedData WritevData(QuicStream* stream,
+                              QuicStreamId id,
+                              size_t write_length,
+                              QuicStreamOffset offset,
+                              StreamSendingState state) override {
+    if (!writable_) {
+      return QuicConsumedData(0, false);
+    }
+
+    // WritevData does not pass down a iovec, data is saved in stream before
+    // data is consumed. Retrieve data from stream.
+    char* buf = new char[write_length];
+    QuicDataWriter writer(write_length, buf, NETWORK_BYTE_ORDER);
+    if (write_length > 0) {
+      stream->WriteStreamData(offset, write_length, &writer);
+    }
+    write_buffer_->append(buf, write_length);
+    delete[] buf;
+    return QuicConsumedData(write_length, state != StreamSendingState::NO_FIN);
+  }
+
+  QuartcStream* CreateIncomingStream(QuicStreamId id) override {
+    return nullptr;
+  }
+
+  QuartcStream* CreateIncomingStream(PendingStream pending) override {
+    return nullptr;
+  }
+
+  const QuicCryptoStream* GetCryptoStream() const override { return nullptr; }
+  QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; }
+  bool ShouldKeepConnectionAlive() const override {
+    return GetNumOpenDynamicStreams() > 0;
+  }
+
+  // Called by QuicStream when they want to close stream.
+  void SendRstStream(QuicStreamId id,
+                     QuicRstStreamErrorCode error,
+                     QuicStreamOffset bytes_written) override {}
+
+  // Sets whether data is written to buffer, or else if this is write blocked.
+  void set_writable(bool writable) { writable_ = writable; }
+
+  // Tracks whether the stream is write blocked and its priority.
+  void RegisterReliableStream(QuicStreamId stream_id,
+                              spdy::SpdyPriority priority) {
+    write_blocked_streams()->RegisterStream(stream_id,
+                                            /*is_static_stream=*/false,
+                                            priority);
+  }
+
+  // The session take ownership of the stream.
+  void ActivateReliableStream(std::unique_ptr<QuicStream> stream) {
+    ActivateStream(std::move(stream));
+  }
+
+ private:
+  // Stores written data from ReliableQuicStreamAdapter.
+  QuicString* write_buffer_;
+  // Whether data is written to write_buffer_.
+  bool writable_ = true;
+};
+
+// Packet writer that does nothing. This is required for QuicConnection but
+// isn't used for writing data.
+class DummyPacketWriter : public QuicPacketWriter {
+ public:
+  DummyPacketWriter() {}
+
+  // QuicPacketWriter overrides.
+  WriteResult WritePacket(const char* buffer,
+                          size_t buf_len,
+                          const QuicIpAddress& self_address,
+                          const QuicSocketAddress& peer_address,
+                          PerPacketOptions* options) override {
+    return WriteResult(WRITE_STATUS_ERROR, 0);
+  }
+
+  bool IsWriteBlocked() const override { return false; }
+
+  void SetWritable() override {}
+
+  QuicByteCount GetMaxPacketSize(
+      const QuicSocketAddress& peer_address) const override {
+    return 0;
+  }
+
+  bool SupportsReleaseTime() const override { return false; }
+
+  bool IsBatchMode() const override { return false; }
+
+  char* GetNextWriteLocation(const QuicIpAddress& self_address,
+                             const QuicSocketAddress& peer_address) override {
+    return nullptr;
+  }
+
+  WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
+};
+
+class MockQuartcStreamDelegate : public QuartcStream::Delegate {
+ public:
+  MockQuartcStreamDelegate(QuicStreamId id, QuicString* read_buffer)
+      : id_(id), read_buffer_(read_buffer) {}
+
+  void OnBufferChanged(QuartcStream* stream) override {
+    last_bytes_buffered_ = stream->BufferedDataBytes();
+    last_bytes_pending_retransmission_ = stream->BytesPendingRetransmission();
+  }
+
+  size_t OnReceived(QuartcStream* stream,
+                    iovec* iov,
+                    size_t iov_length,
+                    bool fin) override {
+    EXPECT_EQ(id_, stream->id());
+    EXPECT_EQ(stream->ReadOffset(), read_buffer_->size());
+    size_t bytes_consumed = 0;
+    for (size_t i = 0; i < iov_length; ++i) {
+      read_buffer_->append(static_cast<const char*>(iov[i].iov_base),
+                           iov[i].iov_len);
+      bytes_consumed += iov[i].iov_len;
+    }
+    return bytes_consumed;
+  }
+
+  void OnClose(QuartcStream* stream) override { closed_ = true; }
+
+  bool closed() { return closed_; }
+
+  QuicByteCount last_bytes_buffered() { return last_bytes_buffered_; }
+  QuicByteCount last_bytes_pending_retransmission() {
+    return last_bytes_pending_retransmission_;
+  }
+
+ protected:
+  QuicStreamId id_;
+  // Data read by the QuicStream.
+  QuicString* read_buffer_;
+  // Whether the QuicStream is closed.
+  bool closed_ = false;
+
+  // Last amount of data observed as buffered.
+  QuicByteCount last_bytes_buffered_ = 0;
+  QuicByteCount last_bytes_pending_retransmission_ = 0;
+};
+
+class QuartcStreamTest : public QuicTest, public QuicConnectionHelperInterface {
+ public:
+  QuartcStreamTest() {
+    // Required to correctly handle StopReading().
+    SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true);
+  }
+
+  ~QuartcStreamTest() override = default;
+
+  void CreateReliableQuicStream() {
+    // Arbitrary values for QuicConnection.
+    Perspective perspective = Perspective::IS_SERVER;
+    QuicIpAddress ip;
+    ip.FromString("0.0.0.0");
+    bool owns_writer = true;
+
+    alarm_factory_ = QuicMakeUnique<test::MockAlarmFactory>();
+
+    connection_ = QuicMakeUnique<QuicConnection>(
+        QuicUtils::CreateZeroConnectionId(
+            CurrentSupportedVersions()[0].transport_version),
+        QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
+        alarm_factory_.get(), new DummyPacketWriter(), owns_writer, perspective,
+        ParsedVersionOfIndex(CurrentSupportedVersions(), 0));
+    clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+    session_ = QuicMakeUnique<MockQuicSession>(connection_.get(), QuicConfig(),
+                                               &write_buffer_);
+    mock_stream_delegate_ =
+        QuicMakeUnique<MockQuartcStreamDelegate>(kStreamId, &read_buffer_);
+    stream_ = new QuartcStream(kStreamId, session_.get());
+    stream_->SetDelegate(mock_stream_delegate_.get());
+    session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_));
+  }
+
+  const QuicClock* GetClock() const override { return &clock_; }
+
+  QuicRandom* GetRandomGenerator() override {
+    return QuicRandom::GetInstance();
+  }
+
+  QuicBufferAllocator* GetStreamSendBufferAllocator() override {
+    return &buffer_allocator_;
+  }
+
+ protected:
+  // The QuicSession will take the ownership.
+  QuartcStream* stream_;
+  std::unique_ptr<MockQuartcStreamDelegate> mock_stream_delegate_;
+  std::unique_ptr<MockQuicSession> session_;
+  // Data written by the ReliableQuicStreamAdapterTest.
+  QuicString write_buffer_;
+  // Data read by the ReliableQuicStreamAdapterTest.
+  QuicString read_buffer_;
+  std::unique_ptr<QuicAlarmFactory> alarm_factory_;
+  std::unique_ptr<QuicConnection> connection_;
+  // Used to implement the QuicConnectionHelperInterface.
+  SimpleBufferAllocator buffer_allocator_;
+  MockClock clock_;
+};
+
+// Write an entire string.
+TEST_F(QuartcStreamTest, WriteDataWhole) {
+  CreateReliableQuicStream();
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+  EXPECT_EQ("Foo bar", write_buffer_);
+}
+
+// Write part of a string.
+TEST_F(QuartcStreamTest, WriteDataPartial) {
+  CreateReliableQuicStream();
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 5)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+  EXPECT_EQ("Foo b", write_buffer_);
+}
+
+// Test that a QuartcStream buffers writes correctly.
+TEST_F(QuartcStreamTest, StreamBuffersData) {
+  CreateReliableQuicStream();
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+
+  // The stream is not yet writable, so data will be buffered.
+  session_->set_writable(false);
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  // Check that data is buffered.
+  EXPECT_TRUE(stream_->HasBufferedData());
+  EXPECT_EQ(7u, stream_->BufferedDataBytes());
+
+  // Check that the stream told its delegate about the buffer change.
+  EXPECT_EQ(7u, mock_stream_delegate_->last_bytes_buffered());
+
+  // Check that none of the data was written yet.
+  // Note that |write_buffer_| actually holds data written by the QuicSession
+  // (not data buffered by the stream).
+  EXPECT_EQ(0ul, write_buffer_.size());
+
+  char message1[] = "xyzzy";
+  test::QuicTestMemSliceVector data1({std::make_pair(message1, 5)});
+
+  // More writes go into the buffer.
+  stream_->WriteMemSlices(data1.span(), /*fin=*/false);
+
+  EXPECT_TRUE(stream_->HasBufferedData());
+  EXPECT_EQ(12u, stream_->BufferedDataBytes());
+  EXPECT_EQ(12u, mock_stream_delegate_->last_bytes_buffered());
+  EXPECT_EQ(0ul, write_buffer_.size());
+
+  // The stream becomes writable, so it sends the buffered data.
+  session_->set_writable(true);
+  stream_->OnCanWrite();
+
+  EXPECT_FALSE(stream_->HasBufferedData());
+  EXPECT_EQ(0u, stream_->BufferedDataBytes());
+  EXPECT_EQ(0u, mock_stream_delegate_->last_bytes_buffered());
+  EXPECT_EQ("Foo barxyzzy", write_buffer_);
+}
+
+// Finish writing to a stream.
+// It delivers the fin bit and closes the write-side as soon as possible.
+TEST_F(QuartcStreamTest, FinishWriting) {
+  CreateReliableQuicStream();
+
+  session_->set_writable(false);
+  stream_->FinishWriting();
+  EXPECT_FALSE(stream_->fin_sent());
+
+  // Fin is sent as soon as the stream becomes writable.
+  session_->set_writable(true);
+  stream_->OnCanWrite();
+  EXPECT_TRUE(stream_->fin_sent());
+  EXPECT_TRUE(stream_->write_side_closed());
+}
+
+// Read an entire string.
+TEST_F(QuartcStreamTest, ReadDataWhole) {
+  CreateReliableQuicStream();
+  QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
+  stream_->OnStreamFrame(frame);
+
+  EXPECT_EQ("Hello, World!", read_buffer_);
+}
+
+// Read part of a string.
+TEST_F(QuartcStreamTest, ReadDataPartial) {
+  CreateReliableQuicStream();
+  QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
+  frame.data_length = 5;
+  stream_->OnStreamFrame(frame);
+
+  EXPECT_EQ("Hello", read_buffer_);
+}
+
+// Streams do not call OnReceived() after StopReading().
+// Note: this is tested here because Quartc relies on this behavior.
+TEST_F(QuartcStreamTest, StopReading) {
+  CreateReliableQuicStream();
+  stream_->StopReading();
+
+  QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
+  stream_->OnStreamFrame(frame);
+
+  EXPECT_EQ(0ul, read_buffer_.size());
+
+  QuicStreamFrame frame2(kStreamId, true, 0, "Hello, World!");
+  stream_->OnStreamFrame(frame2);
+
+  EXPECT_EQ(0ul, read_buffer_.size());
+  EXPECT_TRUE(stream_->fin_received());
+}
+
+// Test that closing the stream results in a callback.
+TEST_F(QuartcStreamTest, CloseStream) {
+  CreateReliableQuicStream();
+  EXPECT_FALSE(mock_stream_delegate_->closed());
+  stream_->OnClose();
+  EXPECT_TRUE(mock_stream_delegate_->closed());
+}
+
+// Both sending and receiving fin automatically closes a stream.
+TEST_F(QuartcStreamTest, CloseOnFins) {
+  CreateReliableQuicStream();
+  QuicStreamFrame frame(kStreamId, true, 0, 0);
+  stream_->OnStreamFrame(frame);
+
+  test::QuicTestMemSliceVector data({});
+  stream_->WriteMemSlices(data.span(), /*fin=*/true);
+
+  // Check that the OnClose() callback occurred.
+  EXPECT_TRUE(mock_stream_delegate_->closed());
+}
+
+TEST_F(QuartcStreamTest, TestCancelOnLossDisabled) {
+  CreateReliableQuicStream();
+
+  // This should be the default state.
+  EXPECT_FALSE(stream_->cancel_on_loss());
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR);
+}
+
+TEST_F(QuartcStreamTest, TestCancelOnLossEnabled) {
+  CreateReliableQuicStream();
+  stream_->set_cancel_on_loss(true);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED);
+}
+
+TEST_F(QuartcStreamTest, MaxRetransmissionsAbsent) {
+  CreateReliableQuicStream();
+
+  // This should be the default state.
+  EXPECT_EQ(stream_->max_retransmission_count(),
+            std::numeric_limits<int>::max());
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR);
+}
+
+TEST_F(QuartcStreamTest, MaxRetransmissionsSet) {
+  CreateReliableQuicStream();
+  stream_->set_max_retransmission_count(2);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED);
+}
+
+TEST_F(QuartcStreamTest, MaxRetransmissionsDisjointFrames) {
+  CreateReliableQuicStream();
+  stream_->set_max_retransmission_count(2);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  // Retransmit bytes [0, 3].
+  stream_->OnStreamFrameLost(0, 4, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo ", write_buffer_);
+
+  // Retransmit bytes [4, 6].  Everything has been retransmitted once.
+  stream_->OnStreamFrameLost(4, 3, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+
+  // Retransmit bytes [0, 6].  Everything can be retransmitted a second time.
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo barFoo bar", write_buffer_);
+}
+
+TEST_F(QuartcStreamTest, MaxRetransmissionsOverlappingFrames) {
+  CreateReliableQuicStream();
+  stream_->set_max_retransmission_count(2);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  // Retransmit bytes 0 to 3.
+  stream_->OnStreamFrameLost(0, 4, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo ", write_buffer_);
+
+  // Retransmit bytes 3 to 6.  Byte 3 has been retransmitted twice.
+  stream_->OnStreamFrameLost(3, 4, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo  bar", write_buffer_);
+
+  // Retransmit byte 3 a third time.  This should cause cancellation.
+  stream_->OnStreamFrameLost(3, 1, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo  bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED);
+}
+
+TEST_F(QuartcStreamTest, MaxRetransmissionsWithAckedFrame) {
+  CreateReliableQuicStream();
+  stream_->set_max_retransmission_count(1);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  // Retransmit bytes [0, 7).
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+
+  // Ack bytes [0, 7).  These bytes should be pruned from the data tracked by
+  // the stream.
+  QuicByteCount newly_acked_length = 0;
+  stream_->OnStreamFrameAcked(0, 7, false, QuicTime::Delta::FromMilliseconds(1),
+                              &newly_acked_length);
+  EXPECT_EQ(7u, newly_acked_length);
+  stream_->OnCanWrite();
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+
+  // Retransmit bytes [0, 7) again.
+  // QUIC will never mark frames as lost after they've been acked, but this lets
+  // us test that QuartcStream stopped tracking these bytes after the acked.
+  stream_->OnStreamFrameLost(0, 7, false);
+  stream_->OnCanWrite();
+
+  // QuartcStream should be cancelled, but it stopped tracking the lost bytes
+  // after they were acked, so it's not.
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR);
+}
+
+TEST_F(QuartcStreamTest, TestBytesPendingRetransmission) {
+  CreateReliableQuicStream();
+  stream_->set_cancel_on_loss(false);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 4, false);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 4u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 4u);
+
+  stream_->OnStreamFrameLost(4, 3, false);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 7u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 7u);
+
+  stream_->OnCanWrite();
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
+
+  EXPECT_EQ("Foo barFoo bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_NO_ERROR);
+}
+
+TEST_F(QuartcStreamTest, TestBytesPendingRetransmissionWithCancelOnLoss) {
+  CreateReliableQuicStream();
+  stream_->set_cancel_on_loss(true);
+
+  char message[] = "Foo bar";
+  test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+
+  stream_->OnStreamFrameLost(0, 4, false);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
+
+  stream_->OnStreamFrameLost(4, 3, false);
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
+
+  stream_->OnCanWrite();
+  EXPECT_EQ(stream_->BytesPendingRetransmission(), 0u);
+  EXPECT_EQ(mock_stream_delegate_->last_bytes_pending_retransmission(), 0u);
+
+  EXPECT_EQ("Foo bar", write_buffer_);
+  EXPECT_EQ(stream_->stream_error(), QUIC_STREAM_CANCELLED);
+}
+
+}  // namespace
+
+}  // namespace quic