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