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 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;
29 class GCMSocketStreamTest
: public testing::Test
{
31 GCMSocketStreamTest();
32 virtual ~GCMSocketStreamTest();
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(uint64 bytes
);
42 // Simulates a google::protobuf::io::CodedOutputStream write.
43 uint64
DoOutputStreamWrite(const base::StringPiece
& write_src
);
45 // Synchronous Refresh wrapper.
46 void WaitForData(size_t msg_size
);
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(); }
55 void OpenConnection();
56 void ResetInputStream();
57 void ResetOutputStream();
59 void ConnectCallback(int result
);
61 // SocketStreams and their data providers.
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_
;
69 scoped_ptr
<net::StreamSocket
> socket_
;
70 net::MockClientSocketFactory socket_factory_
;
71 net::AddressList address_list_
;
73 base::MessageLoopForIO message_loop_
;
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);
82 GCMSocketStreamTest::~GCMSocketStreamTest() {}
84 void GCMSocketStreamTest::BuildSocket(const ReadList
& read_list
,
85 const WriteList
& write_list
) {
86 mock_reads_
= read_list
;
87 mock_writes_
= write_list
;
89 new net::DelayedSocketData(
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());
99 void GCMSocketStreamTest::PumpLoop() {
100 base::RunLoop run_loop
;
101 run_loop
.RunUntilIdle();
104 base::StringPiece
GCMSocketStreamTest::DoInputStreamRead(uint64 bytes
) {
105 uint64 total_bytes_read
= 0;
106 const void* initial_buffer
= NULL
;
107 const void* buffer
= NULL
;
111 DCHECK(socket_input_stream_
->GetState() == SocketInputStream::EMPTY
||
112 socket_input_stream_
->GetState() == SocketInputStream::READY
);
113 if (!socket_input_stream_
->Next(&buffer
, &size
))
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
);
120 initial_buffer
= buffer
;
122 } while (total_bytes_read
< bytes
);
124 if (total_bytes_read
> bytes
) {
125 socket_input_stream_
->BackUp(total_bytes_read
- bytes
);
126 total_bytes_read
= bytes
;
129 return base::StringPiece(static_cast<const char*>(initial_buffer
),
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;
139 size_t bytes
= write_src
.size();
142 if (!socket_output_stream_
->Next(&buffer
, &size
))
144 uint64 bytes_to_write
= (static_cast<uint64
>(size
) < bytes
? size
: bytes
);
146 write_src
.data() + total_bytes_written
,
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
);
153 base::RunLoop run_loop
;
154 if (socket_output_stream_
->Flush(run_loop
.QuitClosure()) ==
155 net::ERR_IO_PENDING
) {
159 return total_bytes_written
;
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
) {
170 if (input_stream()->GetState() == SocketInputStream::CLOSED
)
175 void GCMSocketStreamTest::OpenConnection() {
176 socket_
= socket_factory_
.CreateTransportClientSocket(
177 address_list_
, NULL
, net::NetLog::Source());
179 base::Bind(&GCMSocketStreamTest::ConnectCallback
,
180 base::Unretained(this)));
184 void GCMSocketStreamTest::ConnectCallback(int result
) {}
186 void GCMSocketStreamTest::ResetInputStream() {
187 DCHECK(socket_
.get());
188 socket_input_stream_
.reset(new SocketInputStream(socket_
.get()));
191 void GCMSocketStreamTest::ResetOutputStream() {
192 DCHECK(socket_
.get());
193 socket_output_stream_
.reset(new SocketOutputStream(socket_
.get()));
196 // A read where all data is already available.
197 TEST_F(GCMSocketStreamTest
, ReadDataSync
) {
198 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
203 WaitForData(kReadDataSize
);
204 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
205 DoInputStreamRead(kReadDataSize
));
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
;
214 net::MockRead(net::SYNCHRONOUS
,
218 net::MockRead(net::SYNCHRONOUS
,
219 &kReadData
[first_read_len
],
221 BuildSocket(read_list
, WriteList());
223 WaitForData(kReadDataSize
);
224 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
225 DoInputStreamRead(kReadDataSize
));
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
;
234 net::MockRead(net::SYNCHRONOUS
, net::ERR_IO_PENDING
));
236 net::MockRead(net::ASYNC
, kReadData
, first_read_len
));
238 net::MockRead(net::ASYNC
, &kReadData
[first_read_len
], second_read_len
));
239 BuildSocket(read_list
, WriteList());
241 base::MessageLoop::current()->PostTask(
243 base::Bind(&net::DelayedSocketData::ForceNextRead
,
244 base::Unretained(data_provider())));
245 WaitForData(kReadDataSize
);
246 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
247 DoInputStreamRead(kReadDataSize
));
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
,
259 WaitForData(kReadDataSize
);
260 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
261 DoInputStreamRead(kReadDataSize
));
263 WaitForData(kReadData2Size
);
264 ASSERT_EQ(std::string(kReadData2
, kReadData2Size
),
265 DoInputStreamRead(kReadData2Size
));
268 // Simulate two packets arriving at once. Read them in two calls separated
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
,
278 WaitForData(kReadDataSize
);
279 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
280 DoInputStreamRead(kReadDataSize
));
282 input_stream()->RebuildBuffer();
283 WaitForData(kReadData2Size
);
284 ASSERT_EQ(std::string(kReadData2
, kReadData2Size
),
285 DoInputStreamRead(kReadData2Size
));
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
)),
294 WaitForData(kReadDataSize
);
295 ASSERT_EQ(SocketInputStream::CLOSED
, input_stream()->GetState());
296 ASSERT_EQ(result
, input_stream()->last_error());
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());
308 // Write a full message in one go.
309 TEST_F(GCMSocketStreamTest
, WriteFull
) {
310 BuildSocket(ReadList(),
311 WriteList(1, net::MockWrite(net::SYNCHRONOUS
,
314 ASSERT_EQ(kWriteDataSize
,
315 DoOutputStreamWrite(base::StringPiece(kWriteData
,
319 // Write a message in two go's.
320 TEST_F(GCMSocketStreamTest
, WritePartial
) {
321 WriteList write_list
;
322 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
324 kWriteDataSize
/ 2));
325 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
326 kWriteData
+ kWriteDataSize
/ 2,
327 kWriteDataSize
/ 2));
328 BuildSocket(ReadList(), write_list
);
329 ASSERT_EQ(kWriteDataSize
,
330 DoOutputStreamWrite(base::StringPiece(kWriteData
,
334 // Write a message completely asynchronously (returns IO_PENDING before
335 // finishing the write in two go's).
336 TEST_F(GCMSocketStreamTest
, WriteNone
) {
337 WriteList write_list
;
338 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
340 kWriteDataSize
/ 2));
341 write_list
.push_back(net::MockWrite(net::SYNCHRONOUS
,
342 kWriteData
+ kWriteDataSize
/ 2,
343 kWriteDataSize
/ 2));
344 BuildSocket(ReadList(), write_list
);
345 ASSERT_EQ(kWriteDataSize
,
346 DoOutputStreamWrite(base::StringPiece(kWriteData
,
350 // Write a message then read a message.
351 TEST_F(GCMSocketStreamTest
, WriteThenRead
) {
352 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
355 WriteList(1, net::MockWrite(net::SYNCHRONOUS
,
359 ASSERT_EQ(kWriteDataSize
,
360 DoOutputStreamWrite(base::StringPiece(kWriteData
,
363 WaitForData(kReadDataSize
);
364 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
365 DoInputStreamRead(kReadDataSize
));
368 // Read a message then write a message.
369 TEST_F(GCMSocketStreamTest
, ReadThenWrite
) {
370 BuildSocket(ReadList(1, net::MockRead(net::SYNCHRONOUS
,
373 WriteList(1, net::MockWrite(net::SYNCHRONOUS
,
377 WaitForData(kReadDataSize
);
378 ASSERT_EQ(std::string(kReadData
, kReadDataSize
),
379 DoInputStreamRead(kReadDataSize
));
381 ASSERT_EQ(kWriteDataSize
,
382 DoOutputStreamWrite(base::StringPiece(kWriteData
,
386 // Simulate a write that gets aborted.
387 TEST_F(GCMSocketStreamTest
, WriteError
) {
388 int result
= net::ERR_ABORTED
;
389 BuildSocket(ReadList(),
390 WriteList(1, net::MockWrite(net::SYNCHRONOUS
, result
)));
391 DoOutputStreamWrite(base::StringPiece(kWriteData
, kWriteDataSize
));
392 ASSERT_EQ(SocketOutputStream::CLOSED
, output_stream()->GetState());
393 ASSERT_EQ(result
, output_stream()->last_error());
396 // Simulate a write after the connection is closed.
397 TEST_F(GCMSocketStreamTest
, WriteDisconnected
) {
398 BuildSocket(ReadList(), WriteList());
399 socket()->Disconnect();
400 DoOutputStreamWrite(base::StringPiece(kWriteData
, kWriteDataSize
));
401 ASSERT_EQ(SocketOutputStream::CLOSED
, output_stream()->GetState());
402 ASSERT_EQ(net::ERR_CONNECTION_CLOSED
, output_stream()->last_error());