Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Unified Diff: net/quic/quic_stream_sequencer_test.cc

Issue 11300020: Add QuicStream and friends to QUIC code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: smaller char constant Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/quic/quic_stream_sequencer.cc ('k') | net/quic/reliable_quic_stream.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..e24d30901eb11c172289e37e6ce43350a65af639
--- /dev/null
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -0,0 +1,413 @@
+// 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,
+ 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_; }
+ 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));
+
+ 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));
+
+ 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, 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, 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;
+ 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(),
+ 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);
+ }
+ }
+}
+
+} // namespace
+
+} // namespace net
« no previous file with comments | « net/quic/quic_stream_sequencer.cc ('k') | net/quic/reliable_quic_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698