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

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

Powered by Google App Engine
This is Rietveld 408576698