| 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 89c87f29c29e8c30a33f01cde77080133b754a1c..9d684ac4c76f38bf2563442e731af513a43d4092 100644
|
| --- a/net/quic/quic_headers_stream_test.cc
|
| +++ b/net/quic/quic_headers_stream_test.cc
|
| @@ -14,7 +14,9 @@
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| using base::StringPiece;
|
| +using std::ostream;
|
| using std::string;
|
| +using std::vector;
|
| using testing::Invoke;
|
| using testing::StrictMock;
|
| using testing::WithArgs;
|
| @@ -72,26 +74,47 @@ class MockVisitor : public SpdyFramerVisitorInterface {
|
| MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
|
| };
|
|
|
| -class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
|
| - public:
|
| - static QuicVersionVector GetVersions() {
|
| - QuicVersionVector versions;
|
| - versions.push_back(QuicVersionMax());
|
| - return versions;
|
| +// Run all tests with each version, and client or server
|
| +struct TestParams {
|
| + TestParams(QuicVersion version, bool is_server)
|
| + : version(version), is_server(is_server) {}
|
| +
|
| + friend ostream& operator<<(ostream& os, const TestParams& p) {
|
| + os << "{ version: " << QuicVersionToString(p.version);
|
| + os << ", is_server: " << p.is_server << " }";
|
| + return os;
|
| }
|
|
|
| + QuicVersion version;
|
| + bool is_server;
|
| +};
|
| +
|
| +// Constructs various test permutations.
|
| +vector<TestParams> GetTestParams() {
|
| + vector<TestParams> params;
|
| + QuicVersionVector all_supported_versions = QuicSupportedVersions();
|
| + for (const QuicVersion version : all_supported_versions) {
|
| + params.push_back(TestParams(version, false));
|
| + params.push_back(TestParams(version, true));
|
| + }
|
| + return params;
|
| +}
|
| +
|
| +class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
|
| + public:
|
| QuicHeadersStreamTest()
|
| - : connection_(new StrictMock<MockConnection>(is_server(), GetVersions())),
|
| + : connection_(new StrictMock<MockConnection>(is_server(), GetVersion())),
|
| session_(connection_),
|
| headers_stream_(QuicSessionPeer::GetHeadersStream(&session_)),
|
| body_("hello world"),
|
| - framer_(SPDY3) {
|
| + framer_(version() > QUIC_VERSION_23 ? SPDY4 : SPDY3) {
|
| headers_[":version"] = "HTTP/1.1";
|
| headers_[":status"] = "200 Ok";
|
| headers_["content-length"] = "11";
|
| framer_.set_visitor(&visitor_);
|
| - EXPECT_EQ(QuicVersionMax(), session_.connection()->version());
|
| + EXPECT_EQ(version(), session_.connection()->version());
|
| EXPECT_TRUE(headers_stream_ != nullptr);
|
| + VLOG(1) << GetParam();
|
| }
|
|
|
| QuicConsumedData SaveIov(const IOVector& data) {
|
| @@ -130,15 +153,25 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
|
| // Write the headers and capture the outgoing data
|
| EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, _, nullptr))
|
| .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
|
| - headers_stream_->WriteHeaders(stream_id, headers_, fin, nullptr);
|
| + headers_stream_->WriteHeaders(stream_id, headers_, fin, priority, nullptr);
|
|
|
| // Parse the outgoing data and check that it matches was was written.
|
| if (type == SYN_STREAM) {
|
| - EXPECT_CALL(visitor_, OnSynStream(stream_id, kNoAssociatedStream, 0,
|
| - // priority,
|
| - fin, kNotUnidirectional));
|
| + if (version() > QUIC_VERSION_23) {
|
| + EXPECT_CALL(visitor_, OnHeaders(stream_id, kHasPriority, priority, fin,
|
| + kFrameComplete));
|
| + } else {
|
| + EXPECT_CALL(visitor_,
|
| + OnSynStream(stream_id, kNoAssociatedStream,
|
| + /*priority=*/0, fin, kNotUnidirectional));
|
| + }
|
| } else {
|
| - EXPECT_CALL(visitor_, OnSynReply(stream_id, fin));
|
| + if (version() > QUIC_VERSION_23) {
|
| + EXPECT_CALL(visitor_, OnHeaders(stream_id, !kHasPriority,
|
| + /*priority=*/0, fin, kFrameComplete));
|
| + } else {
|
| + EXPECT_CALL(visitor_, OnSynReply(stream_id, fin));
|
| + }
|
| }
|
| EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
|
| .WillRepeatedly(WithArgs<1, 2>(
|
| @@ -147,7 +180,8 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
|
| EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, nullptr, 0, true));
|
| }
|
| framer_.ProcessInput(saved_data_.data(), saved_data_.length());
|
| - EXPECT_FALSE(framer_.HasError()) << framer_.error_code();
|
| + EXPECT_FALSE(framer_.HasError())
|
| + << SpdyFramer::ErrorCodeToString(framer_.error_code());
|
|
|
| CheckHeaders();
|
| saved_data_.clear();
|
| @@ -163,14 +197,22 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
|
| saved_header_data_.clear();
|
| }
|
|
|
| - bool is_server() {
|
| - return GetParam();
|
| + bool is_server() { return GetParam().is_server; }
|
| +
|
| + QuicVersion version() { return GetParam().version; }
|
| +
|
| + QuicVersionVector GetVersion() {
|
| + QuicVersionVector versions;
|
| + versions.push_back(version());
|
| + return versions;
|
| }
|
|
|
| void CloseConnection() {
|
| QuicConnectionPeer::CloseConnection(connection_);
|
| }
|
|
|
| + static const bool kFrameComplete = true;
|
| + static const bool kHasPriority = true;
|
| static const bool kNotUnidirectional = false;
|
| static const bool kNoAssociatedStream = false;
|
|
|
| @@ -185,7 +227,9 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<bool> {
|
| StrictMock<MockVisitor> visitor_;
|
| };
|
|
|
| -INSTANTIATE_TEST_CASE_P(Tests, QuicHeadersStreamTest, testing::Bool());
|
| +INSTANTIATE_TEST_CASE_P(Tests,
|
| + QuicHeadersStreamTest,
|
| + ::testing::ValuesIn(GetTestParams()));
|
|
|
| TEST_P(QuicHeadersStreamTest, StreamId) {
|
| EXPECT_EQ(3u, headers_stream_->id());
|
| @@ -204,7 +248,8 @@ TEST_P(QuicHeadersStreamTest, WriteHeaders) {
|
| WriteHeadersAndExpectSynReply(stream_id, fin);
|
| } else {
|
| for (QuicPriority priority = 0; priority < 7; ++priority) {
|
| - WriteHeadersAndExpectSynStream(stream_id, fin, priority);
|
| + // TODO(rch): implement priorities correctly.
|
| + WriteHeadersAndExpectSynStream(stream_id, fin, 0);
|
| }
|
| }
|
| }
|
| @@ -220,16 +265,31 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) {
|
| // Replace with "WriteHeadersAndSaveData"
|
| scoped_ptr<SpdySerializedFrame> frame;
|
| if (is_server()) {
|
| - SpdySynStreamIR syn_stream(stream_id);
|
| - syn_stream.set_name_value_block(headers_);
|
| - syn_stream.set_fin(fin);
|
| - frame.reset(framer_.SerializeSynStream(syn_stream));
|
| + if (version() > QUIC_VERSION_23) {
|
| + SpdyHeadersIR headers_frame(stream_id);
|
| + headers_frame.set_name_value_block(headers_);
|
| + headers_frame.set_fin(fin);
|
| + headers_frame.set_has_priority(true);
|
| + frame.reset(framer_.SerializeFrame(headers_frame));
|
| + } else {
|
| + SpdySynStreamIR syn_stream(stream_id);
|
| + syn_stream.set_name_value_block(headers_);
|
| + syn_stream.set_fin(fin);
|
| + frame.reset(framer_.SerializeSynStream(syn_stream));
|
| + }
|
| EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
|
| } else {
|
| - SpdySynReplyIR syn_reply(stream_id);
|
| - syn_reply.set_name_value_block(headers_);
|
| - syn_reply.set_fin(fin);
|
| - frame.reset(framer_.SerializeSynReply(syn_reply));
|
| + if (version() > QUIC_VERSION_23) {
|
| + SpdyHeadersIR headers_frame(stream_id);
|
| + headers_frame.set_name_value_block(headers_);
|
| + headers_frame.set_fin(fin);
|
| + frame.reset(framer_.SerializeFrame(headers_frame));
|
| + } else {
|
| + SpdySynReplyIR syn_reply(stream_id);
|
| + syn_reply.set_name_value_block(headers_);
|
| + syn_reply.set_fin(fin);
|
| + frame.reset(framer_.SerializeSynReply(syn_reply));
|
| + }
|
| }
|
| EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
|
| .WillRepeatedly(WithArgs<1>(
|
| @@ -238,7 +298,59 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) {
|
| EXPECT_CALL(session_,
|
| OnStreamHeadersComplete(stream_id, fin, frame->size()));
|
| headers_stream_->ProcessRawData(frame->data(), frame->size());
|
| + CheckHeaders();
|
| + }
|
| + }
|
| + }
|
| +}
|
|
|
| +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
|
| + // buffer size, which is 32K.
|
| + headers_["key0"] = string(1 << 13, '.');
|
| + headers_["key1"] = string(1 << 13, '.');
|
| + 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 (QuicPriority priority = 0; priority < 7; ++priority) {
|
| + // Replace with "WriteHeadersAndSaveData"
|
| + scoped_ptr<SpdySerializedFrame> frame;
|
| + if (is_server()) {
|
| + if (version() > QUIC_VERSION_23) {
|
| + SpdyHeadersIR headers_frame(stream_id);
|
| + headers_frame.set_name_value_block(headers_);
|
| + headers_frame.set_fin(fin);
|
| + headers_frame.set_has_priority(true);
|
| + frame.reset(framer_.SerializeFrame(headers_frame));
|
| + } else {
|
| + SpdySynStreamIR syn_stream(stream_id);
|
| + syn_stream.set_name_value_block(headers_);
|
| + syn_stream.set_fin(fin);
|
| + frame.reset(framer_.SerializeSynStream(syn_stream));
|
| + }
|
| + EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
|
| + } else {
|
| + if (version() > QUIC_VERSION_23) {
|
| + SpdyHeadersIR headers_frame(stream_id);
|
| + headers_frame.set_name_value_block(headers_);
|
| + headers_frame.set_fin(fin);
|
| + frame.reset(framer_.SerializeFrame(headers_frame));
|
| + } else {
|
| + SpdySynReplyIR syn_reply(stream_id);
|
| + syn_reply.set_name_value_block(headers_);
|
| + syn_reply.set_fin(fin);
|
| + frame.reset(framer_.SerializeSynReply(syn_reply));
|
| + }
|
| + }
|
| + EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
|
| + .WillRepeatedly(WithArgs<1>(Invoke(
|
| + this, &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
|
| + EXPECT_CALL(session_,
|
| + OnStreamHeadersComplete(stream_id, fin, frame->size()));
|
| + headers_stream_->ProcessRawData(frame->data(), frame->size());
|
| CheckHeaders();
|
| }
|
| }
|
| @@ -247,10 +359,9 @@ TEST_P(QuicHeadersStreamTest, ProcessRawData) {
|
|
|
| TEST_P(QuicHeadersStreamTest, ProcessBadData) {
|
| const char kBadData[] = "blah blah blah";
|
| - EXPECT_CALL(*connection_,
|
| - SendConnectionCloseWithDetails(
|
| - QUIC_INVALID_HEADERS_STREAM_DATA,
|
| - "SPDY framing error: SPDY_INVALID_DATA_FRAME_FLAGS"));
|
| + EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
|
| + QUIC_INVALID_HEADERS_STREAM_DATA, _))
|
| + .Times(::testing::AnyNumber());
|
| headers_stream_->ProcessRawData(kBadData, strlen(kBadData));
|
| }
|
|
|
| @@ -279,7 +390,11 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
|
|
|
| TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
|
| SpdySettingsIR data;
|
| - data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0);
|
| + if (version() > QUIC_VERSION_23) {
|
| + data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, 0);
|
| + } else {
|
| + data.AddSetting(SETTINGS_UPLOAD_BANDWIDTH, true, true, 0);
|
| + }
|
| scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
|
| EXPECT_CALL(*connection_,
|
| SendConnectionCloseWithDetails(
|
| @@ -313,6 +428,12 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
|
| }
|
|
|
| TEST_P(QuicHeadersStreamTest, ProcessSpdyHeadersFrame) {
|
| + if (version() > QUIC_VERSION_23) {
|
| + // HEADERS frames are an error when using SPDY/3, but
|
| + // when using SPDY/4 they're the "normal" way of sending headers
|
| + // so we test their handling in the ProcessRawData test.
|
| + return;
|
| + }
|
| SpdyHeadersIR data(1);
|
| scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
|
| EXPECT_CALL(*connection_,
|
|
|