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