| // 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 "quic/core/quic_stream_send_buffer.h" |
| |
| #include <string> |
| |
| #include "absl/strings/string_view.h" |
| #include "quic/core/quic_data_writer.h" |
| #include "quic/core/quic_simple_buffer_allocator.h" |
| #include "quic/core/quic_utils.h" |
| #include "quic/platform/api/quic_expect_bug.h" |
| #include "quic/platform/api/quic_flags.h" |
| #include "quic/platform/api/quic_test.h" |
| #include "quic/test_tools/quic_stream_send_buffer_peer.h" |
| #include "quic/test_tools/quic_test_utils.h" |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| struct iovec MakeIovec(absl::string_view data) { |
| struct iovec iov = {const_cast<char*>(data.data()), |
| static_cast<size_t>(data.size())}; |
| return iov; |
| } |
| |
| class QuicStreamSendBufferTest : public QuicTest { |
| public: |
| QuicStreamSendBufferTest() : send_buffer_(&allocator_) { |
| EXPECT_EQ(0u, send_buffer_.size()); |
| EXPECT_EQ(0u, send_buffer_.stream_bytes_written()); |
| EXPECT_EQ(0u, send_buffer_.stream_bytes_outstanding()); |
| std::string data1(1536, 'a'); |
| std::string data2 = std::string(256, 'b') + std::string(256, 'c'); |
| struct iovec iov[2]; |
| iov[0] = MakeIovec(absl::string_view(data1)); |
| iov[1] = MakeIovec(absl::string_view(data2)); |
| |
| QuicBuffer buffer1(&allocator_, 1024); |
| memset(buffer1.data(), 'c', buffer1.size()); |
| QuicMemSlice slice1(std::move(buffer1)); |
| QuicBuffer buffer2(&allocator_, 768); |
| memset(buffer2.data(), 'd', buffer2.size()); |
| QuicMemSlice slice2(std::move(buffer2)); |
| |
| // The stream offset should be 0 since nothing is written. |
| EXPECT_EQ(0u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| |
| // Save all data. |
| SetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size, 1024); |
| send_buffer_.SaveStreamData(iov, 2, 0, 2048); |
| send_buffer_.SaveMemSlice(std::move(slice1)); |
| EXPECT_TRUE(slice1.empty()); |
| send_buffer_.SaveMemSlice(std::move(slice2)); |
| EXPECT_TRUE(slice2.empty()); |
| |
| EXPECT_EQ(4u, send_buffer_.size()); |
| // At this point, the whole buffer looks like: |
| // | a * 1536 |b * 256| c * 1280 | d * 768 | |
| // | slice1 | slice2 | slice3 | slice4 | |
| } |
| |
| void WriteAllData() { |
| // Write all data. |
| char buf[4000]; |
| QuicDataWriter writer(4000, buf, quiche::HOST_BYTE_ORDER); |
| send_buffer_.WriteStreamData(0, 3840u, &writer); |
| |
| send_buffer_.OnStreamDataConsumed(3840u); |
| EXPECT_EQ(3840u, send_buffer_.stream_bytes_written()); |
| EXPECT_EQ(3840u, send_buffer_.stream_bytes_outstanding()); |
| } |
| |
| SimpleBufferAllocator allocator_; |
| QuicStreamSendBuffer send_buffer_; |
| }; |
| |
| TEST_F(QuicStreamSendBufferTest, CopyDataToBuffer) { |
| char buf[4000]; |
| QuicDataWriter writer(4000, buf, quiche::HOST_BYTE_ORDER); |
| std::string copy1(1024, 'a'); |
| std::string copy2 = |
| std::string(512, 'a') + std::string(256, 'b') + std::string(256, 'c'); |
| std::string copy3(1024, 'c'); |
| std::string copy4(768, 'd'); |
| |
| ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer)); |
| EXPECT_EQ(copy1, absl::string_view(buf, 1024)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(1024, 1024, &writer)); |
| EXPECT_EQ(copy2, absl::string_view(buf + 1024, 1024)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 1024, &writer)); |
| EXPECT_EQ(copy3, absl::string_view(buf + 2048, 1024)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(3072, 768, &writer)); |
| EXPECT_EQ(copy4, absl::string_view(buf + 3072, 768)); |
| |
| // Test data piece across boundries. |
| QuicDataWriter writer2(4000, buf, quiche::HOST_BYTE_ORDER); |
| std::string copy5 = |
| std::string(536, 'a') + std::string(256, 'b') + std::string(232, 'c'); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(1000, 1024, &writer2)); |
| EXPECT_EQ(copy5, absl::string_view(buf, 1024)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(2500, 1024, &writer2)); |
| std::string copy6 = std::string(572, 'c') + std::string(452, 'd'); |
| EXPECT_EQ(copy6, absl::string_view(buf + 1024, 1024)); |
| |
| // Invalid data copy. |
| QuicDataWriter writer3(4000, buf, quiche::HOST_BYTE_ORDER); |
| EXPECT_FALSE(send_buffer_.WriteStreamData(3000, 1024, &writer3)); |
| EXPECT_QUIC_BUG(send_buffer_.WriteStreamData(0, 4000, &writer3), |
| "Writer fails to write."); |
| |
| send_buffer_.OnStreamDataConsumed(3840); |
| EXPECT_EQ(3840u, send_buffer_.stream_bytes_written()); |
| EXPECT_EQ(3840u, send_buffer_.stream_bytes_outstanding()); |
| } |
| |
| // Regression test for b/143491027. |
| TEST_F(QuicStreamSendBufferTest, |
| WriteStreamDataContainsBothRetransmissionAndNewData) { |
| std::string copy1(1024, 'a'); |
| std::string copy2 = |
| std::string(512, 'a') + std::string(256, 'b') + std::string(256, 'c'); |
| std::string copy3 = std::string(1024, 'c') + std::string(100, 'd'); |
| char buf[6000]; |
| QuicDataWriter writer(6000, buf, quiche::HOST_BYTE_ORDER); |
| // Write more than one slice. |
| EXPECT_EQ(0, QuicStreamSendBufferPeer::write_index(&send_buffer_)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer)); |
| EXPECT_EQ(copy1, absl::string_view(buf, 1024)); |
| EXPECT_EQ(1, QuicStreamSendBufferPeer::write_index(&send_buffer_)); |
| |
| // Retransmit the first frame and also send new data. |
| ASSERT_TRUE(send_buffer_.WriteStreamData(0, 2048, &writer)); |
| EXPECT_EQ(copy1 + copy2, absl::string_view(buf + 1024, 2048)); |
| |
| // Write new data. |
| EXPECT_EQ(2048u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 50, &writer)); |
| EXPECT_EQ(std::string(50, 'c'), absl::string_view(buf + 1024 + 2048, 50)); |
| EXPECT_EQ(3072u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(2048, 1124, &writer)); |
| EXPECT_EQ(copy3, absl::string_view(buf + 1024 + 2048 + 50, 1124)); |
| EXPECT_EQ(3840u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, RemoveStreamFrame) { |
| WriteAllData(); |
| |
| QuicByteCount newly_acked_length; |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(1024, 1024, &newly_acked_length)); |
| EXPECT_EQ(1024u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2048, 1024, &newly_acked_length)); |
| EXPECT_EQ(1024u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 1024, &newly_acked_length)); |
| EXPECT_EQ(1024u, newly_acked_length); |
| |
| // Send buffer is cleaned up in order. |
| EXPECT_EQ(1u, send_buffer_.size()); |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(3072, 768, &newly_acked_length)); |
| EXPECT_EQ(768u, newly_acked_length); |
| EXPECT_EQ(0u, send_buffer_.size()); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, RemoveStreamFrameAcrossBoundries) { |
| WriteAllData(); |
| |
| QuicByteCount newly_acked_length; |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2024, 576, &newly_acked_length)); |
| EXPECT_EQ(576u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 1000, &newly_acked_length)); |
| EXPECT_EQ(1000u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(1000, 1024, &newly_acked_length)); |
| EXPECT_EQ(1024u, newly_acked_length); |
| // Send buffer is cleaned up in order. |
| EXPECT_EQ(2u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2600, 1024, &newly_acked_length)); |
| EXPECT_EQ(1024u, newly_acked_length); |
| EXPECT_EQ(1u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(3624, 216, &newly_acked_length)); |
| EXPECT_EQ(216u, newly_acked_length); |
| EXPECT_EQ(0u, send_buffer_.size()); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, AckStreamDataMultipleTimes) { |
| WriteAllData(); |
| QuicByteCount newly_acked_length; |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(100, 1500, &newly_acked_length)); |
| EXPECT_EQ(1500u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2000, 500, &newly_acked_length)); |
| EXPECT_EQ(500u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 2600, &newly_acked_length)); |
| EXPECT_EQ(600u, newly_acked_length); |
| // Send buffer is cleaned up in order. |
| EXPECT_EQ(2u, send_buffer_.size()); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2200, 1640, &newly_acked_length)); |
| EXPECT_EQ(1240u, newly_acked_length); |
| EXPECT_EQ(0u, send_buffer_.size()); |
| |
| EXPECT_FALSE(send_buffer_.OnStreamDataAcked(4000, 100, &newly_acked_length)); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, AckStreamDataOutOfOrder) { |
| WriteAllData(); |
| QuicByteCount newly_acked_length; |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(500, 1000, &newly_acked_length)); |
| EXPECT_EQ(1000u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| EXPECT_EQ(3840u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(1200, 1000, &newly_acked_length)); |
| EXPECT_EQ(700u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| // Slice 2 gets fully acked. |
| EXPECT_EQ(2816u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(2000, 1840, &newly_acked_length)); |
| EXPECT_EQ(1640u, newly_acked_length); |
| EXPECT_EQ(4u, send_buffer_.size()); |
| // Slices 3 and 4 get fully acked. |
| EXPECT_EQ(1024u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); |
| |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 1000, &newly_acked_length)); |
| EXPECT_EQ(500u, newly_acked_length); |
| EXPECT_EQ(0u, send_buffer_.size()); |
| EXPECT_EQ(0u, QuicStreamSendBufferPeer::TotalLength(&send_buffer_)); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, PendingRetransmission) { |
| WriteAllData(); |
| EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(0, 3840)); |
| EXPECT_FALSE(send_buffer_.HasPendingRetransmission()); |
| // Lost data [0, 1200). |
| send_buffer_.OnStreamDataLost(0, 1200); |
| // Lost data [1500, 2000). |
| send_buffer_.OnStreamDataLost(1500, 500); |
| EXPECT_TRUE(send_buffer_.HasPendingRetransmission()); |
| |
| EXPECT_EQ(StreamPendingRetransmission(0, 1200), |
| send_buffer_.NextPendingRetransmission()); |
| // Retransmit data [0, 500). |
| send_buffer_.OnStreamDataRetransmitted(0, 500); |
| EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(0, 500)); |
| EXPECT_EQ(StreamPendingRetransmission(500, 700), |
| send_buffer_.NextPendingRetransmission()); |
| // Ack data [500, 1200). |
| QuicByteCount newly_acked_length = 0; |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(500, 700, &newly_acked_length)); |
| EXPECT_FALSE(send_buffer_.IsStreamDataOutstanding(500, 700)); |
| EXPECT_TRUE(send_buffer_.HasPendingRetransmission()); |
| EXPECT_EQ(StreamPendingRetransmission(1500, 500), |
| send_buffer_.NextPendingRetransmission()); |
| // Retransmit data [1500, 2000). |
| send_buffer_.OnStreamDataRetransmitted(1500, 500); |
| EXPECT_FALSE(send_buffer_.HasPendingRetransmission()); |
| |
| // Lost [200, 800). |
| send_buffer_.OnStreamDataLost(200, 600); |
| EXPECT_TRUE(send_buffer_.HasPendingRetransmission()); |
| // Verify [200, 500) is considered as lost, as [500, 800) has been acked. |
| EXPECT_EQ(StreamPendingRetransmission(200, 300), |
| send_buffer_.NextPendingRetransmission()); |
| |
| // Verify 0 length data is not outstanding. |
| EXPECT_FALSE(send_buffer_.IsStreamDataOutstanding(100, 0)); |
| // Verify partially acked data is outstanding. |
| EXPECT_TRUE(send_buffer_.IsStreamDataOutstanding(400, 800)); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, EndOffset) { |
| char buf[4000]; |
| QuicDataWriter writer(4000, buf, quiche::HOST_BYTE_ORDER); |
| |
| EXPECT_EQ(1024u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| ASSERT_TRUE(send_buffer_.WriteStreamData(0, 1024, &writer)); |
| // Last offset we've seen is 1024 |
| EXPECT_EQ(1024u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| |
| ASSERT_TRUE(send_buffer_.WriteStreamData(1024, 512, &writer)); |
| // Last offset is now 2048 as that's the end of the next slice. |
| EXPECT_EQ(2048u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| send_buffer_.OnStreamDataConsumed(1024); |
| |
| // If data in 1st slice gets ACK'ed, it shouldn't change the indexed slice |
| QuicByteCount newly_acked_length; |
| EXPECT_TRUE(send_buffer_.OnStreamDataAcked(0, 1024, &newly_acked_length)); |
| // Last offset is still 2048. |
| EXPECT_EQ(2048u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| |
| ASSERT_TRUE( |
| send_buffer_.WriteStreamData(1024 + 512, 3840 - 1024 - 512, &writer)); |
| |
| // Last offset is end offset of last slice. |
| EXPECT_EQ(3840u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| QuicBuffer buffer(&allocator_, 60); |
| memset(buffer.data(), 'e', buffer.size()); |
| QuicMemSlice slice(std::move(buffer)); |
| send_buffer_.SaveMemSlice(std::move(slice)); |
| |
| EXPECT_EQ(3840u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_)); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, SaveMemSliceSpan) { |
| SimpleBufferAllocator allocator; |
| QuicStreamSendBuffer send_buffer(&allocator); |
| |
| std::string data(1024, 'a'); |
| std::vector<QuicMemSlice> buffers; |
| for (size_t i = 0; i < 10; ++i) { |
| buffers.push_back(MemSliceFromString(data)); |
| } |
| |
| EXPECT_EQ(10 * 1024u, send_buffer.SaveMemSliceSpan(absl::MakeSpan(buffers))); |
| EXPECT_EQ(10u, send_buffer.size()); |
| } |
| |
| TEST_F(QuicStreamSendBufferTest, SaveEmptyMemSliceSpan) { |
| SimpleBufferAllocator allocator; |
| QuicStreamSendBuffer send_buffer(&allocator); |
| |
| std::string data(1024, 'a'); |
| std::vector<QuicMemSlice> buffers; |
| for (size_t i = 0; i < 10; ++i) { |
| buffers.push_back(MemSliceFromString(data)); |
| } |
| |
| EXPECT_EQ(10 * 1024u, send_buffer.SaveMemSliceSpan(absl::MakeSpan(buffers))); |
| // Verify the empty slice does not get saved. |
| EXPECT_EQ(10u, send_buffer.size()); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace quic |