Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: net/spdy/bidirectional_stream_spdy_job_unittest.cc

Issue 1326503003: Added a net::BidirectionalStream to expose a bidirectional streaming interface (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix bug and added a test Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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.
4
5 #include "net/spdy/bidirectional_stream_spdy_job.h"
6
7 #include <string>
8
9 #include "base/macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_piece.h"
13 #include "base/time/time.h"
14 #include "base/timer/mock_timer.h"
15 #include "net/base/net_errors.h"
16 #include "net/http/http_request_info.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_response_info.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/spdy/spdy_read_queue.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_test_util_common.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace net {
26
27 namespace {
28
29 const char kBodyData[] = "Body data";
30 const size_t kBodyDataSize = arraysize(kBodyData);
31 // Size of the buffer to be allocated for each read.
32 const size_t kReadBufferSize = 4096;
33 // Size of the small buffer used for each read. This is to test the case where
34 // the entire response body does not fit in one buffer.
35 const size_t kSmallReadBufferSize = 4;
36
37 // Delegate that reads data but does not send any data.
38 class TestDelegateBase : public BidirectionalStreamJob::Delegate {
39 public:
40 TestDelegateBase(base::WeakPtr<SpdySession> session,
41 IOBuffer* read_buf,
42 int read_buf_len)
43 : TestDelegateBase(session,
44 read_buf,
45 read_buf_len,
46 make_scoped_ptr(new base::Timer(false, false))) {}
47
48 TestDelegateBase(base::WeakPtr<SpdySession> session,
49 IOBuffer* read_buf,
50 int read_buf_len,
51 scoped_ptr<base::Timer> timer)
52 : stream_(new BidirectionalStreamSpdyJob(session, timer.Pass())),
53 read_buf_(read_buf),
54 read_buf_len_(read_buf_len),
55 loop_(nullptr),
56 error_(OK),
57 bytes_read_(0),
58 on_read_complete_count_(0),
59 on_data_sent_count_(0),
60 do_not_start_read_(false),
61 run_until_completion_(false) {}
62
63 ~TestDelegateBase() override {}
64
65 void OnRequestHeadersSent() override {}
66
67 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
68 response_headers_ = response_headers;
69 if (!do_not_start_read_)
70 StartOrContinueReading();
71 }
72
73 void OnReadCompleted(int bytes_read) override {
74 on_read_complete_count_++;
75 CHECK_GE(bytes_read, OK);
76 bytes_read_ += bytes_read;
77 data_received_.append(read_buf_->data(), bytes_read);
78 if (!do_not_start_read_)
79 StartOrContinueReading();
80 }
81
82 void OnDataSent() override { on_data_sent_count_++; }
83
84 void OnTrailers(const SpdyHeaderBlock& trailers) override {
85 trailers_ = trailers;
86 if (run_until_completion_)
87 loop_->Quit();
88 }
89
90 void OnFailed(int error) override {
91 CHECK_NE(OK, error);
92 error_ = error;
93 if (run_until_completion_)
94 loop_->Quit();
95 }
96
97 void Start(const HttpRequestInfo& request,
98 RequestPriority priority,
99 const BoundNetLog& net_log) {
100 stream_->Start(request, priority, net_log, this);
101 if (run_until_completion_)
102 loop_->Run();
103 }
104
105 void SendData(IOBuffer* data, int length, bool end_of_stream) {
106 stream_->SendData(data, length, end_of_stream);
107 }
108
109 // Starts or continues read data from |stream_| until there is no more byte
110 // can be read synchronously.
111 void StartOrContinueReading() {
112 int rv = ReadData();
113 while (rv > 0) {
114 rv = ReadData();
115 }
116 if (run_until_completion_ && rv == 0)
117 loop_->Quit();
118 }
119
120 // Calls ReadData on the |stream_| and updates internal states.
121 int ReadData() {
122 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
123 if (rv > 0) {
124 data_received_.append(read_buf_->data(), rv);
125 bytes_read_ += rv;
126 }
127 return rv;
128 }
129
130 // Const getters for internal states.
131 const std::string& data_received() const { return data_received_; }
132 int bytes_read() const { return bytes_read_; }
133 int error() const { return error_; }
134 const SpdyHeaderBlock response_headers() const { return response_headers_; }
135 const SpdyHeaderBlock trailers() const { return trailers_; }
136 int on_read_complete_count() const { return on_read_complete_count_; }
137 int on_data_sent_count() const { return on_data_sent_count_; }
138
139 // Sets whether the delegate should automatically start reading.
140 void set_do_not_start_read(bool do_not_start_read) {
141 do_not_start_read_ = do_not_start_read;
142 }
143 // Sets whether the delegate should wait until the completion of the stream.
144 void SetRunUntilCompletion(bool run_until_completion) {
145 run_until_completion_ = run_until_completion;
146 loop_.reset(new base::RunLoop);
147 }
148
149 protected:
150 // Cancels |stream_|.
151 void CancelStream() { stream_->Cancel(); }
152 // Quits |loop_|.
153 void QuitLoop() { loop_->Quit(); }
154
155 private:
156 scoped_ptr<BidirectionalStreamSpdyJob> stream_;
157 scoped_refptr<IOBuffer> read_buf_;
158 int read_buf_len_;
159 std::string data_received_;
160 scoped_ptr<base::RunLoop> loop_;
161 SpdyHeaderBlock response_headers_;
162 SpdyHeaderBlock trailers_;
163 int error_;
164 int bytes_read_;
165 int on_read_complete_count_;
166 int on_data_sent_count_;
167 bool do_not_start_read_;
168 bool run_until_completion_;
169
170 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
171 };
172
173 // A delegate that sends data after request headers are sent.
174 class SendDataDelegate : public TestDelegateBase {
175 public:
176 SendDataDelegate(base::WeakPtr<SpdySession> session,
177 IOBuffer* buf,
178 int buf_len,
179 base::StringPiece data)
180 : TestDelegateBase(session, buf, buf_len), data_(data) {}
181
182 ~SendDataDelegate() override {}
183
184 void OnRequestHeadersSent() override {
185 TestDelegateBase::OnRequestHeadersSent();
186 if (data_.data()) {
187 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string()));
188 SendData(buf.get(), buf->size(), NO_MORE_DATA_TO_SEND);
189 }
190 }
191
192 private:
193 base::StringPiece data_;
194
195 DISALLOW_COPY_AND_ASSIGN(SendDataDelegate);
196 };
197
198 // A delegate that cancels the request after response headers are received.
199 class CancelStreamDelegate : public TestDelegateBase {
200 public:
201 CancelStreamDelegate(base::WeakPtr<SpdySession> session,
202 IOBuffer* buf,
203 int buf_len)
204 : TestDelegateBase(session, buf, buf_len) {}
205
206 ~CancelStreamDelegate() override {}
207
208 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
209 TestDelegateBase::OnHeaders(response_headers);
210 CancelStream();
211 QuitLoop();
212 }
213
214 void OnDataSent() override { NOTREACHED(); }
215
216 void OnReadCompleted(int bytes_read) override { NOTREACHED(); }
217
218 void OnTrailers(const SpdyHeaderBlock& trailers) override { NOTREACHED(); }
219
220 void OnFailed(int error) override { NOTREACHED(); }
221
222 private:
223 DISALLOW_COPY_AND_ASSIGN(CancelStreamDelegate);
224 };
225
226 // A Timer that does not start a delayed task unless the timer is fired.
227 class MockTimer : public base::MockTimer {
228 public:
229 MockTimer() : base::MockTimer(false, false) {}
230 ~MockTimer() override {}
231
232 void Start(const tracked_objects::Location& posted_from,
233 base::TimeDelta delay,
234 const base::Closure& user_task) override {
235 // Sets a maximum delay, so the timer does not fire unless it is told to.
236 base::TimeDelta infinite_delay = base::TimeDelta::Max();
237 base::MockTimer::Start(posted_from, infinite_delay, user_task);
238 }
239
240 private:
241 DISALLOW_COPY_AND_ASSIGN(MockTimer);
242 };
243
244 } // namespace
245
246 class BidirectionalStreamSpdyJobTest : public testing::Test {
247 public:
248 BidirectionalStreamSpdyJobTest()
249 : spdy_util_(kProtoHTTP2, false), session_deps_(kProtoHTTP2) {}
250
251 protected:
252 void TearDown() override {
253 if (sequenced_data_) {
254 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
255 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
256 }
257 if (deterministic_data_) {
258 EXPECT_TRUE(deterministic_data_->AllReadDataConsumed());
259 EXPECT_TRUE(deterministic_data_->AllWriteDataConsumed());
260 }
261 }
262
263 // Initializes the session using SequencedSocketData.
264 void InitSession(MockRead* reads,
265 size_t reads_count,
266 MockWrite* writes,
267 size_t writes_count,
268 const SpdySessionKey& key) {
269 sequenced_data_.reset(
270 new SequencedSocketData(reads, reads_count, writes, writes_count));
271 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
272 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
273 session_ =
274 CreateInsecureSpdySession(http_session_.get(), key, BoundNetLog());
275 }
276
277 // Initializes the session using DeterministicSocketData.
278 void InitSessionDeterministic(MockRead* reads,
279 size_t reads_count,
280 MockWrite* writes,
281 size_t writes_count,
282 const SpdySessionKey& key) {
283 MockConnect connect_data(SYNCHRONOUS, OK);
284 deterministic_data_.reset(
285 new DeterministicSocketData(reads, reads_count, writes, writes_count));
286 deterministic_data_->set_connect_data(connect_data);
287 session_deps_.deterministic_socket_factory->AddSocketDataProvider(
288 deterministic_data_.get());
289 http_session_ =
290 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
291 session_ =
292 CreateInsecureSpdySession(http_session_.get(), key, BoundNetLog());
293 }
294
295 SpdyTestUtil spdy_util_;
296 SpdySessionDependencies session_deps_;
297 scoped_ptr<SequencedSocketData> sequenced_data_;
298 scoped_ptr<DeterministicSocketData> deterministic_data_;
299 scoped_ptr<HttpNetworkSession> http_session_;
300 base::WeakPtr<SpdySession> session_;
301 };
302
303 // Simulates user calling ReadData after END_STREAM has been received in
304 // BidirectionalStreamSpdyJob.
305 TEST_F(BidirectionalStreamSpdyJobTest, TestReadDataAfterClose) {
306 scoped_ptr<SpdyFrame> req(
307 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
308 MockWrite writes[] = {
309 CreateMockWrite(*req.get(), 0),
310 };
311
312 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
313
314 scoped_ptr<SpdyFrame> resp(
315 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
316
317 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
318 // Last body frame has END_STREAM flag set.
319 scoped_ptr<SpdyFrame> last_body_frame(
320 spdy_util_.ConstructSpdyBodyFrame(1, true));
321
322 MockRead reads[] = {
323 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
324 CreateMockRead(*body_frame, 3), CreateMockRead(*last_body_frame, 4),
325 MockRead(SYNCHRONOUS, 0, 5),
326 };
327
328 HostPortPair host_port_pair("www.example.org", 80);
329 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
330 PRIVACY_MODE_DISABLED);
331 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
332 key);
333
334 HttpRequestInfo request;
335 request.method = "GET";
336 request.url = GURL("http://www.example.org/");
337
338 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
339 MockTimer* timer = new MockTimer();
340 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
341 session_, read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
342 delegate->set_do_not_start_read(true);
343 BoundNetLog net_log;
344 delegate->Start(request, DEFAULT_PRIORITY, net_log);
345 // Deliver header frame.
346 deterministic_data_->RunFor(2);
347 base::RunLoop().RunUntilIdle();
348 EXPECT_FALSE(timer->IsRunning());
349 // ReadData returns asynchronously because no data is buffered.
350 int rv = delegate->ReadData();
351 EXPECT_EQ(ERR_IO_PENDING, rv);
352 // Deliver a data frame.
353 deterministic_data_->RunFor(1);
354 base::RunLoop().RunUntilIdle();
355 timer->Fire();
356 // Asynchronous completion callback is invoke.
357 EXPECT_EQ(1, delegate->on_read_complete_count());
358 EXPECT_EQ(kUploadDataSize * 1, delegate->bytes_read());
359
360 // Deliver the rest. Note that user has not called a second ReadData.
361 deterministic_data_->RunFor(4);
362 base::RunLoop().RunUntilIdle();
363 // ReadData now. Read should complete synchronously.
364 rv = delegate->ReadData();
365 EXPECT_EQ(kUploadDataSize * 2, rv);
366 rv = delegate->ReadData();
367 EXPECT_EQ(OK, rv); // EOF.
368 EXPECT_EQ(1, delegate->on_read_complete_count());
369 }
370
371 TEST_F(BidirectionalStreamSpdyJobTest, TestInterleaveReadDataAndSendData) {
372 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
373
374 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
375 scoped_ptr<SpdyFrame> data_frame1(
376 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
377 scoped_ptr<SpdyFrame> data_frame2(
378 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
379 scoped_ptr<SpdyFrame> data_frame3(
380 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
381 MockWrite writes[] = {
382 CreateMockWrite(*req, 0), // request
383 CreateMockWrite(*data_frame1, 2), CreateMockWrite(*data_frame2, 4),
384 CreateMockWrite(*data_frame3, 6),
385 };
386
387 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
388
389 scoped_ptr<SpdyFrame> resp(
390 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
391
392 scoped_ptr<SpdyFrame> response_body_frame1(
393 spdy_util_.ConstructSpdyBodyFrame(1, false));
394 scoped_ptr<SpdyFrame> response_body_frame2(
395 spdy_util_.ConstructSpdyBodyFrame(1, true));
396
397 MockRead reads[] = {
398 CreateMockRead(*resp, 1), CreateMockRead(*response_body_frame1, 3),
399 CreateMockRead(*response_body_frame2, 5), MockRead(ASYNC, 0, 7),
400 };
401
402 HostPortPair host_port_pair("www.example.org", 80);
403 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
404 PRIVACY_MODE_DISABLED);
405 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
406 key);
407
408 HttpRequestInfo request;
409 request.method = "POST";
410 request.url = GURL("http://www.example.org/");
411
412 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
413 MockTimer* timer = new MockTimer();
414 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
415 session_, read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
416 delegate->set_do_not_start_read(true);
417 BoundNetLog net_log;
418 delegate->Start(request, DEFAULT_PRIORITY, net_log);
419 // Send the request and receive response headers.
420 deterministic_data_->RunFor(2);
421 base::RunLoop().RunUntilIdle();
422 EXPECT_FALSE(timer->IsRunning());
423
424 // Send a data frame.
425 scoped_refptr<StringIOBuffer> buf(
426 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
427 delegate->SendData(buf.get(), buf->size(), false);
428 deterministic_data_->RunFor(1);
429 base::RunLoop().RunUntilIdle();
430 EXPECT_EQ(1, delegate->on_data_sent_count());
431
432 // ReadData and it should return asynchronously because no data is buffered.
433 int rv = delegate->ReadData();
434 EXPECT_EQ(ERR_IO_PENDING, rv);
435 // Deliver a data frame, and fire the timer.
436 deterministic_data_->RunFor(1);
437 base::RunLoop().RunUntilIdle();
438 timer->Fire();
439 base::RunLoop().RunUntilIdle();
440 EXPECT_EQ(1, delegate->on_read_complete_count());
441
442 // Send a data frame.
443 delegate->SendData(buf.get(), buf->size(), false);
444 deterministic_data_->RunFor(1);
445 base::RunLoop().RunUntilIdle();
446 EXPECT_EQ(2, delegate->on_data_sent_count());
447
448 // ReadData and it should return asynchronously because no data is buffered.
449 rv = delegate->ReadData();
450 EXPECT_EQ(ERR_IO_PENDING, rv);
451 // Deliver a data frame, and fire the timer.
452 deterministic_data_->RunFor(1);
453 timer->Fire();
454 base::RunLoop().RunUntilIdle();
455 // Last data frame is read. Server half closes.
456 EXPECT_EQ(2, delegate->on_read_complete_count());
457
458 // Send last body frame. Client half closes.
459 delegate->SendData(buf.get(), buf->size(), true);
460 deterministic_data_->RunFor(1);
461 base::RunLoop().RunUntilIdle();
462 EXPECT_EQ(3, delegate->on_data_sent_count());
463
464 // OnClose is invoked since both sides are closed.
465 rv = delegate->ReadData();
466 EXPECT_EQ(OK, rv);
467 deterministic_data_->RunFor(1);
468 EXPECT_EQ(2, delegate->on_read_complete_count());
469 EXPECT_EQ(3, delegate->on_data_sent_count());
470 }
471
472 // Tests that BidirectionalStreamSpdyJob::OnClose will complete any remaining
473 // read even if the read queue is empty.
474 TEST_F(BidirectionalStreamSpdyJobTest, TestCompleteAsyncRead) {
475 scoped_ptr<SpdyFrame> req(
476 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
477 MockWrite writes[] = {
478 CreateMockWrite(*req.get(), 0),
479 };
480
481 scoped_ptr<SpdyFrame> resp(
482 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
483
484 scoped_ptr<SpdyFrame> response_body_frame(
485 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
486
487 MockRead reads[] = {
488 CreateMockRead(*resp, 1), CreateMockRead(*response_body_frame, 2),
489 MockRead(SYNCHRONOUS, 0, 3),
490 };
491
492 HostPortPair host_port_pair("www.example.org", 80);
493 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
494 PRIVACY_MODE_DISABLED);
495 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
496 key);
497
498 HttpRequestInfo request;
499 request.method = "GET";
500 request.url = GURL("http://www.example.org/");
501
502 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
503 MockTimer* timer = new MockTimer();
504 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
505 session_, read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
506 delegate->set_do_not_start_read(true);
507 BoundNetLog net_log;
508 delegate->Start(request, DEFAULT_PRIORITY, net_log);
509 // Send the request and receive response headers.
510 deterministic_data_->RunFor(2);
511 base::RunLoop().RunUntilIdle();
512 EXPECT_FALSE(timer->IsRunning());
513
514 // Let ReadData return asynchronously.
515 int rv = delegate->ReadData();
516 EXPECT_EQ(ERR_IO_PENDING, rv);
517 // Deliver END_STREAM.
518 // OnClose should trigger completion of the remaining read.
519 deterministic_data_->RunFor(3);
520 base::RunLoop().RunUntilIdle();
521 EXPECT_EQ(1, delegate->on_read_complete_count());
522 EXPECT_EQ(0, delegate->bytes_read());
523 }
524
525 TEST_F(BidirectionalStreamSpdyJobTest, TestBuffering) {
526 scoped_ptr<SpdyFrame> req(
527 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
528 MockWrite writes[] = {
529 CreateMockWrite(*req.get(), 0),
530 };
531
532 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
533
534 scoped_ptr<SpdyFrame> resp(
535 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
536
537 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
538 // Last body frame has END_STREAM flag set.
539 scoped_ptr<SpdyFrame> last_body_frame(
540 spdy_util_.ConstructSpdyBodyFrame(1, true));
541
542 MockRead reads[] = {
543 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
544 CreateMockRead(*body_frame, 3), CreateMockRead(*last_body_frame, 4),
545 MockRead(SYNCHRONOUS, 0, 5),
546 };
547
548 HostPortPair host_port_pair("www.example.org", 80);
549 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
550 PRIVACY_MODE_DISABLED);
551 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
552 key);
553
554 HttpRequestInfo request;
555 request.method = "GET";
556 request.url = GURL("http://www.example.org/");
557
558 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
559 MockTimer* timer = new MockTimer();
560 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
561 session_, read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
562 BoundNetLog net_log;
563 delegate->Start(request, DEFAULT_PRIORITY, net_log);
564 // Deliver two data frames together.
565 deterministic_data_->RunFor(4);
566 base::RunLoop().RunUntilIdle();
567 EXPECT_TRUE(timer->IsRunning());
568 timer->Fire();
569 base::RunLoop().RunUntilIdle();
570 // This should trigger |more_read_data_pending_| to execute the task at a
571 // later time, and Delegate::OnReadComplete should not have been called.
572 EXPECT_TRUE(timer->IsRunning());
573 EXPECT_EQ(0, delegate->on_read_complete_count());
574
575 // Fire the timer now, the two data frame should be combined into one
576 // single Delegate::OnReadComplete callback.
577 timer->Fire();
578 base::RunLoop().RunUntilIdle();
579 EXPECT_EQ(1, delegate->on_read_complete_count());
580 EXPECT_EQ(kUploadDataSize * 2, delegate->bytes_read());
581
582 // Read last data frame and EOF. There will be an additional
583 // Delegate::OnReadComplete callback.
584 deterministic_data_->RunFor(2);
585 EXPECT_EQ(2, delegate->on_read_complete_count());
586 const SpdyHeaderBlock response_headers = delegate->response_headers();
587 EXPECT_EQ("200", response_headers.find(":status")->second);
588 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
589
590 EXPECT_EQ(kUploadDataSize * 3, delegate->bytes_read());
591 }
592
593 TEST_F(BidirectionalStreamSpdyJobTest, TestBufferingWithTrailers) {
594 scoped_ptr<SpdyFrame> req(
595 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
596 MockWrite writes[] = {
597 CreateMockWrite(*req.get(), 0),
598 };
599
600 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
601
602 scoped_ptr<SpdyFrame> resp(
603 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
604
605 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
606
607 const char* const kTrailers[] = {"foo", "bar"};
608 scoped_ptr<SpdyFrame> trailers(
609 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
610
611 MockRead reads[] = {
612 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
613 CreateMockRead(*body_frame, 3), CreateMockRead(*body_frame, 4),
614 CreateMockRead(*trailers, 5), MockRead(SYNCHRONOUS, 0, 6),
615 };
616
617 HostPortPair host_port_pair("www.example.org", 80);
618 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
619 PRIVACY_MODE_DISABLED);
620 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
621 key);
622
623 HttpRequestInfo request;
624 request.method = "GET";
625 request.url = GURL("http://www.example.org/");
626
627 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
628 MockTimer* timer = new MockTimer();
629 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
630 session_, read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
631 BoundNetLog net_log;
632 delegate->Start(request, DEFAULT_PRIORITY, net_log);
633 // Deliver all three data frames together.
634 deterministic_data_->RunFor(5);
635 base::RunLoop().RunUntilIdle();
636 EXPECT_TRUE(timer->IsRunning());
637 timer->Fire();
638 base::RunLoop().RunUntilIdle();
639 // This should trigger |more_read_data_pending_| to execute the task at a
640 // later time, and Delegate::OnReadComplete should not have been called.
641 EXPECT_TRUE(timer->IsRunning());
642 EXPECT_EQ(0, delegate->on_read_complete_count());
643
644 // Deliver trailers. Remaining read should be completed, since OnClose is
645 // called right after OnTrailers. The three data frames should be delivered
646 // in a single OnReadCompleted callback.
647 deterministic_data_->RunFor(2);
648 base::RunLoop().RunUntilIdle();
649 EXPECT_FALSE(timer->IsRunning());
650 EXPECT_EQ(1, delegate->on_read_complete_count());
651 EXPECT_EQ(kUploadDataSize * 3, delegate->bytes_read());
652 const SpdyHeaderBlock response_headers = delegate->response_headers();
653 EXPECT_EQ("200", response_headers.find(":status")->second);
654 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
655 }
656
657 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequest) {
658 scoped_ptr<SpdyFrame> req(
659 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
660 MockWrite writes[] = {
661 CreateMockWrite(*req.get(), 0),
662 };
663
664 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
665
666 scoped_ptr<SpdyFrame> resp(
667 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
668
669 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
670
671 const char* const kTrailers[] = {"foo", "bar"};
672 scoped_ptr<SpdyFrame> trailers(
673 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
674
675 MockRead reads[] = {
676 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
677 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
678 };
679
680 HostPortPair host_port_pair("www.example.org", 80);
681 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
682 PRIVACY_MODE_DISABLED);
683 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
684
685 HttpRequestInfo request;
686 request.method = "GET";
687 request.url = GURL("http://www.example.org/");
688
689 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
690 scoped_ptr<TestDelegateBase> delegate(
691 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
692 delegate->SetRunUntilCompletion(true);
693 BoundNetLog net_log;
694 delegate->Start(request, DEFAULT_PRIORITY, net_log);
695 const SpdyHeaderBlock response_headers = delegate->response_headers();
696 EXPECT_EQ("200", response_headers.find(":status")->second);
697 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
698 EXPECT_EQ(kUploadDataSize, delegate->bytes_read());
699 EXPECT_EQ(kUploadData, delegate->data_received());
700 EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
701 }
702
703 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequestSmallReadBuffer) {
704 scoped_ptr<SpdyFrame> req(
705 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
706 MockWrite writes[] = {
707 CreateMockWrite(*req.get(), 0),
708 };
709
710 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
711
712 scoped_ptr<SpdyFrame> resp(
713 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
714
715 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
716
717 const char* const kTrailers[] = {"foo", "bar"};
718 scoped_ptr<SpdyFrame> trailers(
719 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
720
721 MockRead reads[] = {
722 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
723 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
724 };
725
726 HostPortPair host_port_pair("www.example.org", 80);
727 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
728 PRIVACY_MODE_DISABLED);
729 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
730
731 HttpRequestInfo request;
732 request.method = "GET";
733 request.url = GURL("http://www.example.org/");
734
735 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kSmallReadBufferSize));
736 scoped_ptr<TestDelegateBase> delegate(
737 new TestDelegateBase(session_, read_buffer.get(), kSmallReadBufferSize));
738 delegate->SetRunUntilCompletion(true);
739 BoundNetLog net_log;
740 delegate->Start(request, DEFAULT_PRIORITY, net_log);
741 const SpdyHeaderBlock response_headers = delegate->response_headers();
742 EXPECT_EQ("200", response_headers.find(":status")->second);
743 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
744 EXPECT_EQ(kUploadDataSize, delegate->bytes_read());
745 EXPECT_EQ(kUploadData, delegate->data_received());
746 EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
747 }
748
749 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequestNoTrailers) {
750 scoped_ptr<SpdyFrame> req(
751 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
752 MockWrite writes[] = {
753 CreateMockWrite(*req.get(), 0),
754 };
755
756 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
757
758 scoped_ptr<SpdyFrame> resp(
759 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
760
761 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
762
763 MockRead reads[] = {
764 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
765 MockRead(SYNCHRONOUS, 0, 3),
766 };
767
768 HostPortPair host_port_pair("www.example.org", 80);
769 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
770 PRIVACY_MODE_DISABLED);
771 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
772
773 HttpRequestInfo request;
774 request.method = "GET";
775 request.url = GURL("http://www.example.org/");
776
777 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
778 scoped_ptr<TestDelegateBase> delegate(
779 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
780 delegate->SetRunUntilCompletion(true);
781 BoundNetLog net_log;
782 delegate->Start(request, DEFAULT_PRIORITY, net_log);
783 const SpdyHeaderBlock response_headers = delegate->response_headers();
784 EXPECT_EQ("200", response_headers.find(":status")->second);
785 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
786 EXPECT_EQ(kUploadDataSize, delegate->bytes_read());
787 EXPECT_EQ(kUploadData, delegate->data_received());
788 }
789
790 TEST_F(BidirectionalStreamSpdyJobTest, CancelStream) {
791 scoped_ptr<SpdyFrame> req(
792 spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
793 scoped_ptr<SpdyFrame> rst(
794 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
795 MockWrite writes[] = {
796 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
797 };
798
799 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
800
801 scoped_ptr<SpdyFrame> resp(
802 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
803
804 MockRead reads[] = {
805 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
806 };
807
808 HostPortPair host_port_pair("www.example.org", 80);
809 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
810 PRIVACY_MODE_DISABLED);
811 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
812
813 HttpRequestInfo request;
814 request.method = "GET";
815 request.url = GURL("http://www.example.org/");
816
817 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
818 scoped_ptr<CancelStreamDelegate> delegate(
819 new CancelStreamDelegate(session_, read_buffer.get(), kReadBufferSize));
820 delegate->SetRunUntilCompletion(true);
821 BoundNetLog net_log;
822 delegate->Start(request, DEFAULT_PRIORITY, net_log);
823 // Makes sure delegate does not get called.
824 base::RunLoop().RunUntilIdle();
825 const SpdyHeaderBlock response_headers = delegate->response_headers();
826 EXPECT_EQ("200", response_headers.find(":status")->second);
827 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
828 EXPECT_EQ(0, delegate->bytes_read());
829 }
830
831 TEST_F(BidirectionalStreamSpdyJobTest, SendPostRequest) {
832 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
833
834 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
835 scoped_ptr<SpdyFrame> body(
836 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
837 MockWrite writes[] = {
838 CreateMockWrite(*req, 0), // request
839 CreateMockWrite(*body, 1), // POST upload frame
840 };
841 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
842 scoped_ptr<SpdyFrame> resp(
843 spdy_util_.ConstructSpdyPostSynReply(kExtraResponseHeaders, 1));
844
845 scoped_ptr<SpdyFrame> resp_data(
846 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
847
848 const char* const kExtraHeaders[] = {"foo", "bar"};
849 scoped_ptr<SpdyFrame> trailers(
850 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true));
851
852 MockRead reads[] = {
853 CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3),
854 CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF
855 };
856
857 HostPortPair host_port_pair("www.example.org", 80);
858 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
859 PRIVACY_MODE_DISABLED);
860 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
861
862 HttpRequestInfo request;
863 request.method = "POST";
864 request.url = GURL("http://www.example.org/");
865
866 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
867 scoped_ptr<SendDataDelegate> delegate(
868 new SendDataDelegate(session_, read_buffer.get(), kReadBufferSize,
869 base::StringPiece(kBodyData, kBodyDataSize)));
870 delegate->SetRunUntilCompletion(true);
871 BoundNetLog net_log;
872 delegate->Start(request, DEFAULT_PRIORITY, net_log);
873
874 const SpdyHeaderBlock response_headers = delegate->response_headers();
875 EXPECT_EQ("200", response_headers.find(":status")->second);
876 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
877 EXPECT_EQ(static_cast<int>(kBodyDataSize), delegate->bytes_read());
878 EXPECT_EQ(std::string(kBodyData, kBodyDataSize), delegate->data_received());
879 EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
880 }
881
882 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698