| 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 |