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

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: Move GetPeerAddress from QuicReliableClientStream to ReliableQuicStream 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
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 TestSession : public QuicClientSession {
willchan no longer on Chromium 2012/11/23 03:17:43 Can you name these TestQuicSession and TestQuicCon
Ryan Hamilton 2012/11/23 04:19:53 Done. (Though it turned out the Session wasn't ev
43 public:
44 virtual QuicCryptoClientStream* GetCryptoStream() {
45 return QuicClientSession::GetCryptoStream();
46 }
47 };
48
49 class TestConnection : public QuicConnection {
50 public:
51 TestConnection(QuicGuid guid,
52 IPEndPoint address,
53 QuicConnectionHelper* helper)
54 : QuicConnection(guid, address, helper) {
55 }
56
57 void SetScheduler(QuicSendScheduler* scheduler) {
58 QuicConnectionPeer::SetScheduler(this, scheduler);
59 }
60 };
61
62 } // namespace
63
64 class QuicHttpStreamTest : public ::testing::Test {
65 protected:
66 const static bool kFin = true;
67 const static bool kNoFin = false;
68 // Holds a packet to be written to the wire, and the IO mode that should
69 // be used by the mock socket when performing the write.
70 struct PacketToWrite {
71 PacketToWrite(IoMode mode, QuicEncryptedPacket* packet)
72 : mode(mode),
73 packet(packet) {
74 }
75 IoMode mode;
76 QuicEncryptedPacket* packet;
77 };
78
79 QuicHttpStreamTest()
80 : net_log_(BoundNetLog()),
81 read_buffer_(new IOBufferWithSize(4096)),
82 guid_(2),
willchan no longer on Chromium 2012/11/23 03:17:43 What's up with this guy, is he a constant? He seem
Ryan Hamilton 2012/11/23 04:19:53 Yeah, he's const. I added a const annotation to t
83 framer_(QuicDecrypter::Create(kNULL), QuicEncrypter::Create(kNULL)),
84 creator_(guid_, &framer_) {
85 IPAddressNumber ip;
86 CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
87 peer_addr_ = IPEndPoint(ip, 443);
88 self_addr_ = IPEndPoint(ip, 8435);
89 Initialize();
90 }
91
92 ~QuicHttpStreamTest() {
93 for (size_t i = 0; i < writes_.size(); i++) {
94 delete writes_[i].packet;
95 }
96 }
97
98 // Adds a packet to the list of expected writes.
99 void AddWrite(IoMode mode, QuicEncryptedPacket* packet) {
100 writes_.push_back(PacketToWrite(mode, packet));
101 }
102
103 // Returns the packet to be written at position |pos|.
104 QuicEncryptedPacket* GetWrite(size_t pos) {
105 return writes_[pos].packet;
106 }
107
108 bool AtEof() {
109 return socket_data_->at_read_eof() && socket_data_->at_write_eof();
110 }
111
112 void ProcessPacket(const QuicEncryptedPacket& packet) {
113 connection_->ProcessUdpPacket(self_addr_, peer_addr_, packet);
114 }
115
116 // Configures the test fixture to use the list of expected writes.
117 void Initialize() {
118 mock_writes_.reset(new MockWrite[writes_.size()]);
119 for (size_t i = 0; i < writes_.size(); i++) {
120 mock_writes_[i] = MockWrite(writes_[i].mode,
121 writes_[i].packet->data(),
122 writes_[i].packet->length());
123 };
124
125 socket_data_.reset(new StaticSocketDataProvider(NULL, 0, mock_writes_.get(),
126 writes_.size()));
127
128 socket_.reset(new MockUDPClientSocket(socket_data_.get(),
129 net_log_.net_log()));
130 socket_->Connect(peer_addr_);
131 runner_ = new TestTaskRunner(&clock_);
132 helper_ = new QuicConnectionHelper(runner_.get(), &clock_, socket_.get());
willchan no longer on Chromium 2012/11/23 03:17:43 Why is helper_ a member variable? I don't see it g
Ryan Hamilton 2012/11/23 04:19:53 Inlined it into the connection_ initialization.
133 scheduler_ = new MockScheduler();
134 EXPECT_CALL(*scheduler_, TimeUntilSend(_)).
135 WillRepeatedly(testing::Return(QuicTime::Delta()));
136 connection_ = new TestConnection(guid_, peer_addr_, helper_);
137 connection_->set_visitor(&visitor_);
138 connection_->SetScheduler(scheduler_);
139 session_.reset(new QuicClientSession(connection_));
140 CryptoHandshakeMessage message;
141 message.tag = kSHLO;
142 session_->GetCryptoStream()->OnHandshakeMessage(message);
143 EXPECT_TRUE(session_->IsCryptoHandshakeComplete());
144 stream_.reset(new QuicHttpStream(session_->CreateOutgoingReliableStream()));
145 }
146
147 // Returns a newly created packet to send kData on stream 1.
148 QuicEncryptedPacket* ConstructDataPacket(
149 QuicPacketSequenceNumber sequence_number,
150 bool fin,
151 QuicStreamOffset offset,
152 base::StringPiece data) {
153 InitializeHeader(sequence_number);
154 QuicStreamFrame frame(3, fin, offset, data);
155 return ConstructPacket(header_, QuicFrame(&frame));
156 }
157
158 // Returns a newly created packet to send ack data.
159 QuicEncryptedPacket* ConstructAckPacket(
160 QuicPacketSequenceNumber sequence_number,
161 QuicPacketSequenceNumber largest_received,
162 QuicPacketSequenceNumber least_unacked) {
163 InitializeHeader(sequence_number);
164
165 QuicAckFrame ack(largest_received, QuicTime(), least_unacked);
166 ack.congestion_info.type = kFixRate;
167 ack.congestion_info.fix_rate.bitrate_in_bytes_per_second = 100000;
168
169 return ConstructPacket(header_, QuicFrame(&ack));
170 }
171
172 // Returns a newly created packet to send a connection close frame.
173 QuicEncryptedPacket* ConstructClosePacket(
174 QuicPacketSequenceNumber sequence_number,
175 bool with_ack) {
176 InitializeHeader(sequence_number);
177
178 QuicFrames frames;
179 QuicAckFrame ack(0, QuicTime(), 0);
180 if (with_ack) {
181 ack.congestion_info.type = kFixRate;
182 ack.congestion_info.fix_rate.bitrate_in_bytes_per_second = 100000;
183 } else {
184 ack.congestion_info.type = kNone;
185 }
186 QuicConnectionCloseFrame close;
187 close.error_code = QUIC_CONNECTION_TIMED_OUT;
188 close.ack_frame = ack;
189
190 return ConstructPacket(header_, QuicFrame(&close));
191 }
192
193 BoundNetLog net_log_;
194 MockScheduler* scheduler_;
195 scoped_refptr<TestTaskRunner> runner_;
196 QuicConnectionHelper* helper_;
197 scoped_array<MockWrite> mock_writes_;
198 MockClock clock_;
199 TestConnection* connection_;
200 testing::StrictMock<MockConnectionVisitor> visitor_;
201 scoped_ptr<QuicHttpStream> stream_;
202 scoped_ptr<QuicClientSession> session_;
203 TestCompletionCallback callback_;
204 HttpRequestInfo request_;
205 HttpRequestHeaders headers_;
206 HttpResponseInfo response_;
207 scoped_refptr<IOBufferWithSize> read_buffer_;
208
209 private:
210 void InitializeHeader(QuicPacketSequenceNumber sequence_number) {
211 header_.guid = guid_;
212 header_.packet_sequence_number = sequence_number;
213 header_.flags = PACKET_FLAGS_NONE;
214 header_.fec_group = 0;
215 }
216
217 QuicEncryptedPacket* ConstructPacket(const QuicPacketHeader& header,
218 const QuicFrame& frame) {
219 QuicFrames frames;
220 frames.push_back(frame);
221 QuicPacket* packet;
222 framer_.ConstructFrameDataPacket(header_, frames, &packet);
223 QuicEncryptedPacket* encrypted = framer_.EncryptPacket(*packet);
224 delete packet;
225 return encrypted;
226 }
227
228 QuicGuid guid_;
229 QuicFramer framer_;
230 IPEndPoint self_addr_;
231 IPEndPoint peer_addr_;
232 QuicPacketCreator creator_;
233 QuicPacketHeader header_;
234 scoped_ptr<MockUDPClientSocket> socket_;
235 scoped_ptr<StaticSocketDataProvider> socket_data_;
236 std::vector<PacketToWrite> writes_;
237 };
238
239 TEST_F(QuicHttpStreamTest, RenewStreamForAuth) {
240 EXPECT_EQ(NULL, stream_->RenewStreamForAuth());
241 }
242
243 TEST_F(QuicHttpStreamTest, CanFindEndOfResponse) {
244 EXPECT_TRUE(stream_->CanFindEndOfResponse());
245 }
246
247 TEST_F(QuicHttpStreamTest, IsMoreDataBuffered) {
248 EXPECT_FALSE(stream_->IsMoreDataBuffered());
249 }
250
251 TEST_F(QuicHttpStreamTest, IsConnectionReusable) {
252 EXPECT_FALSE(stream_->IsConnectionReusable());
253 }
254
255 TEST_F(QuicHttpStreamTest, GetRequest) {
256 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, kFin, 0,
257 "GET / HTTP/1.1\r\n\r\n"));
258 AddWrite(SYNCHRONOUS, ConstructAckPacket(2, 2, 0));
259 Initialize();
260
261 request_.method = "GET";
262 request_.url = GURL("http://www.google.com/");
263
264 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
265 callback_.callback()));
266 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
267 callback_.callback()));
268 EXPECT_EQ(&response_, stream_->GetResponseInfo());
269
270 // Ack the request.
271 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1, 0));
272 ProcessPacket(*ack);
273
274 EXPECT_EQ(ERR_IO_PENDING,
275 stream_->ReadResponseHeaders(callback_.callback()));
276
277 // Send the response without a body.
278 char kResponseHeaders[] = "HTTP/1.1 404 OK\r\n"
willchan no longer on Chromium 2012/11/23 03:17:43 Can this be a const char[]?
Ryan Hamilton 2012/11/23 04:19:53 Done.
279 "Content-Type: text/plain\r\n\r\n";
280 scoped_ptr<QuicEncryptedPacket> resp(
281 ConstructDataPacket(2, kFin, 0, kResponseHeaders));
282 ProcessPacket(*resp);
283
284 // Now that the headers have been processed, the callback will return.
285 EXPECT_EQ(OK, callback_.WaitForResult());
286 ASSERT_TRUE(response_.headers != NULL);
287 EXPECT_EQ(404, response_.headers->response_code());
288 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
289
290 // There is no body, so this should return immediately.
291 EXPECT_EQ(0, stream_->ReadResponseBody(read_buffer_.get(),
292 read_buffer_->size(),
293 callback_.callback()));
294 EXPECT_TRUE(stream_->IsResponseBodyComplete());
295 EXPECT_TRUE(AtEof());
296 }
297
willchan no longer on Chromium 2012/11/23 03:17:43 Add a test for response headers and body in the sa
Ryan Hamilton 2012/11/23 04:19:53 Done.
298 TEST_F(QuicHttpStreamTest, SendPostRequest) {
299 char kRequestData[] = "POST / HTTP/1.1\r\n\r\n";
300 AddWrite(SYNCHRONOUS, ConstructDataPacket(1, false, 0, kRequestData));
301 AddWrite(SYNCHRONOUS, ConstructDataPacket(2, true, strlen(kRequestData),
302 kUploadData));
303 AddWrite(SYNCHRONOUS, ConstructAckPacket(3, 2, 0));
304 AddWrite(SYNCHRONOUS, ConstructAckPacket(4, 3, 0));
305
306 Initialize();
307
308 UploadData* upload_data = new UploadData();
309 upload_data->AppendBytes(kUploadData, strlen(kUploadData));
310 UploadDataStream upload_data_stream(upload_data);
311 request_.method = "POST";
312 request_.url = GURL("http://www.google.com/");
313 request_.upload_data_stream = &upload_data_stream;
314 ASSERT_EQ(OK, request_.upload_data_stream->InitSync());
315
316 EXPECT_EQ(OK, stream_->InitializeStream(&request_, net_log_,
317 callback_.callback()));
318 EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
319 callback_.callback()));
320 EXPECT_EQ(&response_, stream_->GetResponseInfo());
321
322 // Ack both packets in the request.
323 scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 2, 1));
324 ProcessPacket(*ack);
325
326 // Send the response headers (but not the body).
327 char kResponseHeaders[] = "HTTP/1.1 200 OK\r\n"
328 "Content-Type: text/plain\r\n\r\n";
329 scoped_ptr<QuicEncryptedPacket> resp(
330 ConstructDataPacket(2, kNoFin, 0, kResponseHeaders));
331 ProcessPacket(*resp);
332
333 // Since the headers have already arrived, this should return immediately.
334 EXPECT_EQ(OK, stream_->ReadResponseHeaders(callback_.callback()));
335 ASSERT_TRUE(response_.headers != NULL);
336 EXPECT_EQ(200, response_.headers->response_code());
337 EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
338
339 // Send the response body.
340 char kResponseBody[] = "Hello world!";
341 scoped_ptr<QuicEncryptedPacket> resp_body(
342 ConstructDataPacket(3, kFin, strlen(kResponseHeaders), kResponseBody));
343 ProcessPacket(*resp_body);
344
345 // Since the body has already arrived, this should return immediately.
346 EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
347 stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
348 callback_.callback()));
349
350 EXPECT_TRUE(stream_->IsResponseBodyComplete());
351 EXPECT_TRUE(AtEof());
352 }
willchan no longer on Chromium 2012/11/23 03:22:58 Can you add a test for synchronous completion of t
Ryan Hamilton 2012/11/23 04:19:53 Actually, the existing test already does that. Co
353
354 } // namespace test
355
356 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698