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

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: Remove unneeded return value 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/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_piece.h"
12 #include "net/base/net_errors.h"
13 #include "net/http/http_request_info.h"
14 #include "net/http/http_response_headers.h"
15 #include "net/http/http_response_info.h"
16 #include "net/socket/socket_test_util.h"
17 #include "net/spdy/spdy_read_queue.h"
18 #include "net/spdy/spdy_session.h"
19 #include "net/spdy/spdy_test_util_common.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace net {
23
24 namespace {
25
26 const char kBodyData[] = "Body data";
27 const size_t kBodyDataSize = arraysize(kBodyData);
28 const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize);
mmenke 2015/11/25 18:39:18 Global variables must be POD types using initializ
xunjieli 2015/11/25 22:04:14 Done.
29 // Size of the buffer to be allocated for each read.
30 const size_t kReadBufferSize = 4096;
31 const size_t kSmallReadBufferSize = 4;
mmenke 2015/11/25 18:39:18 Should document kSmallReadBufferSize
xunjieli 2015/11/25 22:04:14 Done.
32
33 class TestBidirectionalStreamSpdyJobDelegate
mmenke 2015/11/25 18:39:18 Should document this class.
xunjieli 2015/11/25 22:04:14 Done.
34 : public BidirectionalStreamJob::Delegate {
35 public:
36 TestBidirectionalStreamSpdyJobDelegate(base::WeakPtr<SpdySession> session,
37 IOBuffer* read_buf,
38 int read_buf_len)
39 : bytes_read_(0),
40 close_status_(ERR_FAILED),
41 stream_(new BidirectionalStreamSpdyJob(session)),
42 loop_(new base::RunLoop),
43 read_buf_(read_buf),
44 read_buf_len_(read_buf_len) {}
45
46 ~TestBidirectionalStreamSpdyJobDelegate() override {}
47
48 void OnRequestHeadersSent() override {}
49
50 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
51 response_headers_ = response_headers;
52 StartOrContinueReading();
53 }
54
55 void OnReadCompleted(int bytes_read) override {
56 CHECK_GT(bytes_read, OK);
57 bytes_read_ += bytes_read;
58 data_received_.append(read_buf_->data(), bytes_read);
59 StartOrContinueReading();
60 }
61
62 void OnDataSent() override {}
63
64 void OnTrailers(const SpdyHeaderBlock& trailers) override {
65 trailers_ = trailers;
66 }
67
68 void OnClose(int status) override {
69 close_status_ = status;
70 loop_->Quit();
71 }
72
73 void Start(const HttpRequestInfo& request,
74 RequestPriority priority,
75 const BoundNetLog& net_log) {
76 stream_->Start(request, priority, net_log, this);
77 loop_->Run();
78 }
79
80 void SendData(IOBuffer* data, int length, bool end_of_stream) {
81 stream_->SendData(data, length, end_of_stream);
82 }
83
84 const std::string& data_received() const { return data_received_; }
85
86 SpdyHeaderBlock response_headers_;
87 SpdyHeaderBlock trailers_;
88 int bytes_read_;
89 int close_status_;
mmenke 2015/11/25 18:39:18 Can we just make these private, and add const acce
xunjieli 2015/11/25 22:04:14 Done.
90
91 protected:
92 scoped_ptr<BidirectionalStreamSpdyJob> stream_;
93 scoped_ptr<base::RunLoop> loop_;
mmenke 2015/11/25 18:39:18 Suggest making these private, too, and adding prot
xunjieli 2015/11/25 22:04:14 Done.
94
95 private:
96 void StartOrContinueReading() {
mmenke 2015/11/25 18:39:18 Should document this.
xunjieli 2015/11/25 22:04:14 Done.
97 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
98 while (rv > 0) {
99 bytes_read_ += rv;
100 data_received_.append(read_buf_->data(), rv);
101 rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
102 }
103 }
104
105 scoped_refptr<IOBuffer> read_buf_;
106 int read_buf_len_;
107 std::string data_received_;
mmenke 2015/11/25 18:39:18 These should all use DISALLOW_COPY_AND_ASSIGN
xunjieli 2015/11/25 22:04:14 Done.
108 };
109
110 // A delegate that sends data after request headers are sent.
111 class SendDataDelegate : public TestBidirectionalStreamSpdyJobDelegate {
112 public:
113 SendDataDelegate(base::WeakPtr<SpdySession> session,
114 IOBuffer* buf,
115 int buf_len,
116 base::StringPiece data)
117 : TestBidirectionalStreamSpdyJobDelegate(session, buf, buf_len),
118 data_(data) {}
119
120 ~SendDataDelegate() override {}
121
122 void OnRequestHeadersSent() override {
123 TestBidirectionalStreamSpdyJobDelegate::OnRequestHeadersSent();
124 if (data_.data()) {
125 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string()));
126 SendData(buf.get(), buf->size(), NO_MORE_DATA_TO_SEND);
127 }
128 }
129
130 private:
131 base::StringPiece data_;
132 };
133
134 // A delegate that cancels the request after response headers are received.
135 class CancelStreamDelegate : public TestBidirectionalStreamSpdyJobDelegate {
136 public:
137 CancelStreamDelegate(base::WeakPtr<SpdySession> session,
138 IOBuffer* buf,
139 int buf_len)
140 : TestBidirectionalStreamSpdyJobDelegate(session, buf, buf_len) {}
141
142 ~CancelStreamDelegate() override {}
143
144 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
145 TestBidirectionalStreamSpdyJobDelegate::OnHeaders(response_headers);
146 stream_->Cancel();
147 loop_->Quit();
148 }
149
150 void OnDataSent() override { ASSERT_TRUE(false); }
mmenke 2015/11/25 18:39:18 GTEST_FAIL() (Or just NOTREACHED()), for all of th
xunjieli 2015/11/25 22:04:14 Done.
151
152 void OnReadCompleted(int bytes_read) override { ASSERT_TRUE(false); }
153
154 void OnTrailers(const SpdyHeaderBlock& trailers) override {
155 ASSERT_TRUE(false);
156 }
157
158 void OnClose(int error) override { ASSERT_TRUE(false); }
159 };
160
161 } // namespace
162
163 class BidirectionalStreamSpdyJobTest : public testing::Test {
164 public:
165 BidirectionalStreamSpdyJobTest()
166 : spdy_util_(kProtoHTTP2, false), session_deps_(kProtoHTTP2) {}
167
168 protected:
169 void TearDown() override {
170 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
171 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
172 }
173
174 // Initializes the session using SequencedSocketData.
175 void InitSession(MockRead* reads,
176 size_t reads_count,
177 MockWrite* writes,
178 size_t writes_count,
179 const SpdySessionKey& key) {
180 sequenced_data_.reset(
181 new SequencedSocketData(reads, reads_count, writes, writes_count));
182 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
183 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
184 session_ =
185 CreateInsecureSpdySession(http_session_.get(), key, BoundNetLog());
186 }
187
188 SpdyTestUtil spdy_util_;
189 SpdySessionDependencies session_deps_;
190 scoped_ptr<SequencedSocketData> sequenced_data_;
191 scoped_ptr<HttpNetworkSession> http_session_;
192 base::WeakPtr<SpdySession> session_;
193 };
194
195 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequest) {
196 scoped_ptr<SpdyFrame> req(
197 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
mmenke 2015/11/25 18:39:18 NULL -> nullptr, for all of these.
xunjieli 2015/11/25 22:04:14 Done.
198 MockWrite writes[] = {
199 CreateMockWrite(*req.get(), 0),
200 };
201
202 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
203
204 scoped_ptr<SpdyFrame> resp(
205 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
206
207 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
208
209 const char* const kTrailers[] = {"foo", "bar"};
210 scoped_ptr<SpdyFrame> trailers(
211 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
212
213 MockRead reads[] = {
214 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
215 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
216 };
217
218 HostPortPair host_port_pair("www.example.org", 80);
219 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
220 PRIVACY_MODE_DISABLED);
221 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
222
223 HttpRequestInfo request;
224 request.method = "GET";
225 request.url = GURL("http://www.example.org/");
226
227 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
228 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
229 new TestBidirectionalStreamSpdyJobDelegate(session_, read_buffer.get(),
230 kReadBufferSize));
231 BoundNetLog net_log;
232 delegate->Start(request, DEFAULT_PRIORITY, net_log);
233 base::StringPiece status = delegate->response_headers_[":status"];
234 EXPECT_EQ("200", status);
235 base::StringPiece extra_header = delegate->response_headers_["header-name"];
236 EXPECT_EQ("header-value", extra_header);
237 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
238 EXPECT_EQ(kUploadData, delegate->data_received());
239 base::StringPiece trailer = delegate->trailers_["foo"];
240 EXPECT_EQ("bar", trailer);
241 EXPECT_EQ(OK, delegate->close_status_);
242 }
243
244 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequestSmallReadBuffer) {
245 scoped_ptr<SpdyFrame> req(
246 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
247 MockWrite writes[] = {
248 CreateMockWrite(*req.get(), 0),
249 };
250
251 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
252
253 scoped_ptr<SpdyFrame> resp(
254 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
255
256 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
257
258 const char* const kTrailers[] = {"foo", "bar"};
259 scoped_ptr<SpdyFrame> trailers(
260 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
261
262 MockRead reads[] = {
263 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
264 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
265 };
266
267 HostPortPair host_port_pair("www.example.org", 80);
268 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
269 PRIVACY_MODE_DISABLED);
270 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
271
272 HttpRequestInfo request;
273 request.method = "GET";
274 request.url = GURL("http://www.example.org/");
275
276 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kSmallReadBufferSize));
277 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
278 new TestBidirectionalStreamSpdyJobDelegate(session_, read_buffer.get(),
279 kSmallReadBufferSize));
280 BoundNetLog net_log;
281 delegate->Start(request, DEFAULT_PRIORITY, net_log);
282 base::StringPiece status = delegate->response_headers_[":status"];
283 EXPECT_EQ("200", status);
284 base::StringPiece extra_header = delegate->response_headers_["header-name"];
285 EXPECT_EQ("header-value", extra_header);
286 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
287 EXPECT_EQ(kUploadData, delegate->data_received());
288 base::StringPiece trailer = delegate->trailers_["foo"];
289 EXPECT_EQ("bar", trailer);
290 EXPECT_EQ(OK, delegate->close_status_);
291 }
292
293 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequestNoTrailers) {
294 scoped_ptr<SpdyFrame> req(
295 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
296 MockWrite writes[] = {
297 CreateMockWrite(*req.get(), 0),
298 };
299
300 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
301
302 scoped_ptr<SpdyFrame> resp(
303 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
304
305 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
306
307 MockRead reads[] = {
308 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
309 MockRead(SYNCHRONOUS, 0, 3),
310 };
311
312 HostPortPair host_port_pair("www.example.org", 80);
313 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
314 PRIVACY_MODE_DISABLED);
315 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
316
317 HttpRequestInfo request;
318 request.method = "GET";
319 request.url = GURL("http://www.example.org/");
320
321 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
322 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
323 new TestBidirectionalStreamSpdyJobDelegate(session_, read_buffer.get(),
324 kReadBufferSize));
325 BoundNetLog net_log;
326 delegate->Start(request, DEFAULT_PRIORITY, net_log);
327 base::StringPiece status = delegate->response_headers_[":status"];
328 EXPECT_EQ("200", status);
329 base::StringPiece extra_header = delegate->response_headers_["header-name"];
330 EXPECT_EQ("header-value", extra_header);
331 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
332 EXPECT_EQ(kUploadData, delegate->data_received());
333 EXPECT_EQ(OK, delegate->close_status_);
334 }
335
336 TEST_F(BidirectionalStreamSpdyJobTest, CancelStream) {
337 scoped_ptr<SpdyFrame> req(
338 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
339 scoped_ptr<SpdyFrame> rst(
340 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
341 MockWrite writes[] = {
342 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
343 };
344
345 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
346
347 scoped_ptr<SpdyFrame> resp(
348 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
349
350 MockRead reads[] = {
351 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
352 };
353
354 HostPortPair host_port_pair("www.example.org", 80);
355 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
356 PRIVACY_MODE_DISABLED);
357 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
358
359 HttpRequestInfo request;
360 request.method = "GET";
361 request.url = GURL("http://www.example.org/");
362
363 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
364 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
365 new CancelStreamDelegate(session_, read_buffer.get(), kReadBufferSize));
366 BoundNetLog net_log;
367 delegate->Start(request, DEFAULT_PRIORITY, net_log);
368 // Makes sure delegate does not get called.
369 base::RunLoop().RunUntilIdle();
370 base::StringPiece status = delegate->response_headers_[":status"];
371 EXPECT_EQ("200", status);
372 base::StringPiece extra_header = delegate->response_headers_["header-name"];
373 EXPECT_EQ("header-value", extra_header);
374 EXPECT_EQ(0, delegate->bytes_read_);
375 }
376
377 TEST_F(BidirectionalStreamSpdyJobTest, SendPostRequest) {
378 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
379
380 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
381 scoped_ptr<SpdyFrame> body(
382 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
383 MockWrite writes[] = {
384 CreateMockWrite(*req, 0), // request
385 CreateMockWrite(*body, 1), // POST upload frame
386 };
387 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
388 scoped_ptr<SpdyFrame> resp(
389 spdy_util_.ConstructSpdyPostSynReply(kExtraResponseHeaders, 1));
390
391 scoped_ptr<SpdyFrame> resp_data(
392 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
393
394 const char* const kExtraHeaders[] = {"foo", "bar"};
395 scoped_ptr<SpdyFrame> trailers(
396 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true));
397
398 MockRead reads[] = {
399 CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3),
400 CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF
401 };
402
403 HostPortPair host_port_pair("www.example.org", 80);
404 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
405 PRIVACY_MODE_DISABLED);
406 InitSession(reads, arraysize(reads), writes, arraysize(writes), 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 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
414 new SendDataDelegate(session_, read_buffer.get(), kReadBufferSize,
415 kBodyDataStringPiece));
416 BoundNetLog net_log;
417 delegate->Start(request, DEFAULT_PRIORITY, net_log);
418
419 base::StringPiece header = delegate->response_headers_[":status"];
420 EXPECT_EQ("200", header);
421 base::StringPiece extra_header = delegate->response_headers_["header-name"];
422 EXPECT_EQ("header-value", extra_header);
423 EXPECT_EQ((int)kBodyDataSize, delegate->bytes_read_);
424 EXPECT_EQ(std::string(kBodyData, kBodyDataSize), delegate->data_received());
425 base::StringPiece trailer = delegate->trailers_["foo"];
426 EXPECT_EQ("bar", trailer);
427 EXPECT_EQ(OK, delegate->close_status_);
428 }
429
430 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698