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