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

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: 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 "base/stl_util.h"
12 #include "base/strings/string_piece.h"
13 #include "net/socket/socket_test_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace gcm {
17 namespace {
18
19 typedef std::vector<net::MockRead> ReadList;
20 typedef std::vector<net::MockWrite> WriteList;
21
22 const char kReadData[] = "read_data";
23 const uint64 kReadDataSize = arraysize(kReadData) - 1;
24 const char kReadData2[] = "read_alternate_data";
25 const uint64 kReadData2Size = arraysize(kReadData2) - 1;
26 const char kWriteData[] = "write_data";
27 const uint64 kWriteDataSize = arraysize(kWriteData) - 1;
28
29 class GCMSocketStreamTest : public testing::Test {
30 public:
31 GCMSocketStreamTest();
32 virtual ~GCMSocketStreamTest();
33
34 // Build a socket with the expected reads and writes.
35 void BuildSocket(const ReadList& read_list, const WriteList& write_list);
36
37 // Pump the message loop until idle.
38 void PumpLoop();
39
40 // Simulates a google::protobuf::io::CodedInputStream read.
41 base::StringPiece DoInputStreamRead(uint64 bytes);
42 // Simulates a google::protobuf::io::CodedOutputStream write.
43 uint64 DoOutputStreamWrite(const base::StringPiece& write_src);
44
45 // Synchronous Refresh wrapper.
46 void WaitForData(size_t 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(
90 0,
91 vector_as_array(&mock_reads_), mock_reads_.size(),
92 vector_as_array(&mock_writes_), mock_writes_.size()));
93 socket_factory_.AddSocketDataProvider(data_provider_.get());
94 OpenConnection();
95 ResetInputStream();
96 ResetOutputStream();
97 }
98
99 void GCMSocketStreamTest::PumpLoop() {
100 base::RunLoop run_loop;
101 run_loop.RunUntilIdle();
102 }
103
104 base::StringPiece GCMSocketStreamTest::DoInputStreamRead(uint64 bytes) {
105 uint64 total_bytes_read = 0;
106 const void* initial_buffer = NULL;
107 const void* buffer = NULL;
108 int size = 0;
109
110 do {
111 DCHECK(socket_input_stream_->GetState() == SocketInputStream::EMPTY ||
112 socket_input_stream_->GetState() == SocketInputStream::READY);
113 if (!socket_input_stream_->Next(&buffer, &size))
114 break;
115 total_bytes_read += size;
116 if (initial_buffer) { // Verify the buffer doesn't skip data.
117 EXPECT_EQ(static_cast<const uint8*>(initial_buffer) + total_bytes_read,
118 static_cast<const uint8*>(buffer) + size);
119 } else {
120 initial_buffer = buffer;
121 }
122 } while (total_bytes_read < bytes);
123
124 if (total_bytes_read > bytes) {
125 socket_input_stream_->BackUp(total_bytes_read - bytes);
126 total_bytes_read = bytes;
127 }
128
129 return base::StringPiece(static_cast<const char*>(initial_buffer),
130 total_bytes_read);
131 }
132
133 uint64 GCMSocketStreamTest::DoOutputStreamWrite(
134 const base::StringPiece& write_src) {
135 DCHECK_EQ(socket_output_stream_->GetState(), SocketOutputStream::EMPTY);
136 uint64 total_bytes_written = 0;
137 void* buffer = NULL;
138 int size = 0;
139 size_t bytes = write_src.size();
140
141 do {
142 if (!socket_output_stream_->Next(&buffer, &size))
143 break;
144 uint64 bytes_to_write = (static_cast<uint64>(size) < bytes ? size : bytes);
145 memcpy(buffer,
146 write_src.data() + total_bytes_written,
147 bytes_to_write);
148 if (bytes_to_write < static_cast<uint64>(size))
149 socket_output_stream_->BackUp(size - bytes_to_write);
150 total_bytes_written += bytes_to_write;
151 } while (total_bytes_written < bytes);
152
153 base::RunLoop run_loop;
154 if (socket_output_stream_->Flush(run_loop.QuitClosure()) ==
155 net::ERR_IO_PENDING) {
156 run_loop.Run();
157 }
158
159 return total_bytes_written;
160 }
161
162 void GCMSocketStreamTest::WaitForData(size_t msg_size) {
163 while (input_stream()->UnreadByteCount() < msg_size) {
164 base::RunLoop run_loop;
165 if (input_stream()->Refresh(run_loop.QuitClosure(),
166 msg_size - input_stream()->UnreadByteCount()) ==
167 net::ERR_IO_PENDING) {
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 WaitForData(kReadDataSize);
204 ASSERT_EQ(std::string(kReadData, kReadDataSize),
205 DoInputStreamRead(kReadDataSize));
206 }
207
208 // A read that comes in two parts.
209 TEST_F(GCMSocketStreamTest, ReadPartialDataSync) {
210 size_t first_read_len = kReadDataSize / 2;
211 size_t second_read_len = kReadDataSize - first_read_len;
212 ReadList read_list;
213 read_list.push_back(
214 net::MockRead(net::SYNCHRONOUS,
215 kReadData,
216 first_read_len));
217 read_list.push_back(
218 net::MockRead(net::SYNCHRONOUS,
219 &kReadData[first_read_len],
220 second_read_len));
221 BuildSocket(read_list, WriteList());
222
223 WaitForData(kReadDataSize);
224 ASSERT_EQ(std::string(kReadData, kReadDataSize),
225 DoInputStreamRead(kReadDataSize));
226 }
227
228 // A read where no data is available at first (IO_PENDING will be returned).
229 TEST_F(GCMSocketStreamTest, ReadAsync) {
230 size_t first_read_len = kReadDataSize / 2;
231 size_t second_read_len = kReadDataSize - first_read_len;
232 ReadList read_list;
233 read_list.push_back(
234 net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING));
235 read_list.push_back(
236 net::MockRead(net::ASYNC, kReadData, first_read_len));
237 read_list.push_back(
238 net::MockRead(net::ASYNC, &kReadData[first_read_len], second_read_len));
239 BuildSocket(read_list, WriteList());
240
241 base::MessageLoop::current()->PostTask(
242 FROM_HERE,
243 base::Bind(&net::DelayedSocketData::ForceNextRead,
244 base::Unretained(data_provider())));
245 WaitForData(kReadDataSize);
246 ASSERT_EQ(std::string(kReadData, kReadDataSize),
247 DoInputStreamRead(kReadDataSize));
248 }
249
250 // Simulate two packets arriving at once. Read them in two separate calls.
251 TEST_F(GCMSocketStreamTest, TwoReadsAtOnce) {
252 std::string long_data = std::string(kReadData, kReadDataSize) +
253 std::string(kReadData2, kReadData2Size);
254 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
255 long_data.c_str(),
256 long_data.size())),
257 WriteList());
258
259 WaitForData(kReadDataSize);
260 ASSERT_EQ(std::string(kReadData, kReadDataSize),
261 DoInputStreamRead(kReadDataSize));
262
263 WaitForData(kReadData2Size);
264 ASSERT_EQ(std::string(kReadData2, kReadData2Size),
265 DoInputStreamRead(kReadData2Size));
266 }
267
268 // Simulate two packets arriving at once. Read them in two calls separated
269 // by a Rebuild.
270 TEST_F(GCMSocketStreamTest, TwoReadsAtOnceWithRebuild) {
271 std::string long_data = std::string(kReadData, kReadDataSize) +
272 std::string(kReadData2, kReadData2Size);
273 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
274 long_data.c_str(),
275 long_data.size())),
276 WriteList());
277
278 WaitForData(kReadDataSize);
279 ASSERT_EQ(std::string(kReadData, kReadDataSize),
280 DoInputStreamRead(kReadDataSize));
281
282 input_stream()->RebuildBuffer();
283 WaitForData(kReadData2Size);
284 ASSERT_EQ(std::string(kReadData2, kReadData2Size),
285 DoInputStreamRead(kReadData2Size));
286 }
287
288 // Simulate a read that is aborted.
289 TEST_F(GCMSocketStreamTest, ReadError) {
290 int result = net::ERR_ABORTED;
291 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS, result)),
292 WriteList());
293
294 WaitForData(kReadDataSize);
295 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->GetState());
296 ASSERT_EQ(result, input_stream()->last_error());
297 }
298
299 // Simulate a read after the connection is closed.
300 TEST_F(GCMSocketStreamTest, ReadDisconnected) {
301 BuildSocket(ReadList(), WriteList());
302 socket()->Disconnect();
303 WaitForData(kReadDataSize);
304 ASSERT_EQ(SocketInputStream::CLOSED, input_stream()->GetState());
305 ASSERT_EQ(net::ERR_CONNECTION_CLOSED, input_stream()->last_error());
306 }
307
308 // Write a full message in one go.
309 TEST_F(GCMSocketStreamTest, WriteFull) {
310 BuildSocket(ReadList(),
311 WriteList(1, net::MockWrite(net::SYNCHRONOUS,
312 kWriteData,
313 kWriteDataSize)));
314 ASSERT_EQ(kWriteDataSize,
315 DoOutputStreamWrite(base::StringPiece(kWriteData,
316 kWriteDataSize)));
317 }
318
319 // Write a message in two go's.
320 TEST_F(GCMSocketStreamTest, WritePartial) {
321 std::string part1 = std::string(kWriteData, 0, kWriteDataSize / 2);
322 std::string part2 =
323 std::string(kWriteData, kWriteDataSize / 2, kWriteDataSize / 2);
324 WriteList write_list;
325 write_list.push_back(net::MockWrite(net::SYNCHRONOUS,
326 part1.c_str(),
327 part1.size()));
328 write_list.push_back(net::MockWrite(net::SYNCHRONOUS,
329 part2.c_str(),
330 part2.size()));
331 BuildSocket(ReadList(), write_list);
332 ASSERT_EQ(kWriteDataSize,
333 DoOutputStreamWrite(base::StringPiece(kWriteData,
334 kWriteDataSize)));
335 }
336
337 // Write a message completely asynchronously (returns IO_PENDING before
338 // finishing the write in two go's).
339 TEST_F(GCMSocketStreamTest, WriteNone) {
340 std::string part1 = std::string(kWriteData, 0, kWriteDataSize / 2);
341 std::string part2 =
342 std::string(kWriteData, kWriteDataSize / 2, kWriteDataSize / 2);
343 WriteList write_list;
344 write_list.push_back(net::MockWrite(net::ASYNC,
345 part1.c_str(),
346 part1.size()));
347 write_list.push_back(net::MockWrite(net::ASYNC,
348 part2.c_str(),
349 part2.size()));
350 BuildSocket(ReadList(), write_list);
351 ASSERT_EQ(kWriteDataSize,
352 DoOutputStreamWrite(base::StringPiece(kWriteData,
353 kWriteDataSize)));
354 }
355
356 // Write a message then read a message.
357 TEST_F(GCMSocketStreamTest, WriteThenRead) {
358 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
359 kReadData,
360 kReadDataSize)),
361 WriteList(1, net::MockWrite(net::SYNCHRONOUS,
362 kWriteData,
363 kWriteDataSize)));
364
365 ASSERT_EQ(kWriteDataSize,
366 DoOutputStreamWrite(base::StringPiece(kWriteData,
367 kWriteDataSize)));
368
369 WaitForData(kReadDataSize);
370 ASSERT_EQ(std::string(kReadData, kReadDataSize),
371 DoInputStreamRead(kReadDataSize));
372 }
373
374 // Read a message then write a message.
375 TEST_F(GCMSocketStreamTest, ReadThenWrite) {
376 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS,
377 kReadData,
378 kReadDataSize)),
379 WriteList(1, net::MockWrite(net::SYNCHRONOUS,
380 kWriteData,
381 kWriteDataSize)));
382
383 WaitForData(kReadDataSize);
384 ASSERT_EQ(std::string(kReadData, kReadDataSize),
385 DoInputStreamRead(kReadDataSize));
386
387 ASSERT_EQ(kWriteDataSize,
388 DoOutputStreamWrite(base::StringPiece(kWriteData,
389 kWriteDataSize)));
390 }
391
392 // Simulate a write that gets aborted.
393 TEST_F(GCMSocketStreamTest, WriteError) {
394 int result = net::ERR_ABORTED;
395 BuildSocket(ReadList(),
396 WriteList(1, net::MockWrite(net::SYNCHRONOUS, result)));
397 DoOutputStreamWrite(base::StringPiece(kWriteData, kWriteDataSize));
398 ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->GetState());
399 ASSERT_EQ(result, output_stream()->last_error());
400 }
401
402 // Simulate a write after the connection is closed.
403 TEST_F(GCMSocketStreamTest, WriteDisconnected) {
404 BuildSocket(ReadList(), WriteList());
405 socket()->Disconnect();
406 DoOutputStreamWrite(base::StringPiece(kWriteData, kWriteDataSize));
407 ASSERT_EQ(SocketOutputStream::CLOSED, output_stream()->GetState());
408 ASSERT_EQ(net::ERR_CONNECTION_CLOSED, output_stream()->last_error());
409 }
410
411 } // namespace
412 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698