OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_headers_stream.h" | 5 #include "net/quic/quic_headers_stream.h" |
6 | 6 |
| 7 #include "base/test/histogram_tester.h" |
7 #include "net/quic/quic_utils.h" | 8 #include "net/quic/quic_utils.h" |
8 #include "net/quic/spdy_utils.h" | 9 #include "net/quic/spdy_utils.h" |
9 #include "net/quic/test_tools/quic_connection_peer.h" | 10 #include "net/quic/test_tools/quic_connection_peer.h" |
10 #include "net/quic/test_tools/quic_spdy_session_peer.h" | 11 #include "net/quic/test_tools/quic_spdy_session_peer.h" |
11 #include "net/quic/test_tools/quic_test_utils.h" | 12 #include "net/quic/test_tools/quic_test_utils.h" |
12 #include "net/quic/test_tools/reliable_quic_stream_peer.h" | 13 #include "net/quic/test_tools/reliable_quic_stream_peer.h" |
13 #include "net/spdy/spdy_protocol.h" | 14 #include "net/spdy/spdy_protocol.h" |
14 #include "net/spdy/spdy_test_utils.h" | 15 #include "net/spdy/spdy_test_utils.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
16 | 17 |
| 18 using base::Bucket; |
| 19 using base::HistogramTester; |
17 using base::StringPiece; | 20 using base::StringPiece; |
18 using std::ostream; | 21 using std::ostream; |
19 using std::string; | 22 using std::string; |
20 using std::vector; | 23 using std::vector; |
| 24 using testing::ElementsAre; |
| 25 using testing::InSequence; |
21 using testing::Invoke; | 26 using testing::Invoke; |
22 using testing::StrictMock; | 27 using testing::StrictMock; |
23 using testing::WithArgs; | 28 using testing::WithArgs; |
24 using testing::_; | 29 using testing::_; |
25 | 30 |
26 namespace net { | 31 namespace net { |
27 namespace test { | 32 namespace test { |
28 namespace { | 33 namespace { |
29 | 34 |
| 35 // TODO(ckrasic): this workaround is due to absence of std::initializer_list |
| 36 const bool kFins[] = {false, true}; |
| 37 |
30 class MockVisitor : public SpdyFramerVisitorInterface { | 38 class MockVisitor : public SpdyFramerVisitorInterface { |
31 public: | 39 public: |
32 MOCK_METHOD1(OnError, void(SpdyFramer* framer)); | 40 MOCK_METHOD1(OnError, void(SpdyFramer* framer)); |
33 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id, | 41 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id, |
34 size_t length, | 42 size_t length, |
35 bool fin)); | 43 bool fin)); |
36 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id, | 44 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id, |
37 const char* data, | 45 const char* data, |
38 size_t len, | 46 size_t len, |
39 bool fin)); | 47 bool fin)); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 body_("hello world"), | 125 body_("hello world"), |
118 framer_(HTTP2), | 126 framer_(HTTP2), |
119 stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, "") { | 127 stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, "") { |
120 headers_[":version"] = "HTTP/1.1"; | 128 headers_[":version"] = "HTTP/1.1"; |
121 headers_[":status"] = "200 Ok"; | 129 headers_[":status"] = "200 Ok"; |
122 headers_["content-length"] = "11"; | 130 headers_["content-length"] = "11"; |
123 framer_.set_visitor(&visitor_); | 131 framer_.set_visitor(&visitor_); |
124 EXPECT_EQ(version(), session_.connection()->version()); | 132 EXPECT_EQ(version(), session_.connection()->version()); |
125 EXPECT_TRUE(headers_stream_ != nullptr); | 133 EXPECT_TRUE(headers_stream_ != nullptr); |
126 VLOG(1) << GetParam(); | 134 VLOG(1) << GetParam(); |
| 135 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
127 } | 136 } |
128 | 137 |
129 QuicConsumedData SaveIov(const QuicIOVector& data) { | 138 QuicConsumedData SaveIov(const QuicIOVector& data) { |
130 const iovec* iov = data.iov; | 139 const iovec* iov = data.iov; |
131 int count = data.iov_count; | 140 int count = data.iov_count; |
132 for (int i = 0 ; i < count; ++i) { | 141 for (int i = 0 ; i < count; ++i) { |
133 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); | 142 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); |
134 } | 143 } |
135 return QuicConsumedData(saved_data_.length(), false); | 144 return QuicConsumedData(saved_data_.length(), false); |
136 } | 145 } |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 EXPECT_EQ(3u, headers_stream_->id()); | 248 EXPECT_EQ(3u, headers_stream_->id()); |
240 } | 249 } |
241 | 250 |
242 TEST_P(QuicHeadersStreamTest, EffectivePriority) { | 251 TEST_P(QuicHeadersStreamTest, EffectivePriority) { |
243 EXPECT_EQ(0u, headers_stream_->EffectivePriority()); | 252 EXPECT_EQ(0u, headers_stream_->EffectivePriority()); |
244 } | 253 } |
245 | 254 |
246 TEST_P(QuicHeadersStreamTest, WriteHeaders) { | 255 TEST_P(QuicHeadersStreamTest, WriteHeaders) { |
247 for (QuicStreamId stream_id = kClientDataStreamId1; | 256 for (QuicStreamId stream_id = kClientDataStreamId1; |
248 stream_id < kClientDataStreamId3; stream_id += 2) { | 257 stream_id < kClientDataStreamId3; stream_id += 2) { |
249 for (int count = 0; count < 2; ++count) { | 258 for (bool fin : kFins) { |
250 bool fin = (count == 0); | |
251 if (perspective() == Perspective::IS_SERVER) { | 259 if (perspective() == Perspective::IS_SERVER) { |
252 WriteHeadersAndExpectSynReply(stream_id, fin); | 260 WriteHeadersAndExpectSynReply(stream_id, fin); |
253 } else { | 261 } else { |
254 for (QuicPriority priority = 0; priority < 7; ++priority) { | 262 for (QuicPriority priority = 0; priority < 7; ++priority) { |
255 // TODO(rch): implement priorities correctly. | 263 // TODO(rch): implement priorities correctly. |
256 WriteHeadersAndExpectSynStream(stream_id, fin, 0); | 264 WriteHeadersAndExpectSynStream(stream_id, fin, 0); |
257 } | 265 } |
258 } | 266 } |
259 } | 267 } |
260 } | 268 } |
261 } | 269 } |
262 | 270 |
263 TEST_P(QuicHeadersStreamTest, ProcessRawData) { | 271 TEST_P(QuicHeadersStreamTest, ProcessRawData) { |
264 for (QuicStreamId stream_id = kClientDataStreamId1; | 272 for (QuicStreamId stream_id = kClientDataStreamId1; |
265 stream_id < kClientDataStreamId3; stream_id += 2) { | 273 stream_id < kClientDataStreamId3; stream_id += 2) { |
266 for (int count = 0; count < 2; ++count) { | 274 for (bool fin : kFins) { |
267 bool fin = (count == 0); | |
268 for (QuicPriority priority = 0; priority < 7; ++priority) { | 275 for (QuicPriority priority = 0; priority < 7; ++priority) { |
269 // Replace with "WriteHeadersAndSaveData" | 276 // Replace with "WriteHeadersAndSaveData" |
270 scoped_ptr<SpdySerializedFrame> frame; | 277 scoped_ptr<SpdySerializedFrame> frame; |
271 if (perspective() == Perspective::IS_SERVER) { | 278 if (perspective() == Perspective::IS_SERVER) { |
272 SpdyHeadersIR headers_frame(stream_id); | 279 SpdyHeadersIR headers_frame(stream_id); |
273 headers_frame.set_header_block(headers_); | 280 headers_frame.set_header_block(headers_); |
274 headers_frame.set_fin(fin); | 281 headers_frame.set_fin(fin); |
275 headers_frame.set_has_priority(true); | 282 headers_frame.set_has_priority(true); |
276 frame.reset(framer_.SerializeFrame(headers_frame)); | 283 frame.reset(framer_.SerializeFrame(headers_frame)); |
277 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); | 284 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); |
(...skipping 11 matching lines...) Expand all Loading... |
289 OnStreamHeadersComplete(stream_id, fin, frame->size())); | 296 OnStreamHeadersComplete(stream_id, fin, frame->size())); |
290 stream_frame_.data = StringPiece(frame->data(), frame->size()); | 297 stream_frame_.data = StringPiece(frame->data(), frame->size()); |
291 headers_stream_->OnStreamFrame(stream_frame_); | 298 headers_stream_->OnStreamFrame(stream_frame_); |
292 stream_frame_.offset += frame->size(); | 299 stream_frame_.offset += frame->size(); |
293 CheckHeaders(); | 300 CheckHeaders(); |
294 } | 301 } |
295 } | 302 } |
296 } | 303 } |
297 } | 304 } |
298 | 305 |
| 306 TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) { |
| 307 // In the absence of surfacing HOL measurements externally, via UMA |
| 308 // or tcp connection stats, log messages are the only indication. |
| 309 // This test verifies that false positives are not generated when |
| 310 // headers arrive in order. |
| 311 #if 0 |
| 312 ScopedMockLog log(kDoNotCaptureLogsYet); |
| 313 EXPECT_CALL(log, Log(_, _, _)).Times(0); |
| 314 log.StartCapturingLogs(); |
| 315 #endif |
| 316 InSequence seq; |
| 317 HistogramTester histogram_tester; |
| 318 bool fin = true; |
| 319 for (int stream_num = 0; stream_num < 10; stream_num++) { |
| 320 QuicStreamId stream_id = QuicClientDataStreamId(stream_num); |
| 321 // Replace with "WriteHeadersAndSaveData" |
| 322 scoped_ptr<SpdySerializedFrame> frame; |
| 323 if (perspective() == Perspective::IS_SERVER) { |
| 324 SpdyHeadersIR headers_frame(stream_id); |
| 325 headers_frame.set_header_block(headers_); |
| 326 headers_frame.set_fin(fin); |
| 327 headers_frame.set_has_priority(true); |
| 328 frame.reset(framer_.SerializeFrame(headers_frame)); |
| 329 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); |
| 330 } else { |
| 331 SpdyHeadersIR headers_frame(stream_id); |
| 332 headers_frame.set_header_block(headers_); |
| 333 headers_frame.set_fin(fin); |
| 334 frame.reset(framer_.SerializeFrame(headers_frame)); |
| 335 } |
| 336 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)); |
| 337 EXPECT_CALL(session_, |
| 338 OnStreamHeadersComplete(stream_id, fin, frame->size())); |
| 339 stream_frame_.data = StringPiece(frame->data(), frame->size()); |
| 340 headers_stream_->OnStreamFrame(stream_frame_); |
| 341 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
| 342 stream_frame_.offset += frame->size(); |
| 343 } |
| 344 histogram_tester.ExpectTotalCount("Net.QuicSession.HeadersHOLBlockedTime", 0); |
| 345 } |
| 346 |
| 347 TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) { |
| 348 // In the absence of surfacing HOL measurements externally, via UMA |
| 349 // or tcp connection stats, log messages are the only indication. |
| 350 // This test verifies that HOL blocking log messages are correct |
| 351 // when there are out of order arrivals. |
| 352 #if 0 |
| 353 ScopedMockLog log(kDoNotCaptureLogsYet); |
| 354 #endif |
| 355 HistogramTester histogram_tester; |
| 356 QuicStreamId stream_id; |
| 357 bool fin = true; |
| 358 QuicStreamFrame stream_frames[10]; |
| 359 scoped_ptr<SpdySerializedFrame> frames[10]; |
| 360 // First create all the frames in order |
| 361 { |
| 362 InSequence seq; |
| 363 for (int stream_num = 0; stream_num < 10; ++stream_num) { |
| 364 stream_id = QuicClientDataStreamId(stream_num); |
| 365 if (perspective() == Perspective::IS_SERVER) { |
| 366 SpdyHeadersIR headers_frame(stream_id); |
| 367 headers_frame.set_header_block(headers_); |
| 368 headers_frame.set_fin(fin); |
| 369 headers_frame.set_has_priority(true); |
| 370 frames[stream_num].reset(framer_.SerializeFrame(headers_frame)); |
| 371 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)).Times(1); |
| 372 } else { |
| 373 SpdyHeadersIR headers_frame(stream_id); |
| 374 headers_frame.set_header_block(headers_); |
| 375 headers_frame.set_fin(fin); |
| 376 frames[stream_num].reset(framer_.SerializeFrame(headers_frame)); |
| 377 } |
| 378 stream_frames[stream_num] = stream_frame_; |
| 379 stream_frames[stream_num].data = |
| 380 StringPiece(frames[stream_num]->data(), frames[stream_num]->size()); |
| 381 DVLOG(1) << "make frame for stream " << stream_num << " offset " |
| 382 << stream_frames[stream_num].offset; |
| 383 stream_frame_.offset += frames[stream_num]->size(); |
| 384 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)).Times(1); |
| 385 EXPECT_CALL(session_, OnStreamHeadersComplete(stream_id, fin, _)) |
| 386 .Times(1); |
| 387 } |
| 388 } |
| 389 #if 0 |
| 390 // Actually writing the frames in reverse order will trigger log messages. |
| 391 { |
| 392 InSequence seq; |
| 393 for (int stream_num = 0; stream_num < 10; ++stream_num) { |
| 394 stream_id = QuicClientDataStreamId(stream_num); |
| 395 if (stream_num > 0) { |
| 396 string expected_msg = StringPrintf( |
| 397 "stream %d: Net.QuicSession.HeadersHOLBlockedTime %d", |
| 398 stream_id, stream_num); |
| 399 #ifndef NDEBUG |
| 400 EXPECT_CALL(log, Log(INFO, _, expected_msg)); |
| 401 #endif |
| 402 } |
| 403 } |
| 404 } |
| 405 log.StartCapturingLogs(); |
| 406 #endif |
| 407 for (int stream_num = 9; stream_num >= 0; --stream_num) { |
| 408 DVLOG(1) << "OnStreamFrame for stream " << stream_num << " offset " |
| 409 << stream_frames[stream_num].offset; |
| 410 headers_stream_->OnStreamFrame(stream_frames[stream_num]); |
| 411 connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
| 412 } |
| 413 // We expect 1 sample each for delays from 1 to 9 ms (8 and 9 go |
| 414 // into the same bucket). |
| 415 EXPECT_THAT( |
| 416 histogram_tester.GetAllSamples("Net.QuicSession.HeadersHOLBlockedTime"), |
| 417 ElementsAre(Bucket(1, 1), Bucket(2, 1), Bucket(3, 1), Bucket(4, 1), |
| 418 Bucket(5, 1), Bucket(6, 1), Bucket(7, 1), Bucket(8, 2))); |
| 419 } |
| 420 |
299 TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { | 421 TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { |
300 // We want to create a frame that is more than the SPDY Framer's max control | 422 // We want to create a frame that is more than the SPDY Framer's max control |
301 // frame size, which is 16K, but less than the HPACK decoders max decode | 423 // frame size, which is 16K, but less than the HPACK decoders max decode |
302 // buffer size, which is 32K. | 424 // buffer size, which is 32K. |
303 headers_["key0"] = string(1 << 13, '.'); | 425 headers_["key0"] = string(1 << 13, '.'); |
304 headers_["key1"] = string(1 << 13, '.'); | 426 headers_["key1"] = string(1 << 13, '.'); |
305 headers_["key2"] = string(1 << 13, '.'); | 427 headers_["key2"] = string(1 << 13, '.'); |
306 for (QuicStreamId stream_id = kClientDataStreamId1; | 428 for (QuicStreamId stream_id = kClientDataStreamId1; |
307 stream_id < kClientDataStreamId3; stream_id += 2) { | 429 stream_id < kClientDataStreamId3; stream_id += 2) { |
308 for (int count = 0; count < 2; ++count) { | 430 for (bool fin : kFins) { |
309 bool fin = (count == 0); | |
310 for (QuicPriority priority = 0; priority < 7; ++priority) { | 431 for (QuicPriority priority = 0; priority < 7; ++priority) { |
311 // Replace with "WriteHeadersAndSaveData" | 432 // Replace with "WriteHeadersAndSaveData" |
312 scoped_ptr<SpdySerializedFrame> frame; | 433 scoped_ptr<SpdySerializedFrame> frame; |
313 if (perspective() == Perspective::IS_SERVER) { | 434 if (perspective() == Perspective::IS_SERVER) { |
314 SpdyHeadersIR headers_frame(stream_id); | 435 SpdyHeadersIR headers_frame(stream_id); |
315 headers_frame.set_header_block(headers_); | 436 headers_frame.set_header_block(headers_); |
316 headers_frame.set_fin(fin); | 437 headers_frame.set_fin(fin); |
317 headers_frame.set_has_priority(true); | 438 headers_frame.set_has_priority(true); |
318 frame.reset(framer_.SerializeFrame(headers_frame)); | 439 frame.reset(framer_.SerializeFrame(headers_frame)); |
319 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); | 440 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 } | 544 } |
424 | 545 |
425 TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { | 546 TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { |
426 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( | 547 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( |
427 headers_stream_)); | 548 headers_stream_)); |
428 } | 549 } |
429 | 550 |
430 } // namespace | 551 } // namespace |
431 } // namespace test | 552 } // namespace test |
432 } // namespace net | 553 } // namespace net |
OLD | NEW |