Roll WebRTC 9745:9761, Libjingle 9742:9761
[chromium-blink-merge.git] / net / quic / quic_headers_stream_test.cc
blobfd566bfbace8a9a4a11b27067e864601fa91c98c
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
3 // found in the LICENSE file.
5 #include "net/quic/quic_headers_stream.h"
7 #include "net/quic/quic_utils.h"
8 #include "net/quic/spdy_utils.h"
9 #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_test_utils.h"
12 #include "net/quic/test_tools/reliable_quic_stream_peer.h"
13 #include "net/spdy/spdy_protocol.h"
14 #include "net/spdy/spdy_test_utils.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 using base::StringPiece;
18 using std::ostream;
19 using std::string;
20 using std::vector;
21 using testing::Invoke;
22 using testing::StrictMock;
23 using testing::WithArgs;
24 using testing::_;
26 namespace net {
27 namespace test {
28 namespace {
30 class MockVisitor : public SpdyFramerVisitorInterface {
31 public:
32 MOCK_METHOD1(OnError, void(SpdyFramer* framer));
33 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id,
34 size_t length,
35 bool fin));
36 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id,
37 const char* data,
38 size_t len,
39 bool fin));
40 MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len));
41 MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id,
42 const char* header_data,
43 size_t len));
44 MOCK_METHOD5(OnSynStream, void(SpdyStreamId stream_id,
45 SpdyStreamId associated_stream_id,
46 SpdyPriority priority,
47 bool fin,
48 bool unidirectional));
49 MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
50 MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id,
51 SpdyRstStreamStatus status));
52 MOCK_METHOD1(OnSettings, void(bool clear_persisted));
53 MOCK_METHOD3(OnSetting, void(SpdySettingsIds id, uint8 flags, uint32 value));
54 MOCK_METHOD0(OnSettingsAck, void());
55 MOCK_METHOD0(OnSettingsEnd, void());
56 MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
57 MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
58 SpdyGoAwayStatus status));
59 MOCK_METHOD7(OnHeaders,
60 void(SpdyStreamId stream_id,
61 bool has_priority,
62 SpdyPriority priority,
63 SpdyStreamId parent_stream_id,
64 bool exclusive,
65 bool fin,
66 bool end));
67 MOCK_METHOD2(OnWindowUpdate,
68 void(SpdyStreamId stream_id, int delta_window_size));
69 MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
70 size_t len));
71 MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
72 MOCK_METHOD3(OnPushPromise, void(SpdyStreamId stream_id,
73 SpdyStreamId promised_stream_id,
74 bool end));
75 MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
76 MOCK_METHOD3(OnAltSvc,
77 void(SpdyStreamId stream_id,
78 StringPiece origin,
79 const SpdyAltSvcWireFormat::AlternativeServiceVector&
80 altsvc_vector));
81 MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
84 // Run all tests with each version, and client or server
85 struct TestParams {
86 TestParams(QuicVersion version, Perspective perspective)
87 : version(version), perspective(perspective) {}
89 friend ostream& operator<<(ostream& os, const TestParams& p) {
90 os << "{ version: " << QuicVersionToString(p.version);
91 os << ", perspective: " << p.perspective << " }";
92 return os;
95 QuicVersion version;
96 Perspective perspective;
99 // Constructs various test permutations.
100 vector<TestParams> GetTestParams() {
101 vector<TestParams> params;
102 QuicVersionVector all_supported_versions = QuicSupportedVersions();
103 for (const QuicVersion version : all_supported_versions) {
104 params.push_back(TestParams(version, Perspective::IS_CLIENT));
105 params.push_back(TestParams(version, Perspective::IS_SERVER));
107 return params;
110 class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
111 public:
112 QuicHeadersStreamTest()
113 : connection_(
114 new StrictMock<MockConnection>(perspective(), GetVersion())),
115 session_(connection_),
116 headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)),
117 body_("hello world"),
118 framer_(HTTP2),
119 stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, "") {
120 headers_[":version"] = "HTTP/1.1";
121 headers_[":status"] = "200 Ok";
122 headers_["content-length"] = "11";
123 framer_.set_visitor(&visitor_);
124 EXPECT_EQ(version(), session_.connection()->version());
125 EXPECT_TRUE(headers_stream_ != nullptr);
126 VLOG(1) << GetParam();
129 QuicConsumedData SaveIov(const QuicIOVector& data) {
130 const iovec* iov = data.iov;
131 int count = data.iov_count;
132 for (int i = 0 ; i < count; ++i) {
133 saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
135 return QuicConsumedData(saved_data_.length(), false);
138 bool SaveHeaderData(const char* data, int len) {
139 saved_header_data_.append(data, len);
140 return true;
143 void SaveHeaderDataStringPiece(StringPiece data) {
144 saved_header_data_.append(data.data(), data.length());
147 void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
148 bool fin,
149 QuicPriority priority) {
150 WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
153 void WriteHeadersAndExpectSynReply(QuicStreamId stream_id,
154 bool fin) {
155 WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
158 void WriteHeadersAndCheckData(QuicStreamId stream_id,
159 bool fin,
160 QuicPriority priority,
161 SpdyFrameType type) {
162 // Write the headers and capture the outgoing data
163 EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, _, nullptr))
164 .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
165 headers_stream_->WriteHeaders(stream_id, headers_, fin, priority, nullptr);
167 // Parse the outgoing data and check that it matches was was written.
168 if (type == SYN_STREAM) {
169 EXPECT_CALL(visitor_, OnHeaders(stream_id, kHasPriority, priority,
170 /*parent_stream_id=*/0,
171 /*exclusive=*/false,
173 fin, kFrameComplete));
174 } else {
175 EXPECT_CALL(visitor_,
176 OnHeaders(stream_id, !kHasPriority,
177 /*priority=*/0,
178 /*parent_stream_id=*/0,
179 /*exclusive=*/false, fin, kFrameComplete));
181 EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _))
182 .WillRepeatedly(WithArgs<1, 2>(
183 Invoke(this, &QuicHeadersStreamTest::SaveHeaderData)));
184 if (fin) {
185 EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, nullptr, 0, true));
187 framer_.ProcessInput(saved_data_.data(), saved_data_.length());
188 EXPECT_FALSE(framer_.HasError())
189 << SpdyFramer::ErrorCodeToString(framer_.error_code());
191 CheckHeaders();
192 saved_data_.clear();
195 void CheckHeaders() {
196 SpdyHeaderBlock headers;
197 EXPECT_EQ(saved_header_data_.length(),
198 framer_.ParseHeaderBlockInBuffer(saved_header_data_.data(),
199 saved_header_data_.length(),
200 &headers));
201 EXPECT_TRUE(CompareSpdyHeaderBlocks(headers_, headers));
202 saved_header_data_.clear();
205 Perspective perspective() { return GetParam().perspective; }
207 QuicVersion version() { return GetParam().version; }
209 QuicVersionVector GetVersion() {
210 QuicVersionVector versions;
211 versions.push_back(version());
212 return versions;
215 void CloseConnection() {
216 QuicConnectionPeer::CloseConnection(connection_);
219 static const bool kFrameComplete = true;
220 static const bool kHasPriority = true;
222 StrictMock<MockConnection>* connection_;
223 StrictMock<MockQuicSpdySession> session_;
224 QuicHeadersStream* headers_stream_;
225 SpdyHeaderBlock headers_;
226 string body_;
227 string saved_data_;
228 string saved_header_data_;
229 SpdyFramer framer_;
230 StrictMock<MockVisitor> visitor_;
231 QuicStreamFrame stream_frame_;
234 INSTANTIATE_TEST_CASE_P(Tests,
235 QuicHeadersStreamTest,
236 ::testing::ValuesIn(GetTestParams()));
238 TEST_P(QuicHeadersStreamTest, StreamId) {
239 EXPECT_EQ(3u, headers_stream_->id());
242 TEST_P(QuicHeadersStreamTest, EffectivePriority) {
243 EXPECT_EQ(0u, headers_stream_->EffectivePriority());
246 TEST_P(QuicHeadersStreamTest, WriteHeaders) {
247 for (QuicStreamId stream_id = kClientDataStreamId1;
248 stream_id < kClientDataStreamId3; stream_id += 2) {
249 for (int count = 0; count < 2; ++count) {
250 bool fin = (count == 0);
251 if (perspective() == Perspective::IS_SERVER) {
252 WriteHeadersAndExpectSynReply(stream_id, fin);
253 } else {
254 for (QuicPriority priority = 0; priority < 7; ++priority) {
255 // TODO(rch): implement priorities correctly.
256 WriteHeadersAndExpectSynStream(stream_id, fin, 0);
263 TEST_P(QuicHeadersStreamTest, ProcessRawData) {
264 for (QuicStreamId stream_id = kClientDataStreamId1;
265 stream_id < kClientDataStreamId3; stream_id += 2) {
266 for (int count = 0; count < 2; ++count) {
267 bool fin = (count == 0);
268 for (QuicPriority priority = 0; priority < 7; ++priority) {
269 // Replace with "WriteHeadersAndSaveData"
270 scoped_ptr<SpdySerializedFrame> frame;
271 if (perspective() == Perspective::IS_SERVER) {
272 SpdyHeadersIR headers_frame(stream_id);
273 headers_frame.set_header_block(headers_);
274 headers_frame.set_fin(fin);
275 headers_frame.set_has_priority(true);
276 frame.reset(framer_.SerializeFrame(headers_frame));
277 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
278 } else {
279 SpdyHeadersIR headers_frame(stream_id);
280 headers_frame.set_header_block(headers_);
281 headers_frame.set_fin(fin);
282 frame.reset(framer_.SerializeFrame(headers_frame));
284 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
285 .WillRepeatedly(WithArgs<1>(
286 Invoke(this,
287 &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
288 EXPECT_CALL(session_,
289 OnStreamHeadersComplete(stream_id, fin, frame->size()));
290 stream_frame_.data = StringPiece(frame->data(), frame->size());
291 headers_stream_->OnStreamFrame(stream_frame_);
292 stream_frame_.offset += frame->size();
293 CheckHeaders();
299 TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) {
300 // 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
302 // buffer size, which is 32K.
303 headers_["key0"] = string(1 << 13, '.');
304 headers_["key1"] = string(1 << 13, '.');
305 headers_["key2"] = string(1 << 13, '.');
306 for (QuicStreamId stream_id = kClientDataStreamId1;
307 stream_id < kClientDataStreamId3; stream_id += 2) {
308 for (int count = 0; count < 2; ++count) {
309 bool fin = (count == 0);
310 for (QuicPriority priority = 0; priority < 7; ++priority) {
311 // Replace with "WriteHeadersAndSaveData"
312 scoped_ptr<SpdySerializedFrame> frame;
313 if (perspective() == Perspective::IS_SERVER) {
314 SpdyHeadersIR headers_frame(stream_id);
315 headers_frame.set_header_block(headers_);
316 headers_frame.set_fin(fin);
317 headers_frame.set_has_priority(true);
318 frame.reset(framer_.SerializeFrame(headers_frame));
319 EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
320 } else {
321 SpdyHeadersIR headers_frame(stream_id);
322 headers_frame.set_header_block(headers_);
323 headers_frame.set_fin(fin);
324 frame.reset(framer_.SerializeFrame(headers_frame));
326 EXPECT_CALL(session_, OnStreamHeaders(stream_id, _))
327 .WillRepeatedly(WithArgs<1>(Invoke(
328 this, &QuicHeadersStreamTest::SaveHeaderDataStringPiece)));
329 EXPECT_CALL(session_,
330 OnStreamHeadersComplete(stream_id, fin, frame->size()));
331 stream_frame_.data = StringPiece(frame->data(), frame->size());
332 headers_stream_->OnStreamFrame(stream_frame_);
333 stream_frame_.offset += frame->size();
334 CheckHeaders();
340 TEST_P(QuicHeadersStreamTest, ProcessBadData) {
341 const char kBadData[] = "blah blah blah";
342 EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
343 QUIC_INVALID_HEADERS_STREAM_DATA, _))
344 .Times(::testing::AnyNumber());
345 stream_frame_.data = StringPiece(kBadData, strlen(kBadData));
346 headers_stream_->OnStreamFrame(stream_frame_);
349 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
350 SpdyDataIR data(2, "");
351 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
352 EXPECT_CALL(*connection_,
353 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
354 "SPDY DATA frame received."))
355 .WillOnce(InvokeWithoutArgs(this,
356 &QuicHeadersStreamTest::CloseConnection));
357 stream_frame_.data = StringPiece(frame->data(), frame->size());
358 headers_stream_->OnStreamFrame(stream_frame_);
361 TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
362 SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR, "");
363 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
364 EXPECT_CALL(*connection_,
365 SendConnectionCloseWithDetails(
366 QUIC_INVALID_HEADERS_STREAM_DATA,
367 "SPDY RST_STREAM frame received."))
368 .WillOnce(InvokeWithoutArgs(this,
369 &QuicHeadersStreamTest::CloseConnection));
370 stream_frame_.data = StringPiece(frame->data(), frame->size());
371 headers_stream_->OnStreamFrame(stream_frame_);
374 TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
375 SpdySettingsIR data;
376 data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, 0);
377 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
378 EXPECT_CALL(*connection_,
379 SendConnectionCloseWithDetails(
380 QUIC_INVALID_HEADERS_STREAM_DATA,
381 "SPDY SETTINGS frame received."))
382 .WillOnce(InvokeWithoutArgs(this,
383 &QuicHeadersStreamTest::CloseConnection));
384 stream_frame_.data = StringPiece(frame->data(), frame->size());
385 headers_stream_->OnStreamFrame(stream_frame_);
388 TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
389 SpdyPingIR data(1);
390 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
391 EXPECT_CALL(*connection_,
392 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
393 "SPDY PING frame received."))
394 .WillOnce(InvokeWithoutArgs(this,
395 &QuicHeadersStreamTest::CloseConnection));
396 stream_frame_.data = StringPiece(frame->data(), frame->size());
397 headers_stream_->OnStreamFrame(stream_frame_);
400 TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
401 SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
402 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
403 EXPECT_CALL(*connection_,
404 SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
405 "SPDY GOAWAY frame received."))
406 .WillOnce(InvokeWithoutArgs(this,
407 &QuicHeadersStreamTest::CloseConnection));
408 stream_frame_.data = StringPiece(frame->data(), frame->size());
409 headers_stream_->OnStreamFrame(stream_frame_);
412 TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
413 SpdyWindowUpdateIR data(1, 1);
414 scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data));
415 EXPECT_CALL(*connection_,
416 SendConnectionCloseWithDetails(
417 QUIC_INVALID_HEADERS_STREAM_DATA,
418 "SPDY WINDOW_UPDATE frame received."))
419 .WillOnce(InvokeWithoutArgs(this,
420 &QuicHeadersStreamTest::CloseConnection));
421 stream_frame_.data = StringPiece(frame->data(), frame->size());
422 headers_stream_->OnStreamFrame(stream_frame_);
425 TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) {
426 EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(
427 headers_stream_));
430 } // namespace
431 } // namespace test
432 } // namespace net