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