Index: net/quic/quic_headers_stream_test.cc |
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc |
index fd566bfbace8a9a4a11b27067e864601fa91c98c..661a0e88c089f9e6501ae9dc2bc5029e3c8f716f 100644 |
--- a/net/quic/quic_headers_stream_test.cc |
+++ b/net/quic/quic_headers_stream_test.cc |
@@ -4,6 +4,7 @@ |
#include "net/quic/quic_headers_stream.h" |
+#include "base/test/histogram_tester.h" |
#include "net/quic/quic_utils.h" |
#include "net/quic/spdy_utils.h" |
#include "net/quic/test_tools/quic_connection_peer.h" |
@@ -14,10 +15,14 @@ |
#include "net/spdy/spdy_test_utils.h" |
#include "testing/gtest/include/gtest/gtest.h" |
+using base::Bucket; |
+using base::HistogramTester; |
using base::StringPiece; |
using std::ostream; |
using std::string; |
using std::vector; |
+using testing::ElementsAre; |
+using testing::InSequence; |
using testing::Invoke; |
using testing::StrictMock; |
using testing::WithArgs; |
@@ -27,6 +32,9 @@ namespace net { |
namespace test { |
namespace { |
+// TODO(ckrasic): this workaround is due to absence of std::initializer_list |
+const bool kFins[] = {false, true}; |
+ |
class MockVisitor : public SpdyFramerVisitorInterface { |
public: |
MOCK_METHOD1(OnError, void(SpdyFramer* framer)); |
@@ -124,6 +132,7 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> { |
EXPECT_EQ(version(), session_.connection()->version()); |
EXPECT_TRUE(headers_stream_ != nullptr); |
VLOG(1) << GetParam(); |
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
} |
QuicConsumedData SaveIov(const QuicIOVector& data) { |
@@ -246,8 +255,7 @@ TEST_P(QuicHeadersStreamTest, EffectivePriority) { |
TEST_P(QuicHeadersStreamTest, WriteHeaders) { |
for (QuicStreamId stream_id = kClientDataStreamId1; |
stream_id < kClientDataStreamId3; stream_id += 2) { |
- for (int count = 0; count < 2; ++count) { |
- bool fin = (count == 0); |
+ for (bool fin : kFins) { |
if (perspective() == Perspective::IS_SERVER) { |
WriteHeadersAndExpectSynReply(stream_id, fin); |
} else { |
@@ -263,8 +271,7 @@ TEST_P(QuicHeadersStreamTest, WriteHeaders) { |
TEST_P(QuicHeadersStreamTest, ProcessRawData) { |
for (QuicStreamId stream_id = kClientDataStreamId1; |
stream_id < kClientDataStreamId3; stream_id += 2) { |
- for (int count = 0; count < 2; ++count) { |
- bool fin = (count == 0); |
+ for (bool fin : kFins) { |
for (QuicPriority priority = 0; priority < 7; ++priority) { |
// Replace with "WriteHeadersAndSaveData" |
scoped_ptr<SpdySerializedFrame> frame; |
@@ -296,6 +303,121 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) { |
} |
} |
+TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) { |
+// In the absence of surfacing HOL measurements externally, via UMA |
+// or tcp connection stats, log messages are the only indication. |
+// This test verifies that false positives are not generated when |
+// headers arrive in order. |
+#if 0 |
+ ScopedMockLog log(kDoNotCaptureLogsYet); |
+ EXPECT_CALL(log, Log(_, _, _)).Times(0); |
+ log.StartCapturingLogs(); |
+#endif |
+ InSequence seq; |
+ HistogramTester histogram_tester; |
+ bool fin = true; |
+ for (int stream_num = 0; stream_num < 10; stream_num++) { |
+ QuicStreamId stream_id = QuicClientDataStreamId(stream_num); |
+ // Replace with "WriteHeadersAndSaveData" |
+ scoped_ptr<SpdySerializedFrame> frame; |
+ if (perspective() == Perspective::IS_SERVER) { |
+ SpdyHeadersIR headers_frame(stream_id); |
+ headers_frame.set_header_block(headers_); |
+ headers_frame.set_fin(fin); |
+ headers_frame.set_has_priority(true); |
+ frame.reset(framer_.SerializeFrame(headers_frame)); |
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); |
+ } else { |
+ SpdyHeadersIR headers_frame(stream_id); |
+ headers_frame.set_header_block(headers_); |
+ headers_frame.set_fin(fin); |
+ frame.reset(framer_.SerializeFrame(headers_frame)); |
+ } |
+ EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)); |
+ EXPECT_CALL(session_, |
+ OnStreamHeadersComplete(stream_id, fin, frame->size())); |
+ stream_frame_.data = StringPiece(frame->data(), frame->size()); |
+ headers_stream_->OnStreamFrame(stream_frame_); |
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
+ stream_frame_.offset += frame->size(); |
+ } |
+ histogram_tester.ExpectTotalCount("Net.QuicSession.HeadersHOLBlockedTime", 0); |
+} |
+ |
+TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) { |
+// In the absence of surfacing HOL measurements externally, via UMA |
+// or tcp connection stats, log messages are the only indication. |
+// This test verifies that HOL blocking log messages are correct |
+// when there are out of order arrivals. |
+#if 0 |
+ ScopedMockLog log(kDoNotCaptureLogsYet); |
+#endif |
+ HistogramTester histogram_tester; |
+ QuicStreamId stream_id; |
+ bool fin = true; |
+ QuicStreamFrame stream_frames[10]; |
+ scoped_ptr<SpdySerializedFrame> frames[10]; |
+ // First create all the frames in order |
+ { |
+ InSequence seq; |
+ for (int stream_num = 0; stream_num < 10; ++stream_num) { |
+ stream_id = QuicClientDataStreamId(stream_num); |
+ if (perspective() == Perspective::IS_SERVER) { |
+ SpdyHeadersIR headers_frame(stream_id); |
+ headers_frame.set_header_block(headers_); |
+ headers_frame.set_fin(fin); |
+ headers_frame.set_has_priority(true); |
+ frames[stream_num].reset(framer_.SerializeFrame(headers_frame)); |
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)).Times(1); |
+ } else { |
+ SpdyHeadersIR headers_frame(stream_id); |
+ headers_frame.set_header_block(headers_); |
+ headers_frame.set_fin(fin); |
+ frames[stream_num].reset(framer_.SerializeFrame(headers_frame)); |
+ } |
+ stream_frames[stream_num] = stream_frame_; |
+ stream_frames[stream_num].data = |
+ StringPiece(frames[stream_num]->data(), frames[stream_num]->size()); |
+ DVLOG(1) << "make frame for stream " << stream_num << " offset " |
+ << stream_frames[stream_num].offset; |
+ stream_frame_.offset += frames[stream_num]->size(); |
+ EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)).Times(1); |
+ EXPECT_CALL(session_, OnStreamHeadersComplete(stream_id, fin, _)) |
+ .Times(1); |
+ } |
+ } |
+#if 0 |
+ // Actually writing the frames in reverse order will trigger log messages. |
+ { |
+ InSequence seq; |
+ for (int stream_num = 0; stream_num < 10; ++stream_num) { |
+ stream_id = QuicClientDataStreamId(stream_num); |
+ if (stream_num > 0) { |
+ string expected_msg = StringPrintf( |
+ "stream %d: Net.QuicSession.HeadersHOLBlockedTime %d", |
+ stream_id, stream_num); |
+#ifndef NDEBUG |
+ EXPECT_CALL(log, Log(INFO, _, expected_msg)); |
+#endif |
+ } |
+ } |
+ } |
+ log.StartCapturingLogs(); |
+#endif |
+ for (int stream_num = 9; stream_num >= 0; --stream_num) { |
+ DVLOG(1) << "OnStreamFrame for stream " << stream_num << " offset " |
+ << stream_frames[stream_num].offset; |
+ headers_stream_->OnStreamFrame(stream_frames[stream_num]); |
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
+ } |
+ // We expect 1 sample each for delays from 1 to 9 ms (8 and 9 go |
+ // into the same bucket). |
+ EXPECT_THAT( |
+ histogram_tester.GetAllSamples("Net.QuicSession.HeadersHOLBlockedTime"), |
+ ElementsAre(Bucket(1, 1), Bucket(2, 1), Bucket(3, 1), Bucket(4, 1), |
+ Bucket(5, 1), Bucket(6, 1), Bucket(7, 1), Bucket(8, 2))); |
+} |
+ |
TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { |
// We want to create a frame that is more than the SPDY Framer's max control |
// frame size, which is 16K, but less than the HPACK decoders max decode |
@@ -305,8 +427,7 @@ TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { |
headers_["key2"] = string(1 << 13, '.'); |
for (QuicStreamId stream_id = kClientDataStreamId1; |
stream_id < kClientDataStreamId3; stream_id += 2) { |
- for (int count = 0; count < 2; ++count) { |
- bool fin = (count == 0); |
+ for (bool fin : kFins) { |
for (QuicPriority priority = 0; priority < 7; ++priority) { |
// Replace with "WriteHeadersAndSaveData" |
scoped_ptr<SpdySerializedFrame> frame; |