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

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

Powered by Google App Engine
This is Rietveld 408576698