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. 4 5#include "google_apis/gcm/engine/connection_handler_impl.h" 6 7#include "base/bind.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" 20 21namespace gcm { 22namespace { 23 24typedef scoped_ptr<google::protobuf::MessageLite> ScopedMessage; 25typedef std::vector<net::MockRead> ReadList; 26typedef std::vector<net::MockWrite> WriteList; 27 28const uint64 kAuthId = 54321; 29const uint64 kAuthToken = 12345; 30const char kMCSVersion = 38; // The protocol version. 31const int kMCSPort = 5228; // The server port. 32const char kDataMsgFrom[] = "data_from"; 33const char kDataMsgCategory[] = "data_category"; 34const char kDataMsgFrom2[] = "data_from2"; 35const char kDataMsgCategory2[] = "data_category2"; 36const char kDataMsgFromLong[] = 37 "this is a long from that will result in a message > 128 bytes"; 38const char kDataMsgCategoryLong[] = 39 "this is a long category that will result in a message > 128 bytes"; 40const char kDataMsgFromLong2[] = 41 "this is a second long from that will result in a message > 128 bytes"; 42const char kDataMsgCategoryLong2[] = 43 "this is a second long category that will result in a message > 128 bytes"; 44 45// ---- Helpers for building messages. ---- 46 47// Encode a protobuf packet with protobuf type |tag| and serialized protobuf 48// bytes |proto| into the MCS message form (tag + varint size + bytes). 49std::string EncodePacket(uint8 tag, const std::string& proto) { 50 std::string result; 51 google::protobuf::io::StringOutputStream string_output_stream(&result); 52 google::protobuf::io::CodedOutputStream coded_output_stream( 53 &string_output_stream); 54 const unsigned char tag_byte[1] = {tag}; 55 coded_output_stream.WriteRaw(tag_byte, 1); 56 coded_output_stream.WriteVarint32(proto.size()); 57 coded_output_stream.WriteRaw(proto.c_str(), proto.size()); 58 return result; 59} 60 61// Encode a handshake request into the MCS message form. 62std::string EncodeHandshakeRequest() { 63 std::string result; 64 const char version_byte[1] = {kMCSVersion}; 65 result.append(version_byte, 1); 66 ScopedMessage login_request(BuildLoginRequest(kAuthId, kAuthToken)); 67 result.append(EncodePacket(kLoginRequestTag, 68 login_request->SerializeAsString())); 69 return result; 70} 71 72// Build a serialized login response protobuf. 73std::string BuildLoginResponse() { 74 std::string result; 75 mcs_proto::LoginResponse login_response; 76 login_response.set_id("id"); 77 result.append(login_response.SerializeAsString()); 78 return result; 79} 80 81// Encoode a handshake response into the MCS message form. 82std::string EncodeHandshakeResponse() { 83 std::string result; 84 const char version_byte[1] = {kMCSVersion}; 85 result.append(version_byte, 1); 86 result.append(EncodePacket(kLoginResponseTag, BuildLoginResponse())); 87 return result; 88} 89 90// Build a serialized data message stanza protobuf. 91std::string BuildDataMessage(const std::string& from, 92 const std::string& category) { 93 std::string result; 94 mcs_proto::DataMessageStanza data_message; 95 data_message.set_from(from); 96 data_message.set_category(category); 97 return data_message.SerializeAsString(); 98} 99 100class GCMConnectionHandlerImplTest : public testing::Test { 101 public: 102 GCMConnectionHandlerImplTest(); 103 virtual ~GCMConnectionHandlerImplTest(); 104 105 net::StreamSocket* BuildSocket(const ReadList& read_list, 106 const WriteList& write_list); 107 108 // Pump |message_loop_|, resetting |run_loop_| after completion. 109 void PumpLoop(); 110 111 ConnectionHandlerImpl* connection_handler() { 112 return connection_handler_.get(); 113 } 114 base::MessageLoop* message_loop() { return &message_loop_; }; 115 net::DelayedSocketData* data_provider() { return data_provider_.get(); } 116 int last_error() const { return last_error_; } 117 118 // Initialize the connection handler, setting |dst_proto| as the destination 119 // for any received messages. 120 void Connect(ScopedMessage* dst_proto); 121 122 // Runs the message loop until a message is received. 123 void WaitForMessage(); 124 125 private: 126 void ReadContinuation(ScopedMessage* dst_proto, ScopedMessage new_proto); 127 void WriteContinuation(); 128 void ConnectionContinuation(int error); 129 130 // SocketStreams and their data provider. 131 ReadList mock_reads_; 132 WriteList mock_writes_; 133 scoped_ptr<net::DelayedSocketData> data_provider_; 134 scoped_ptr<SocketInputStream> socket_input_stream_; 135 scoped_ptr<SocketOutputStream> socket_output_stream_; 136 137 // The connection handler being tested. 138 scoped_ptr<ConnectionHandlerImpl> connection_handler_; 139 140 // The last connection error received. 141 int last_error_; 142 143 // net:: components. 144 scoped_ptr<net::StreamSocket> socket_; 145 net::MockClientSocketFactory socket_factory_; 146 net::AddressList address_list_; 147 148 base::MessageLoopForIO message_loop_; 149 scoped_ptr<base::RunLoop> run_loop_; 150}; 151 152GCMConnectionHandlerImplTest::GCMConnectionHandlerImplTest() 153 : last_error_(0) { 154 net::IPAddressNumber ip_number; 155 net::ParseIPLiteralToNumber("127.0.0.1", &ip_number); 156 address_list_ = net::AddressList::CreateFromIPAddress(ip_number, kMCSPort); 157} 158 159GCMConnectionHandlerImplTest::~GCMConnectionHandlerImplTest() { 160} 161 162net::StreamSocket* GCMConnectionHandlerImplTest::BuildSocket( 163 const ReadList& read_list, 164 const WriteList& write_list) { 165 mock_reads_ = read_list; 166 mock_writes_ = write_list; 167 data_provider_.reset( 168 new net::DelayedSocketData(0, 169 &(mock_reads_[0]), mock_reads_.size(), 170 &(mock_writes_[0]), mock_writes_.size())); 171 socket_factory_.AddSocketDataProvider(data_provider_.get()); 172 173 socket_ = socket_factory_.CreateTransportClientSocket( 174 address_list_, NULL, net::NetLog::Source()); 175 socket_->Connect(net::CompletionCallback()); 176 177 run_loop_.reset(new base::RunLoop()); 178 PumpLoop(); 179 180 DCHECK(socket_->IsConnected()); 181 return socket_.get(); 182} 183 184void GCMConnectionHandlerImplTest::PumpLoop() { 185 run_loop_->RunUntilIdle(); 186 run_loop_.reset(new base::RunLoop()); 187} 188 189void GCMConnectionHandlerImplTest::Connect( 190 ScopedMessage* dst_proto) { 191 connection_handler_.reset(new ConnectionHandlerImpl( 192 TestTimeouts::tiny_timeout(), 193 base::Bind(&GCMConnectionHandlerImplTest::ReadContinuation, 194 base::Unretained(this), 195 dst_proto), 196 base::Bind(&GCMConnectionHandlerImplTest::WriteContinuation, 197 base::Unretained(this)), 198 base::Bind(&GCMConnectionHandlerImplTest::ConnectionContinuation, 199 base::Unretained(this)))); 200 EXPECT_FALSE(connection_handler()->CanSendMessage()); 201 connection_handler_->Init(*BuildLoginRequest(kAuthId, kAuthToken), 202 socket_.Pass()); 203} 204 205void GCMConnectionHandlerImplTest::ReadContinuation( 206 ScopedMessage* dst_proto, 207 ScopedMessage new_proto) { 208 *dst_proto = new_proto.Pass(); 209 run_loop_->Quit(); 210} 211 212void GCMConnectionHandlerImplTest::WaitForMessage() { 213 run_loop_->Run(); 214 run_loop_.reset(new base::RunLoop()); 215} 216 217void GCMConnectionHandlerImplTest::WriteContinuation() { 218 run_loop_->Quit(); 219} 220 221void GCMConnectionHandlerImplTest::ConnectionContinuation(int error) { 222 last_error_ = error; 223 run_loop_->Quit(); 224} 225 226// Initialize the connection handler and ensure the handshake completes 227// successfully. 228TEST_F(GCMConnectionHandlerImplTest, Init) { 229 std::string handshake_request = EncodeHandshakeRequest(); 230 WriteList write_list(1, net::MockWrite(net::ASYNC, 231 handshake_request.c_str(), 232 handshake_request.size())); 233 std::string handshake_response = EncodeHandshakeResponse(); 234 ReadList read_list(1, net::MockRead(net::ASYNC, 235 handshake_response.c_str(), 236 handshake_response.size())); 237 BuildSocket(read_list, write_list); 238 239 ScopedMessage received_message; 240 Connect(&received_message); 241 EXPECT_FALSE(connection_handler()->CanSendMessage()); 242 WaitForMessage(); // The login send. 243 WaitForMessage(); // The login response. 244 ASSERT_TRUE(received_message.get()); 245 EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString()); 246 EXPECT_TRUE(connection_handler()->CanSendMessage()); 247} 248 249// Simulate the handshake response returning an older version. Initialization 250// should fail. 251TEST_F(GCMConnectionHandlerImplTest, InitFailedVersionCheck) { 252 std::string handshake_request = EncodeHandshakeRequest(); 253 WriteList write_list(1, net::MockWrite(net::ASYNC, 254 handshake_request.c_str(), 255 handshake_request.size())); 256 std::string handshake_response = EncodeHandshakeResponse(); 257 // Overwrite the version byte. 258 handshake_response[0] = 37; 259 ReadList read_list(1, net::MockRead(net::ASYNC, 260 handshake_response.c_str(), 261 handshake_response.size())); 262 BuildSocket(read_list, write_list); 263 264 ScopedMessage received_message; 265 Connect(&received_message); 266 WaitForMessage(); // The login send. 267 WaitForMessage(); // The login response. Should result in a connection error. 268 EXPECT_FALSE(received_message.get()); 269 EXPECT_FALSE(connection_handler()->CanSendMessage()); 270 EXPECT_EQ(net::ERR_FAILED, last_error()); 271} 272 273// Attempt to initialize, but receive no server response, resulting in a time 274// out. 275TEST_F(GCMConnectionHandlerImplTest, InitTimeout) { 276 std::string handshake_request = EncodeHandshakeRequest(); 277 WriteList write_list(1, net::MockWrite(net::ASYNC, 278 handshake_request.c_str(), 279 handshake_request.size())); 280 ReadList read_list(1, net::MockRead(net::SYNCHRONOUS, 281 net::ERR_IO_PENDING)); 282 BuildSocket(read_list, write_list); 283 284 ScopedMessage received_message; 285 Connect(&received_message); 286 WaitForMessage(); // The login send. 287 WaitForMessage(); // The login response. Should result in a connection error. 288 EXPECT_FALSE(received_message.get()); 289 EXPECT_FALSE(connection_handler()->CanSendMessage()); 290 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); 291} 292 293// Attempt to initialize, but receive an incomplete server response, resulting 294// in a time out. 295TEST_F(GCMConnectionHandlerImplTest, InitIncompleteTimeout) { 296 std::string handshake_request = EncodeHandshakeRequest(); 297 WriteList write_list(1, net::MockWrite(net::ASYNC, 298 handshake_request.c_str(), 299 handshake_request.size())); 300 std::string handshake_response = EncodeHandshakeResponse(); 301 ReadList read_list; 302 read_list.push_back(net::MockRead(net::ASYNC, 303 handshake_response.c_str(), 304 handshake_response.size() / 2)); 305 read_list.push_back(net::MockRead(net::SYNCHRONOUS, 306 net::ERR_IO_PENDING)); 307 BuildSocket(read_list, write_list); 308 309 ScopedMessage received_message; 310 Connect(&received_message); 311 WaitForMessage(); // The login send. 312 WaitForMessage(); // The login response. Should result in a connection error. 313 EXPECT_FALSE(received_message.get()); 314 EXPECT_FALSE(connection_handler()->CanSendMessage()); 315 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); 316} 317 318// Reinitialize the connection handler after failing to initialize. 319TEST_F(GCMConnectionHandlerImplTest, ReInit) { 320 std::string handshake_request = EncodeHandshakeRequest(); 321 WriteList write_list(1, net::MockWrite(net::ASYNC, 322 handshake_request.c_str(), 323 handshake_request.size())); 324 ReadList read_list(1, net::MockRead(net::SYNCHRONOUS, 325 net::ERR_IO_PENDING)); 326 BuildSocket(read_list, write_list); 327 328 ScopedMessage received_message; 329 Connect(&received_message); 330 WaitForMessage(); // The login send. 331 WaitForMessage(); // The login response. Should result in a connection error. 332 EXPECT_FALSE(received_message.get()); 333 EXPECT_FALSE(connection_handler()->CanSendMessage()); 334 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); 335 336 // Build a new socket and reconnect, successfully this time. 337 std::string handshake_response = EncodeHandshakeResponse(); 338 read_list[0] = net::MockRead(net::ASYNC, 339 handshake_response.c_str(), 340 handshake_response.size()); 341 BuildSocket(read_list, write_list); 342 Connect(&received_message); 343 EXPECT_FALSE(connection_handler()->CanSendMessage()); 344 WaitForMessage(); // The login send. 345 WaitForMessage(); // The login response. 346 ASSERT_TRUE(received_message.get()); 347 EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString()); 348 EXPECT_TRUE(connection_handler()->CanSendMessage()); 349} 350 351// Verify that messages can be received after initialization. 352TEST_F(GCMConnectionHandlerImplTest, RecvMsg) { 353 std::string handshake_request = EncodeHandshakeRequest(); 354 WriteList write_list(1, net::MockWrite(net::ASYNC, 355 handshake_request.c_str(), 356 handshake_request.size())); 357 std::string handshake_response = EncodeHandshakeResponse(); 358 359 std::string data_message_proto = BuildDataMessage(kDataMsgFrom, 360 kDataMsgCategory); 361 std::string data_message_pkt = 362 EncodePacket(kDataMessageStanzaTag, data_message_proto); 363 ReadList read_list; 364 read_list.push_back(net::MockRead(net::ASYNC, 365 handshake_response.c_str(), 366 handshake_response.size())); 367 read_list.push_back(net::MockRead(net::ASYNC, 368 data_message_pkt.c_str(), 369 data_message_pkt.size())); 370 BuildSocket(read_list, write_list); 371 372 ScopedMessage received_message; 373 Connect(&received_message); 374 WaitForMessage(); // The login send. 375 WaitForMessage(); // The login response. 376 WaitForMessage(); // The data message. 377 ASSERT_TRUE(received_message.get()); 378 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); 379} 380 381// Verify that if two messages arrive at once, they're treated appropriately. 382TEST_F(GCMConnectionHandlerImplTest, Recv2Msgs) { 383 std::string handshake_request = EncodeHandshakeRequest(); 384 WriteList write_list(1, net::MockWrite(net::ASYNC, 385 handshake_request.c_str(), 386 handshake_request.size())); 387 std::string handshake_response = EncodeHandshakeResponse(); 388 389 std::string data_message_proto = BuildDataMessage(kDataMsgFrom, 390 kDataMsgCategory); 391 std::string data_message_proto2 = BuildDataMessage(kDataMsgFrom2, 392 kDataMsgCategory2); 393 std::string data_message_pkt = 394 EncodePacket(kDataMessageStanzaTag, data_message_proto); 395 data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2); 396 ReadList read_list; 397 read_list.push_back(net::MockRead(net::ASYNC, 398 handshake_response.c_str(), 399 handshake_response.size())); 400 read_list.push_back(net::MockRead(net::SYNCHRONOUS, 401 data_message_pkt.c_str(), 402 data_message_pkt.size())); 403 BuildSocket(read_list, write_list); 404 405 ScopedMessage received_message; 406 Connect(&received_message); 407 WaitForMessage(); // The login send. 408 WaitForMessage(); // The login response. 409 WaitForMessage(); // The first data message. 410 ASSERT_TRUE(received_message.get()); 411 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); 412 received_message.reset(); 413 WaitForMessage(); // The second data message. 414 ASSERT_TRUE(received_message.get()); 415 EXPECT_EQ(data_message_proto2, received_message->SerializeAsString()); 416} 417 418// Receive a long (>128 bytes) message. 419TEST_F(GCMConnectionHandlerImplTest, RecvLongMsg) { 420 std::string handshake_request = EncodeHandshakeRequest(); 421 WriteList write_list(1, net::MockWrite(net::ASYNC, 422 handshake_request.c_str(), 423 handshake_request.size())); 424 std::string handshake_response = EncodeHandshakeResponse(); 425 426 std::string data_message_proto = 427 BuildDataMessage(kDataMsgFromLong, kDataMsgCategoryLong); 428 std::string data_message_pkt = 429 EncodePacket(kDataMessageStanzaTag, data_message_proto); 430 DCHECK_GT(data_message_pkt.size(), 128U); 431 ReadList read_list; 432 read_list.push_back(net::MockRead(net::ASYNC, 433 handshake_response.c_str(), 434 handshake_response.size())); 435 read_list.push_back(net::MockRead(net::ASYNC, 436 data_message_pkt.c_str(), 437 data_message_pkt.size())); 438 BuildSocket(read_list, write_list); 439 440 ScopedMessage received_message; 441 Connect(&received_message); 442 WaitForMessage(); // The login send. 443 WaitForMessage(); // The login response. 444 WaitForMessage(); // The data message. 445 ASSERT_TRUE(received_message.get()); 446 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); 447} 448 449// Receive two long (>128 bytes) message. 450TEST_F(GCMConnectionHandlerImplTest, Recv2LongMsgs) { 451 std::string handshake_request = EncodeHandshakeRequest(); 452 WriteList write_list(1, net::MockWrite(net::ASYNC, 453 handshake_request.c_str(), 454 handshake_request.size())); 455 std::string handshake_response = EncodeHandshakeResponse(); 456 457 std::string data_message_proto = 458 BuildDataMessage(kDataMsgFromLong, kDataMsgCategoryLong); 459 std::string data_message_proto2 = 460 BuildDataMessage(kDataMsgFromLong2, kDataMsgCategoryLong2); 461 std::string data_message_pkt = 462 EncodePacket(kDataMessageStanzaTag, data_message_proto); 463 data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2); 464 DCHECK_GT(data_message_pkt.size(), 256U); 465 ReadList read_list; 466 read_list.push_back(net::MockRead(net::ASYNC, 467 handshake_response.c_str(), 468 handshake_response.size())); 469 read_list.push_back(net::MockRead(net::SYNCHRONOUS, 470 data_message_pkt.c_str(), 471 data_message_pkt.size())); 472 BuildSocket(read_list, write_list); 473 474 ScopedMessage received_message; 475 Connect(&received_message); 476 WaitForMessage(); // The login send. 477 WaitForMessage(); // The login response. 478 WaitForMessage(); // The first data message. 479 ASSERT_TRUE(received_message.get()); 480 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); 481 received_message.reset(); 482 WaitForMessage(); // The second data message. 483 ASSERT_TRUE(received_message.get()); 484 EXPECT_EQ(data_message_proto2, received_message->SerializeAsString()); 485} 486 487// Simulate a message where the end of the data does not arrive in time and the 488// read times out. 489TEST_F(GCMConnectionHandlerImplTest, ReadTimeout) { 490 std::string handshake_request = EncodeHandshakeRequest(); 491 WriteList write_list(1, net::MockWrite(net::ASYNC, 492 handshake_request.c_str(), 493 handshake_request.size())); 494 std::string handshake_response = EncodeHandshakeResponse(); 495 496 std::string data_message_proto = BuildDataMessage(kDataMsgFrom, 497 kDataMsgCategory); 498 std::string data_message_pkt = 499 EncodePacket(kDataMessageStanzaTag, data_message_proto); 500 int bytes_in_first_message = data_message_pkt.size() / 2; 501 ReadList read_list; 502 read_list.push_back(net::MockRead(net::ASYNC, 503 handshake_response.c_str(), 504 handshake_response.size())); 505 read_list.push_back(net::MockRead(net::ASYNC, 506 data_message_pkt.c_str(), 507 bytes_in_first_message)); 508 read_list.push_back(net::MockRead(net::SYNCHRONOUS, 509 net::ERR_IO_PENDING)); 510 read_list.push_back(net::MockRead(net::ASYNC, 511 data_message_pkt.c_str() + 512 bytes_in_first_message, 513 data_message_pkt.size() - 514 bytes_in_first_message)); 515 BuildSocket(read_list, write_list); 516 517 ScopedMessage received_message; 518 Connect(&received_message); 519 WaitForMessage(); // The login send. 520 WaitForMessage(); // The login response. 521 received_message.reset(); 522 WaitForMessage(); // Should time out. 523 EXPECT_FALSE(received_message.get()); 524 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); 525 EXPECT_FALSE(connection_handler()->CanSendMessage()); 526 527 // Finish the socket read. Should have no effect. 528 data_provider()->ForceNextRead(); 529} 530 531// Receive a message with zero data bytes. 532TEST_F(GCMConnectionHandlerImplTest, RecvMsgNoData) { 533 std::string handshake_request = EncodeHandshakeRequest(); 534 WriteList write_list(1, net::MockWrite(net::ASYNC, 535 handshake_request.c_str(), 536 handshake_request.size())); 537 std::string handshake_response = EncodeHandshakeResponse(); 538 539 std::string data_message_pkt = EncodePacket(kHeartbeatPingTag, ""); 540 ASSERT_EQ(data_message_pkt.size(), 2U); 541 ReadList read_list; 542 read_list.push_back(net::MockRead(net::ASYNC, 543 handshake_response.c_str(), 544 handshake_response.size())); 545 read_list.push_back(net::MockRead(net::ASYNC, 546 data_message_pkt.c_str(), 547 data_message_pkt.size())); 548 BuildSocket(read_list, write_list); 549 550 ScopedMessage received_message; 551 Connect(&received_message); 552 WaitForMessage(); // The login send. 553 WaitForMessage(); // The login response. 554 received_message.reset(); 555 WaitForMessage(); // The heartbeat ping. 556 EXPECT_TRUE(received_message.get()); 557 EXPECT_EQ(GetMCSProtoTag(*received_message), kHeartbeatPingTag); 558 EXPECT_EQ(net::OK, last_error()); 559 EXPECT_TRUE(connection_handler()->CanSendMessage()); 560} 561 562// Send a message after performing the handshake. 563TEST_F(GCMConnectionHandlerImplTest, SendMsg) { 564 mcs_proto::DataMessageStanza data_message; 565 data_message.set_from(kDataMsgFrom); 566 data_message.set_category(kDataMsgCategory); 567 std::string handshake_request = EncodeHandshakeRequest(); 568 std::string data_message_pkt = 569 EncodePacket(kDataMessageStanzaTag, data_message.SerializeAsString()); 570 WriteList write_list; 571 write_list.push_back(net::MockWrite(net::ASYNC, 572 handshake_request.c_str(), 573 handshake_request.size())); 574 write_list.push_back(net::MockWrite(net::ASYNC, 575 data_message_pkt.c_str(), 576 data_message_pkt.size())); 577 std::string handshake_response = EncodeHandshakeResponse(); 578 ReadList read_list; 579 read_list.push_back(net::MockRead(net::ASYNC, 580 handshake_response.c_str(), 581 handshake_response.size())); 582 read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)); 583 BuildSocket(read_list, write_list); 584 585 ScopedMessage received_message; 586 Connect(&received_message); 587 WaitForMessage(); // The login send. 588 WaitForMessage(); // The login response. 589 EXPECT_TRUE(connection_handler()->CanSendMessage()); 590 connection_handler()->SendMessage(data_message); 591 EXPECT_FALSE(connection_handler()->CanSendMessage()); 592 WaitForMessage(); // The message send. 593 EXPECT_TRUE(connection_handler()->CanSendMessage()); 594} 595 596// Attempt to send a message after the socket is disconnected due to a timeout. 597TEST_F(GCMConnectionHandlerImplTest, SendMsgSocketDisconnected) { 598 std::string handshake_request = EncodeHandshakeRequest(); 599 WriteList write_list; 600 write_list.push_back(net::MockWrite(net::ASYNC, 601 handshake_request.c_str(), 602 handshake_request.size())); 603 std::string handshake_response = EncodeHandshakeResponse(); 604 ReadList read_list; 605 read_list.push_back(net::MockRead(net::ASYNC, 606 handshake_response.c_str(), 607 handshake_response.size())); 608 read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)); 609 net::StreamSocket* socket = BuildSocket(read_list, write_list); 610 611 ScopedMessage received_message; 612 Connect(&received_message); 613 WaitForMessage(); // The login send. 614 WaitForMessage(); // The login response. 615 EXPECT_TRUE(connection_handler()->CanSendMessage()); 616 socket->Disconnect(); 617 mcs_proto::DataMessageStanza data_message; 618 data_message.set_from(kDataMsgFrom); 619 data_message.set_category(kDataMsgCategory); 620 connection_handler()->SendMessage(data_message); 621 EXPECT_FALSE(connection_handler()->CanSendMessage()); 622 WaitForMessage(); // The message send. Should result in an error 623 EXPECT_FALSE(connection_handler()->CanSendMessage()); 624 EXPECT_EQ(net::ERR_CONNECTION_CLOSED, last_error()); 625} 626 627} // namespace 628} // namespace gcm 629