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

Side by Side Diff: google_apis/gcm/base/socket_stream_unittest.cc

Issue 23684017: [GCM] Initial work to set up directory structure and introduce socket integration (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 7 years, 3 months 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) 2013 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 "google_apis/gcm/base/socket_stream.h"
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/test/test_timeouts.h"
11 #include "net/socket/socket_test_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace gcm {
15 namespace {
16
17 typedef std::vector<net::MockRead> ReadList;
18 typedef std::vector<net::MockWrite> WriteList;
19
20 const char kReadData[] = "read_data";
21 const char kReadData2[] = "read_alternate_data";
22 const char kWriteData[] = "write_data";
23
24 class GCMSocketStreamTest : public testing::Test {
25 public:
26 GCMSocketStreamTest();
27 virtual ~GCMSocketStreamTest();
28
29 // Build a socket with the expected reads and writes.
30 void BuildSocket(const ReadList& read_list, const WriteList& write_list);
31
32 // Pump the message loop until idle.
33 void PumpLoop();
34
35 // Simulates a google::protobuf::io::CodedInputStream read.
36 uint64 DoInputStreamRead(uint64 bytes,
37 bool set_limit,
38 const void** output_buffer);
39 // Simulates a google::protobuf::io::CodedOutputStream write.
40 uint64 DoOutputStreamWrite(uint64 bytes);
41
42 // Synchronous GetNextMessage wrapper.
43 void DoGetNextMessage(int msg_size);
44
45 // Synchronous Refresh wrapper.
46 void DoRefresh();
47
48 base::MessageLoop* message_loop() { return &message_loop_; };
49 net::DelayedSocketData* data_provider() { return data_provider_.get(); }
50 SocketInputStream* input_stream() { return socket_input_stream_.get(); }
51 SocketOutputStream* output_stream() { return socket_output_stream_.get(); }
52 net::StreamSocket* socket() { return socket_.get(); }
53
54 private:
55 void OpenConnection();
56 void ResetInputStream();
57 void ResetOutputStream();
58
59 void ConnectCallback(int result);
60
61 // SocketStreams and their data providers.
62 ReadList mock_reads_;
63 WriteList mock_writes_;
64 scoped_ptr<net::DelayedSocketData> data_provider_;
65 scoped_ptr<SocketInputStream> socket_input_stream_;
66 scoped_ptr<SocketOutputStream> socket_output_stream_;
67
68 // net:: components.
69 scoped_ptr<net::StreamSocket> socket_;
70 net::MockClientSocketFactory socket_factory_;
71 net::AddressList address_list_;
72
73 base::MessageLoopForIO message_loop_;
74 };
75
76 GCMSocketStreamTest::GCMSocketStreamTest() {
77 net::IPAddressNumber ip_number;
78 net::ParseIPLiteralToNumber("127.0.0.1", &ip_number);
79 address_list_ = net::AddressList::CreateFromIPAddress(ip_number, 5228);
80 }
81
82 GCMSocketStreamTest::~GCMSocketStreamTest() {}
83
84 void GCMSocketStreamTest::BuildSocket(const ReadList& read_list,
85 const WriteList& write_list) {
86 mock_reads_ = read_list;
87 mock_writes_ = write_list;
88 data_provider_.reset(
89 new net::DelayedSocketData(0,
90 &(mock_reads_[0]), mock_reads_.size(),
91 &(mock_writes_[0]), mock_writes_.size()));
92 socket_factory_.AddSocketDataProvider(data_provider_.get());
93 OpenConnection();
94 ResetInputStream();
95 ResetOutputStream();
96 }
97
98 void GCMSocketStreamTest::PumpLoop() {
99 base::RunLoop run_loop;
100 run_loop.RunUntilIdle();
101 }
102
103 uint64 GCMSocketStreamTest::DoInputStreamRead(uint64 bytes,
104 bool set_limit,
105 const void** output_buffer) {
106 uint64 total_bytes_read = 0;
107 const char* initial_buffer = NULL;
108 const char* buffer = NULL;
109 int size = 0;
110
111 do {
112 DCHECK(socket_input_stream_->state() == SocketInputStream::EMPTY ||
113 socket_input_stream_->state() == SocketInputStream::READY);
114 if (!socket_input_stream_->Next((const void **)&buffer, &size))
115 break;
116 total_bytes_read += size;
117 if (initial_buffer != NULL) // Verify the buffer doesn't skip data.
118 EXPECT_EQ(initial_buffer + total_bytes_read, buffer + size);
119 else
120 initial_buffer = buffer;
121 } while (total_bytes_read < bytes);
122
123 *output_buffer = (const void*)initial_buffer;
124
125 if (total_bytes_read > bytes) {
126 socket_input_stream_->BackUp(total_bytes_read - bytes);
127 total_bytes_read = bytes;
128 }
129
130 return total_bytes_read;
131 }
132
133 uint64 GCMSocketStreamTest::DoOutputStreamWrite(uint64 bytes) {
134 DCHECK_EQ(socket_output_stream_->state(), SocketOutputStream::EMPTY);
135 uint64 total_bytes_written = 0;
136 char* buffer = NULL;
137 int size = 0;
138 const char* write_src = kWriteData;
139
140 do {
141 if (!socket_output_stream_->Next((void **)&buffer, &size))
142 break;
143 uint64 bytes_to_write = ((uint64)size < bytes ? size : bytes);
144 memcpy(buffer, &write_src[total_bytes_written], bytes_to_write);
145 if (bytes_to_write < (uint64)size)
146 socket_output_stream_->BackUp(size - bytes_to_write);
147 total_bytes_written += bytes_to_write;
148 } while (total_bytes_written < bytes);
149
150 base::RunLoop run_loop;
151 socket_output_stream_->Flush(run_loop.QuitClosure());
152 run_loop.Run();
153
154 return total_bytes_written;
155 }
156
157 void ReadCallback(base::RunLoop* run_loop) {
158 run_loop->Quit();
159 }
160
161 void GCMSocketStreamTest::DoGetNextMessage(int msg_size) {
162 base::RunLoop run_loop;
163 input_stream()->GetNextMessage(msg_size,
164 base::Bind(&ReadCallback,
165 base::Unretained(&run_loop)));
166 run_loop.Run();
167 }
168
169 void GCMSocketStreamTest::DoRefresh() {
170 base::RunLoop run_loop;
171 input_stream()->Refresh(base::Bind(&ReadCallback,
172 base::Unretained(&run_loop)));
173 run_loop.Run();
174 }
175
176 void GCMSocketStreamTest::OpenConnection() {
177 socket_ = socket_factory_.CreateTransportClientSocket(
178 address_list_, NULL, net::NetLog::Source());
179 socket_->Connect(
180 base::Bind(&GCMSocketStreamTest::ConnectCallback,
181 base::Unretained(this)));
182 PumpLoop();
183 }
184
185 void GCMSocketStreamTest::ConnectCallback(int result) {}
186
187 void GCMSocketStreamTest::ResetInputStream() {
188 DCHECK(socket_.get());
189 socket_input_stream_.reset(
190 new SocketInputStream(TestTimeouts::tiny_timeout(),
191 socket_.get()));
192 }
193
194 void GCMSocketStreamTest::ResetOutputStream() {
195 DCHECK(socket_.get());
196 socket_output_stream_.reset(new SocketOutputStream(socket_.get()));
197 }
198
199 // A read where all data is already available.
200 TEST_F(GCMSocketStreamTest, ReadPendingData) {
201 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, kReadData)),
202 WriteList());
203
204 const void* output = NULL;
205 DoGetNextMessage(strlen(kReadData));
206 ASSERT_EQ(strlen(kReadData),
207 DoInputStreamRead(strlen(kReadData), false, &output));
208 ASSERT_EQ(std::string(kReadData),
209 std::string((const char*)output, strlen(kReadData)));
210 }
211
212 TEST_F(GCMSocketStreamTest, RefreshThenRead) {
213 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, kReadData)),
214 WriteList());
215
216 const void* output = NULL;
217 DoRefresh();
218 DoGetNextMessage(strlen(kReadData));
219 ASSERT_EQ(strlen(kReadData),
220 DoInputStreamRead(strlen(kReadData), false, &output));
221 ASSERT_EQ(std::string(kReadData),
222 std::string((const char*)output, strlen(kReadData)));
223 }
224
225 // A read that comes in two parts.
226 TEST_F(GCMSocketStreamTest, ReadPartialData) {
227 size_t first_read_len = strlen(kReadData)/2;
228 size_t second_read_len = strlen(kReadData) - first_read_len;
229 ReadList read_list;
230 read_list.push_back(
231 net::MockRead(net::SYNCHRONOUS,
232 kReadData, first_read_len));
233 read_list.push_back(
234 net::MockRead(net::SYNCHRONOUS,
235 &kReadData[first_read_len], second_read_len));
236 BuildSocket(read_list, WriteList());
237
238 const void* output = NULL;
239 DoGetNextMessage(strlen(kReadData));
240 ASSERT_EQ(strlen(kReadData),
241 DoInputStreamRead(strlen(kReadData), false, &output));
242 ASSERT_EQ(std::string(kReadData),
243 std::string((const char*)output, strlen(kReadData)));
244 }
245
246 // A read where no data is available at first (IO_PENDING will be returned).
247 TEST_F(GCMSocketStreamTest, ReadNoData) {
248 size_t first_read_len = strlen(kReadData)/2;
249 size_t second_read_len = strlen(kReadData) - first_read_len;
250 ReadList read_list;
251 read_list.push_back(
252 net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
253 read_list.push_back(
254 net::MockRead(net::ASYNC, kReadData, first_read_len));
255 read_list.push_back(
256 net::MockRead(net::ASYNC, &kReadData[first_read_len], second_read_len));
257 BuildSocket(read_list, WriteList());
258
259 const void* output = NULL;
260 base::MessageLoop::current()->PostTask(
261 FROM_HERE,
262 base::Bind(&net::DelayedSocketData::ForceNextRead,
263 base::Unretained(data_provider())));
264 DoGetNextMessage(strlen(kReadData));
265 ASSERT_EQ(strlen(kReadData),
266 DoInputStreamRead(strlen(kReadData), false, &output));
267 ASSERT_EQ(std::string(kReadData),
268 std::string((const char*)output, strlen(kReadData)));
269 }
270
271 // A read where a second message arrives at the same time. The second message
272 // is then read.
273 TEST_F(GCMSocketStreamTest, TwoReadsAtOnce) {
274 std::string long_data = std::string(kReadData) + std::string(kReadData2);
275 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, long_data.c_str())),
276 WriteList());
277 const void* output = NULL;
278
279 DoGetNextMessage(strlen(kReadData));
280 ASSERT_EQ(strlen(kReadData),
281 DoInputStreamRead(strlen(kReadData), false, &output));
282 ASSERT_EQ(std::string(kReadData, strlen(kReadData)),
283 std::string((const char*)output, strlen(kReadData)));
284
285 DoGetNextMessage(strlen(kReadData) + strlen(kReadData2));
286 ASSERT_EQ(strlen(kReadData2),
287 DoInputStreamRead(strlen(kReadData2), false, &output));
288 ASSERT_EQ(std::string(kReadData2, strlen(kReadData)),
289 std::string((const char*)output, strlen(kReadData)));
290 }
291
292 // A read where a second message arrives at the same time. The input stream
293 // is rebuilt before the second message is read.
294 TEST_F(GCMSocketStreamTest, TwoReadsAtOnceWithRebuild) {
295 std::string long_data = std::string(kReadData) + std::string(kReadData2);
296 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, long_data.c_str())),
297 WriteList());
298
299 const void* output = NULL;
300 DoGetNextMessage(strlen(kReadData));
301 ASSERT_EQ(strlen(kReadData),
302 DoInputStreamRead(strlen(kReadData), false, &output));
303 ASSERT_EQ(std::string(kReadData, strlen(kReadData)),
304 std::string((const char*)output, strlen(kReadData)));
305
306 input_stream()->Rebuild();
307 DoGetNextMessage(strlen(kReadData2));
308 ASSERT_EQ(strlen(kReadData2),
309 DoInputStreamRead(strlen(kReadData2), false, &output));
310 ASSERT_EQ(std::string(kReadData2, strlen(kReadData2)),
311 std::string((const char*)output, strlen(kReadData2)));
312 }
313
314 // Simulate a read timing out.
315 TEST_F(GCMSocketStreamTest, ReadTimeout) {
316 int result = net::ERR_TIMED_OUT;
317 std::string original_data = std::string(kReadData);
318 std::string partial_data = original_data.substr(original_data.size()/2);
319
320 ReadList read_list;
321 read_list.push_back(
322 net::MockRead(net::ASYNC, partial_data.c_str(), partial_data.length()));
323 read_list.push_back(
324 net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
325 read_list.push_back(
326 net::MockRead(net::ASYNC,
327 &original_data.c_str()[partial_data.size()],
328 original_data.size() - partial_data.size()));
329 BuildSocket(read_list, WriteList());
330
331 // Get part of the data.
332 DoGetNextMessage(strlen(kReadData));
333 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->state());
334 ASSERT_EQ(result, input_stream()->last_error());
335
336 // Get the rest of the data. Should have no effect.
337 data_provider()->ForceNextRead();
338 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->state());
339 ASSERT_EQ(result, input_stream()->last_error());
340 }
341
342 // Simulate a read that is aborted.
343 TEST_F(GCMSocketStreamTest, ReadError) {
344 int result = net::ERR_ABORTED;
345 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, result)),
346 WriteList());
347
348 DoGetNextMessage(strlen(kReadData));
349 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->state());
350 ASSERT_EQ(result, input_stream()->last_error());
351 }
352
353 // Simulate a read after the connection is closed.
354 TEST_F(GCMSocketStreamTest, ReadDisconnected) {
355 BuildSocket(ReadList(), WriteList());
356 socket()->Disconnect();
357 DoGetNextMessage(strlen(kReadData));
358 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->state());
359 ASSERT_EQ(net::ERR_CONNECTION_CLOSED, input_stream()->last_error());
360 }
361
362 // Write a full message in one go.
363 TEST_F(GCMSocketStreamTest, WriteFull) {
364 BuildSocket(ReadList(),
365 WriteList(1, net::MockWrite(net::SYNCHRONOUS, kWriteData)));
366 ASSERT_EQ(strlen(kWriteData), DoOutputStreamWrite(strlen(kWriteData)));
367 }
368
369 // Write a message in two go's.
370 TEST_F(GCMSocketStreamTest, WritePartial) {
371 std::string full_data = std::string(kWriteData);
372 std::string part1 = full_data.substr(0, full_data.length()/2);
373 std::string part2 = full_data.substr(full_data.length()/2);
374 WriteList write_list;
375 write_list.push_back(net::MockWrite(net::SYNCHRONOUS, part1.c_str()));
376 write_list.push_back(net::MockWrite(net::SYNCHRONOUS, part2.c_str()));
377 BuildSocket(ReadList(), write_list);
378 ASSERT_EQ(strlen(kWriteData), DoOutputStreamWrite(strlen(kWriteData)));
379 }
380
381 // Write a message completely asynchronously (returns IO_PENDING before
382 // finishing the write in two go's).
383 TEST_F(GCMSocketStreamTest, WriteNone) {
384 std::string full_data = std::string(kWriteData);
385 std::string part1 = full_data.substr(0, full_data.length()/2);
386 std::string part2 = full_data.substr(full_data.length()/2);
387 WriteList write_list;
388 write_list.push_back(net::MockWrite(net::ASYNC, part1.c_str()));
389 write_list.push_back(net::MockWrite(net::ASYNC, part2.c_str()));
390 BuildSocket(ReadList(), write_list);
391 ASSERT_EQ(strlen(kWriteData), DoOutputStreamWrite(strlen(kWriteData)));
392 }
393
394 // Write a message then read a message.
395 TEST_F(GCMSocketStreamTest, WriteThenRead) {
396 BuildSocket(ReadList(1, net::MockRead(kReadData)),
397 WriteList(1, net::MockWrite(kWriteData)));
398
399 ASSERT_EQ(strlen(kWriteData), DoOutputStreamWrite(strlen(kWriteData)));
400
401 const void* output = NULL;
402 DoGetNextMessage(strlen(kReadData));
403 ASSERT_EQ(strlen(kReadData),
404 DoInputStreamRead(strlen(kReadData), false, &output));
405 ASSERT_EQ(std::string(kReadData),
406 std::string((const char*)output, strlen(kReadData)));
407 }
408
409 // Read a message then write a message.
410 TEST_F(GCMSocketStreamTest, ReadThenWrite) {
411 BuildSocket(ReadList(1, net::MockRead(kReadData)),
412 WriteList(1, net::MockWrite(kWriteData)));
413
414 const void* output = NULL;
415 DoGetNextMessage(strlen(kReadData));
416 ASSERT_EQ(strlen(kReadData),
417 DoInputStreamRead(strlen(kReadData), false, &output));
418 ASSERT_EQ(std::string(kReadData),
419 std::string((const char*)output, strlen(kReadData)));
420
421 ASSERT_EQ(strlen(kWriteData), DoOutputStreamWrite(strlen(kWriteData)));
422 }
423
424 // Simulate a write that gets aborted.
425 TEST_F(GCMSocketStreamTest, WriteError) {
426 int result = net::ERR_ABORTED;
427 BuildSocket(ReadList(),
428 WriteList(1, net::MockWrite(net::SYNCHRONOUS, result)));
429 DoOutputStreamWrite(strlen(kWriteData));
430 ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->state());
431 ASSERT_EQ(result, output_stream()->last_error());
432 }
433
434 // Simulate a write after the connection is closed.
435 TEST_F(GCMSocketStreamTest, WriteDisconnected) {
436 BuildSocket(ReadList(), WriteList());
437 socket()->Disconnect();
438 DoOutputStreamWrite(strlen(kWriteData));
439 ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->state());
440 ASSERT_EQ(net::ERR_CONNECTION_CLOSED, output_stream()->last_error());
441 }
442
443 } // namespace
444 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698