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

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, 2 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/basictypes.h"
8 #include "base/bind.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.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 uint64 kReadDataSize = arraysize(kReadData) - 1;
22 const char kReadData2[] = "read_alternate_data";
23 const uint64 kReadData2Size = arraysize(kReadData2) - 1;
24 const char kWriteData[] = "write_data";
25 const uint64 kWriteDataSize = arraysize(kWriteData) - 1;
26
27 class GCMSocketStreamTest : public testing::Test {
28 public:
29 GCMSocketStreamTest();
30 virtual ~GCMSocketStreamTest();
31
32 // Build a socket with the expected reads and writes.
33 void BuildSocket(const ReadList& read_list, const WriteList& write_list);
34
35 // Pump the message loop until idle.
36 void PumpLoop();
37
38 // Simulates a google::protobuf::io::CodedInputStream read.
39 uint64 DoInputStreamRead(uint64 bytes,
40 bool set_limit,
41 const void** output_buffer);
42 // Simulates a google::protobuf::io::CodedOutputStream write.
43 uint64 DoOutputStreamWrite(uint64 bytes);
44
45 // Synchronous Refresh wrapper.
46 void WaitForData(int msg_size);
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,
akalin 2013/10/15 00:56:07 perhaps have DoInputStreamRead() return a std::str
Nicolas Zea 2013/10/15 20:07:38 That's what output_buffer is used for. I don't ret
akalin 2013/10/15 23:24:15 I see. What about returning a base::StringPiece?
Nicolas Zea 2013/10/16 01:20:40 Done.
104 bool set_limit,
akalin 2013/10/15 00:56:07 you don't seem to use set_limit. Remove?
Nicolas Zea 2013/10/15 20:07:38 Done.
105 const void** output_buffer) {
106 uint64 total_bytes_read = 0;
107 const void* initial_buffer = NULL;
108 const void* buffer = NULL;
109 int size = 0;
110
111 do {
112 DCHECK(socket_input_stream_->GetState() == SocketInputStream::EMPTY ||
113 socket_input_stream_->GetState() == SocketInputStream::READY);
114 if (!socket_input_stream_->Next(&buffer, &size))
115 break;
116 total_bytes_read += size;
117 if (initial_buffer) { // Verify the buffer doesn't skip data.
akalin 2013/10/15 00:56:07 two spaces before //
Nicolas Zea 2013/10/15 20:07:38 Done.
118 EXPECT_EQ(static_cast<const uint8*>(initial_buffer) + total_bytes_read,
119 static_cast<const uint8*>(buffer) + size);
120 } else {
121 initial_buffer = buffer;
122 }
123 } while (total_bytes_read < bytes);
124
125 *output_buffer = initial_buffer;
126
127 if (total_bytes_read > bytes) {
128 socket_input_stream_->BackUp(total_bytes_read - bytes);
129 total_bytes_read = bytes;
130 }
131
132 return total_bytes_read;
133 }
134
135 uint64 GCMSocketStreamTest::DoOutputStreamWrite(uint64 bytes) {
akalin 2013/10/15 00:56:07 avoid depending on kWriteData explicitly and chang
Nicolas Zea 2013/10/15 20:07:38 Done.
136 DCHECK_EQ(socket_output_stream_->GetState(), SocketOutputStream::EMPTY);
137 uint64 total_bytes_written = 0;
138 void* buffer = NULL;
139 int size = 0;
140 const void* write_src = kWriteData;
141
142 do {
143 if (!socket_output_stream_->Next(&buffer, &size))
144 break;
145 uint64 bytes_to_write = (static_cast<uint64>(size) < bytes ? size : bytes);
146 memcpy(buffer,
147 static_cast<const uint8*>(write_src) + total_bytes_written,
148 bytes_to_write);
149 if (bytes_to_write < static_cast<uint64>(size))
150 socket_output_stream_->BackUp(size - bytes_to_write);
151 total_bytes_written += bytes_to_write;
152 } while (total_bytes_written < bytes);
153
154 base::RunLoop run_loop;
155 if (socket_output_stream_->Flush(run_loop.QuitClosure()) ==
akalin 2013/10/15 23:24:15 if Next() returns false in the above loop, isn't i
156 net::ERR_IO_PENDING) {
157 run_loop.Run();
158 }
159
160 return total_bytes_written;
akalin 2013/10/15 00:56:07 Do you need to return total_bytes_written? Perhaps
Nicolas Zea 2013/10/15 20:07:38 That's not true in the cases where an error is enc
161 }
162
163 void GCMSocketStreamTest::WaitForData(int msg_size) {
164 while (input_stream()->ByteCount() < msg_size) {
165 base::RunLoop run_loop;
166 if (input_stream()->Refresh(run_loop.QuitClosure(),
167 msg_size) == net::ERR_IO_PENDING) {
akalin 2013/10/15 00:56:07 don't you mean msg_size - input_stream()->ByteCoun
Nicolas Zea 2013/10/15 20:07:38 This method is waiting for |msg_size| new bytes, n
akalin 2013/10/15 23:24:15 Right, but that's only for the first call to Refre
Nicolas Zea 2013/10/16 01:20:40 Ah, the thing is that ByteCount is actually BytesC
168 run_loop.Run();
169 }
170 if (input_stream()->GetState() == SocketInputStream::CLOSED)
171 return;
172 }
173 }
174
175 void GCMSocketStreamTest::OpenConnection() {
176 socket_ = socket_factory_.CreateTransportClientSocket(
177 address_list_, NULL, net::NetLog::Source());
178 socket_->Connect(
179 base::Bind(&GCMSocketStreamTest::ConnectCallback,
180 base::Unretained(this)));
181 PumpLoop();
182 }
183
184 void GCMSocketStreamTest::ConnectCallback(int result) {}
185
186 void GCMSocketStreamTest::ResetInputStream() {
187 DCHECK(socket_.get());
188 socket_input_stream_.reset(new SocketInputStream(socket_.get()));
189 }
190
191 void GCMSocketStreamTest::ResetOutputStream() {
192 DCHECK(socket_.get());
193 socket_output_stream_.reset(new SocketOutputStream(socket_.get()));
194 }
195
196 // A read where all data is already available.
197 TEST_F(GCMSocketStreamTest, ReadDataSync) {
198 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
199 kReadData,
200 kReadDataSize)),
201 WriteList());
202
203 const void* output = NULL;
204 WaitForData(kReadDataSize);
205 ASSERT_EQ(kReadDataSize,
206 DoInputStreamRead(kReadDataSize, false, &output));
207 ASSERT_EQ(std::string(kReadData),
208 std::string(static_cast<const char*>(output), kReadDataSize));
209 }
210
211 // A read that comes in two parts.
212 TEST_F(GCMSocketStreamTest, ReadPartialDataSync) {
213 size_t first_read_len = kReadDataSize/2;
214 size_t second_read_len = kReadDataSize - first_read_len;
215 ReadList read_list;
216 read_list.push_back(
217 net::MockRead(net::SYNCHRONOUS,
218 kReadData,
219 first_read_len));
220 read_list.push_back(
221 net::MockRead(net::SYNCHRONOUS,
222 &kReadData[first_read_len],
223 second_read_len));
224 BuildSocket(read_list, WriteList());
225
226 const void* output = NULL;
227 WaitForData(kReadDataSize);
228 ASSERT_EQ(kReadDataSize,
229 DoInputStreamRead(kReadDataSize, false, &output));
230 ASSERT_EQ(std::string(kReadData),
231 std::string(static_cast<const char*>(output), kReadDataSize));
232 }
233
234 // A read where no data is available at first (IO_PENDING will be returned).
235 TEST_F(GCMSocketStreamTest, ReadAsync) {
236 size_t first_read_len = kReadDataSize/2;
237 size_t second_read_len = kReadDataSize - first_read_len;
238 ReadList read_list;
239 read_list.push_back(
240 net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
241 read_list.push_back(
242 net::MockRead(net::ASYNC, kReadData, first_read_len));
243 read_list.push_back(
244 net::MockRead(net::ASYNC, &kReadData[first_read_len], second_read_len));
245 BuildSocket(read_list, WriteList());
246
247 const void* output = NULL;
248 base::MessageLoop::current()->PostTask(
249 FROM_HERE,
250 base::Bind(&net::DelayedSocketData::ForceNextRead,
251 base::Unretained(data_provider())));
252 WaitForData(kReadDataSize);
253 ASSERT_EQ(kReadDataSize,
254 DoInputStreamRead(kReadDataSize, false, &output));
255 ASSERT_EQ(std::string(kReadData),
256 std::string(static_cast<const char*>(output), kReadDataSize));
257 }
258
259 // Simulate two packets arriving at once. Read them in two separate calls.
260 TEST_F(GCMSocketStreamTest, TwoReadsAtOnce) {
261 std::string long_data = std::string(kReadData) + std::string(kReadData2);
262 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
263 long_data.c_str(),
264 long_data.size())),
265 WriteList());
266 const void* output = NULL;
267
268 WaitForData(kReadDataSize);
269 ASSERT_EQ(kReadDataSize,
270 DoInputStreamRead(kReadDataSize, false, &output));
271 ASSERT_EQ(std::string(kReadData, kReadDataSize),
272 std::string(static_cast<const char*>(output), kReadDataSize));
273
274 WaitForData(kReadData2Size);
275 ASSERT_EQ(kReadData2Size,
276 DoInputStreamRead(kReadData2Size, false, &output));
277 ASSERT_EQ(std::string(kReadData2, kReadDataSize),
278 std::string(static_cast<const char*>(output), kReadDataSize));
279 }
280
281 // Simulate two packets arriving at once. Read them in two calls separated
282 // by a Rebuild.
283 TEST_F(GCMSocketStreamTest, TwoReadsAtOnceWithRebuild) {
284 std::string long_data = std::string(kReadData) + std::string(kReadData2);
285 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
286 long_data.c_str(),
287 long_data.size())),
288 WriteList());
289
290 const void* output = NULL;
291 WaitForData(kReadDataSize);
292 ASSERT_EQ(kReadDataSize,
293 DoInputStreamRead(kReadDataSize, false, &output));
294 ASSERT_EQ(std::string(kReadData, kReadDataSize),
295 std::string(static_cast<const char*>(output), kReadDataSize));
296
297 input_stream()->RebuildBuffer();
298 WaitForData(kReadData2Size);
299 ASSERT_EQ(kReadData2Size,
300 DoInputStreamRead(kReadData2Size, false, &output));
301 ASSERT_EQ(std::string(kReadData2, kReadData2Size),
302 std::string(static_cast<const char*>(output), kReadData2Size));
303 }
304
305 // Simulate a read that is aborted.
306 TEST_F(GCMSocketStreamTest, ReadError) {
307 int result = net::ERR_ABORTED;
308 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, result)),
309 WriteList());
310
311 WaitForData(kReadDataSize);
312 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->GetState());
313 ASSERT_EQ(result, input_stream()->last_error());
314 }
315
316 // Simulate a read after the connection is closed.
317 TEST_F(GCMSocketStreamTest, ReadDisconnected) {
318 BuildSocket(ReadList(), WriteList());
319 socket()->Disconnect();
320 WaitForData(kReadDataSize);
321 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->GetState());
322 ASSERT_EQ(net::ERR_CONNECTION_CLOSED, input_stream()->last_error());
323 }
324
325 // Write a full message in one go.
326 TEST_F(GCMSocketStreamTest, WriteFull) {
327 BuildSocket(ReadList(),
328 WriteList(1, net::MockWrite(net::SYNCHRONOUS,
329 kWriteData,
330 kWriteDataSize)));
331 ASSERT_EQ(kWriteDataSize, DoOutputStreamWrite(kWriteDataSize));
332 }
333
334 // Write a message in two go's.
335 TEST_F(GCMSocketStreamTest, WritePartial) {
336 std::string full_data = std::string(kWriteData);
337 std::string part1 = full_data.substr(0, full_data.length()/2);
338 std::string part2 = full_data.substr(full_data.length()/2);
339 WriteList write_list;
340 write_list.push_back(net::MockWrite(net::SYNCHRONOUS,
341 part1.c_str(),
342 part1.size()));
343 write_list.push_back(net::MockWrite(net::SYNCHRONOUS,
344 part2.c_str(),
345 part2.size()));
346 BuildSocket(ReadList(), write_list);
347 ASSERT_EQ(kWriteDataSize, DoOutputStreamWrite(kWriteDataSize));
348 }
349
350 // Write a message completely asynchronously (returns IO_PENDING before
351 // finishing the write in two go's).
352 TEST_F(GCMSocketStreamTest, WriteNone) {
353 std::string full_data = std::string(kWriteData);
354 std::string part1 = full_data.substr(0, full_data.length()/2);
355 std::string part2 = full_data.substr(full_data.length()/2);
356 WriteList write_list;
357 write_list.push_back(net::MockWrite(net::ASYNC,
358 part1.c_str(),
359 part1.size()));
360 write_list.push_back(net::MockWrite(net::ASYNC,
361 part2.c_str(),
362 part2.size()));
363 BuildSocket(ReadList(), write_list);
364 ASSERT_EQ(kWriteDataSize, DoOutputStreamWrite(kWriteDataSize));
365 }
366
367 // Write a message then read a message.
368 TEST_F(GCMSocketStreamTest, WriteThenRead) {
369 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
370 kReadData,
371 kReadDataSize)),
372 WriteList(1, net::MockWrite(net::SYNCHRONOUS,
373 kWriteData,
374 kWriteDataSize)));
375
376 ASSERT_EQ(kWriteDataSize, DoOutputStreamWrite(kWriteDataSize));
377
378 const void* output = NULL;
379 WaitForData(kReadDataSize);
380 ASSERT_EQ(kReadDataSize,
381 DoInputStreamRead(kReadDataSize, false, &output));
382 ASSERT_EQ(std::string(kReadData),
383 std::string(static_cast<const char*>(output), kReadDataSize));
384 }
385
386 // Read a message then write a message.
387 TEST_F(GCMSocketStreamTest, ReadThenWrite) {
388 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
389 kReadData,
390 kReadDataSize)),
391 WriteList(1, net::MockWrite(net::SYNCHRONOUS,
392 kWriteData,
393 kWriteDataSize)));
394
395 const void* output = NULL;
396 WaitForData(kReadDataSize);
397 ASSERT_EQ(kReadDataSize,
398 DoInputStreamRead(kReadDataSize, false, &output));
399 ASSERT_EQ(std::string(kReadData),
400 std::string(static_cast<const char*>(output), kReadDataSize));
401
402 ASSERT_EQ(kWriteDataSize, DoOutputStreamWrite(kWriteDataSize));
403 }
404
405 // Simulate a write that gets aborted.
406 TEST_F(GCMSocketStreamTest, WriteError) {
407 int result = net::ERR_ABORTED;
408 BuildSocket(ReadList(),
409 WriteList(1, net::MockWrite(net::SYNCHRONOUS, result)));
410 DoOutputStreamWrite(kWriteDataSize);
411 ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->GetState());
412 ASSERT_EQ(result, output_stream()->last_error());
413 }
414
415 // Simulate a write after the connection is closed.
416 TEST_F(GCMSocketStreamTest, WriteDisconnected) {
417 BuildSocket(ReadList(), WriteList());
418 socket()->Disconnect();
419 DoOutputStreamWrite(kWriteDataSize);
420 ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->GetState());
421 ASSERT_EQ(net::ERR_CONNECTION_CLOSED, output_stream()->last_error());
422 }
423
424 } // namespace
425 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698