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

Side by Side Diff: net/spdy/bidirectional_spdy_stream_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: Make the wrapper class own the stream Created 5 years, 1 month 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_spdy_stream.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);
29 // Size of the buffer to be allocated for each read.
30 const size_t kReadBufferSize = 4096;
31 const size_t kSmallReadBufferSize = 4;
32
33 class TestBidirectionalStreamDelegate : public BidirectionalStream::Delegate {
34 public:
35 TestBidirectionalStreamDelegate(base::WeakPtr<SpdySession> session,
36 IOBuffer* buf,
37 int buf_len)
38 : bytes_read_(0),
39 close_status_(ERR_FAILED),
40 stream_(new BidirectionalSpdyStream(session)),
41 loop_(new base::RunLoop),
42 buf_(buf),
43 buf_len_(buf_len) {}
44
45 ~TestBidirectionalStreamDelegate() override {}
46
47 void OnFailed(int rv) override { loop_->Quit(); }
48
49 void OnRequestHeadersSent() override {}
50
51 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
52 response_headers_ = response_headers;
53 StartOrContinueReading();
54 }
55
56 void OnReadCompleted(int bytes_read) override {
57 CHECK_GT(bytes_read, OK);
58 bytes_read_ += bytes_read;
59 data_received_.append(buf_->data(), bytes_read_);
60 StartOrContinueReading();
61 }
62
63 void OnDataSent() override {}
64
65 void OnTrailers(const SpdyHeaderBlock& trailers) override {
66 trailers_ = trailers;
67 }
68
69 void OnClose(int status) override {
70 close_status_ = status;
71 loop_->Quit();
72 }
73
74 void Start(const HttpRequestInfo& request,
75 RequestPriority priority,
76 const BoundNetLog& net_log) {
77 stream_->Start(request, priority, net_log, this);
78 loop_->Run();
79 }
80
81 void SendData(IOBuffer* data, int length, bool end_of_stream) {
82 stream_->SendData(data, length, end_of_stream);
83 }
84
85 const std::string& data_received() const { return data_received_; }
86
87 SpdyHeaderBlock response_headers_;
88 SpdyHeaderBlock trailers_;
89 int bytes_read_;
90 int close_status_;
91
92 protected:
93 scoped_ptr<BidirectionalStream> stream_;
94 scoped_ptr<base::RunLoop> loop_;
95
96 private:
97 void StartOrContinueReading() {
98 int rv = stream_->ReadData(buf_.get(), buf_len_);
99 while (rv > 0) {
100 bytes_read_ += rv;
101 data_received_.append(buf_->data(), rv);
102 rv = stream_->ReadData(buf_.get(), buf_len_);
103 }
104 }
105
106 scoped_refptr<IOBuffer> buf_;
107 int buf_len_;
108 std::string data_received_;
109 };
110
111 // A delegate that sends data after request headers are sent.
112 class SendDataDelegate : public TestBidirectionalStreamDelegate {
113 public:
114 SendDataDelegate(base::WeakPtr<SpdySession> session,
115 IOBuffer* buf,
116 int buf_len,
117 base::StringPiece data)
118 : TestBidirectionalStreamDelegate(session, buf, buf_len), data_(data) {}
119
120 ~SendDataDelegate() override {}
121
122 void OnRequestHeadersSent() override {
123 TestBidirectionalStreamDelegate::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 TestBidirectionalStreamDelegate {
136 public:
137 CancelStreamDelegate(base::WeakPtr<SpdySession> session,
138 IOBuffer* buf,
139 int buf_len)
140 : TestBidirectionalStreamDelegate(session, buf, buf_len) {}
141
142 ~CancelStreamDelegate() override {}
143
144 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
145 TestBidirectionalStreamDelegate::OnHeaders(response_headers);
146 stream_->Cancel();
147 loop_->Quit();
148 }
149
150 void OnDataSent() override { ASSERT_TRUE(false); }
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 BidirectionalSpdyStreamTest : public testing::Test {
164 public:
165 BidirectionalSpdyStreamTest()
166 : spdy_util_(kProtoHTTP2), 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(BidirectionalSpdyStreamTest, SendGetRequest) {
196 scoped_ptr<SpdyFrame> req(
197 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
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<TestBidirectionalStreamDelegate> delegate(
229 new TestBidirectionalStreamDelegate(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(BidirectionalSpdyStreamTest, 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<TestBidirectionalStreamDelegate> delegate(
278 new TestBidirectionalStreamDelegate(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 TEST_F(BidirectionalSpdyStreamTest, SendGetRequestNoTrailers) {
293 scoped_ptr<SpdyFrame> req(
294 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
295 MockWrite writes[] = {
296 CreateMockWrite(*req.get(), 0),
297 };
298
299 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
300
301 scoped_ptr<SpdyFrame> resp(
302 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
303
304 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
305
306 MockRead reads[] = {
307 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
308 MockRead(SYNCHRONOUS, 0, 3),
309 };
310
311 HostPortPair host_port_pair("www.example.org", 80);
312 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
313 PRIVACY_MODE_DISABLED);
314 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
315
316 HttpRequestInfo request;
317 request.method = "GET";
318 request.url = GURL("http://www.example.org/");
319
320 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
321 scoped_ptr<TestBidirectionalStreamDelegate> delegate(
322 new TestBidirectionalStreamDelegate(session_, read_buffer.get(),
323 kReadBufferSize));
324 BoundNetLog net_log;
325 delegate->Start(request, DEFAULT_PRIORITY, net_log);
326 base::StringPiece status = delegate->response_headers_[":status"];
327 EXPECT_EQ("200", status);
328 base::StringPiece extra_header = delegate->response_headers_["header-name"];
329 EXPECT_EQ("header-value", extra_header);
330 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
331 EXPECT_EQ(kUploadData, delegate->data_received());
332 EXPECT_EQ(OK, delegate->close_status_);
333 }
334
335 TEST_F(BidirectionalSpdyStreamTest, CancelStream) {
336 scoped_ptr<SpdyFrame> req(
337 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
338 scoped_ptr<SpdyFrame> rst(
339 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
340 MockWrite writes[] = {
341 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
342 };
343
344 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
345
346 scoped_ptr<SpdyFrame> resp(
347 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
348
349 MockRead reads[] = {
350 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
351 };
352
353 HostPortPair host_port_pair("www.example.org", 80);
354 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
355 PRIVACY_MODE_DISABLED);
356 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
357
358 HttpRequestInfo request;
359 request.method = "GET";
360 request.url = GURL("http://www.example.org/");
361
362 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
363 scoped_ptr<TestBidirectionalStreamDelegate> delegate(
364 new CancelStreamDelegate(session_, read_buffer.get(), kReadBufferSize));
365 BoundNetLog net_log;
366 delegate->Start(request, DEFAULT_PRIORITY, net_log);
367 // Makes sure delegate does not get called.
368 base::RunLoop().RunUntilIdle();
369 base::StringPiece status = delegate->response_headers_[":status"];
370 EXPECT_EQ("200", status);
371 base::StringPiece extra_header = delegate->response_headers_["header-name"];
372 EXPECT_EQ("header-value", extra_header);
373 EXPECT_EQ(0, delegate->bytes_read_);
374 }
375
376 TEST_F(BidirectionalSpdyStreamTest, SendPostRequest) {
377 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
378
379 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
380 scoped_ptr<SpdyFrame> body(
381 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
382 MockWrite writes[] = {
383 CreateMockWrite(*req, 0), // request
384 CreateMockWrite(*body, 1), // POST upload frame
385 };
386 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
387 scoped_ptr<SpdyFrame> resp(
388 spdy_util_.ConstructSpdyPostSynReply(kExtraResponseHeaders, 1));
389
390 scoped_ptr<SpdyFrame> resp_data(
391 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
392
393 const char* const kExtraHeaders[] = {"foo", "bar"};
394 scoped_ptr<SpdyFrame> trailers(
395 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true));
396
397 MockRead reads[] = {
398 CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3),
399 CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF
400 };
401
402 HostPortPair host_port_pair("www.example.org", 80);
403 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
404 PRIVACY_MODE_DISABLED);
405 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
406
407 HttpRequestInfo request;
408 request.method = "POST";
409 request.url = GURL("http://www.example.org/");
410
411 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
412 scoped_ptr<TestBidirectionalStreamDelegate> delegate(new SendDataDelegate(
413 session_, read_buffer.get(), kReadBufferSize, kBodyDataStringPiece));
414 BoundNetLog net_log;
415 delegate->Start(request, DEFAULT_PRIORITY, net_log);
416
417 base::StringPiece header = delegate->response_headers_[":status"];
418 EXPECT_EQ("200", header);
419 base::StringPiece extra_header = delegate->response_headers_["header-name"];
420 EXPECT_EQ("header-value", extra_header);
421 EXPECT_EQ((int)kBodyDataSize, delegate->bytes_read_);
422 EXPECT_EQ(std::string(kBodyData, kBodyDataSize), delegate->data_received());
423 base::StringPiece trailer = delegate->trailers_["foo"];
424 EXPECT_EQ("bar", trailer);
425 EXPECT_EQ(OK, delegate->close_status_);
426 }
427
428 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698