1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright 2013 The Chromium Authors. All rights reserved.
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Use of this source code is governed by a BSD-style license that can be
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file.
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "google_apis/gcm/engine/connection_handler_impl.h"
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "base/bind.h"
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "base/memory/scoped_ptr.h"
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "base/run_loop.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "base/strings/string_number_conversions.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "base/test/test_timeouts.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "google/protobuf/io/coded_stream.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "google_apis/gcm/base/mcs_util.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "google_apis/gcm/base/socket_stream.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "google_apis/gcm/protocol/mcs.pb.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/socket/socket_test_util.h"
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/socket/stream_socket.h"
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "testing/gtest/include/gtest/gtest.h"
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comnamespace gcm {
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comnamespace {
23d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com
24d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comtypedef scoped_ptr<google::protobuf::MessageLite> ScopedMessage;
25d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comtypedef std::vector<net::MockRead> ReadList;
26d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comtypedef std::vector<net::MockWrite> WriteList;
27a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
28d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comconst uint64 kAuthId = 54321;
29d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comconst uint64 kAuthToken = 12345;
30a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst char kMCSVersion = 41;  // The protocol version.
31a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst int kMCSPort = 5228;    // The server port.
32a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst char kDataMsgFrom[] = "data_from";
33a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst char kDataMsgCategory[] = "data_category";
34d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comconst char kDataMsgFrom2[] = "data_from2";
35d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comconst char kDataMsgCategory2[] = "data_category2";
36d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comconst char kDataMsgFromLong[] =
37d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com    "this is a long from that will result in a message > 128 bytes";
38a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst char kDataMsgCategoryLong[] =
39a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    "this is a long category that will result in a message > 128 bytes";
40a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst char kDataMsgFromLong2[] =
41d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com    "this is a second long from that will result in a message > 128 bytes";
42a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.comconst char kDataMsgCategoryLong2[] =
43d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com    "this is a second long category that will result in a message > 128 bytes";
44d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comconst uint8 kInvalidTag = 100;  // An invalid tag.
45a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com
46a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com// ---- Helpers for building messages. ----
47d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com
48d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com// Encode a protobuf packet with protobuf type |tag| and serialized protobuf
49d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com// bytes |proto| into the MCS message form (tag + varint size + bytes).
50d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comstd::string EncodePacket(uint8 tag, const std::string& proto) {
51d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com  std::string result;
52ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com  google::protobuf::io::StringOutputStream string_output_stream(&result);
53ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com  {
54ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    google::protobuf::io::CodedOutputStream coded_output_stream(
55ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com      &string_output_stream);
56ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    const unsigned char tag_byte[1] = { tag };
57ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    coded_output_stream.WriteRaw(tag_byte, 1);
58ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    coded_output_stream.WriteVarint32(proto.size());
59ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    coded_output_stream.WriteRaw(proto.c_str(), proto.size());
60ba28d03e94dc221d6a803bf2a84a420b9159255cdjsollen@google.com    // ~CodedOutputStream must run before the move constructor at the
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // return statement. http://crbug.com/338962
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return result;
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Encode a handshake request into the MCS message form.
677ffb1b21abcc7bbed5a0fc711f6dd7b9dbb4f577ctguil@chromium.orgstd::string EncodeHandshakeRequest() {
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  std::string result;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const char version_byte[1] = {kMCSVersion};
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  result.append(version_byte, 1);
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ScopedMessage login_request(
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      BuildLoginRequest(kAuthId, kAuthToken, ""));
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  result.append(EncodePacket(kLoginRequestTag,
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             login_request->SerializeAsString()));
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return result;
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Build a serialized login response protobuf.
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstd::string BuildLoginResponse() {
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  std::string result;
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  mcs_proto::LoginResponse login_response;
82a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com  login_response.set_id("id");
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  result.append(login_response.SerializeAsString());
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return result;
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Encoode a handshake response into the MCS message form.
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstd::string EncodeHandshakeResponse() {
89a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com  std::string result;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const char version_byte[1] = {kMCSVersion};
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  result.append(version_byte, 1);
9254924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com  result.append(EncodePacket(kLoginResponseTag, BuildLoginResponse()));
9354924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com  return result;
9454924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com}
9554924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com
9654924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com// Build a serialized data message stanza protobuf.
97d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comstd::string BuildDataMessage(const std::string& from,
98d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com                             const std::string& category) {
99d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com  std::string result;
100d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com  mcs_proto::DataMessageStanza data_message;
101d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com  data_message.set_from(from);
1029d0c6ecb8440e8e546881a4ff850eb6333f24541caryclark@google.com  data_message.set_category(category);
1039d0c6ecb8440e8e546881a4ff850eb6333f24541caryclark@google.com  return data_message.SerializeAsString();
10454924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com}
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass GCMConnectionHandlerImplTest : public testing::Test {
107f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com public:
108f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com  GCMConnectionHandlerImplTest();
109f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com  virtual ~GCMConnectionHandlerImplTest();
110f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com
111f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com  net::StreamSocket* BuildSocket(const ReadList& read_list,
112f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com                                 const WriteList& write_list);
113f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com
114f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com  // Pump |message_loop_|, resetting |run_loop_| after completion.
115f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com  void PumpLoop();
116f2eb5ab7806a62e89b8cb572b1b33b70b83b13abreed@google.com
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ConnectionHandlerImpl* connection_handler() {
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return connection_handler_.get();
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  base::MessageLoop* message_loop() { return &message_loop_; };
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  net::DelayedSocketData* data_provider() { return data_provider_.get(); }
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int last_error() const { return last_error_; }
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Initialize the connection handler, setting |dst_proto| as the destination
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // for any received messages.
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void Connect(ScopedMessage* dst_proto);
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Runs the message loop until a message is received.
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void WaitForMessage();
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private:
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void ReadContinuation(ScopedMessage* dst_proto, ScopedMessage new_proto);
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void WriteContinuation();
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void ConnectionContinuation(int error);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // SocketStreams and their data provider.
1376bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  ReadList mock_reads_;
1386bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  WriteList mock_writes_;
1396bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  scoped_ptr<net::DelayedSocketData> data_provider_;
1406bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
1416bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  // The connection handler being tested.
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<ConnectionHandlerImpl> connection_handler_;
1436bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // The last connection error received.
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int last_error_;
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1476bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  // net:: components.
1486bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  scoped_ptr<net::StreamSocket> socket_;
1496bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  net::MockClientSocketFactory socket_factory_;
1506bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  net::AddressList address_list_;
1516bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
1526bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  base::MessageLoopForIO message_loop_;
1536bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  scoped_ptr<base::RunLoop> run_loop_;
1546bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com};
1556bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
1566bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.comGCMConnectionHandlerImplTest::GCMConnectionHandlerImplTest()
1576bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  : last_error_(0) {
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  net::IPAddressNumber ip_number;
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  net::ParseIPLiteralToNumber("127.0.0.1", &ip_number);
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  address_list_ = net::AddressList::CreateFromIPAddress(ip_number, kMCSPort);
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comGCMConnectionHandlerImplTest::~GCMConnectionHandlerImplTest() {
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comnet::StreamSocket* GCMConnectionHandlerImplTest::BuildSocket(
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const ReadList& read_list,
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const WriteList& write_list) {
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  mock_reads_ = read_list;
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  mock_writes_ = write_list;
1716bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  data_provider_.reset(
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new net::DelayedSocketData(0,
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                 &(mock_reads_[0]), mock_reads_.size(),
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                 &(mock_writes_[0]), mock_writes_.size()));
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  socket_factory_.AddSocketDataProvider(data_provider_.get());
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  socket_ = socket_factory_.CreateTransportClientSocket(
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      address_list_, NULL, net::NetLog::Source());
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  socket_->Connect(net::CompletionCallback());
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  run_loop_.reset(new base::RunLoop());
182e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org  PumpLoop();
183e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org
184e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org  DCHECK(socket_->IsConnected());
185e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org  return socket_.get();
186e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org}
187e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid GCMConnectionHandlerImplTest::PumpLoop() {
189e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org  run_loop_->RunUntilIdle();
190e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org  run_loop_.reset(new base::RunLoop());
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid GCMConnectionHandlerImplTest::Connect(
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ScopedMessage* dst_proto) {
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  connection_handler_.reset(new ConnectionHandlerImpl(
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      TestTimeouts::tiny_timeout(),
197e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org          base::Bind(&GCMConnectionHandlerImplTest::ReadContinuation,
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     base::Unretained(this),
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     dst_proto),
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          base::Bind(&GCMConnectionHandlerImplTest::WriteContinuation,
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     base::Unretained(this)),
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          base::Bind(&GCMConnectionHandlerImplTest::ConnectionContinuation,
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     base::Unretained(this))));
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(connection_handler()->CanSendMessage());
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  connection_handler_->Init(
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      *BuildLoginRequest(kAuthId, kAuthToken, ""),
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      socket_.get());
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
209e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org
210e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.orgvoid GCMConnectionHandlerImplTest::ReadContinuation(
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ScopedMessage* dst_proto,
212e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org    ScopedMessage new_proto) {
213e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org  *dst_proto = new_proto.Pass();
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  run_loop_->Quit();
215e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org}
216e9e08cc7b29f97ee9e823e68c3daf0f55c84b21amike@reedtribe.org
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid GCMConnectionHandlerImplTest::WaitForMessage() {
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  run_loop_->Run();
2196bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  run_loop_.reset(new base::RunLoop());
2206bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com}
2216bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
2226bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.comvoid GCMConnectionHandlerImplTest::WriteContinuation() {
2236bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  run_loop_->Quit();
2246bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com}
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2266bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.comvoid GCMConnectionHandlerImplTest::ConnectionContinuation(int error) {
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  last_error_ = error;
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  run_loop_->Quit();
2296bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com}
2306bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
2316bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com// Initialize the connection handler and ensure the handshake completes
2326bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com// successfully.
2336bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.comTEST_F(GCMConnectionHandlerImplTest, Init) {
2346bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  std::string handshake_request = EncodeHandshakeRequest();
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  WriteList write_list(1, net::MockWrite(net::ASYNC,
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                         handshake_request.c_str(),
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                         handshake_request.size()));
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  std::string handshake_response = EncodeHandshakeResponse();
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ReadList read_list(1, net::MockRead(net::ASYNC,
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                      handshake_response.c_str(),
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                      handshake_response.size()));
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  BuildSocket(read_list, write_list);
2436bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
2446bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  ScopedMessage received_message;
2456bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  Connect(&received_message);
2466bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com  EXPECT_FALSE(connection_handler()->CanSendMessage());
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  WaitForMessage();  // The login send.
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  WaitForMessage();  // The login response.
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(received_message.get());
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString());
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(connection_handler()->CanSendMessage());
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
253
254// Simulate the handshake response returning an older version. Initialization
255// should fail.
256TEST_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);
268
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());
276}
277
278// Attempt to initialize, but receive no server response, resulting in a time
279// out.
280TEST_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);
288
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());
296}
297
298// Attempt to initialize, but receive an incomplete server response, resulting
299// in a time out.
300TEST_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();
306  ReadList read_list;
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);
313
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());
321}
322
323// Reinitialize the connection handler after failing to initialize.
324TEST_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);
332
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());
340
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());
354}
355
356// Verify that messages can be received after initialization.
357TEST_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();
363
364  std::string data_message_proto = BuildDataMessage(kDataMsgFrom,
365                                                    kDataMsgCategory);
366  std::string data_message_pkt =
367      EncodePacket(kDataMessageStanzaTag, data_message_proto);
368  ReadList read_list;
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);
376
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());
385}
386
387// Verify that if two messages arrive at once, they're treated appropriately.
388TEST_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();
394
395  std::string data_message_proto = BuildDataMessage(kDataMsgFrom,
396                                                    kDataMsgCategory);
397  std::string data_message_proto2 = BuildDataMessage(kDataMsgFrom2,
398                                                     kDataMsgCategory2);
399  std::string data_message_pkt =
400      EncodePacket(kDataMessageStanzaTag, data_message_proto);
401  data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2);
402  ReadList read_list;
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);
410
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());
423}
424
425// Receive a long (>128 bytes) message.
426TEST_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();
432
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);
438  ReadList read_list;
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);
446
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());
455}
456
457// Receive a long (>128 bytes) message in two synchronous parts.
458TEST_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();
464
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);
470  ReadList read_list;
471  read_list.push_back(net::MockRead(net::ASYNC,
472                                    handshake_response.c_str(),
473                                    handshake_response.size()));
474
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);
485
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());
494}
495
496// Receive two long (>128 bytes) message.
497TEST_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();
503
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);
512  ReadList read_list;
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);
520
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());
533}
534
535// Simulate a message where the end of the data does not arrive in time and the
536// read times out.
537TEST_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();
543
544  std::string data_message_proto = BuildDataMessage(kDataMsgFrom,
545                                                    kDataMsgCategory);
546  std::string data_message_pkt =
547      EncodePacket(kDataMessageStanzaTag, data_message_proto);
548  int bytes_in_first_message = data_message_pkt.size() / 2;
549  ReadList read_list;
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);
564
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());
574
575  // Finish the socket read. Should have no effect.
576  data_provider()->ForceNextRead();
577}
578
579// Receive a message with zero data bytes.
580TEST_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();
586
587  std::string data_message_pkt = EncodePacket(kHeartbeatPingTag, "");
588  ASSERT_EQ(data_message_pkt.size(), 2U);
589  ReadList read_list;
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);
597
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());
608}
609
610// Send a message after performing the handshake.
611TEST_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();
626  ReadList read_list;
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);
632
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());
642}
643
644// Attempt to send a message after the socket is disconnected due to a timeout.
645TEST_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();
652  ReadList read_list;
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);
658
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());
673}
674
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.
677TEST_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();
683
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);
688  ReadList read_list;
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);
696
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());
705}
706
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.
709TEST_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();
715
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);
721  ReadList read_list;
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);
729
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());
738}
739
740// Make sure a message with an invalid tag is handled gracefully and resets
741// the connection with an invalid argument error.
742TEST_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();
748
749  std::string invalid_message = "0";
750  std::string invalid_message_pkt =
751      EncodePacket(kInvalidTag, invalid_message);
752  ReadList read_list;
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);
760
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());
769}
770
771// Receive a message where the size field spans two socket reads.
772TEST_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();
778
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);
784  ReadList read_list;
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(),
791                                    2));
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);
797
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());
806}
807
808}  // namespace
809}  // namespace gcm
810