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

Side by Side Diff: net/quic/quic_http_stream_test.cc

Issue 11364068: Add a QuicHttpStream class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 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 | Annotate | Revision Log
« no previous file with comments | « net/quic/quic_http_stream.cc ('k') | net/quic/quic_protocol.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/quic/quic_http_stream.h"
6
7 #include <vector>
8
9 #include "net/base/net_errors.h"
10 #include "net/base/test_completion_callback.h"
11 #include "net/base/upload_data.h"
12 #include "net/base/upload_data_stream.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/quic/quic_client_session.h"
15 #include "net/quic/quic_connection.h"
16 #include "net/quic/quic_connection_helper.h"
17 #include "net/quic/test_tools/mock_clock.h"
18 #include "net/quic/test_tools/quic_test_utils.h"
19 #include "net/quic/test_tools/test_task_runner.h"
20 #include "net/socket/socket_test_util.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 using testing::_;
25
26 namespace net {
27
28 class QuicConnectionPeer {
29 public:
30 static void SetScheduler(QuicConnection* connection,
31 QuicSendScheduler* scheduler) {
32 connection->scheduler_.reset(scheduler);
33 }
34 };
35
36 namespace test {
37
38 namespace {
39
40 const char kUploadData[] = "hello world!";
41
42 class TestQuicConnection : public QuicConnection {
43 public:
44 TestQuicConnection(QuicGuid guid,
45 IPEndPoint address,
jar (doing other things) 2012/12/03 20:16:51 nit: indent
46 QuicConnectionHelper* helper)
47 : QuicConnection(guid, address, helper) {
48 }
49
50 void SetScheduler(QuicSendScheduler* scheduler) {
51 QuicConnectionPeer::SetScheduler(this, scheduler);
52 }
53 };
54
55 } // namespace
56
57 class QuicHttpStreamTest : public ::testing::Test {
58 protected:
59 const static bool kFin = true;
60 const static bool kNoFin = false;
61 // Holds a packet to be written to the wire, and the IO mode that should
62 // be used by the mock socket when performing the write.
63 struct PacketToWrite {
64 PacketToWrite(IoMode mode, QuicEncryptedPacket* packet)
65 : mode(mode),
66 packet(packet) {
67 }
68 IoMode mode;
69 QuicEncryptedPacket* packet;
70 };
71
72 QuicHttpStreamTest()
73 : net_log_(BoundNetLog()),
74 read_buffer_(new IOBufferWithSize(4096)),
75 guid_(2),
76 framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)),
77 creator_(guid_, &framer_) {
78 IPAddressNumber ip;
79 CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
80 peer_addr_ = IPEndPoint(ip, 443);
81 self_addr_ = IPEndPoint(ip, 8435);
82 Initialize();
jar (doing other things) 2012/12/03 20:16:51 nit: add comment "Do null initialization to help s
83 }
84
85 ~QuicHttpStreamTest() {
86 for (size_t i = 0; i < writes_.size(); i++) {
87 delete writes_[i].packet;
88 }
89 }
90
91 // Adds a packet to the list of expected writes.
92 void AddWrite(IoMode mode, QuicEncryptedPacket* packet) {
93 writes_.push_back(PacketToWrite(mode, packet));
94 }
95
96 // Returns the packet to be written at position |pos|.
97 QuicEncryptedPacket* GetWrite(size_t pos) {
98 return writes_[pos].packet;
99 }
100
101 bool AtEof() {
102 return socket_data_->at_read_eof() && socket_data_->at_write_eof();
103 }
104
105 void ProcessPacket(const QuicEncryptedPacket& packet) {
106 connection_->ProcessUdpPacket(self_addr_, peer_addr_, packet);
107 }
108
109 // Configures the test fixture to use the list of expected writes.
110 void Initialize() {
111 mock_writes_.reset(new MockWrite[writes_.size()]);
112 for (size_t i = 0; i < writes_.size(); i++) {
113 mock_writes_[i] = MockWrite(writes_[i].mode,
114 writes_[i].packet->data(),
115 writes_[i].packet->length());
116 };
117
118 socket_data_.reset(new StaticSocketDataProvider(NULL, 0, mock_writes_.get(),
119 writes_.size()));
120
121 socket_.reset(new MockUDPClientSocket(socket_data_.get(),
122 net_log_.net_log()));
123 socket_->Connect(peer_addr_);
124 runner_ = new TestTaskRunner(&clock_);
125 scheduler_ = new MockScheduler();
126 EXPECT_CALL(*scheduler_, TimeUntilSend(_)).
127 WillRepeatedly(testing::Return(QuicTime::Delta()));
128 connection_ = new TestQuicConnection(
129 guid_, peer_addr_, new QuicConnectionHelper(
130 runner_.get(), &clock_, socket_.get()));
131 connection_->set_visitor(&visitor_);
132 connection_->SetScheduler(scheduler_);
133 session_.reset(new QuicClientSession(connection_));
134 CryptoHandshakeMessage message;
135 message.tag = kSHLO;
136 session_->GetCryptoStream()->OnHandshakeMessage(message);
137 EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
138 stream_.reset(new QuicHttpStream(session_->CreateOutgoingReliableStream()));
139 }
140
141 // Returns a newly created packet to send kData on stream 1.
142 QuicEncryptedPacket* ConstructDataPacket(
143 QuicPacketSequenceNumber sequence_number,
144 bool fin,
145 QuicStreamOffset offset,
146 base::StringPiece data) {
147 InitializeHeader(sequence_number);
148 QuicStreamFrame frame(3, fin, offset, data);
149 return ConstructPacket(header_, QuicFrame(&frame));
150 }
151
152 // Returns a newly created packet to send ack data.
153 QuicEncryptedPacket* ConstructAckPacket(
154 QuicPacketSequenceNumber sequence_number,
155 QuicPacketSequenceNumber largest_received,
156 QuicPacketSequenceNumber least_unacked) {
157 InitializeHeader(sequence_number);
158
159 QuicAckFrame ack(largest_received, QuicTime(), least_unacked);
160 ack.congestion_info.type = kFixRate;
161 ack.congestion_info.fix_rate.bitrate_in_bytes_per_second = 100000;
162
163 return ConstructPacket(header_, QuicFrame(&ack));
164 }
165
166 // Returns a newly created packet to send a connection close frame.
167 QuicEncryptedPacket* ConstructClosePacket(
168 QuicPacketSequenceNumber sequence_number,
169 bool with_ack) {
jar (doing other things) 2012/12/03 20:16:51 nit: (per your suggestion): with_congestion_info
170 InitializeHeader(sequence_number);
171
172 QuicFrames frames;
173 QuicAckFrame ack(0, QuicTime(), 0);
174 if (with_ack) {
175 ack.congestion_info.type = kFixRate;
176 ack.congestion_info.fix_rate.bitrate_in_bytes_per_second = 100000;
177 } else {
178 ack.congestion_info.type = kNone;
179 }
180 QuicConnectionCloseFrame close;
181 close.error_code = QUIC_CONNECTION_TIMED_OUT;
182 close.ack_frame = ack;
183
184 return ConstructPacket(header_, QuicFrame(&close));
185 }
186
187 BoundNetLog net_log_;
188 MockScheduler* scheduler_;
189 scoped_refptr<TestTaskRunner> runner_;
190 scoped_array<MockWrite> mock_writes_;
191 MockClock clock_;
192 TestQuicConnection* connection_;
193 testing::StrictMock<MockConnectionVisitor> visitor_;
194 scoped_ptr<QuicHttpStream> stream_;
195 scoped_ptr<QuicClientSession> session_;
196 TestCompletionCallback callback_;
197 HttpRequestInfo request_;
198 HttpRequestHeaders headers_;
199 HttpResponseInfo response_;
200 scoped_refptr<IOBufferWithSize> read_buffer_;
201
202 private:
203 void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
204 header_.guid = guid_;
205 header_.packet_sequence_number = sequence_number;
206 header_.flags = PACKET_FLAGS_NONE;
207 header_.fec_group = 0;
208 }
209
210 QuicEncryptedPacket* ConstructPacket(const QuicPacketHeader& header,
211 const QuicFrame& frame) {
212 QuicFrames frames;
213 frames.push_back(frame);
214 QuicPacket* packet;
215 framer_.ConstructFrameDataPacket(header_, frames, &packet);
216 QuicEncryptedPacket* encrypted = framer_.EncryptPacket(*packet);
217 delete packet;
218 return encrypted;
219 }
220
221 const QuicGuid guid_;
222 QuicFramer framer_;
223 IPEndPoint self_addr_;
224 IPEndPoint peer_addr_;
225 QuicPacketCreator creator_;
226 QuicPacketHeader header_;
227 scoped_ptr<MockUDPClientSocket> socket_;
228 scoped_ptr<StaticSocketDataProvider> socket_data_;
229 std::vector<PacketToWrite> writes_;
230 };
231
232 TEST_F(QuicHttpStreamTest, RenewStreamForAuth) {
233 EXPECT_EQ(NULL, stream_->RenewStreamForAuth());
234 }
235
236 TEST_F(QuicHttpStreamTest, CanFindEndOfResponse) {
237 EXPECT_TRUE(stream_->CanFindEndOfResponse());
238 }
239
240 TEST_F(QuicHttpStreamTest, IsMoreDataBuffered) {
241 EXPECT_FALSE(stream_->IsMoreDataBuffered());
242 }
243
244 TEST_F(QuicHttpStreamTest, IsConnectionReusable) {
245 EXPECT_FALSE(stream_->IsConnectionReusable());
246 }
247
248 TEST_F(QuicHttpStreamTest, GetRequest) {
249 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
250 "GET / HTTP/1.1\r\n\r\n"));
251 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 0));
252 Initialize();
253
254 request_.method = "GET";
255 request_.url = GURL("http://www.google.com/");
256
257 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
258 callback_.callback()));
259 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
260 callback_.callback()));
261 EXPECT_EQ(&response_, stream_->GetResponseInfo());
262
263 // Ack the request.
264 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1, 0));
265 ProcessPacket(*ack);
266
267 EXPECT_EQ(ERR_IO_PENDING,
268 stream_->ReadResponseHeaders(callback_.callback()));
269
270 // Send the response without a body.
271 const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
272 "Content-Type: text/plain\r\n\r\n";
273 scoped_ptr<QuicEncryptedPacket> resp(
274 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
275 ProcessPacket(*resp);
276
277 // Now that the headers have been processed, the callback will return.
278 EXPECT_EQ(OK, callback_.WaitForResult());
279 ASSERT_TRUE(response_.headers != NULL);
280 EXPECT_EQ(404, response_.headers->response_code());
281 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
282
283 // There is no body, so this should return immediately.
284 EXPECT_EQ(0, stream_->ReadResponseBody(read_buffer_.get(),
285 read_buffer_->size(),
286 callback_.callback()));
287 EXPECT_TRUE(stream_->IsResponseBodyComplete());
288 EXPECT_TRUE(AtEof());
289 }
290
291 TEST_F(QuicHttpStreamTest, GetRequestFullResponseInSinglePacket) {
292 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
293 "GET / HTTP/1.1\r\n\r\n"));
294 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 0));
295 Initialize();
296
297 request_.method = "GET";
298 request_.url = GURL("http://www.google.com/");
299
300 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
301 callback_.callback()));
302 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
303 callback_.callback()));
304 EXPECT_EQ(&response_, stream_->GetResponseInfo());
305
306 // Ack the request.
307 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1, 0));
308 ProcessPacket(*ack);
309
310 EXPECT_EQ(ERR_IO_PENDING,
311 stream_->ReadResponseHeaders(callback_.callback()));
312
313 // Send the response with a body.
314 const char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
315 "Content-Type: text/plain\r\n\r\nhello world!";
316 scoped_ptr<QuicEncryptedPacket> resp(
317 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
318 ProcessPacket(*resp);
319
320 // Now that the headers have been processed, the callback will return.
321 EXPECT_EQ(OK, callback_.WaitForResult());
322 ASSERT_TRUE(response_.headers != NULL);
323 EXPECT_EQ(404, response_.headers->response_code());
324 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
325
326 // There is no body, so this should return immediately.
327 // Since the body has already arrived, this should return immediately.
328 EXPECT_EQ(12, stream_->ReadResponseBody(read_buffer_.get(),
329 read_buffer_->size(),
330 callback_.callback()));
331 EXPECT_TRUE(stream_->IsResponseBodyComplete());
332 EXPECT_TRUE(AtEof());
333 }
334
335 TEST_F(QuicHttpStreamTest, SendPostRequest) {
336 const char kRequestData[] = "POST / HTTP/1.1\r\n\r\n";
337 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, false, 0, kRequestData));
338 AddWrite(SYNCHRONOUS, ConstructDataPacket(2, true, strlen(kRequestData),
jar (doing other things) 2012/12/03 20:16:51 nit: use kFin and kNoFin
339 kUploadData));
340 AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 0));
341 AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 3, 0));
342
343 Initialize();
344
345 UploadData* upload_data = new UploadData();
346 upload_data->AppendBytes(kUploadData, strlen(kUploadData));
347 UploadDataStream upload_data_stream(upload_data);
348 request_.method = "POST";
349 request_.url = GURL("http://www.google.com/");
350 request_.upload_data_stream = &upload_data_stream;
351 ASSERT_EQ(OK, request_.upload_data_stream->InitSync());
352
353 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
354 callback_.callback()));
355 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
356 callback_.callback()));
357 EXPECT_EQ(&response_, stream_->GetResponseInfo());
358
359 // Ack both packets in the request.
360 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 2, 1));
361 ProcessPacket(*ack);
362
363 // Send the response headers (but not the body).
364 const char kResponseHeaders[] = "HTTP/1.1 200 OK\r\n"
365 "Content-Type: text/plain\r\n\r\n";
366 scoped_ptr<QuicEncryptedPacket> resp(
367 ConstructDataPacket(2, kNoFin, 0, kResponseHeaders));
368 ProcessPacket(*resp);
369
370 // Since the headers have already arrived, this should return immediately.
371 EXPECT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback()));
372 ASSERT_TRUE(response_.headers != NULL);
373 EXPECT_EQ(200, response_.headers->response_code());
374 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
375
376 // Send the response body.
377 const char kResponseBody[] = "Hello world!";
378 scoped_ptr<QuicEncryptedPacket> resp_body(
379 ConstructDataPacket(3, kFin, strlen(kResponseHeaders), kResponseBody));
380 ProcessPacket(*resp_body);
381
382 // Since the body has already arrived, this should return immediately.
383 EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
384 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
385 callback_.callback()));
386
387 EXPECT_TRUE(stream_->IsResponseBodyComplete());
388 EXPECT_TRUE(AtEof());
389 }
390
391 } // namespace test
392
393 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_http_stream.cc ('k') | net/quic/quic_protocol.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698