Chromium Code Reviews| Index: net/quic/quic_stream_sequencer_test.cc |
| diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0bba035db0820383558e416c9274aadae300b9a2 |
| --- /dev/null |
| +++ b/net/quic/quic_stream_sequencer_test.cc |
| @@ -0,0 +1,624 @@ |
| +// 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/quic/quic_stream_sequencer.h" |
| + |
| +#include <utility> |
| +#include <vector> |
| + |
| +#include "base/rand_util.h" |
| +#include "net/quic/reliable_quic_stream.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +using base::StringPiece; |
| +using std::min; |
| +using std::pair; |
| +using std::vector; |
| +using testing::_; |
| +using testing::AnyNumber; |
| +using testing::InSequence; |
| +using testing::Return; |
| +using testing::StrEq; |
| + |
| +namespace net { |
| + |
| +class QuicStreamSequencerPeer : public QuicStreamSequencer { |
| + public: |
| + explicit QuicStreamSequencerPeer(ReliableQuicStream* stream) |
| + : QuicStreamSequencer(stream) { |
| + } |
| + |
| + QuicStreamSequencerPeer(int32 max_mem, ReliableQuicStream* stream) |
| + : QuicStreamSequencer(max_mem, stream) {} |
| + |
| + virtual bool OnFrame(QuicStreamOffset byte_offset, |
| + const char* data, |
|
jar (doing other things)
2012/11/01 22:21:10
nit: indent
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + uint32 data_len) { |
| + QuicStreamFrame frame; |
| + frame.stream_id = 1; |
| + frame.offset = byte_offset; |
| + frame.data = StringPiece(data, data_len); |
| + return OnStreamFrame(frame); |
| + } |
| + |
| + void SetMemoryLimit(size_t limit) { |
| + max_frame_memory_ = limit; |
| + } |
| + |
| + ReliableQuicStream* stream() { return stream_; } |
|
jar (doing other things)
2012/11/01 22:21:10
nit: most of these should be const methods. line 5
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + uint64 num_bytes_consumed() { return num_bytes_consumed_; } |
| + FrameMap* frames() { return &frames_; } |
| + int32 max_frame_memory() { return max_frame_memory_; } |
| + QuicStreamOffset close_offset() { return close_offset_; } |
| +}; |
| + |
| +class MockStream : public ReliableQuicStream { |
| + public: |
| + MockStream(QuicSession* session, QuicStreamId id) |
| + : ReliableQuicStream(id, session) { |
| + } |
| + |
| + MOCK_METHOD1(TerminateFromPeer, void(bool half_close)); |
| + MOCK_METHOD2(ProcessData, uint32(const char* data, uint32 data_len)); |
| + MOCK_METHOD1(Close, void(QuicErrorCode error)); |
| +}; |
| + |
| +namespace { |
| + |
| +static const char kPayload[] = |
| + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| + |
| +class QuicStreamSequencerTest : public ::testing::Test { |
| + protected: |
| + QuicStreamSequencerTest() |
| + : session_(NULL), |
| + stream_(session_, 1), |
| + sequencer_(new QuicStreamSequencerPeer(&stream_)) { |
| + } |
| + |
| + QuicSession* session_; |
| + testing::StrictMock<MockStream> stream_; |
| + scoped_ptr<QuicStreamSequencerPeer> sequencer_; |
| +}; |
| + |
| +TEST_F(QuicStreamSequencerTest, RejectOldFrame) { |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)) |
| + .WillOnce(Return(3)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(0u, sequencer_->frames()->size()); |
| + EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); |
| + // Nack this - it matches a past sequence number and we should not see it |
| + // again. |
| + EXPECT_FALSE(sequencer_->OnFrame(0, "def", 3)); |
| + EXPECT_EQ(0u, sequencer_->frames()->size()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, RejectOverlyLargeFrame) { |
| + /* |
| + EXPECT_DFATAL(sequencer_.reset(new QuicStreamSequencerPeer(2, &stream_)), |
| + "Setting max frame memory to 2. " |
| + "Some frames will be impossible to handle."); |
| + |
| + EXPECT_DEBUG_DEATH(sequencer_->OnFrame(0, "abc", 3), ""); |
| + */ |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, DropFramePastBuffering) { |
| + sequencer_->SetMemoryLimit(3); |
| + |
| + EXPECT_FALSE(sequencer_->OnFrame(3, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) { |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(1u, sequencer_->frames()->size()); |
| + EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); |
| + // Ignore this - it matches a buffered frame. |
| + // Right now there's no checking that the payload is consistent. |
| + EXPECT_FALSE(sequencer_->OnFrame(0, "def", 3)); |
| + EXPECT_EQ(1u, sequencer_->frames()->size()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, FullFrameConsumed) { |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)) |
| + .WillOnce(Return(3)); |
|
jar (doing other things)
2012/11/01 22:21:10
nit: indent
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(0u, sequencer_->frames()->size()); |
| + EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, PartialFrameConsumed) { |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)) |
| + .WillOnce(Return(2)); |
|
jar (doing other things)
2012/11/01 22:21:10
nit: indent (happens several more times).
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(1u, sequencer_->frames()->size()); |
| + EXPECT_EQ(2u, sequencer_->num_bytes_consumed()); |
| + EXPECT_EQ("c", sequencer_->frames()->find(2)->second); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, NextxFrameNotConsumed) { |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)) |
| + .WillOnce(Return(0)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(1u, sequencer_->frames()->size()); |
| + EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); |
| + EXPECT_EQ("abc", sequencer_->frames()->find(0)->second); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, FutureFrameNotProcessed) { |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "abc", 3)); |
| + EXPECT_EQ(1u, sequencer_->frames()->size()); |
| + EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); |
| + EXPECT_EQ("abc", sequencer_->frames()->find(3)->second); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) { |
| + // Buffer the first |
| + EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3)); |
| + EXPECT_EQ(1u, sequencer_->frames()->size()); |
| + EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); |
| + // Buffer the second |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3)); |
| + EXPECT_EQ(2u, sequencer_->frames()->size()); |
| + EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("ghi"), 3)).WillOnce(Return(3)); |
| + |
| + // Ack right away |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(9u, sequencer_->num_bytes_consumed()); |
| + |
| + EXPECT_EQ(0u, sequencer_->frames()->size()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, OutOfOrderFramesProcessedWithBuffering) { |
| + sequencer_->SetMemoryLimit(9); |
| + |
| + // Too far to buffer. |
| + EXPECT_FALSE(sequencer_->OnFrame(9, "jkl", 3)); |
| + |
| + // We can afford to buffer this. |
| + EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3)); |
| + EXPECT_EQ(0u, sequencer_->num_bytes_consumed()); |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData("abc", 3)).WillOnce(Return(3)); |
| + |
| + // Ack right away |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); |
| + |
| + // We should be willing to buffer this now. |
| + EXPECT_TRUE(sequencer_->OnFrame(9, "jkl", 3)); |
| + EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); |
| + |
| + EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("ghi"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("jkl"), 3)).WillOnce(Return(3)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3)); |
| + EXPECT_EQ(12u, sequencer_->num_bytes_consumed()); |
| + EXPECT_EQ(0u, sequencer_->frames()->size()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, OutOfOrderFramesBlockignWithReadv) { |
| + sequencer_->SetMemoryLimit(9); |
| + char buffer[20]; |
| + iovec iov[2]; |
| + iov[0].iov_base = &buffer[0]; |
| + iov[0].iov_len = 1; |
| + iov[1].iov_base = &buffer[1]; |
| + iov[1].iov_len = 2; |
| + |
| + // Push abc - process. |
| + // Push jkl - buffer (not next data) |
| + // Push def - don't process. |
| + // Push mno - drop (too far out) |
| + // Push ghi - buffer (def not processed) |
| + // Read 2. |
| + // Push mno - buffer (not all read) |
| + // Read all |
| + // Push pqr - process |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(0)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("pqr"), 3)).WillOnce(Return(3)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(9, "jkl", 3)); |
| + EXPECT_FALSE(sequencer_->OnFrame(12, "mno", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3)); |
| + |
| + // Read 3 bytes. |
| + EXPECT_EQ(3u, sequencer_->Readv(iov, 2)); |
| + EXPECT_EQ(0, strncmp(buffer, "def", 3)); |
| + |
| + // Now we have space to bufer this. |
| + EXPECT_TRUE(sequencer_->OnFrame(12, "mno", 3)); |
| + |
| + // Read the remaining 9 bytes. |
| + iov[1].iov_len = 19; |
| + EXPECT_EQ(9u, sequencer_->Readv(iov, 2)); |
| + EXPECT_EQ(0, strncmp(buffer, "ghijklmno", 9)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(15, "pqr", 3)); |
| +} |
| + |
| +// Same as above, just using a different method for reading. |
| +TEST_F(QuicStreamSequencerTest, OutOfOrderFramesBlockignWithGetReadableRegion) { |
| + sequencer_->SetMemoryLimit(9); |
| + iovec iov[5]; |
|
jar (doing other things)
2012/11/01 22:21:10
nit: move closer to first use.
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(0)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("pqr"), 3)).WillOnce(Return(3)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(9, "jkl", 3)); |
| + EXPECT_FALSE(sequencer_->OnFrame(12, "mno", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(6, "ghi", 3)); |
| + |
| + // Read 3 bytes. |
| + ASSERT_EQ(3u, sequencer_->GetReadableRegions(iov, 5)); |
| + ASSERT_EQ(3u, iov[0].iov_len); |
| + ASSERT_EQ(3u, iov[1].iov_len); |
| + ASSERT_EQ(3u, iov[2].iov_len); |
| + ASSERT_EQ(0, memcmp(iov[0].iov_base, "def", 3)); |
| + ASSERT_EQ(0, memcmp(iov[1].iov_base, "ghi", 3)); |
| + ASSERT_EQ(0, memcmp(iov[2].iov_base, "jkl", 3)); |
| + sequencer_->AdvanceReadablePtr(3); |
| + |
| + // Now we have space to bufer this. |
| + EXPECT_TRUE(sequencer_->OnFrame(12, "mno", 3)); |
| + |
| + // Read the remaining 9 bytes. |
| + ASSERT_EQ(3u, sequencer_->GetReadableRegions(iov, 5)); |
| + ASSERT_EQ(3u, iov[0].iov_len); |
| + ASSERT_EQ(3u, iov[1].iov_len); |
| + ASSERT_EQ(3u, iov[2].iov_len); |
| + ASSERT_EQ(0, memcmp(iov[0].iov_base, "ghi", 3)); |
| + ASSERT_EQ(0, memcmp(iov[1].iov_base, "jkl", 3)); |
| + ASSERT_EQ(0, memcmp(iov[2].iov_base, "mno", 3)); |
| + sequencer_->AdvanceReadablePtr(9); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(15, "pqr", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, BasicCloseOrdered) { |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + |
| + EXPECT_CALL(stream_, TerminateFromPeer(false)); |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, BasicHalfOrdered) { |
| + InSequence s; |
| + |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + |
| + EXPECT_CALL(stream_, TerminateFromPeer(true)); |
| + sequencer_->CloseStreamAtOffset(3, true); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, BasicCloseUnordered) { |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, TerminateFromPeer(false)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, BasicHalfUnorderedWithFlush) { |
| + sequencer_->CloseStreamAtOffset(6, true); |
| + EXPECT_EQ(6u, sequencer_->close_offset()); |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, TerminateFromPeer(true)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, BasicCloseUnorderedWithFlush) { |
| + sequencer_->CloseStreamAtOffset(6, false); |
| + EXPECT_EQ(6u, sequencer_->close_offset()); |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, ProcessData(StrEq("def"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, TerminateFromPeer(false)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(3, "def", 3)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, BasicHalfUnordered) { |
| + sequencer_->CloseStreamAtOffset(3, true); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, TerminateFromPeer(true)); |
| + |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, CloseStreamBeforeCloseEqual) { |
| + sequencer_->CloseStreamAtOffset(3, true); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, TerminateFromPeer(false)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, CloseBeforeTermianteEqual) { |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + sequencer_->CloseStreamAtOffset(3, true); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + InSequence s; |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| + EXPECT_CALL(stream_, TerminateFromPeer(false)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, TerminateWithReadv) { |
| + char buffer[3]; |
| + iovec iov = { &buffer[0], 3 }; |
|
jar (doing other things)
2012/11/01 22:21:10
nit: move closer to first use. (next test as well)
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + |
| + sequencer_->CloseStreamAtOffset(3, true); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + EXPECT_FALSE(sequencer_->IsHalfClosed()); |
| + |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + |
| + int bytes_read = sequencer_->Readv(&iov, 1); |
| + EXPECT_EQ(3, bytes_read); |
| + EXPECT_TRUE(sequencer_->IsHalfClosed()); |
| + EXPECT_FALSE(sequencer_->IsClosed()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, CloseWithReadv) { |
| + char buffer[3]; |
| + iovec iov = { &buffer[0], 3 }; |
| + |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + EXPECT_FALSE(sequencer_->IsClosed()); |
| + |
| + EXPECT_CALL(stream_, ProcessData(StrEq("abc"), 3)).WillOnce(Return(0)); |
| + EXPECT_TRUE(sequencer_->OnFrame(0, "abc", 3)); |
| + |
| + int bytes_read = sequencer_->Readv(&iov, 1); |
| + EXPECT_EQ(3, bytes_read); |
| + EXPECT_TRUE(sequencer_->IsHalfClosed()); |
| + EXPECT_TRUE(sequencer_->IsClosed()); |
| +} |
| + |
| +TEST_F(QuicStreamSequencerTest, MutipleOffsets) { |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + EXPECT_CALL(stream_, Close(QUIC_MULTIPLE_TERMINATION_OFFSETS)); |
| + sequencer_->CloseStreamAtOffset(5, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + EXPECT_CALL(stream_, Close(QUIC_MULTIPLE_TERMINATION_OFFSETS)); |
| + sequencer_->CloseStreamAtOffset(1, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| + |
| + sequencer_->CloseStreamAtOffset(3, false); |
| + EXPECT_EQ(3u, sequencer_->close_offset()); |
| +} |
| + |
| +class QuicSequencerRandomTest : public QuicStreamSequencerTest { |
| + public: |
| + typedef pair<int, string> Frame; |
| + typedef vector<Frame> FrameList; |
| + |
| + void CreateFrames() { |
| + int payload_size = arraysize(kPayload) - 1; |
| + int remaining_payload = payload_size; |
| + while (remaining_payload != 0) { |
| + int size = min(OneToN(6), remaining_payload); |
| + int idx = payload_size - remaining_payload; |
|
jar (doing other things)
2012/11/01 22:21:10
nit: (assuming you went with the longer spelling i
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + list_.push_back(make_pair(idx, string(kPayload + idx, size))); |
| + remaining_payload -= size; |
| + } |
| + } |
| + |
| + QuicSequencerRandomTest() { |
| + //int32 seed = ACMRandom::HostnamePidTimeSeed(); |
| + //LOG(INFO) << "**** The current seed is " << seed << " ****"; |
| + //random_.reset(new ACMRandom(seed)); |
| + |
| + CreateFrames(); |
| + } |
| + |
| + int OneToN(int n) { |
| + return base::RandInt(1, n); |
| + } |
| + |
| + int MaybeProcessMaybeBuffer(const char* data, uint32 len) { |
| + int to_process = len; |
| + if (base::RandUint64() % 2 != 0) { |
| + to_process = base::RandInt(0, len); |
| + } |
| + output_.append(data, to_process); |
| + LOG(ERROR) << output_; |
| + return to_process; |
| + } |
| + |
| + string output_; |
| + //scoped_ptr<ACMRandom> random_; |
| + FrameList list_; |
| +}; |
| + |
| +// All frames are processed as soon as we have sequential data. |
| +// Infinite buffering, so all frames are acked right away. |
| +TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) { |
| + InSequence s; |
| + for (size_t i = 0; i < list_.size(); ++i) { |
| + string* data = &list_[i].second; |
| + EXPECT_CALL(stream_, ProcessData(StrEq(*data), data->size())) |
| + .WillOnce(Return(data->size())); |
| + } |
| + |
| + while (list_.size() != 0) { |
| + int idx = OneToN(list_.size()) - 1; |
| + LOG(ERROR) << "Sending index " << idx << " " << list_[idx].second.c_str(); |
| + EXPECT_TRUE(sequencer_->OnFrame( |
| + list_[idx].first, list_[idx].second.c_str(), |
|
jar (doing other things)
2012/11/01 22:21:10
nit: probably avoid c_str() (in favor of data()) u
Ryan Hamilton
2012/11/01 22:52:20
Fixed upstream.
|
| + list_[idx].second.size())); |
| + list_.erase(list_.begin() + idx); |
| + } |
| +} |
| + |
| +// All frames are processed as soon as we have sequential data. |
| +// Buffering, so some frames are rejected. |
| +TEST_F(QuicSequencerRandomTest, RandomFramesDroppingNoBackup) { |
| + sequencer_->SetMemoryLimit(26); |
| + |
| + InSequence s; |
| + for (size_t i = 0; i < list_.size(); ++i) { |
| + string* data = &list_[i].second; |
| + EXPECT_CALL(stream_, ProcessData(StrEq(*data), data->size())) |
| + .WillOnce(Return(data->size())); |
| + } |
| + |
| + while (list_.size() != 0) { |
| + int idx = OneToN(list_.size()) - 1; |
| + LOG(ERROR) << "Sending index " << idx << " " << list_[idx].second.c_str(); |
| + bool acked = sequencer_->OnFrame( |
| + list_[idx].first, list_[idx].second.c_str(), |
| + list_[idx].second.size()); |
| + if (acked) { |
| + list_.erase(list_.begin() + idx); |
| + } |
| + } |
| +} |
| + |
| +TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) { |
| + char buffer[10]; |
| + iovec iov[2]; |
| + iov[0].iov_base = &buffer[0]; |
| + iov[0].iov_len = 5; |
| + iov[1].iov_base = &buffer[5]; |
| + iov[1].iov_len = 5; |
| + |
| + EXPECT_CALL(stream_, ProcessData(_, _)) |
| + .Times(AnyNumber()) |
| + .WillRepeatedly(Invoke( |
| + this, &QuicSequencerRandomTest::MaybeProcessMaybeBuffer)); |
| + |
| + while (output_.size() != arraysize(kPayload) - 1) { |
| + if (list_.size() != 0 && base::RandUint64() % 2 != 0) { // Send data |
| + int idx = OneToN(list_.size()) - 1; |
| + ASSERT_TRUE(sequencer_->OnFrame( |
| + list_[idx].first, list_[idx].second.c_str(), |
| + list_[idx].second.size())); |
| + list_.erase(list_.begin() + idx); |
| + } else { // Read data |
| + int bytes_read = sequencer_->Readv(iov, 1); |
| + output_.append(buffer, bytes_read); |
| + } |
| + } |
| + EXPECT_EQ(0, strcmp(kPayload, output_.c_str())); |
| +} |
| + |
| +TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackupLocalBuffers) { |
| + EXPECT_CALL(stream_, ProcessData(_, _)) |
| + .Times(AnyNumber()) |
| + .WillRepeatedly(Invoke( |
| + this, &QuicSequencerRandomTest::MaybeProcessMaybeBuffer)); |
| + |
| + while (output_.size() != arraysize(kPayload) - 1) { |
| + if (list_.size() != 0 && base::RandUint64() % 2 == 0) { // Send data |
| + int idx = OneToN(list_.size()) - 1; |
| + ASSERT_TRUE(sequencer_->OnFrame( |
| + list_[idx].first, list_[idx].second.c_str(), |
| + list_[idx].second.size())); |
| + list_.erase(list_.begin() + idx); |
| + } else { // Read data |
| + bool has_bytes = sequencer_->HasBytesToRead(); |
| + iovec iov[2]; |
| + int iovs = sequencer_->GetReadableRegions(iov, 2); |
| + int initial_size = output_.size(); |
| + if (has_bytes) { |
| + ASSERT_LT(0, iovs); |
| + } else { |
| + ASSERT_EQ(0, iovs); |
| + } |
| + for (int i = 0; i < iovs; ++i) { |
| + output_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); |
| + } |
| + sequencer_->AdvanceReadablePtr(output_.size() - initial_size); |
| + } |
| + } |
| + EXPECT_EQ(0, strcmp(kPayload, output_.c_str())); |
| +} |
| + |
| +TEST_F(QuicSequencerRandomTest, RandomFramesDroppingBackup) { |
| + sequencer_->SetMemoryLimit(26); |
| + |
| + EXPECT_CALL(stream_, ProcessData(_, _)) |
| + .Times(AnyNumber()) |
| + .WillRepeatedly(Invoke( |
| + this, &QuicSequencerRandomTest::MaybeProcessMaybeBuffer)); |
| + |
| + while (output_.size() != arraysize(kPayload) - 1) { |
| + if (list_.size() != 0 && base::RandUint64() % 2 == 0) { // Send data |
| + int idx = OneToN(list_.size()) - 1; |
| + if (sequencer_->OnFrame(list_[idx].first, list_[idx].second.c_str(), |
| + list_[idx].second.size())) { |
| + list_.erase(list_.begin() + idx); |
| + } |
| + } else { // Read data |
| + iovec iov[2]; |
| + int iovs = sequencer_->GetReadableRegions(iov, 2); |
| + int initial_size = output_.size(); |
| + for (int i = 0; i < iovs; ++i) { |
| + output_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); |
| + } |
| + sequencer_->AdvanceReadablePtr(output_.size() - initial_size); |
| + } |
| + } |
| + EXPECT_EQ(0, strcmp(kPayload, output_.c_str())); |
| +} |
| + |
| +} // namespace |
| + |
| +} // namespace net |