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 |