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
= 38; // 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";
45 // ---- Helpers for building messages. ----
47 // Encode a protobuf packet with protobuf type |tag| and serialized protobuf
48 // bytes |proto| into the MCS message form (tag + varint size + bytes).
49 std::string
EncodePacket(uint8 tag
, const std::string
& proto
) {
51 google::protobuf::io::StringOutputStream
string_output_stream(&result
);
53 google::protobuf::io::CodedOutputStream
coded_output_stream(
54 &string_output_stream
);
55 const unsigned char tag_byte
[1] = { tag
};
56 coded_output_stream
.WriteRaw(tag_byte
, 1);
57 coded_output_stream
.WriteVarint32(proto
.size());
58 coded_output_stream
.WriteRaw(proto
.c_str(), proto
.size());
59 // ~CodedOutputStream must run before the move constructor at the
60 // return statement. http://crbug.com/338962
65 // Encode a handshake request into the MCS message form.
66 std::string
EncodeHandshakeRequest() {
68 const char version_byte
[1] = {kMCSVersion
};
69 result
.append(version_byte
, 1);
70 std::vector
<int64
> user_serial_numbers
;
71 ScopedMessage
login_request(
72 BuildLoginRequest(kAuthId
, kAuthToken
, user_serial_numbers
));
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 virtual ~GCMConnectionHandlerImplTest();
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_
;
140 scoped_ptr
<SocketInputStream
> socket_input_stream_
;
141 scoped_ptr
<SocketOutputStream
> socket_output_stream_
;
143 // The connection handler being tested.
144 scoped_ptr
<ConnectionHandlerImpl
> connection_handler_
;
146 // The last connection error received.
150 scoped_ptr
<net::StreamSocket
> socket_
;
151 net::MockClientSocketFactory socket_factory_
;
152 net::AddressList address_list_
;
154 base::MessageLoopForIO message_loop_
;
155 scoped_ptr
<base::RunLoop
> run_loop_
;
158 GCMConnectionHandlerImplTest::GCMConnectionHandlerImplTest()
160 net::IPAddressNumber ip_number
;
161 net::ParseIPLiteralToNumber("127.0.0.1", &ip_number
);
162 address_list_
= net::AddressList::CreateFromIPAddress(ip_number
, kMCSPort
);
165 GCMConnectionHandlerImplTest::~GCMConnectionHandlerImplTest() {
168 net::StreamSocket
* GCMConnectionHandlerImplTest::BuildSocket(
169 const ReadList
& read_list
,
170 const WriteList
& write_list
) {
171 mock_reads_
= read_list
;
172 mock_writes_
= write_list
;
173 data_provider_
.reset(
174 new net::DelayedSocketData(0,
175 &(mock_reads_
[0]), mock_reads_
.size(),
176 &(mock_writes_
[0]), mock_writes_
.size()));
177 socket_factory_
.AddSocketDataProvider(data_provider_
.get());
179 socket_
= socket_factory_
.CreateTransportClientSocket(
180 address_list_
, NULL
, net::NetLog::Source());
181 socket_
->Connect(net::CompletionCallback());
183 run_loop_
.reset(new base::RunLoop());
186 DCHECK(socket_
->IsConnected());
187 return socket_
.get();
190 void GCMConnectionHandlerImplTest::PumpLoop() {
191 run_loop_
->RunUntilIdle();
192 run_loop_
.reset(new base::RunLoop());
195 void GCMConnectionHandlerImplTest::Connect(
196 ScopedMessage
* dst_proto
) {
197 connection_handler_
.reset(new ConnectionHandlerImpl(
198 TestTimeouts::tiny_timeout(),
199 base::Bind(&GCMConnectionHandlerImplTest::ReadContinuation
,
200 base::Unretained(this),
202 base::Bind(&GCMConnectionHandlerImplTest::WriteContinuation
,
203 base::Unretained(this)),
204 base::Bind(&GCMConnectionHandlerImplTest::ConnectionContinuation
,
205 base::Unretained(this))));
206 EXPECT_FALSE(connection_handler()->CanSendMessage());
207 std::vector
<int64
> user_serial_numbers
;
208 connection_handler_
->Init(
209 *BuildLoginRequest(kAuthId
, kAuthToken
, user_serial_numbers
),
213 void GCMConnectionHandlerImplTest::ReadContinuation(
214 ScopedMessage
* dst_proto
,
215 ScopedMessage new_proto
) {
216 *dst_proto
= new_proto
.Pass();
220 void GCMConnectionHandlerImplTest::WaitForMessage() {
222 run_loop_
.reset(new base::RunLoop());
225 void GCMConnectionHandlerImplTest::WriteContinuation() {
229 void GCMConnectionHandlerImplTest::ConnectionContinuation(int error
) {
234 // Initialize the connection handler and ensure the handshake completes
236 TEST_F(GCMConnectionHandlerImplTest
, Init
) {
237 std::string handshake_request
= EncodeHandshakeRequest();
238 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
239 handshake_request
.c_str(),
240 handshake_request
.size()));
241 std::string handshake_response
= EncodeHandshakeResponse();
242 ReadList
read_list(1, net::MockRead(net::ASYNC
,
243 handshake_response
.c_str(),
244 handshake_response
.size()));
245 BuildSocket(read_list
, write_list
);
247 ScopedMessage received_message
;
248 Connect(&received_message
);
249 EXPECT_FALSE(connection_handler()->CanSendMessage());
250 WaitForMessage(); // The login send.
251 WaitForMessage(); // The login response.
252 ASSERT_TRUE(received_message
.get());
253 EXPECT_EQ(BuildLoginResponse(), received_message
->SerializeAsString());
254 EXPECT_TRUE(connection_handler()->CanSendMessage());
257 // Simulate the handshake response returning an older version. Initialization
259 TEST_F(GCMConnectionHandlerImplTest
, InitFailedVersionCheck
) {
260 std::string handshake_request
= EncodeHandshakeRequest();
261 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
262 handshake_request
.c_str(),
263 handshake_request
.size()));
264 std::string handshake_response
= EncodeHandshakeResponse();
265 // Overwrite the version byte.
266 handshake_response
[0] = 37;
267 ReadList
read_list(1, net::MockRead(net::ASYNC
,
268 handshake_response
.c_str(),
269 handshake_response
.size()));
270 BuildSocket(read_list
, write_list
);
272 ScopedMessage received_message
;
273 Connect(&received_message
);
274 WaitForMessage(); // The login send.
275 WaitForMessage(); // The login response. Should result in a connection error.
276 EXPECT_FALSE(received_message
.get());
277 EXPECT_FALSE(connection_handler()->CanSendMessage());
278 EXPECT_EQ(net::ERR_FAILED
, last_error());
281 // Attempt to initialize, but receive no server response, resulting in a time
283 TEST_F(GCMConnectionHandlerImplTest
, InitTimeout
) {
284 std::string handshake_request
= EncodeHandshakeRequest();
285 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
286 handshake_request
.c_str(),
287 handshake_request
.size()));
288 ReadList
read_list(1, net::MockRead(net::SYNCHRONOUS
,
289 net::ERR_IO_PENDING
));
290 BuildSocket(read_list
, write_list
);
292 ScopedMessage received_message
;
293 Connect(&received_message
);
294 WaitForMessage(); // The login send.
295 WaitForMessage(); // The login response. Should result in a connection error.
296 EXPECT_FALSE(received_message
.get());
297 EXPECT_FALSE(connection_handler()->CanSendMessage());
298 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
301 // Attempt to initialize, but receive an incomplete server response, resulting
303 TEST_F(GCMConnectionHandlerImplTest
, InitIncompleteTimeout
) {
304 std::string handshake_request
= EncodeHandshakeRequest();
305 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
306 handshake_request
.c_str(),
307 handshake_request
.size()));
308 std::string handshake_response
= EncodeHandshakeResponse();
310 read_list
.push_back(net::MockRead(net::ASYNC
,
311 handshake_response
.c_str(),
312 handshake_response
.size() / 2));
313 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
314 net::ERR_IO_PENDING
));
315 BuildSocket(read_list
, write_list
);
317 ScopedMessage received_message
;
318 Connect(&received_message
);
319 WaitForMessage(); // The login send.
320 WaitForMessage(); // The login response. Should result in a connection error.
321 EXPECT_FALSE(received_message
.get());
322 EXPECT_FALSE(connection_handler()->CanSendMessage());
323 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
326 // Reinitialize the connection handler after failing to initialize.
327 TEST_F(GCMConnectionHandlerImplTest
, ReInit
) {
328 std::string handshake_request
= EncodeHandshakeRequest();
329 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
330 handshake_request
.c_str(),
331 handshake_request
.size()));
332 ReadList
read_list(1, net::MockRead(net::SYNCHRONOUS
,
333 net::ERR_IO_PENDING
));
334 BuildSocket(read_list
, write_list
);
336 ScopedMessage received_message
;
337 Connect(&received_message
);
338 WaitForMessage(); // The login send.
339 WaitForMessage(); // The login response. Should result in a connection error.
340 EXPECT_FALSE(received_message
.get());
341 EXPECT_FALSE(connection_handler()->CanSendMessage());
342 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
344 // Build a new socket and reconnect, successfully this time.
345 std::string handshake_response
= EncodeHandshakeResponse();
346 read_list
[0] = net::MockRead(net::ASYNC
,
347 handshake_response
.c_str(),
348 handshake_response
.size());
349 BuildSocket(read_list
, write_list
);
350 Connect(&received_message
);
351 EXPECT_FALSE(connection_handler()->CanSendMessage());
352 WaitForMessage(); // The login send.
353 WaitForMessage(); // The login response.
354 ASSERT_TRUE(received_message
.get());
355 EXPECT_EQ(BuildLoginResponse(), received_message
->SerializeAsString());
356 EXPECT_TRUE(connection_handler()->CanSendMessage());
359 // Verify that messages can be received after initialization.
360 TEST_F(GCMConnectionHandlerImplTest
, RecvMsg
) {
361 std::string handshake_request
= EncodeHandshakeRequest();
362 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
363 handshake_request
.c_str(),
364 handshake_request
.size()));
365 std::string handshake_response
= EncodeHandshakeResponse();
367 std::string data_message_proto
= BuildDataMessage(kDataMsgFrom
,
369 std::string data_message_pkt
=
370 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
372 read_list
.push_back(net::MockRead(net::ASYNC
,
373 handshake_response
.c_str(),
374 handshake_response
.size()));
375 read_list
.push_back(net::MockRead(net::ASYNC
,
376 data_message_pkt
.c_str(),
377 data_message_pkt
.size()));
378 BuildSocket(read_list
, write_list
);
380 ScopedMessage received_message
;
381 Connect(&received_message
);
382 WaitForMessage(); // The login send.
383 WaitForMessage(); // The login response.
384 WaitForMessage(); // The data message.
385 ASSERT_TRUE(received_message
.get());
386 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
389 // Verify that if two messages arrive at once, they're treated appropriately.
390 TEST_F(GCMConnectionHandlerImplTest
, Recv2Msgs
) {
391 std::string handshake_request
= EncodeHandshakeRequest();
392 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
393 handshake_request
.c_str(),
394 handshake_request
.size()));
395 std::string handshake_response
= EncodeHandshakeResponse();
397 std::string data_message_proto
= BuildDataMessage(kDataMsgFrom
,
399 std::string data_message_proto2
= BuildDataMessage(kDataMsgFrom2
,
401 std::string data_message_pkt
=
402 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
403 data_message_pkt
+= EncodePacket(kDataMessageStanzaTag
, data_message_proto2
);
405 read_list
.push_back(net::MockRead(net::ASYNC
,
406 handshake_response
.c_str(),
407 handshake_response
.size()));
408 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
409 data_message_pkt
.c_str(),
410 data_message_pkt
.size()));
411 BuildSocket(read_list
, write_list
);
413 ScopedMessage received_message
;
414 Connect(&received_message
);
415 WaitForMessage(); // The login send.
416 WaitForMessage(); // The login response.
417 WaitForMessage(); // The first data message.
418 ASSERT_TRUE(received_message
.get());
419 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
420 received_message
.reset();
421 WaitForMessage(); // The second data message.
422 ASSERT_TRUE(received_message
.get());
423 EXPECT_EQ(data_message_proto2
, received_message
->SerializeAsString());
426 // Receive a long (>128 bytes) message.
427 TEST_F(GCMConnectionHandlerImplTest
, RecvLongMsg
) {
428 std::string handshake_request
= EncodeHandshakeRequest();
429 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
430 handshake_request
.c_str(),
431 handshake_request
.size()));
432 std::string handshake_response
= EncodeHandshakeResponse();
434 std::string data_message_proto
=
435 BuildDataMessage(kDataMsgFromLong
, kDataMsgCategoryLong
);
436 std::string data_message_pkt
=
437 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
438 DCHECK_GT(data_message_pkt
.size(), 128U);
440 read_list
.push_back(net::MockRead(net::ASYNC
,
441 handshake_response
.c_str(),
442 handshake_response
.size()));
443 read_list
.push_back(net::MockRead(net::ASYNC
,
444 data_message_pkt
.c_str(),
445 data_message_pkt
.size()));
446 BuildSocket(read_list
, write_list
);
448 ScopedMessage received_message
;
449 Connect(&received_message
);
450 WaitForMessage(); // The login send.
451 WaitForMessage(); // The login response.
452 WaitForMessage(); // The data message.
453 ASSERT_TRUE(received_message
.get());
454 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
457 // Receive two long (>128 bytes) message.
458 TEST_F(GCMConnectionHandlerImplTest
, Recv2LongMsgs
) {
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_proto2
=
468 BuildDataMessage(kDataMsgFromLong2
, kDataMsgCategoryLong2
);
469 std::string data_message_pkt
=
470 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
471 data_message_pkt
+= EncodePacket(kDataMessageStanzaTag
, data_message_proto2
);
472 DCHECK_GT(data_message_pkt
.size(), 256U);
474 read_list
.push_back(net::MockRead(net::ASYNC
,
475 handshake_response
.c_str(),
476 handshake_response
.size()));
477 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
478 data_message_pkt
.c_str(),
479 data_message_pkt
.size()));
480 BuildSocket(read_list
, write_list
);
482 ScopedMessage received_message
;
483 Connect(&received_message
);
484 WaitForMessage(); // The login send.
485 WaitForMessage(); // The login response.
486 WaitForMessage(); // The first data message.
487 ASSERT_TRUE(received_message
.get());
488 EXPECT_EQ(data_message_proto
, received_message
->SerializeAsString());
489 received_message
.reset();
490 WaitForMessage(); // The second data message.
491 ASSERT_TRUE(received_message
.get());
492 EXPECT_EQ(data_message_proto2
, received_message
->SerializeAsString());
495 // Simulate a message where the end of the data does not arrive in time and the
497 TEST_F(GCMConnectionHandlerImplTest
, ReadTimeout
) {
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
= BuildDataMessage(kDataMsgFrom
,
506 std::string data_message_pkt
=
507 EncodePacket(kDataMessageStanzaTag
, data_message_proto
);
508 int bytes_in_first_message
= data_message_pkt
.size() / 2;
510 read_list
.push_back(net::MockRead(net::ASYNC
,
511 handshake_response
.c_str(),
512 handshake_response
.size()));
513 read_list
.push_back(net::MockRead(net::ASYNC
,
514 data_message_pkt
.c_str(),
515 bytes_in_first_message
));
516 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
,
517 net::ERR_IO_PENDING
));
518 read_list
.push_back(net::MockRead(net::ASYNC
,
519 data_message_pkt
.c_str() +
520 bytes_in_first_message
,
521 data_message_pkt
.size() -
522 bytes_in_first_message
));
523 BuildSocket(read_list
, write_list
);
525 ScopedMessage received_message
;
526 Connect(&received_message
);
527 WaitForMessage(); // The login send.
528 WaitForMessage(); // The login response.
529 received_message
.reset();
530 WaitForMessage(); // Should time out.
531 EXPECT_FALSE(received_message
.get());
532 EXPECT_EQ(net::ERR_TIMED_OUT
, last_error());
533 EXPECT_FALSE(connection_handler()->CanSendMessage());
535 // Finish the socket read. Should have no effect.
536 data_provider()->ForceNextRead();
539 // Receive a message with zero data bytes.
540 TEST_F(GCMConnectionHandlerImplTest
, RecvMsgNoData
) {
541 std::string handshake_request
= EncodeHandshakeRequest();
542 WriteList
write_list(1, net::MockWrite(net::ASYNC
,
543 handshake_request
.c_str(),
544 handshake_request
.size()));
545 std::string handshake_response
= EncodeHandshakeResponse();
547 std::string data_message_pkt
= EncodePacket(kHeartbeatPingTag
, "");
548 ASSERT_EQ(data_message_pkt
.size(), 2U);
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 data_message_pkt
.size()));
556 BuildSocket(read_list
, write_list
);
558 ScopedMessage received_message
;
559 Connect(&received_message
);
560 WaitForMessage(); // The login send.
561 WaitForMessage(); // The login response.
562 received_message
.reset();
563 WaitForMessage(); // The heartbeat ping.
564 EXPECT_TRUE(received_message
.get());
565 EXPECT_EQ(GetMCSProtoTag(*received_message
), kHeartbeatPingTag
);
566 EXPECT_EQ(net::OK
, last_error());
567 EXPECT_TRUE(connection_handler()->CanSendMessage());
570 // Send a message after performing the handshake.
571 TEST_F(GCMConnectionHandlerImplTest
, SendMsg
) {
572 mcs_proto::DataMessageStanza data_message
;
573 data_message
.set_from(kDataMsgFrom
);
574 data_message
.set_category(kDataMsgCategory
);
575 std::string handshake_request
= EncodeHandshakeRequest();
576 std::string data_message_pkt
=
577 EncodePacket(kDataMessageStanzaTag
, data_message
.SerializeAsString());
578 WriteList write_list
;
579 write_list
.push_back(net::MockWrite(net::ASYNC
,
580 handshake_request
.c_str(),
581 handshake_request
.size()));
582 write_list
.push_back(net::MockWrite(net::ASYNC
,
583 data_message_pkt
.c_str(),
584 data_message_pkt
.size()));
585 std::string handshake_response
= EncodeHandshakeResponse();
587 read_list
.push_back(net::MockRead(net::ASYNC
,
588 handshake_response
.c_str(),
589 handshake_response
.size()));
590 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
, net::ERR_IO_PENDING
));
591 BuildSocket(read_list
, write_list
);
593 ScopedMessage received_message
;
594 Connect(&received_message
);
595 WaitForMessage(); // The login send.
596 WaitForMessage(); // The login response.
597 EXPECT_TRUE(connection_handler()->CanSendMessage());
598 connection_handler()->SendMessage(data_message
);
599 EXPECT_FALSE(connection_handler()->CanSendMessage());
600 WaitForMessage(); // The message send.
601 EXPECT_TRUE(connection_handler()->CanSendMessage());
604 // Attempt to send a message after the socket is disconnected due to a timeout.
605 TEST_F(GCMConnectionHandlerImplTest
, SendMsgSocketDisconnected
) {
606 std::string handshake_request
= EncodeHandshakeRequest();
607 WriteList write_list
;
608 write_list
.push_back(net::MockWrite(net::ASYNC
,
609 handshake_request
.c_str(),
610 handshake_request
.size()));
611 std::string handshake_response
= EncodeHandshakeResponse();
613 read_list
.push_back(net::MockRead(net::ASYNC
,
614 handshake_response
.c_str(),
615 handshake_response
.size()));
616 read_list
.push_back(net::MockRead(net::SYNCHRONOUS
, net::ERR_IO_PENDING
));
617 net::StreamSocket
* socket
= BuildSocket(read_list
, write_list
);
619 ScopedMessage received_message
;
620 Connect(&received_message
);
621 WaitForMessage(); // The login send.
622 WaitForMessage(); // The login response.
623 EXPECT_TRUE(connection_handler()->CanSendMessage());
624 socket
->Disconnect();
625 mcs_proto::DataMessageStanza data_message
;
626 data_message
.set_from(kDataMsgFrom
);
627 data_message
.set_category(kDataMsgCategory
);
628 connection_handler()->SendMessage(data_message
);
629 EXPECT_FALSE(connection_handler()->CanSendMessage());
630 WaitForMessage(); // The message send. Should result in an error
631 EXPECT_FALSE(connection_handler()->CanSendMessage());
632 EXPECT_EQ(net::ERR_CONNECTION_CLOSED
, last_error());