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/engine/connection_handler_impl.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/test/test_timeouts.h"
12 #include "google/protobuf/io/coded_stream.h"
13 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
14 #include "google_apis/gcm/base/mcs_util.h"
15 #include "google_apis/gcm/base/socket_stream.h"
16 #include "google_apis/gcm/protocol/mcs.pb.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/socket/stream_socket.h"
19 #include "testing/gtest/include/gtest/gtest.h"
24 typedef scoped_ptr
<google::protobuf::MessageLite
> ScopedMessage
;
25 typedef std::vector
<net::MockRead
> ReadList
;
26 typedef std::vector
<net::MockWrite
> WriteList
;
28 const uint64 kAuthId
= 54321;
29 const uint64 kAuthToken
= 12345;
30 const char kMCSVersion
= 41; // The protocol version.
31 const int kMCSPort
= 5228; // The server port.
32 const char kDataMsgFrom
[] = "data_from";
33 const char kDataMsgCategory
[] = "data_category";
34 const char kDataMsgFrom2
[] = "data_from2";
35 const char kDataMsgCategory2
[] = "data_category2";
36 const char kDataMsgFromLong
[] =
37 "this is a long from that will result in a message > 128 bytes";
38 const char kDataMsgCategoryLong
[] =
39 "this is a long category that will result in a message > 128 bytes";
40 const char kDataMsgFromLong2
[] =
41 "this is a second long from that will result in a message > 128 bytes";
42 const char kDataMsgCategoryLong2
[] =
43 "this is a second long category that will result in a message > 128 bytes";
44 const uint8 kInvalidTag
= 100; // An invalid tag.
46 // ---- Helpers for building messages. ----
48 // Encode a protobuf packet with protobuf type |tag| and serialized protobuf
49 // bytes |proto| into the MCS message form (tag + varint size + bytes).
50 std::string
EncodePacket(uint8 tag
, const std::string
& proto
) {
52 google::protobuf::io::StringOutputStream
string_output_stream(&result
);
54 google::protobuf::io::CodedOutputStream
coded_output_stream(
55 &string_output_stream
);
56 const unsigned char tag_byte
[1] = { tag
};
57 coded_output_stream
.WriteRaw(tag_byte
, 1);
58 coded_output_stream
.WriteVarint32(proto
.size());
59 coded_output_stream
.WriteRaw(proto
.c_str(), proto
.size());
60 // ~CodedOutputStream must run before the move constructor at the
61 // return statement. http://crbug.com/338962
66 // Encode a handshake request into the MCS message form.
67 std::string
EncodeHandshakeRequest() {
69 const char version_byte
[1] = {kMCSVersion
};
70 result
.append(version_byte
, 1);
71 ScopedMessage
login_request(
72 BuildLoginRequest(kAuthId
, kAuthToken
, ""));
73 result
.append(EncodePacket(kLoginRequestTag
,
74 login_request
->SerializeAsString()));
78 // Build a serialized login response protobuf.
79 std::string
BuildLoginResponse() {
81 mcs_proto::LoginResponse login_response
;
82 login_response
.set_id("id");
83 result
.append(login_response
.SerializeAsString());
87 // Encoode a handshake response into the MCS message form.
88 std::string
EncodeHandshakeResponse() {
90 const char version_byte
[1] = {kMCSVersion
};
91 result
.append(version_byte
, 1);
92 result
.append(EncodePacket(kLoginResponseTag
, BuildLoginResponse()));
96 // Build a serialized data message stanza protobuf.
97 std::string
BuildDataMessage(const std::string
& from
,
98 const std::string
& category
) {
100 mcs_proto::DataMessageStanza data_message
;
101 data_message
.set_from(from
);
102 data_message
.set_category(category
);
103 return data_message
.SerializeAsString();
106 class GCMConnectionHandlerImplTest
: public testing::Test
{
108 GCMConnectionHandlerImplTest();
109 ~GCMConnectionHandlerImplTest() override
;
111 net::StreamSocket
* BuildSocket(const ReadList
& read_list
,
112 const WriteList
& write_list
);
114 // Pump |message_loop_|, resetting |run_loop_| after completion.
117 ConnectionHandlerImpl
* connection_handler() {
118 return connection_handler_
.get();
120 base::MessageLoop
* message_loop() { return &message_loop_
; };
121 net::DelayedSocketData
* data_provider() { return data_provider_
.get(); }
122 int last_error() const { return last_error_
; }
124 // Initialize the connection handler, setting |dst_proto| as the destination
125 // for any received messages.
126 void Connect(ScopedMessage
* dst_proto
);
128 // Runs the message loop until a message is received.
129 void WaitForMessage();
132 void ReadContinuation(ScopedMessage
* dst_proto
, ScopedMessage new_proto
);
133 void WriteContinuation();
134 void ConnectionContinuation(int error
);
136 // SocketStreams and their data provider.
137 ReadList mock_reads_
;
138 WriteList mock_writes_
;
139 scoped_ptr
<net::DelayedSocketData
> data_provider_
;
141 // The connection handler being tested.
142 scoped_ptr
<ConnectionHandlerImpl
> connection_handler_
;
144 // The last connection error received.
148 scoped_ptr
<net::StreamSocket
> socket_
;
149 net::MockClientSocketFactory socket_factory_
;
150 net::AddressList address_list_
;
152 base::MessageLoopForIO message_loop_
;
153 scoped_ptr
<base::RunLoop
> run_loop_
;
156 GCMConnectionHandlerImplTest::GCMConnectionHandlerImplTest()
158 net::IPAddressNumber ip_number
;
159 net::ParseIPLiteralToNumber("127.0.0.1", &ip_number
);
160 address_list_
= net::AddressList::CreateFromIPAddress(ip_number
, kMCSPort
);
163 GCMConnectionHandlerImplTest::~GCMConnectionHandlerImplTest() {
166 net::StreamSocket
* GCMConnectionHandlerImplTest::BuildSocket(
167 const ReadList
& read_list
,
168 const WriteList
& write_list
) {
169 mock_reads_
= read_list
;
170 mock_writes_
= write_list
;
171 data_provider_
.reset(
172 new net::DelayedSocketData(0,
173 &(mock_reads_
[0]), mock_reads_
.size(),
174 &(mock_writes_
[0]), mock_writes_
.size()));
175 socket_factory_
.AddSocketDataProvider(data_provider_
.get());
177 socket_
= socket_factory_
.CreateTransportClientSocket(
178 address_list_
, NULL
, net::NetLog::Source());
179 socket_
->Connect(net::CompletionCallback());
181 run_loop_
.reset(new base::RunLoop());
184 DCHECK(socket_
->IsConnected());
185 return socket_
.get();
188 void GCMConnectionHandlerImplTest::PumpLoop() {
189 run_loop_
->RunUntilIdle();
190 run_loop_
.reset(new base::RunLoop());
193 void GCMConnectionHandlerImplTest::Connect(
194 ScopedMessage
* dst_proto
) {
195 connection_handler_
.reset(new ConnectionHandlerImpl(
196 TestTimeouts::tiny_timeout(),
197 base::Bind(&GCMConnectionHandlerImplTest::ReadContinuation
,
198 base::Unretained(this),
200 base::Bind(&GCMConnectionHandlerImplTest::WriteContinuation
,
201 base::Unretained(this)),
202 base::Bind(&GCMConnectionHandlerImplTest::ConnectionContinuation
,
203 base::Unretained(this))));
204 EXPECT_FALSE(connection_handler()->CanSendMessage());
205 connection_handler_
->Init(
206 *BuildLoginRequest(kAuthId
, kAuthToken
, ""),
210 void GCMConnectionHandlerImplTest::ReadContinuation(
211 ScopedMessage
* dst_proto
,
212 ScopedMessage new_proto
) {
213 *dst_proto
= new_proto
.Pass();
217 void GCMConnectionHandlerImplTest::WaitForMessage() {
219 run_loop_
.reset(new base::RunLoop());
222 void GCMConnectionHandlerImplTest::WriteContinuation() {
226 void GCMConnectionHandlerImplTest::ConnectionContinuation(int error
) {
231 // Initialize the connection handler and ensure the handshake completes
233 TEST_F(GCMConnectionHandlerImplTest
, Init
) {
234 std::string handshake_request
= EncodeHandshakeRequest();
235 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
236 handshake_request
.c_str(),
237 handshake_request
.size()));
238 std::string handshake_response
= EncodeHandshakeResponse();
239 ReadList
read_list(1, net::MockRead(net::ASYNC
,
240 handshake_response
.c_str(),
241 handshake_response
.size()));
242 BuildSocket(read_list
, write_list
);
244 ScopedMessage received_message
;
245 Connect(&received_message
);
246 EXPECT_FALSE(connection_handler()->CanSendMessage());
247 WaitForMessage(); // The login send.
248 WaitForMessage(); // The login response.
249 ASSERT_TRUE(received_message
.get());
250 EXPECT_EQ(BuildLoginResponse(), received_message
->SerializeAsString());
251 EXPECT_TRUE(connection_handler()->CanSendMessage());
254 // Simulate the handshake response returning an older version. Initialization
256 TEST_F(GCMConnectionHandlerImplTest
, InitFailedVersionCheck
) {
257 std::string handshake_request
= EncodeHandshakeRequest();
258 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
259 handshake_request
.c_str(),
260 handshake_request
.size()));
261 std::string handshake_response
= EncodeHandshakeResponse();
262 // Overwrite the version byte.
263 handshake_response
[0] = 37;
264 ReadList
read_list(1, net::MockRead(net::ASYNC
,
265 handshake_response
.c_str(),
266 handshake_response
.size()));
267 BuildSocket(read_list
, write_list
);
269 ScopedMessage received_message
;
270 Connect(&received_message
);
271 WaitForMessage(); // The login send.
272 WaitForMessage(); // The login response. Should result in a connection error.
273 EXPECT_FALSE(received_message
.get());
274 EXPECT_FALSE(connection_handler()->CanSendMessage());
275 EXPECT_EQ(net::ERR_FAILED
, last_error());
278 // Attempt to initialize, but receive no server response, resulting in a time
280 TEST_F(GCMConnectionHandlerImplTest
, InitTimeout
) {
281 std::string handshake_request
= EncodeHandshakeRequest();
282 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
283 handshake_request
.c_str(),
284 handshake_request
.size()));
285 ReadList
read_list(1, net::MockRead(net::SYNCHRONOUS
,
286 net::ERR_IO_PENDING
));
287 BuildSocket(read_list
, write_list
);
289 ScopedMessage received_message
;
290 Connect(&received_message
);
291 WaitForMessage(); // The login send.
292 WaitForMessage(); // The login response. Should result in a connection error.
293 EXPECT_FALSE(received_message
.get());
294 EXPECT_FALSE(connection_handler()->CanSendMessage());
295 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
298 // Attempt to initialize, but receive an incomplete server response, resulting
300 TEST_F(GCMConnectionHandlerImplTest
, InitIncompleteTimeout
) {
301 std::string handshake_request
= EncodeHandshakeRequest();
302 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
303 handshake_request
.c_str(),
304 handshake_request
.size()));
305 std::string handshake_response
= EncodeHandshakeResponse();
307 read_list
.push_back(net::MockRead(net::ASYNC
,
308 handshake_response
.c_str(),
309 handshake_response
.size() / 2));
310 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
311 net::ERR_IO_PENDING
));
312 BuildSocket(read_list
, write_list
);
314 ScopedMessage received_message
;
315 Connect(&received_message
);
316 WaitForMessage(); // The login send.
317 WaitForMessage(); // The login response. Should result in a connection error.
318 EXPECT_FALSE(received_message
.get());
319 EXPECT_FALSE(connection_handler()->CanSendMessage());
320 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
323 // Reinitialize the connection handler after failing to initialize.
324 TEST_F(GCMConnectionHandlerImplTest
, ReInit
) {
325 std::string handshake_request
= EncodeHandshakeRequest();
326 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
327 handshake_request
.c_str(),
328 handshake_request
.size()));
329 ReadList
read_list(1, net::MockRead(net::SYNCHRONOUS
,
330 net::ERR_IO_PENDING
));
331 BuildSocket(read_list
, write_list
);
333 ScopedMessage received_message
;
334 Connect(&received_message
);
335 WaitForMessage(); // The login send.
336 WaitForMessage(); // The login response. Should result in a connection error.
337 EXPECT_FALSE(received_message
.get());
338 EXPECT_FALSE(connection_handler()->CanSendMessage());
339 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
341 // Build a new socket and reconnect, successfully this time.
342 std::string handshake_response
= EncodeHandshakeResponse();
343 read_list
[0] = net::MockRead(net::ASYNC
,
344 handshake_response
.c_str(),
345 handshake_response
.size());
346 BuildSocket(read_list
, write_list
);
347 Connect(&received_message
);
348 EXPECT_FALSE(connection_handler()->CanSendMessage());
349 WaitForMessage(); // The login send.
350 WaitForMessage(); // The login response.
351 ASSERT_TRUE(received_message
.get());
352 EXPECT_EQ(BuildLoginResponse(), received_message
->SerializeAsString());
353 EXPECT_TRUE(connection_handler()->CanSendMessage());
356 // Verify that messages can be received after initialization.
357 TEST_F(GCMConnectionHandlerImplTest
, RecvMsg
) {
358 std::string handshake_request
= EncodeHandshakeRequest();
359 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
360 handshake_request
.c_str(),
361 handshake_request
.size()));
362 std::string handshake_response
= EncodeHandshakeResponse();
364 std::string data_message_proto
= BuildDataMessage(kDataMsgFrom
,
366 std::string data_message_pkt
=
367 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
369 read_list
.push_back(net::MockRead(net::ASYNC
,
370 handshake_response
.c_str(),
371 handshake_response
.size()));
372 read_list
.push_back(net::MockRead(net::ASYNC
,
373 data_message_pkt
.c_str(),
374 data_message_pkt
.size()));
375 BuildSocket(read_list
, write_list
);
377 ScopedMessage received_message
;
378 Connect(&received_message
);
379 WaitForMessage(); // The login send.
380 WaitForMessage(); // The login response.
381 WaitForMessage(); // The data message.
382 ASSERT_TRUE(received_message
.get());
383 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
384 EXPECT_EQ(net::OK
, last_error());
387 // Verify that if two messages arrive at once, they're treated appropriately.
388 TEST_F(GCMConnectionHandlerImplTest
, Recv2Msgs
) {
389 std::string handshake_request
= EncodeHandshakeRequest();
390 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
391 handshake_request
.c_str(),
392 handshake_request
.size()));
393 std::string handshake_response
= EncodeHandshakeResponse();
395 std::string data_message_proto
= BuildDataMessage(kDataMsgFrom
,
397 std::string data_message_proto2
= BuildDataMessage(kDataMsgFrom2
,
399 std::string data_message_pkt
=
400 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
401 data_message_pkt
+= EncodePacket(kDataMessageStanzaTag
, data_message_proto2
);
403 read_list
.push_back(net::MockRead(net::ASYNC
,
404 handshake_response
.c_str(),
405 handshake_response
.size()));
406 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
407 data_message_pkt
.c_str(),
408 data_message_pkt
.size()));
409 BuildSocket(read_list
, write_list
);
411 ScopedMessage received_message
;
412 Connect(&received_message
);
413 WaitForMessage(); // The login send.
414 WaitForMessage(); // The login response.
415 WaitForMessage(); // The first data message.
416 ASSERT_TRUE(received_message
.get());
417 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
418 received_message
.reset();
419 WaitForMessage(); // The second data message.
420 ASSERT_TRUE(received_message
.get());
421 EXPECT_EQ(data_message_proto2
, received_message
->SerializeAsString());
422 EXPECT_EQ(net::OK
, last_error());
425 // Receive a long (>128 bytes) message.
426 TEST_F(GCMConnectionHandlerImplTest
, RecvLongMsg
) {
427 std::string handshake_request
= EncodeHandshakeRequest();
428 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
429 handshake_request
.c_str(),
430 handshake_request
.size()));
431 std::string handshake_response
= EncodeHandshakeResponse();
433 std::string data_message_proto
=
434 BuildDataMessage(kDataMsgFromLong
, kDataMsgCategoryLong
);
435 std::string data_message_pkt
=
436 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
437 DCHECK_GT(data_message_pkt
.size(), 128U);
439 read_list
.push_back(net::MockRead(net::ASYNC
,
440 handshake_response
.c_str(),
441 handshake_response
.size()));
442 read_list
.push_back(net::MockRead(net::ASYNC
,
443 data_message_pkt
.c_str(),
444 data_message_pkt
.size()));
445 BuildSocket(read_list
, write_list
);
447 ScopedMessage received_message
;
448 Connect(&received_message
);
449 WaitForMessage(); // The login send.
450 WaitForMessage(); // The login response.
451 WaitForMessage(); // The data message.
452 ASSERT_TRUE(received_message
.get());
453 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
454 EXPECT_EQ(net::OK
, last_error());
457 // Receive a long (>128 bytes) message in two synchronous parts.
458 TEST_F(GCMConnectionHandlerImplTest
, RecvLongMsg2Parts
) {
459 std::string handshake_request
= EncodeHandshakeRequest();
460 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
461 handshake_request
.c_str(),
462 handshake_request
.size()));
463 std::string handshake_response
= EncodeHandshakeResponse();
465 std::string data_message_proto
=
466 BuildDataMessage(kDataMsgFromLong
, kDataMsgCategoryLong
);
467 std::string data_message_pkt
=
468 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
469 DCHECK_GT(data_message_pkt
.size(), 128U);
471 read_list
.push_back(net::MockRead(net::ASYNC
,
472 handshake_response
.c_str(),
473 handshake_response
.size()));
475 int bytes_in_first_message
= data_message_pkt
.size() / 2;
476 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
477 data_message_pkt
.c_str(),
478 bytes_in_first_message
));
479 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
480 data_message_pkt
.c_str() +
481 bytes_in_first_message
,
482 data_message_pkt
.size() -
483 bytes_in_first_message
));
484 BuildSocket(read_list
, write_list
);
486 ScopedMessage received_message
;
487 Connect(&received_message
);
488 WaitForMessage(); // The login send.
489 WaitForMessage(); // The login response.
490 WaitForMessage(); // The data message.
491 ASSERT_TRUE(received_message
.get());
492 EXPECT_EQ(net::OK
, last_error());
493 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
496 // Receive two long (>128 bytes) message.
497 TEST_F(GCMConnectionHandlerImplTest
, Recv2LongMsgs
) {
498 std::string handshake_request
= EncodeHandshakeRequest();
499 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
500 handshake_request
.c_str(),
501 handshake_request
.size()));
502 std::string handshake_response
= EncodeHandshakeResponse();
504 std::string data_message_proto
=
505 BuildDataMessage(kDataMsgFromLong
, kDataMsgCategoryLong
);
506 std::string data_message_proto2
=
507 BuildDataMessage(kDataMsgFromLong2
, kDataMsgCategoryLong2
);
508 std::string data_message_pkt
=
509 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
510 data_message_pkt
+= EncodePacket(kDataMessageStanzaTag
, data_message_proto2
);
511 DCHECK_GT(data_message_pkt
.size(), 256U);
513 read_list
.push_back(net::MockRead(net::ASYNC
,
514 handshake_response
.c_str(),
515 handshake_response
.size()));
516 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
517 data_message_pkt
.c_str(),
518 data_message_pkt
.size()));
519 BuildSocket(read_list
, write_list
);
521 ScopedMessage received_message
;
522 Connect(&received_message
);
523 WaitForMessage(); // The login send.
524 WaitForMessage(); // The login response.
525 WaitForMessage(); // The first data message.
526 ASSERT_TRUE(received_message
.get());
527 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
528 received_message
.reset();
529 WaitForMessage(); // The second data message.
530 ASSERT_TRUE(received_message
.get());
531 EXPECT_EQ(data_message_proto2
, received_message
->SerializeAsString());
532 EXPECT_EQ(net::OK
, last_error());
535 // Simulate a message where the end of the data does not arrive in time and the
537 TEST_F(GCMConnectionHandlerImplTest
, ReadTimeout
) {
538 std::string handshake_request
= EncodeHandshakeRequest();
539 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
540 handshake_request
.c_str(),
541 handshake_request
.size()));
542 std::string handshake_response
= EncodeHandshakeResponse();
544 std::string data_message_proto
= BuildDataMessage(kDataMsgFrom
,
546 std::string data_message_pkt
=
547 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
548 int bytes_in_first_message
= data_message_pkt
.size() / 2;
550 read_list
.push_back(net::MockRead(net::ASYNC
,
551 handshake_response
.c_str(),
552 handshake_response
.size()));
553 read_list
.push_back(net::MockRead(net::ASYNC
,
554 data_message_pkt
.c_str(),
555 bytes_in_first_message
));
556 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
557 net::ERR_IO_PENDING
));
558 read_list
.push_back(net::MockRead(net::ASYNC
,
559 data_message_pkt
.c_str() +
560 bytes_in_first_message
,
561 data_message_pkt
.size() -
562 bytes_in_first_message
));
563 BuildSocket(read_list
, write_list
);
565 ScopedMessage received_message
;
566 Connect(&received_message
);
567 WaitForMessage(); // The login send.
568 WaitForMessage(); // The login response.
569 received_message
.reset();
570 WaitForMessage(); // Should time out.
571 EXPECT_FALSE(received_message
.get());
572 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
573 EXPECT_FALSE(connection_handler()->CanSendMessage());
575 // Finish the socket read. Should have no effect.
576 data_provider()->ForceNextRead();
579 // Receive a message with zero data bytes.
580 TEST_F(GCMConnectionHandlerImplTest
, RecvMsgNoData
) {
581 std::string handshake_request
= EncodeHandshakeRequest();
582 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
583 handshake_request
.c_str(),
584 handshake_request
.size()));
585 std::string handshake_response
= EncodeHandshakeResponse();
587 std::string data_message_pkt
= EncodePacket(kHeartbeatPingTag
, "");
588 ASSERT_EQ(data_message_pkt
.size(), 2U);
590 read_list
.push_back(net::MockRead(net::ASYNC
,
591 handshake_response
.c_str(),
592 handshake_response
.size()));
593 read_list
.push_back(net::MockRead(net::ASYNC
,
594 data_message_pkt
.c_str(),
595 data_message_pkt
.size()));
596 BuildSocket(read_list
, write_list
);
598 ScopedMessage received_message
;
599 Connect(&received_message
);
600 WaitForMessage(); // The login send.
601 WaitForMessage(); // The login response.
602 received_message
.reset();
603 WaitForMessage(); // The heartbeat ping.
604 EXPECT_TRUE(received_message
.get());
605 EXPECT_EQ(GetMCSProtoTag(*received_message
), kHeartbeatPingTag
);
606 EXPECT_EQ(net::OK
, last_error());
607 EXPECT_TRUE(connection_handler()->CanSendMessage());
610 // Send a message after performing the handshake.
611 TEST_F(GCMConnectionHandlerImplTest
, SendMsg
) {
612 mcs_proto::DataMessageStanza data_message
;
613 data_message
.set_from(kDataMsgFrom
);
614 data_message
.set_category(kDataMsgCategory
);
615 std::string handshake_request
= EncodeHandshakeRequest();
616 std::string data_message_pkt
=
617 EncodePacket(kDataMessageStanzaTag
, data_message
.SerializeAsString());
618 WriteList write_list
;
619 write_list
.push_back(net::MockWrite(net::ASYNC
,
620 handshake_request
.c_str(),
621 handshake_request
.size()));
622 write_list
.push_back(net::MockWrite(net::ASYNC
,
623 data_message_pkt
.c_str(),
624 data_message_pkt
.size()));
625 std::string handshake_response
= EncodeHandshakeResponse();
627 read_list
.push_back(net::MockRead(net::ASYNC
,
628 handshake_response
.c_str(),
629 handshake_response
.size()));
630 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
, net::ERR_IO_PENDING
));
631 BuildSocket(read_list
, write_list
);
633 ScopedMessage received_message
;
634 Connect(&received_message
);
635 WaitForMessage(); // The login send.
636 WaitForMessage(); // The login response.
637 EXPECT_TRUE(connection_handler()->CanSendMessage());
638 connection_handler()->SendMessage(data_message
);
639 EXPECT_FALSE(connection_handler()->CanSendMessage());
640 WaitForMessage(); // The message send.
641 EXPECT_TRUE(connection_handler()->CanSendMessage());
644 // Attempt to send a message after the socket is disconnected due to a timeout.
645 TEST_F(GCMConnectionHandlerImplTest
, SendMsgSocketDisconnected
) {
646 std::string handshake_request
= EncodeHandshakeRequest();
647 WriteList write_list
;
648 write_list
.push_back(net::MockWrite(net::ASYNC
,
649 handshake_request
.c_str(),
650 handshake_request
.size()));
651 std::string handshake_response
= EncodeHandshakeResponse();
653 read_list
.push_back(net::MockRead(net::ASYNC
,
654 handshake_response
.c_str(),
655 handshake_response
.size()));
656 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
, net::ERR_IO_PENDING
));
657 net::StreamSocket
* socket
= BuildSocket(read_list
, write_list
);
659 ScopedMessage received_message
;
660 Connect(&received_message
);
661 WaitForMessage(); // The login send.
662 WaitForMessage(); // The login response.
663 EXPECT_TRUE(connection_handler()->CanSendMessage());
664 socket
->Disconnect();
665 mcs_proto::DataMessageStanza data_message
;
666 data_message
.set_from(kDataMsgFrom
);
667 data_message
.set_category(kDataMsgCategory
);
668 connection_handler()->SendMessage(data_message
);
669 EXPECT_FALSE(connection_handler()->CanSendMessage());
670 WaitForMessage(); // The message send. Should result in an error
671 EXPECT_FALSE(connection_handler()->CanSendMessage());
672 EXPECT_EQ(net::ERR_CONNECTION_CLOSED
, last_error());
675 // Receive a message whose size field was corrupted and is larger than the
676 // socket's buffer. Should fail gracefully with a size error.
677 TEST_F(GCMConnectionHandlerImplTest
, OutOfBuffer
) {
678 std::string handshake_request
= EncodeHandshakeRequest();
679 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
680 handshake_request
.c_str(),
681 handshake_request
.size()));
682 std::string handshake_response
= EncodeHandshakeResponse();
684 // Fill a string with 9000 character zero.
685 std::string
data_message_proto(9000, '0');
686 std::string data_message_pkt
=
687 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
689 read_list
.push_back(net::MockRead(net::ASYNC
,
690 handshake_response
.c_str(),
691 handshake_response
.size()));
692 read_list
.push_back(net::MockRead(net::ASYNC
,
693 data_message_pkt
.c_str(),
694 data_message_pkt
.size()));
695 BuildSocket(read_list
, write_list
);
697 ScopedMessage received_message
;
698 Connect(&received_message
);
699 WaitForMessage(); // The login send.
700 WaitForMessage(); // The login response.
701 received_message
.reset();
702 WaitForMessage(); // The data message.
703 EXPECT_FALSE(received_message
.get());
704 EXPECT_EQ(net::ERR_FILE_TOO_BIG
, last_error());
707 // Receive a message whose size field was corrupted and takes more than two
708 // bytes to encode. Should fail gracefully with a size error.
709 TEST_F(GCMConnectionHandlerImplTest
, InvalidSizePacket
) {
710 std::string handshake_request
= EncodeHandshakeRequest();
711 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
712 handshake_request
.c_str(),
713 handshake_request
.size()));
714 std::string handshake_response
= EncodeHandshakeResponse();
716 // Fill a string with 20000 character zero (which uses more than 2 bytes to
717 // encode the size packet).
718 std::string
data_message_proto(20000, '0');
719 std::string data_message_pkt
=
720 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
722 read_list
.push_back(net::MockRead(net::ASYNC
,
723 handshake_response
.c_str(),
724 handshake_response
.size()));
725 read_list
.push_back(net::MockRead(net::ASYNC
,
726 data_message_pkt
.c_str(),
727 data_message_pkt
.size()));
728 BuildSocket(read_list
, write_list
);
730 ScopedMessage received_message
;
731 Connect(&received_message
);
732 WaitForMessage(); // The login send.
733 WaitForMessage(); // The login response.
734 received_message
.reset();
735 WaitForMessage(); // The data message.
736 EXPECT_FALSE(received_message
.get());
737 EXPECT_EQ(net::ERR_FILE_TOO_BIG
, last_error());
740 // Make sure a message with an invalid tag is handled gracefully and resets
741 // the connection with an invalid argument error.
742 TEST_F(GCMConnectionHandlerImplTest
, InvalidTag
) {
743 std::string handshake_request
= EncodeHandshakeRequest();
744 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
745 handshake_request
.c_str(),
746 handshake_request
.size()));
747 std::string handshake_response
= EncodeHandshakeResponse();
749 std::string invalid_message
= "0";
750 std::string invalid_message_pkt
=
751 EncodePacket(kInvalidTag
, invalid_message
);
753 read_list
.push_back(net::MockRead(net::ASYNC
,
754 handshake_response
.c_str(),
755 handshake_response
.size()));
756 read_list
.push_back(net::MockRead(net::ASYNC
,
757 invalid_message_pkt
.c_str(),
758 invalid_message_pkt
.size()));
759 BuildSocket(read_list
, write_list
);
761 ScopedMessage received_message
;
762 Connect(&received_message
);
763 WaitForMessage(); // The login send.
764 WaitForMessage(); // The login response.
765 received_message
.reset();
766 WaitForMessage(); // The invalid message.
767 EXPECT_FALSE(received_message
.get());
768 EXPECT_EQ(net::ERR_INVALID_ARGUMENT
, last_error());
771 // Receive a message where the size field spans two socket reads.
772 TEST_F(GCMConnectionHandlerImplTest
, RecvMsgSplitSize
) {
773 std::string handshake_request
= EncodeHandshakeRequest();
774 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
775 handshake_request
.c_str(),
776 handshake_request
.size()));
777 std::string handshake_response
= EncodeHandshakeResponse();
779 std::string data_message_proto
=
780 BuildDataMessage(kDataMsgFromLong
, kDataMsgCategoryLong
);
781 std::string data_message_pkt
=
782 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
783 DCHECK_GT(data_message_pkt
.size(), 128U);
785 read_list
.push_back(net::MockRead(net::ASYNC
,
786 handshake_response
.c_str(),
787 handshake_response
.size()));
788 // The first two bytes are the tag byte and the first byte of the size packet.
789 read_list
.push_back(net::MockRead(net::ASYNC
,
790 data_message_pkt
.c_str(),
792 // Start from the second byte of the size packet.
793 read_list
.push_back(net::MockRead(net::ASYNC
,
794 data_message_pkt
.c_str() + 2,
795 data_message_pkt
.size() - 2));
796 BuildSocket(read_list
, write_list
);
798 ScopedMessage received_message
;
799 Connect(&received_message
);
800 WaitForMessage(); // The login send.
801 WaitForMessage(); // The login response.
802 WaitForMessage(); // The data message.
803 ASSERT_TRUE(received_message
.get());
804 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
805 EXPECT_EQ(net::OK
, last_error());