| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_stream_sequencer.h" | 5 #include "net/quic/quic_stream_sequencer.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 using testing::InSequence; | 26 using testing::InSequence; |
| 27 using testing::Return; | 27 using testing::Return; |
| 28 using testing::StrEq; | 28 using testing::StrEq; |
| 29 | 29 |
| 30 namespace net { | 30 namespace net { |
| 31 namespace test { | 31 namespace test { |
| 32 | 32 |
| 33 class QuicStreamSequencerPeer : public QuicStreamSequencer { | 33 class QuicStreamSequencerPeer : public QuicStreamSequencer { |
| 34 public: | 34 public: |
| 35 explicit QuicStreamSequencerPeer(ReliableQuicStream* stream) | 35 explicit QuicStreamSequencerPeer(ReliableQuicStream* stream) |
| 36 : QuicStreamSequencer(stream) { | 36 : QuicStreamSequencer(stream) {} |
| 37 } | |
| 38 | 37 |
| 39 virtual bool OnFinFrame(QuicStreamOffset byte_offset, const char* data) { | 38 virtual bool OnFinFrame(QuicStreamOffset byte_offset, const char* data) { |
| 40 QuicStreamFrame frame; | 39 QuicStreamFrame frame; |
| 41 frame.stream_id = 1; | 40 frame.stream_id = 1; |
| 42 frame.offset = byte_offset; | 41 frame.offset = byte_offset; |
| 43 frame.data.Append(const_cast<char*>(data), strlen(data)); | 42 frame.data.Append(const_cast<char*>(data), strlen(data)); |
| 44 frame.fin = true; | 43 frame.fin = true; |
| 45 return OnStreamFrame(frame); | 44 return OnStreamFrame(frame); |
| 46 } | 45 } |
| 47 | 46 |
| 48 virtual bool OnFrame(QuicStreamOffset byte_offset, const char* data) { | 47 virtual bool OnFrame(QuicStreamOffset byte_offset, const char* data) { |
| 49 QuicStreamFrame frame; | 48 QuicStreamFrame frame; |
| 50 frame.stream_id = 1; | 49 frame.stream_id = 1; |
| 51 frame.offset = byte_offset; | 50 frame.offset = byte_offset; |
| 52 frame.data.Append(const_cast<char*>(data), strlen(data)); | 51 frame.data.Append(const_cast<char*>(data), strlen(data)); |
| 53 frame.fin = false; | 52 frame.fin = false; |
| 54 return OnStreamFrame(frame); | 53 return OnStreamFrame(frame); |
| 55 } | 54 } |
| 56 | 55 |
| 57 uint64 num_bytes_consumed() const { return num_bytes_consumed_; } | 56 uint64 num_bytes_consumed() const { return num_bytes_consumed_; } |
| 58 const FrameMap* frames() const { return &frames_; } | 57 const FrameMap* frames() const { return &frames_; } |
| 59 QuicStreamOffset close_offset() const { return close_offset_; } | 58 QuicStreamOffset close_offset() const { return close_offset_; } |
| 60 }; | 59 }; |
| 61 | 60 |
| 62 class MockStream : public ReliableQuicStream { | 61 class MockStream : public ReliableQuicStream { |
| 63 public: | 62 public: |
| 64 MockStream(QuicSession* session, QuicStreamId id) | 63 MockStream(QuicSession* session, QuicStreamId id) |
| 65 : ReliableQuicStream(id, session) { | 64 : ReliableQuicStream(id, session) {} |
| 66 } | |
| 67 | 65 |
| 68 MOCK_METHOD0(OnFinRead, void()); | 66 MOCK_METHOD0(OnFinRead, void()); |
| 69 MOCK_METHOD2(ProcessRawData, uint32(const char* data, uint32 data_len)); | 67 MOCK_METHOD2(ProcessRawData, uint32(const char* data, uint32 data_len)); |
| 70 MOCK_METHOD2(CloseConnectionWithDetails, void(QuicErrorCode error, | 68 MOCK_METHOD2(CloseConnectionWithDetails, |
| 71 const string& details)); | 69 void(QuicErrorCode error, const string& details)); |
| 72 MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error)); | 70 MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error)); |
| 73 MOCK_METHOD0(OnCanWrite, void()); | 71 MOCK_METHOD0(OnCanWrite, void()); |
| 74 virtual QuicPriority EffectivePriority() const { | 72 virtual QuicPriority EffectivePriority() const { |
| 75 return QuicUtils::HighestPriority(); | 73 return QuicUtils::HighestPriority(); |
| 76 } | 74 } |
| 77 virtual bool IsFlowControlEnabled() const { | 75 virtual bool IsFlowControlEnabled() const { return true; } |
| 78 return true; | |
| 79 } | |
| 80 }; | 76 }; |
| 81 | 77 |
| 82 namespace { | 78 namespace { |
| 83 | 79 |
| 84 static const char kPayload[] = | 80 static const char kPayload[] = |
| 85 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | 81 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| 86 | 82 |
| 87 class QuicStreamSequencerTest : public ::testing::Test { | 83 class QuicStreamSequencerTest : public ::testing::Test { |
| 88 protected: | 84 protected: |
| 89 QuicStreamSequencerTest() | 85 QuicStreamSequencerTest() |
| 90 : connection_(new MockConnection(false)), | 86 : connection_(new MockConnection(false)), |
| 91 session_(connection_), | 87 session_(connection_), |
| 92 stream_(&session_, 1), | 88 stream_(&session_, 1), |
| 93 sequencer_(new QuicStreamSequencerPeer(&stream_)) { | 89 sequencer_(new QuicStreamSequencerPeer(&stream_)) {} |
| 94 } | |
| 95 | 90 |
| 96 bool VerifyReadableRegions(const char** expected, size_t num_expected) { | 91 bool VerifyReadableRegions(const char** expected, size_t num_expected) { |
| 97 iovec iovecs[5]; | 92 iovec iovecs[5]; |
| 98 size_t num_iovecs = sequencer_->GetReadableRegions(iovecs, | 93 size_t num_iovecs = |
| 99 arraysize(iovecs)); | 94 sequencer_->GetReadableRegions(iovecs, arraysize(iovecs)); |
| 100 return VerifyIovecs(iovecs, num_iovecs, expected, num_expected); | 95 return VerifyIovecs(iovecs, num_iovecs, expected, num_expected); |
| 101 } | 96 } |
| 102 | 97 |
| 103 bool VerifyIovecs(iovec* iovecs, | 98 bool VerifyIovecs(iovec* iovecs, |
| 104 size_t num_iovecs, | 99 size_t num_iovecs, |
| 105 const char** expected, | 100 const char** expected, |
| 106 size_t num_expected) { | 101 size_t num_expected) { |
| 107 if (num_expected != num_iovecs) { | 102 if (num_expected != num_iovecs) { |
| 108 LOG(ERROR) << "Incorrect number of iovecs. Expected: " | 103 LOG(ERROR) << "Incorrect number of iovecs. Expected: " << num_expected |
| 109 << num_expected << " Actual: " << num_iovecs; | 104 << " Actual: " << num_iovecs; |
| 110 return false; | 105 return false; |
| 111 } | 106 } |
| 112 for (size_t i = 0; i < num_expected; ++i) { | 107 for (size_t i = 0; i < num_expected; ++i) { |
| 113 if (!VerifyIovec(iovecs[i], expected[i])) { | 108 if (!VerifyIovec(iovecs[i], expected[i])) { |
| 114 return false; | 109 return false; |
| 115 } | 110 } |
| 116 } | 111 } |
| 117 return true; | 112 return true; |
| 118 } | 113 } |
| 119 | 114 |
| 120 bool VerifyIovec(const iovec& iovec, StringPiece expected) { | 115 bool VerifyIovec(const iovec& iovec, StringPiece expected) { |
| 121 if (iovec.iov_len != expected.length()) { | 116 if (iovec.iov_len != expected.length()) { |
| 122 LOG(ERROR) << "Invalid length: " << iovec.iov_len | 117 LOG(ERROR) << "Invalid length: " << iovec.iov_len << " vs " |
| 123 << " vs " << expected.length(); | 118 << expected.length(); |
| 124 return false; | 119 return false; |
| 125 } | 120 } |
| 126 if (memcmp(iovec.iov_base, expected.data(), expected.length()) != 0) { | 121 if (memcmp(iovec.iov_base, expected.data(), expected.length()) != 0) { |
| 127 LOG(ERROR) << "Invalid data: " << static_cast<char*>(iovec.iov_base) | 122 LOG(ERROR) << "Invalid data: " << static_cast<char*>(iovec.iov_base) |
| 128 << " vs " << expected.data(); | 123 << " vs " << expected.data(); |
| 129 return false; | 124 return false; |
| 130 } | 125 } |
| 131 return true; | 126 return true; |
| 132 } | 127 } |
| 133 | 128 |
| 134 MockConnection* connection_; | 129 MockConnection* connection_; |
| 135 MockSession session_; | 130 MockSession session_; |
| 136 testing::StrictMock<MockStream> stream_; | 131 testing::StrictMock<MockStream> stream_; |
| 137 scoped_ptr<QuicStreamSequencerPeer> sequencer_; | 132 scoped_ptr<QuicStreamSequencerPeer> sequencer_; |
| 138 }; | 133 }; |
| 139 | 134 |
| 140 TEST_F(QuicStreamSequencerTest, RejectOldFrame) { | 135 TEST_F(QuicStreamSequencerTest, RejectOldFrame) { |
| 141 EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)) | 136 EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| 142 .WillOnce(Return(3)); | |
| 143 | 137 |
| 144 EXPECT_TRUE(sequencer_->OnFrame(0, "abc")); | 138 EXPECT_TRUE(sequencer_->OnFrame(0, "abc")); |
| 145 EXPECT_EQ(0u, sequencer_->frames()->size()); | 139 EXPECT_EQ(0u, sequencer_->frames()->size()); |
| 146 EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); | 140 EXPECT_EQ(3u, sequencer_->num_bytes_consumed()); |
| 147 // Ignore this - it matches a past sequence number and we should not see it | 141 // Ignore this - it matches a past sequence number and we should not see it |
| 148 // again. | 142 // again. |
| 149 EXPECT_TRUE(sequencer_->OnFrame(0, "def")); | 143 EXPECT_TRUE(sequencer_->OnFrame(0, "def")); |
| 150 EXPECT_EQ(0u, sequencer_->frames()->size()); | 144 EXPECT_EQ(0u, sequencer_->frames()->size()); |
| 151 } | 145 } |
| 152 | 146 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 EXPECT_CALL(stream_, ProcessRawData(StrEq("ghi"), 3)).WillOnce(Return(3)); | 253 EXPECT_CALL(stream_, ProcessRawData(StrEq("ghi"), 3)).WillOnce(Return(3)); |
| 260 | 254 |
| 261 // Ack right away | 255 // Ack right away |
| 262 EXPECT_TRUE(sequencer_->OnFrame(0, "abc")); | 256 EXPECT_TRUE(sequencer_->OnFrame(0, "abc")); |
| 263 EXPECT_EQ(9u, sequencer_->num_bytes_consumed()); | 257 EXPECT_EQ(9u, sequencer_->num_bytes_consumed()); |
| 264 EXPECT_EQ(0u, sequencer_->num_bytes_buffered()); | 258 EXPECT_EQ(0u, sequencer_->num_bytes_buffered()); |
| 265 | 259 |
| 266 EXPECT_EQ(0u, sequencer_->frames()->size()); | 260 EXPECT_EQ(0u, sequencer_->frames()->size()); |
| 267 } | 261 } |
| 268 | 262 |
| 269 | |
| 270 TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) { | 263 TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) { |
| 271 InSequence s; | 264 InSequence s; |
| 272 | 265 |
| 273 EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3)); | 266 EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(3)); |
| 274 EXPECT_CALL(stream_, OnFinRead()); | 267 EXPECT_CALL(stream_, OnFinRead()); |
| 275 EXPECT_TRUE(sequencer_->OnFinFrame(0, "abc")); | 268 EXPECT_TRUE(sequencer_->OnFinFrame(0, "abc")); |
| 276 | 269 |
| 277 EXPECT_EQ(3u, sequencer_->close_offset()); | 270 EXPECT_EQ(3u, sequencer_->close_offset()); |
| 278 } | 271 } |
| 279 | 272 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 303 char buffer[3]; | 296 char buffer[3]; |
| 304 | 297 |
| 305 sequencer_->OnFinFrame(3, ""); | 298 sequencer_->OnFinFrame(3, ""); |
| 306 EXPECT_EQ(3u, sequencer_->close_offset()); | 299 EXPECT_EQ(3u, sequencer_->close_offset()); |
| 307 | 300 |
| 308 EXPECT_FALSE(sequencer_->IsClosed()); | 301 EXPECT_FALSE(sequencer_->IsClosed()); |
| 309 | 302 |
| 310 EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(0)); | 303 EXPECT_CALL(stream_, ProcessRawData(StrEq("abc"), 3)).WillOnce(Return(0)); |
| 311 EXPECT_TRUE(sequencer_->OnFrame(0, "abc")); | 304 EXPECT_TRUE(sequencer_->OnFrame(0, "abc")); |
| 312 | 305 |
| 313 iovec iov = { &buffer[0], 3 }; | 306 iovec iov = {&buffer[0], 3}; |
| 314 int bytes_read = sequencer_->Readv(&iov, 1); | 307 int bytes_read = sequencer_->Readv(&iov, 1); |
| 315 EXPECT_EQ(3, bytes_read); | 308 EXPECT_EQ(3, bytes_read); |
| 316 EXPECT_TRUE(sequencer_->IsClosed()); | 309 EXPECT_TRUE(sequencer_->IsClosed()); |
| 317 } | 310 } |
| 318 | 311 |
| 319 TEST_F(QuicStreamSequencerTest, MutipleOffsets) { | 312 TEST_F(QuicStreamSequencerTest, MutipleOffsets) { |
| 320 sequencer_->OnFinFrame(3, ""); | 313 sequencer_->OnFinFrame(3, ""); |
| 321 EXPECT_EQ(3u, sequencer_->close_offset()); | 314 EXPECT_EQ(3u, sequencer_->close_offset()); |
| 322 | 315 |
| 323 EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); | 316 EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 341 int payload_size = arraysize(kPayload) - 1; | 334 int payload_size = arraysize(kPayload) - 1; |
| 342 int remaining_payload = payload_size; | 335 int remaining_payload = payload_size; |
| 343 while (remaining_payload != 0) { | 336 while (remaining_payload != 0) { |
| 344 int size = min(OneToN(6), remaining_payload); | 337 int size = min(OneToN(6), remaining_payload); |
| 345 int index = payload_size - remaining_payload; | 338 int index = payload_size - remaining_payload; |
| 346 list_.push_back(make_pair(index, string(kPayload + index, size))); | 339 list_.push_back(make_pair(index, string(kPayload + index, size))); |
| 347 remaining_payload -= size; | 340 remaining_payload -= size; |
| 348 } | 341 } |
| 349 } | 342 } |
| 350 | 343 |
| 351 QuicSequencerRandomTest() { | 344 QuicSequencerRandomTest() { CreateFrames(); } |
| 352 CreateFrames(); | |
| 353 } | |
| 354 | 345 |
| 355 int OneToN(int n) { | 346 int OneToN(int n) { return base::RandInt(1, n); } |
| 356 return base::RandInt(1, n); | |
| 357 } | |
| 358 | 347 |
| 359 int MaybeProcessMaybeBuffer(const char* data, uint32 len) { | 348 int MaybeProcessMaybeBuffer(const char* data, uint32 len) { |
| 360 int to_process = len; | 349 int to_process = len; |
| 361 if (base::RandUint64() % 2 != 0) { | 350 if (base::RandUint64() % 2 != 0) { |
| 362 to_process = base::RandInt(0, len); | 351 to_process = base::RandInt(0, len); |
| 363 } | 352 } |
| 364 output_.append(data, to_process); | 353 output_.append(data, to_process); |
| 365 return to_process; | 354 return to_process; |
| 366 } | 355 } |
| 367 | 356 |
| 368 string output_; | 357 string output_; |
| 369 FrameList list_; | 358 FrameList list_; |
| 370 }; | 359 }; |
| 371 | 360 |
| 372 // All frames are processed as soon as we have sequential data. | 361 // All frames are processed as soon as we have sequential data. |
| 373 // Infinite buffering, so all frames are acked right away. | 362 // Infinite buffering, so all frames are acked right away. |
| 374 TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) { | 363 TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) { |
| 375 InSequence s; | 364 InSequence s; |
| 376 for (size_t i = 0; i < list_.size(); ++i) { | 365 for (size_t i = 0; i < list_.size(); ++i) { |
| 377 string* data = &list_[i].second; | 366 string* data = &list_[i].second; |
| 378 EXPECT_CALL(stream_, ProcessRawData(StrEq(*data), data->size())) | 367 EXPECT_CALL(stream_, ProcessRawData(StrEq(*data), data->size())) |
| 379 .WillOnce(Return(data->size())); | 368 .WillOnce(Return(data->size())); |
| 380 } | 369 } |
| 381 | 370 |
| 382 while (!list_.empty()) { | 371 while (!list_.empty()) { |
| 383 int index = OneToN(list_.size()) - 1; | 372 int index = OneToN(list_.size()) - 1; |
| 384 LOG(ERROR) << "Sending index " << index << " " | 373 LOG(ERROR) << "Sending index " << index << " " |
| 385 << list_[index].second.data(); | 374 << list_[index].second.data(); |
| 386 EXPECT_TRUE(sequencer_->OnFrame(list_[index].first, | 375 EXPECT_TRUE( |
| 387 list_[index].second.data())); | 376 sequencer_->OnFrame(list_[index].first, list_[index].second.data())); |
| 388 | 377 |
| 389 list_.erase(list_.begin() + index); | 378 list_.erase(list_.begin() + index); |
| 390 } | 379 } |
| 391 } | 380 } |
| 392 | 381 |
| 393 } // namespace | 382 } // namespace |
| 394 } // namespace test | 383 } // namespace test |
| 395 } // namespace net | 384 } // namespace net |
| OLD | NEW |