1 // Copyright 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.
5 #include "google_apis/gcm/base/socket_stream.h"
7 #include "base/basictypes.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"
19 typedef std::vector
<net::MockRead
> ReadList
;
20 typedef std::vector
<net::MockWrite
> WriteList
;
22 const char kReadData
[] = "read_data";
23 const int kReadDataSize
= arraysize(kReadData
) - 1;
24 const char kReadData2
[] = "read_alternate_data";
25 const int kReadData2Size
= arraysize(kReadData2
) - 1;
26 const char kWriteData
[] = "write_data";
27 const int kWriteDataSize
= arraysize(kWriteData
) - 1;
29 class GCMSocketStreamTest
: public testing::Test
{
31 GCMSocketStreamTest();
32 ~GCMSocketStreamTest() override
;
34 // Build a socket with the expected reads and writes.
35 void BuildSocket(const ReadList
& read_list
, const WriteList
& write_list
);
37 // Pump the message loop until idle.
40 // Simulates a google::protobuf::io::CodedInputStream read.
41 base::StringPiece
DoInputStreamRead(int bytes
);
42 // Simulates a google::protobuf::io::CodedOutputStream write.
43 int DoOutputStreamWrite(const base::StringPiece
& write_src
);
45 // Synchronous Refresh wrapper.
46 void WaitForData(int msg_size
);
48 base::MessageLoop
* message_loop() { return &message_loop_
; };
49 net::StaticSocketDataProvider
* data_provider() {
50 return data_provider_
.get();
52 SocketInputStream
* input_stream() { return socket_input_stream_
.get(); }
53 SocketOutputStream
* output_stream() { return socket_output_stream_
.get(); }
54 net::StreamSocket
* socket() { return socket_
.get(); }
57 void OpenConnection();
58 void ResetInputStream();
59 void ResetOutputStream();
61 void ConnectCallback(int result
);
63 // SocketStreams and their data providers.
65 WriteList mock_writes_
;
66 scoped_ptr
<net::StaticSocketDataProvider
> data_provider_
;
67 scoped_ptr
<SocketInputStream
> socket_input_stream_
;
68 scoped_ptr
<SocketOutputStream
> socket_output_stream_
;
71 scoped_ptr
<net::StreamSocket
> socket_
;
72 net::MockClientSocketFactory socket_factory_
;
73 net::AddressList address_list_
;
75 base::MessageLoopForIO message_loop_
;
78 GCMSocketStreamTest::GCMSocketStreamTest() {
79 net::IPAddressNumber ip_number
;
80 net::ParseIPLiteralToNumber("127.0.0.1", &ip_number
);
81 address_list_
= net::AddressList::CreateFromIPAddress(ip_number
, 5228);
84 GCMSocketStreamTest::~GCMSocketStreamTest() {}
86 void GCMSocketStreamTest::BuildSocket(const ReadList
& read_list
,
87 const WriteList
& write_list
) {
88 mock_reads_
= read_list
;
89 mock_writes_
= write_list
;
91 new net::StaticSocketDataProvider(
92 vector_as_array(&mock_reads_
), mock_reads_
.size(),
93 vector_as_array(&mock_writes_
), mock_writes_
.size()));
94 socket_factory_
.AddSocketDataProvider(data_provider_
.get());
100 void GCMSocketStreamTest::PumpLoop() {
101 base::RunLoop run_loop
;
102 run_loop
.RunUntilIdle();
105 base::StringPiece
GCMSocketStreamTest::DoInputStreamRead(int bytes
) {
106 int total_bytes_read
= 0;
107 const void* initial_buffer
= NULL
;
108 const void* buffer
= NULL
;
112 DCHECK(socket_input_stream_
->GetState() == SocketInputStream::EMPTY
||
113 socket_input_stream_
->GetState() == SocketInputStream::READY
);
114 if (!socket_input_stream_
->Next(&buffer
, &size
))
116 total_bytes_read
+= size
;
117 if (initial_buffer
) { // Verify the buffer doesn't skip data.
118 EXPECT_EQ(static_cast<const uint8
*>(initial_buffer
) + total_bytes_read
,
119 static_cast<const uint8
*>(buffer
) + size
);
121 initial_buffer
= buffer
;
123 } while (total_bytes_read
< bytes
);
125 if (total_bytes_read
> bytes
) {
126 socket_input_stream_
->BackUp(total_bytes_read
- bytes
);
127 total_bytes_read
= bytes
;
130 return base::StringPiece(static_cast<const char*>(initial_buffer
),
134 int GCMSocketStreamTest::DoOutputStreamWrite(
135 const base::StringPiece
& write_src
) {
136 DCHECK_EQ(socket_output_stream_
->GetState(), SocketOutputStream::EMPTY
);
137 int total_bytes_written
= 0;
140 int bytes
= write_src
.size();
143 if (!socket_output_stream_
->Next(&buffer
, &size
))
145 int bytes_to_write
= (size
< bytes
? size
: bytes
);
147 write_src
.data() + total_bytes_written
,
149 if (bytes_to_write
< size
)
150 socket_output_stream_
->BackUp(size
- bytes_to_write
);
151 total_bytes_written
+= bytes_to_write
;
152 } while (total_bytes_written
< bytes
);
154 base::RunLoop run_loop
;
155 if (socket_output_stream_
->Flush(run_loop
.QuitClosure()) ==
156 net::ERR_IO_PENDING
) {
160 return total_bytes_written
;
163 void GCMSocketStreamTest::WaitForData(int msg_size
) {
164 while (input_stream()->UnreadByteCount() < msg_size
) {
165 base::RunLoop run_loop
;
166 if (input_stream()->Refresh(run_loop
.QuitClosure(),
167 msg_size
- input_stream()->UnreadByteCount()) ==
168 net::ERR_IO_PENDING
) {
171 if (input_stream()->GetState() == SocketInputStream::CLOSED
)
176 void GCMSocketStreamTest::OpenConnection() {
177 socket_
= socket_factory_
.CreateTransportClientSocket(
178 address_list_
, NULL
, net::NetLog::Source());
180 base::Bind(&GCMSocketStreamTest::ConnectCallback
,
181 base::Unretained(this)));
185 void GCMSocketStreamTest::ConnectCallback(int result
) {}
187 void GCMSocketStreamTest::ResetInputStream() {
188 DCHECK(socket_
.get());
189 socket_input_stream_
.reset(new SocketInputStream(socket_
.get()));
192 void GCMSocketStreamTest::ResetOutputStream() {
193 DCHECK(socket_
.get());
194 socket_output_stream_
.reset(new SocketOutputStream(socket_
.get()));
197 // A read where all data is already available.
198 TEST_F(GCMSocketStreamTest
, ReadDataSync
) {
199 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
204 WaitForData(kReadDataSize
);
205 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
206 DoInputStreamRead(kReadDataSize
));
209 // A read that comes in two parts.
210 TEST_F(GCMSocketStreamTest
, ReadPartialDataSync
) {
211 int first_read_len
= kReadDataSize
/ 2;
212 int second_read_len
= kReadDataSize
- first_read_len
;
215 net::MockRead(net::SYNCHRONOUS
,
219 net::MockRead(net::SYNCHRONOUS
,
220 &kReadData
[first_read_len
],
222 BuildSocket(read_list
, WriteList());
224 WaitForData(kReadDataSize
);
225 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
226 DoInputStreamRead(kReadDataSize
));
229 // A read where no data is available at first (IO_PENDING will be returned).
230 TEST_F(GCMSocketStreamTest
, ReadAsync
) {
231 int first_read_len
= kReadDataSize
/ 2;
232 int second_read_len
= kReadDataSize
- first_read_len
;
235 net::MockRead(net::ASYNC
, kReadData
, first_read_len
));
237 net::MockRead(net::ASYNC
, &kReadData
[first_read_len
], second_read_len
));
238 BuildSocket(read_list
, WriteList());
239 WaitForData(kReadDataSize
);
240 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
241 DoInputStreamRead(kReadDataSize
));
244 // Simulate two packets arriving at once. Read them in two separate calls.
245 TEST_F(GCMSocketStreamTest
, TwoReadsAtOnce
) {
246 std::string long_data
= std::string(kReadData
, kReadDataSize
) +
247 std::string(kReadData2
, kReadData2Size
);
248 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
253 WaitForData(kReadDataSize
);
254 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
255 DoInputStreamRead(kReadDataSize
));
257 WaitForData(kReadData2Size
);
258 ASSERT_EQ(std::string(kReadData2
, kReadData2Size
),
259 DoInputStreamRead(kReadData2Size
));
262 // Simulate two packets arriving at once. Read them in two calls separated
264 TEST_F(GCMSocketStreamTest
, TwoReadsAtOnceWithRebuild
) {
265 std::string long_data
= std::string(kReadData
, kReadDataSize
) +
266 std::string(kReadData2
, kReadData2Size
);
267 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
272 WaitForData(kReadDataSize
);
273 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
274 DoInputStreamRead(kReadDataSize
));
276 input_stream()->RebuildBuffer();
277 WaitForData(kReadData2Size
);
278 ASSERT_EQ(std::string(kReadData2
, kReadData2Size
),
279 DoInputStreamRead(kReadData2Size
));
282 // Simulate a read that is aborted.
283 TEST_F(GCMSocketStreamTest
, ReadError
) {
284 int result
= net::ERR_ABORTED
;
285 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
, result
)),
288 WaitForData(kReadDataSize
);
289 ASSERT_EQ(SocketInputStream::CLOSED
, input_stream()->GetState());
290 ASSERT_EQ(result
, input_stream()->last_error());
293 // Simulate a read after the connection is closed.
294 TEST_F(GCMSocketStreamTest
, ReadDisconnected
) {
295 BuildSocket(ReadList(), WriteList());
296 socket()->Disconnect();
297 WaitForData(kReadDataSize
);
298 ASSERT_EQ(SocketInputStream::CLOSED
, input_stream()->GetState());
299 ASSERT_EQ(net::ERR_CONNECTION_CLOSED
, input_stream()->last_error());
302 // Write a full message in one go.
303 TEST_F(GCMSocketStreamTest
, WriteFull
) {
304 BuildSocket(ReadList(),
305 WriteList(1, net::MockWrite(net::SYNCHRONOUS
,
308 ASSERT_EQ(kWriteDataSize
,
309 DoOutputStreamWrite(base::StringPiece(kWriteData
,
313 // Write a message in two go's.
314 TEST_F(GCMSocketStreamTest
, WritePartial
) {
315 WriteList write_list
;
316 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
318 kWriteDataSize
/ 2));
319 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
320 kWriteData
+ kWriteDataSize
/ 2,
321 kWriteDataSize
/ 2));
322 BuildSocket(ReadList(), write_list
);
323 ASSERT_EQ(kWriteDataSize
,
324 DoOutputStreamWrite(base::StringPiece(kWriteData
,
328 // Write a message completely asynchronously (returns IO_PENDING before
329 // finishing the write in two go's).
330 TEST_F(GCMSocketStreamTest
, WriteNone
) {
331 WriteList write_list
;
332 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
334 kWriteDataSize
/ 2));
335 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
336 kWriteData
+ kWriteDataSize
/ 2,
337 kWriteDataSize
/ 2));
338 BuildSocket(ReadList(), write_list
);
339 ASSERT_EQ(kWriteDataSize
,
340 DoOutputStreamWrite(base::StringPiece(kWriteData
,
344 // Write a message then read a message.
345 TEST_F(GCMSocketStreamTest
, WriteThenRead
) {
346 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
349 WriteList(1, net::MockWrite(net::SYNCHRONOUS
,
353 ASSERT_EQ(kWriteDataSize
,
354 DoOutputStreamWrite(base::StringPiece(kWriteData
,
357 WaitForData(kReadDataSize
);
358 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
359 DoInputStreamRead(kReadDataSize
));
362 // Read a message then write a message.
363 TEST_F(GCMSocketStreamTest
, ReadThenWrite
) {
364 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
367 WriteList(1, net::MockWrite(net::SYNCHRONOUS
,
371 WaitForData(kReadDataSize
);
372 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
373 DoInputStreamRead(kReadDataSize
));
375 ASSERT_EQ(kWriteDataSize
,
376 DoOutputStreamWrite(base::StringPiece(kWriteData
,
380 // Simulate a write that gets aborted.
381 TEST_F(GCMSocketStreamTest
, WriteError
) {
382 int result
= net::ERR_ABORTED
;
383 BuildSocket(ReadList(),
384 WriteList(1, net::MockWrite(net::SYNCHRONOUS
, result
)));
385 DoOutputStreamWrite(base::StringPiece(kWriteData
, kWriteDataSize
));
386 ASSERT_EQ(SocketOutputStream::CLOSED
, output_stream()->GetState());
387 ASSERT_EQ(result
, output_stream()->last_error());
390 // Simulate a write after the connection is closed.
391 TEST_F(GCMSocketStreamTest
, WriteDisconnected
) {
392 BuildSocket(ReadList(), WriteList());
393 socket()->Disconnect();
394 DoOutputStreamWrite(base::StringPiece(kWriteData
, kWriteDataSize
));
395 ASSERT_EQ(SocketOutputStream::CLOSED
, output_stream()->GetState());
396 ASSERT_EQ(net::ERR_CONNECTION_CLOSED
, output_stream()->last_error());