Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / google_apis / gcm / engine / mcs_client_unittest.cc
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/mcs_client.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/test/simple_test_clock.h"
16 #include "base/timer/timer.h"
17 #include "google_apis/gcm/base/fake_encryptor.h"
18 #include "google_apis/gcm/base/mcs_util.h"
19 #include "google_apis/gcm/engine/fake_connection_factory.h"
20 #include "google_apis/gcm/engine/fake_connection_handler.h"
21 #include "google_apis/gcm/engine/gcm_store_impl.h"
22 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace gcm {
26
27 namespace {
28
29 const uint64 kAndroidId = 54321;
30 const uint64 kSecurityToken = 12345;
31
32 // Number of messages to send when testing batching.
33 // Note: must be even for tests that split batches in half.
34 const int kMessageBatchSize = 6;
35
36 // The number of unacked messages the client will receive before sending a
37 // stream ack.
38 // TODO(zea): get this (and other constants) directly from the mcs client.
39 const int kAckLimitSize = 10;
40
41 // TTL value for reliable messages.
42 const int kTTLValue = 5 * 60;  // 5 minutes.
43
44 // Helper for building arbitrary data messages.
45 MCSMessage BuildDataMessage(const std::string& from,
46                             const std::string& category,
47                             const std::string& message_id,
48                             int last_stream_id_received,
49                             const std::string& persistent_id,
50                             int ttl,
51                             uint64 sent,
52                             int queued,
53                             const std::string& token,
54                             const uint64& user_id) {
55   mcs_proto::DataMessageStanza data_message;
56   data_message.set_id(message_id);
57   data_message.set_from(from);
58   data_message.set_category(category);
59   data_message.set_last_stream_id_received(last_stream_id_received);
60   if (!persistent_id.empty())
61     data_message.set_persistent_id(persistent_id);
62   data_message.set_ttl(ttl);
63   data_message.set_sent(sent);
64   data_message.set_queued(queued);
65   data_message.set_token(token);
66   data_message.set_device_user_id(user_id);
67   return MCSMessage(kDataMessageStanzaTag, data_message);
68 }
69
70 // MCSClient with overriden exposed persistent id logic.
71 class TestMCSClient : public MCSClient {
72  public:
73   TestMCSClient(base::Clock* clock,
74                 ConnectionFactory* connection_factory,
75                 GCMStore* gcm_store,
76                 gcm::GCMStatsRecorder* recorder)
77     : MCSClient("", clock, connection_factory, gcm_store, recorder,
78                 make_scoped_ptr(new base::Timer(true, false))),
79       next_id_(0) {
80   }
81
82   std::string GetNextPersistentId() override {
83     return base::UintToString(++next_id_);
84   }
85
86  private:
87   uint32 next_id_;
88 };
89
90 class MCSClientTest : public testing::Test {
91  public:
92   MCSClientTest();
93   virtual ~MCSClientTest();
94
95   virtual void SetUp() override;
96
97   void BuildMCSClient();
98   void InitializeClient();
99   void StoreCredentials();
100   void LoginClient(const std::vector<std::string>& acknowledged_ids);
101
102   base::SimpleTestClock* clock() { return &clock_; }
103   TestMCSClient* mcs_client() const { return mcs_client_.get(); }
104   FakeConnectionFactory* connection_factory() {
105     return &connection_factory_;
106   }
107   bool init_success() const { return init_success_; }
108   uint64 restored_android_id() const { return restored_android_id_; }
109   uint64 restored_security_token() const { return restored_security_token_; }
110   MCSMessage* received_message() const { return received_message_.get(); }
111   std::string sent_message_id() const { return sent_message_id_;}
112   MCSClient::MessageSendStatus message_send_status() const {
113     return message_send_status_;
114   }
115
116   void SetDeviceCredentialsCallback(bool success);
117
118   FakeConnectionHandler* GetFakeHandler() const;
119
120   void WaitForMCSEvent();
121   void PumpLoop();
122
123  private:
124   void ErrorCallback();
125   void MessageReceivedCallback(const MCSMessage& message);
126   void MessageSentCallback(int64 user_serial_number,
127                            const std::string& app_id,
128                            const std::string& message_id,
129                            MCSClient::MessageSendStatus status);
130
131   base::SimpleTestClock clock_;
132
133   base::ScopedTempDir temp_directory_;
134   base::MessageLoop message_loop_;
135   scoped_ptr<base::RunLoop> run_loop_;
136   scoped_ptr<GCMStore> gcm_store_;
137
138   FakeConnectionFactory connection_factory_;
139   scoped_ptr<TestMCSClient> mcs_client_;
140   bool init_success_;
141   uint64 restored_android_id_;
142   uint64 restored_security_token_;
143   scoped_ptr<MCSMessage> received_message_;
144   std::string sent_message_id_;
145   MCSClient::MessageSendStatus message_send_status_;
146
147   gcm::FakeGCMStatsRecorder recorder_;
148 };
149
150 MCSClientTest::MCSClientTest()
151     : run_loop_(new base::RunLoop()),
152       init_success_(true),
153       restored_android_id_(0),
154       restored_security_token_(0),
155       message_send_status_(MCSClient::SENT) {
156   EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
157   run_loop_.reset(new base::RunLoop());
158
159   // Advance the clock to a non-zero time.
160   clock_.Advance(base::TimeDelta::FromSeconds(1));
161 }
162
163 MCSClientTest::~MCSClientTest() {}
164
165 void MCSClientTest::SetUp() {
166   testing::Test::SetUp();
167 }
168
169 void MCSClientTest::BuildMCSClient() {
170   gcm_store_.reset(new GCMStoreImpl(
171       temp_directory_.path(),
172       message_loop_.message_loop_proxy(),
173       make_scoped_ptr<Encryptor>(new FakeEncryptor)));
174   mcs_client_.reset(new TestMCSClient(&clock_,
175                                       &connection_factory_,
176                                       gcm_store_.get(),
177                                       &recorder_));
178 }
179
180 void MCSClientTest::InitializeClient() {
181   gcm_store_->Load(base::Bind(
182       &MCSClient::Initialize,
183       base::Unretained(mcs_client_.get()),
184       base::Bind(&MCSClientTest::ErrorCallback,
185                  base::Unretained(this)),
186       base::Bind(&MCSClientTest::MessageReceivedCallback,
187                  base::Unretained(this)),
188       base::Bind(&MCSClientTest::MessageSentCallback, base::Unretained(this))));
189   run_loop_->RunUntilIdle();
190   run_loop_.reset(new base::RunLoop());
191 }
192
193 void MCSClientTest::LoginClient(
194     const std::vector<std::string>& acknowledged_ids) {
195   scoped_ptr<mcs_proto::LoginRequest> login_request =
196       BuildLoginRequest(kAndroidId, kSecurityToken, "");
197   for (size_t i = 0; i < acknowledged_ids.size(); ++i)
198     login_request->add_received_persistent_id(acknowledged_ids[i]);
199   GetFakeHandler()->ExpectOutgoingMessage(
200       MCSMessage(kLoginRequestTag, login_request.Pass()));
201   mcs_client_->Login(kAndroidId, kSecurityToken);
202   run_loop_->Run();
203   run_loop_.reset(new base::RunLoop());
204 }
205
206 void MCSClientTest::StoreCredentials() {
207   gcm_store_->SetDeviceCredentials(
208       kAndroidId, kSecurityToken,
209       base::Bind(&MCSClientTest::SetDeviceCredentialsCallback,
210                  base::Unretained(this)));
211   run_loop_->Run();
212   run_loop_.reset(new base::RunLoop());
213 }
214
215 FakeConnectionHandler* MCSClientTest::GetFakeHandler() const {
216   return reinterpret_cast<FakeConnectionHandler*>(
217       connection_factory_.GetConnectionHandler());
218 }
219
220 void MCSClientTest::WaitForMCSEvent() {
221   run_loop_->Run();
222   run_loop_.reset(new base::RunLoop());
223 }
224
225 void MCSClientTest::PumpLoop() {
226   run_loop_->RunUntilIdle();
227   run_loop_.reset(new base::RunLoop());
228 }
229
230 void MCSClientTest::ErrorCallback() {
231   init_success_ = false;
232   DVLOG(1) << "Error callback invoked, killing loop.";
233   run_loop_->Quit();
234 }
235
236 void MCSClientTest::MessageReceivedCallback(const MCSMessage& message) {
237   received_message_.reset(new MCSMessage(message));
238   DVLOG(1) << "Message received callback invoked, killing loop.";
239   run_loop_->Quit();
240 }
241
242 void MCSClientTest::MessageSentCallback(int64 user_serial_number,
243                                         const std::string& app_id,
244                                         const std::string& message_id,
245                                         MCSClient::MessageSendStatus status) {
246   DVLOG(1) << "Message sent callback invoked, killing loop.";
247   sent_message_id_ = message_id;
248   message_send_status_ = status;
249   run_loop_->Quit();
250 }
251
252 void MCSClientTest::SetDeviceCredentialsCallback(bool success) {
253   ASSERT_TRUE(success);
254   run_loop_->Quit();
255 }
256
257 // Initialize a new client.
258 TEST_F(MCSClientTest, InitializeNew) {
259   BuildMCSClient();
260   InitializeClient();
261   EXPECT_TRUE(init_success());
262 }
263
264 // Initialize a new client, shut it down, then restart the client. Should
265 // reload the existing device credentials.
266 TEST_F(MCSClientTest, InitializeExisting) {
267   BuildMCSClient();
268   InitializeClient();
269   LoginClient(std::vector<std::string>());
270
271   // Rebuild the client, to reload from the GCM store.
272   StoreCredentials();
273   BuildMCSClient();
274   InitializeClient();
275   EXPECT_TRUE(init_success());
276 }
277
278 // Log in successfully to the MCS endpoint.
279 TEST_F(MCSClientTest, LoginSuccess) {
280   BuildMCSClient();
281   InitializeClient();
282   LoginClient(std::vector<std::string>());
283   EXPECT_TRUE(connection_factory()->IsEndpointReachable());
284   EXPECT_TRUE(init_success());
285   ASSERT_TRUE(received_message());
286   EXPECT_EQ(kLoginResponseTag, received_message()->tag());
287 }
288
289 // Encounter a server error during the login attempt. Should trigger a
290 // reconnect.
291 TEST_F(MCSClientTest, FailLogin) {
292   BuildMCSClient();
293   InitializeClient();
294   GetFakeHandler()->set_fail_login(true);
295   connection_factory()->set_delay_reconnect(true);
296   LoginClient(std::vector<std::string>());
297   EXPECT_FALSE(connection_factory()->IsEndpointReachable());
298   EXPECT_FALSE(init_success());
299   EXPECT_FALSE(received_message());
300   EXPECT_TRUE(connection_factory()->reconnect_pending());
301 }
302
303 // Send a message without RMQ support.
304 TEST_F(MCSClientTest, SendMessageNoRMQ) {
305   BuildMCSClient();
306   InitializeClient();
307   LoginClient(std::vector<std::string>());
308   MCSMessage message(
309       BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
310   GetFakeHandler()->ExpectOutgoingMessage(message);
311   mcs_client()->SendMessage(message);
312   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
313 }
314
315 // Send a message without RMQ support while disconnected. Message send should
316 // fail immediately, invoking callback.
317 TEST_F(MCSClientTest, SendMessageNoRMQWhileDisconnected) {
318   BuildMCSClient();
319   InitializeClient();
320
321   EXPECT_TRUE(sent_message_id().empty());
322   MCSMessage message(
323       BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
324   mcs_client()->SendMessage(message);
325
326   // Message sent callback should be invoked, but no message should actually
327   // be sent.
328   EXPECT_EQ("X", sent_message_id());
329   EXPECT_EQ(MCSClient::NO_CONNECTION_ON_ZERO_TTL, message_send_status());
330   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
331 }
332
333 // Send a message with RMQ support.
334 TEST_F(MCSClientTest, SendMessageRMQ) {
335   BuildMCSClient();
336   InitializeClient();
337   LoginClient(std::vector<std::string>());
338   MCSMessage message(BuildDataMessage(
339       "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
340   GetFakeHandler()->ExpectOutgoingMessage(message);
341   mcs_client()->SendMessage(message);
342   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
343 }
344
345 // Send a message with RMQ support while disconnected. On reconnect, the message
346 // should be resent.
347 TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
348   BuildMCSClient();
349   InitializeClient();
350   LoginClient(std::vector<std::string>());
351   GetFakeHandler()->set_fail_send(true);
352   MCSMessage message(BuildDataMessage(
353       "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
354
355   // The initial (failed) send.
356   GetFakeHandler()->ExpectOutgoingMessage(message);
357   // The login request.
358   GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(
359       kLoginRequestTag, BuildLoginRequest(kAndroidId, kSecurityToken, "")));
360   // The second (re)send.
361   MCSMessage message2(BuildDataMessage(
362       "from", "category", "X", 1, "1", kTTLValue, 1, kTTLValue - 1, "", 0));
363   GetFakeHandler()->ExpectOutgoingMessage(message2);
364   mcs_client()->SendMessage(message);
365   PumpLoop();         // Wait for the queuing to happen.
366   EXPECT_EQ(MCSClient::QUEUED, message_send_status());
367   EXPECT_EQ("X", sent_message_id());
368   EXPECT_FALSE(GetFakeHandler()->AllOutgoingMessagesReceived());
369   GetFakeHandler()->set_fail_send(false);
370   clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
371   connection_factory()->Connect();
372   WaitForMCSEvent();  // Wait for the login to finish.
373   PumpLoop();         // Wait for the send to happen.
374
375   // Receive the ack.
376   scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
377   ack->set_last_stream_id_received(2);
378   GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
379   WaitForMCSEvent();
380
381   EXPECT_EQ(MCSClient::SENT, message_send_status());
382   EXPECT_EQ("X", sent_message_id());
383   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
384 }
385
386 // Send a message with RMQ support without receiving an acknowledgement. On
387 // restart the message should be resent.
388 TEST_F(MCSClientTest, SendMessageRMQOnRestart) {
389   BuildMCSClient();
390   InitializeClient();
391   LoginClient(std::vector<std::string>());
392   GetFakeHandler()->set_fail_send(true);
393   MCSMessage message(BuildDataMessage(
394       "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
395
396   // The initial (failed) send.
397   GetFakeHandler()->ExpectOutgoingMessage(message);
398   GetFakeHandler()->set_fail_send(false);
399   mcs_client()->SendMessage(message);
400   PumpLoop();
401   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
402
403   // Rebuild the client, which should resend the old message.
404   StoreCredentials();
405   BuildMCSClient();
406   InitializeClient();
407
408   clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
409   MCSMessage message2(BuildDataMessage(
410       "from", "category", "X", 1, "1", kTTLValue, 1, kTTLValue - 1, "", 0));
411   LoginClient(std::vector<std::string>());
412   GetFakeHandler()->ExpectOutgoingMessage(message2);
413   PumpLoop();
414   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
415 }
416
417 // Send messages with RMQ support, followed by receiving a stream ack. On
418 // restart nothing should be recent.
419 TEST_F(MCSClientTest, SendMessageRMQWithStreamAck) {
420   BuildMCSClient();
421   InitializeClient();
422   LoginClient(std::vector<std::string>());
423
424   // Send some messages.
425   for (int i = 1; i <= kMessageBatchSize; ++i) {
426     MCSMessage message(BuildDataMessage("from",
427                                         "category",
428                                         "X",
429                                         1,
430                                         base::IntToString(i),
431                                         kTTLValue,
432                                         1,
433                                         0,
434                                         "",
435                                         0));
436     GetFakeHandler()->ExpectOutgoingMessage(message);
437     mcs_client()->SendMessage(message);
438     PumpLoop();
439   }
440   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
441
442   // Receive the ack.
443   scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
444   ack->set_last_stream_id_received(kMessageBatchSize + 1);
445   GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
446   WaitForMCSEvent();
447
448   // Reconnect and ensure no messages are resent.
449   StoreCredentials();
450   BuildMCSClient();
451   InitializeClient();
452   LoginClient(std::vector<std::string>());
453   PumpLoop();
454 }
455
456 // Send messages with RMQ support. On restart, receive a SelectiveAck with
457 // the login response. No messages should be resent.
458 TEST_F(MCSClientTest, SendMessageRMQAckOnReconnect) {
459   BuildMCSClient();
460   InitializeClient();
461   LoginClient(std::vector<std::string>());
462
463   // Send some messages.
464   std::vector<std::string> id_list;
465   for (int i = 1; i <= kMessageBatchSize; ++i) {
466     id_list.push_back(base::IntToString(i));
467     MCSMessage message(BuildDataMessage("from",
468                                         "category",
469                                         id_list.back(),
470                                         1,
471                                         id_list.back(),
472                                         kTTLValue,
473                                         1,
474                                         0,
475                                         "",
476                                         0));
477     GetFakeHandler()->ExpectOutgoingMessage(message);
478     mcs_client()->SendMessage(message);
479     PumpLoop();
480   }
481   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
482
483   // Rebuild the client, and receive an acknowledgment for the messages as
484   // part of the login response.
485   StoreCredentials();
486   BuildMCSClient();
487   InitializeClient();
488   LoginClient(std::vector<std::string>());
489   scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(id_list));
490   GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
491   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
492 }
493
494 // Send messages with RMQ support. On restart, receive a SelectiveAck with
495 // the login response that only acks some messages. The unacked messages should
496 // be resent.
497 TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) {
498   BuildMCSClient();
499   InitializeClient();
500   LoginClient(std::vector<std::string>());
501
502   // Send some messages.
503   std::vector<std::string> id_list;
504   for (int i = 1; i <= kMessageBatchSize; ++i) {
505     id_list.push_back(base::IntToString(i));
506     MCSMessage message(BuildDataMessage("from",
507                                         "category",
508                                         id_list.back(),
509                                         1,
510                                         id_list.back(),
511                                         kTTLValue,
512                                         1,
513                                         0,
514                                         "",
515                                         0));
516     GetFakeHandler()->ExpectOutgoingMessage(message);
517     mcs_client()->SendMessage(message);
518     PumpLoop();
519   }
520   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
521
522   // Rebuild the client, and receive an acknowledgment for the messages as
523   // part of the login response.
524   StoreCredentials();
525   BuildMCSClient();
526   InitializeClient();
527   LoginClient(std::vector<std::string>());
528
529   std::vector<std::string> acked_ids, remaining_ids;
530   acked_ids.insert(acked_ids.end(),
531                    id_list.begin(),
532                    id_list.begin() + kMessageBatchSize / 2);
533   remaining_ids.insert(remaining_ids.end(),
534                        id_list.begin() + kMessageBatchSize / 2,
535                        id_list.end());
536   for (int i = 1; i <= kMessageBatchSize / 2; ++i) {
537     MCSMessage message(BuildDataMessage("from",
538                                         "category",
539                                         remaining_ids[i - 1],
540                                         2,
541                                         remaining_ids[i - 1],
542                                         kTTLValue,
543                                         1,
544                                         0,
545                                         "",
546                                         0));
547     GetFakeHandler()->ExpectOutgoingMessage(message);
548   }
549   scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
550   GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
551   WaitForMCSEvent();
552   PumpLoop();
553   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
554 }
555
556 // Handle a selective ack that only acks some messages. The remaining unacked
557 // messages should be resent. On restart, those same unacked messages should be
558 // resent, and any pending acks for incoming messages should also be resent.
559 TEST_F(MCSClientTest, SelectiveAckMidStream) {
560   BuildMCSClient();
561   InitializeClient();
562   LoginClient(std::vector<std::string>());
563
564   // Server stream id 2 ("s1").
565   // Acks client stream id 0 (login).
566   MCSMessage sMessage1(BuildDataMessage(
567       "from", "category", "X", 0, "s1", kTTLValue, 1, 0, "", 0));
568   GetFakeHandler()->ReceiveMessage(sMessage1);
569   WaitForMCSEvent();
570   PumpLoop();
571
572   // Client stream id 1 ("1").
573   // Acks server stream id 2 ("s1").
574   MCSMessage cMessage1(BuildDataMessage(
575       "from", "category", "Y", 2, "1", kTTLValue, 1, 0, "", 0));
576   GetFakeHandler()->ExpectOutgoingMessage(cMessage1);
577   mcs_client()->SendMessage(cMessage1);
578   PumpLoop();
579   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
580
581   // Server stream id 3 ("s2").
582   // Acks client stream id 1 ("1").
583   // Confirms ack of server stream id 2 ("s1").
584   MCSMessage sMessage2(BuildDataMessage(
585       "from", "category", "X", 1, "s2", kTTLValue, 1, 0, "", 0));
586   GetFakeHandler()->ReceiveMessage(sMessage2);
587   WaitForMCSEvent();
588   PumpLoop();
589
590   // Client Stream id 2 ("2").
591   // Acks server stream id 3 ("s2").
592   MCSMessage cMessage2(BuildDataMessage(
593       "from", "category", "Y", 3, "2", kTTLValue, 1, 0, "", 0));
594   GetFakeHandler()->ExpectOutgoingMessage(cMessage2);
595   mcs_client()->SendMessage(cMessage2);
596   PumpLoop();
597   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
598
599   // Simulate the last message being dropped by having the server selectively
600   // ack client message "1".
601   // Client message "2" should be resent, acking server stream id 4 (selective
602   // ack).
603   MCSMessage cMessage3(BuildDataMessage(
604       "from", "category", "Y", 4, "2", kTTLValue, 1, 0, "", 0));
605   GetFakeHandler()->ExpectOutgoingMessage(cMessage3);
606   std::vector<std::string> acked_ids(1, "1");
607   scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
608   GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
609   WaitForMCSEvent();
610   PumpLoop();
611   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
612
613   // Rebuild the client without any further acks from server. Note that this
614   // resets the stream ids.
615   // Sever message "s2" should be acked as part of login.
616   // Client message "2" should be resent.
617   StoreCredentials();
618   BuildMCSClient();
619   InitializeClient();
620
621   acked_ids[0] = "s2";
622   LoginClient(acked_ids);
623
624   MCSMessage cMessage4(BuildDataMessage(
625       "from", "category", "Y", 1, "2", kTTLValue, 1, 0, "", 0));
626   GetFakeHandler()->ExpectOutgoingMessage(cMessage4);
627   PumpLoop();
628   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
629 }
630
631 // Receive some messages. On restart, the login request should contain the
632 // appropriate acknowledged ids.
633 TEST_F(MCSClientTest, AckOnLogin) {
634   BuildMCSClient();
635   InitializeClient();
636   LoginClient(std::vector<std::string>());
637
638   // Receive some messages.
639   std::vector<std::string> id_list;
640   for (int i = 1; i <= kMessageBatchSize; ++i) {
641     id_list.push_back(base::IntToString(i));
642     MCSMessage message(BuildDataMessage(
643         "from", "category", "X", 1, id_list.back(), kTTLValue, 1, 0, "", 0));
644     GetFakeHandler()->ReceiveMessage(message);
645     WaitForMCSEvent();
646     PumpLoop();
647   }
648
649   // Restart the client.
650   StoreCredentials();
651   BuildMCSClient();
652   InitializeClient();
653   LoginClient(id_list);
654 }
655
656 // Receive some messages. On the next send, the outgoing message should contain
657 // the appropriate last stream id received field to ack the received messages.
658 TEST_F(MCSClientTest, AckOnSend) {
659   BuildMCSClient();
660   InitializeClient();
661   LoginClient(std::vector<std::string>());
662
663   // Receive some messages.
664   std::vector<std::string> id_list;
665   for (int i = 1; i <= kMessageBatchSize; ++i) {
666     id_list.push_back(base::IntToString(i));
667     MCSMessage message(BuildDataMessage("from",
668                                         "category",
669                                         id_list.back(),
670                                         1,
671                                         id_list.back(),
672                                         kTTLValue,
673                                         1,
674                                         0,
675                                         "",
676                                         0));
677     GetFakeHandler()->ReceiveMessage(message);
678     PumpLoop();
679   }
680
681   // Trigger a message send, which should acknowledge via stream ack.
682   MCSMessage message(BuildDataMessage("from",
683                                       "category",
684                                       "X",
685                                       kMessageBatchSize + 1,
686                                       "1",
687                                       kTTLValue,
688                                       1,
689                                       0,
690                                       "",
691                                       0));
692   GetFakeHandler()->ExpectOutgoingMessage(message);
693   mcs_client()->SendMessage(message);
694   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
695 }
696
697 // Receive the ack limit in messages, which should trigger an automatic
698 // stream ack. Receive a heartbeat to confirm the ack.
699 TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) {
700   BuildMCSClient();
701   InitializeClient();
702   LoginClient(std::vector<std::string>());
703
704   // The stream ack.
705   scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
706   ack->set_last_stream_id_received(kAckLimitSize + 1);
707   GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
708
709   // Receive some messages.
710   std::vector<std::string> id_list;
711   for (int i = 1; i <= kAckLimitSize; ++i) {
712     id_list.push_back(base::IntToString(i));
713     MCSMessage message(BuildDataMessage("from",
714                                         "category",
715                                         id_list.back(),
716                                         1,
717                                         id_list.back(),
718                                         kTTLValue,
719                                         1,
720                                         0,
721                                         "",
722                                         0));
723     GetFakeHandler()->ReceiveMessage(message);
724     WaitForMCSEvent();
725     PumpLoop();
726   }
727   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
728
729   // Receive a heartbeat confirming the ack (and receive the heartbeat ack).
730   scoped_ptr<mcs_proto::HeartbeatPing> heartbeat(
731       new mcs_proto::HeartbeatPing());
732   heartbeat->set_last_stream_id_received(2);
733
734   scoped_ptr<mcs_proto::HeartbeatAck> heartbeat_ack(
735       new mcs_proto::HeartbeatAck());
736   heartbeat_ack->set_last_stream_id_received(kAckLimitSize + 2);
737   GetFakeHandler()->ExpectOutgoingMessage(
738       MCSMessage(kHeartbeatAckTag, heartbeat_ack.Pass()));
739
740   GetFakeHandler()->ReceiveMessage(
741       MCSMessage(kHeartbeatPingTag, heartbeat.Pass()));
742   PumpLoop();
743   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
744
745   // Rebuild the client. Nothing should be sent on login.
746   StoreCredentials();
747   BuildMCSClient();
748   InitializeClient();
749   LoginClient(std::vector<std::string>());
750   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
751 }
752
753 // If a message's TTL has expired by the time it reaches the front of the send
754 // queue, it should be dropped.
755 TEST_F(MCSClientTest, ExpiredTTLOnSend) {
756   BuildMCSClient();
757   InitializeClient();
758   LoginClient(std::vector<std::string>());
759   MCSMessage message(BuildDataMessage(
760       "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
761
762   // Advance time to after the TTL.
763   clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 2));
764   EXPECT_TRUE(sent_message_id().empty());
765   mcs_client()->SendMessage(message);
766
767   // No messages should be sent, but the callback should still be invoked.
768   EXPECT_EQ("X", sent_message_id());
769   EXPECT_EQ(MCSClient::TTL_EXCEEDED, message_send_status());
770   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
771 }
772
773 TEST_F(MCSClientTest, ExpiredTTLOnRestart) {
774   BuildMCSClient();
775   InitializeClient();
776   LoginClient(std::vector<std::string>());
777   GetFakeHandler()->set_fail_send(true);
778   MCSMessage message(BuildDataMessage(
779       "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
780
781   // The initial (failed) send.
782   GetFakeHandler()->ExpectOutgoingMessage(message);
783   GetFakeHandler()->set_fail_send(false);
784   mcs_client()->SendMessage(message);
785   PumpLoop();
786   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
787
788   // Move the clock forward and rebuild the client, which should fail the
789   // message send on restart.
790   clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 2));
791   StoreCredentials();
792   BuildMCSClient();
793   InitializeClient();
794   LoginClient(std::vector<std::string>());
795   PumpLoop();
796   EXPECT_EQ("X", sent_message_id());
797   EXPECT_EQ(MCSClient::TTL_EXCEEDED, message_send_status());
798   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
799 }
800
801 // Sending two messages with the same collapse key and same app id while
802 // disconnected should only send the latter of the two on reconnection.
803 TEST_F(MCSClientTest, CollapseKeysSameApp) {
804   BuildMCSClient();
805   InitializeClient();
806   MCSMessage message(BuildDataMessage(
807       "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
808   mcs_client()->SendMessage(message);
809
810   MCSMessage message2(BuildDataMessage(
811       "from", "app", "message id 2", 1, "1", kTTLValue, 1, 0, "token", 0));
812   mcs_client()->SendMessage(message2);
813
814   LoginClient(std::vector<std::string>());
815   GetFakeHandler()->ExpectOutgoingMessage(message2);
816   PumpLoop();
817 }
818
819 // Sending two messages with the same collapse key and different app id while
820 // disconnected should not perform any collapsing.
821 TEST_F(MCSClientTest, CollapseKeysDifferentApp) {
822   BuildMCSClient();
823   InitializeClient();
824   MCSMessage message(BuildDataMessage(
825       "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
826   mcs_client()->SendMessage(message);
827
828   MCSMessage message2(BuildDataMessage("from",
829                                        "app 2",
830                                        "message id 2",
831                                        1,
832                                        "2",
833                                        kTTLValue,
834                                        1,
835                                        0,
836                                        "token",
837                                        0));
838   mcs_client()->SendMessage(message2);
839
840   LoginClient(std::vector<std::string>());
841   GetFakeHandler()->ExpectOutgoingMessage(message);
842   GetFakeHandler()->ExpectOutgoingMessage(message2);
843   PumpLoop();
844 }
845
846 // Sending two messages with the same collapse key and app id, but different
847 // user, while disconnected, should not perform any collapsing.
848 TEST_F(MCSClientTest, CollapseKeysDifferentUser) {
849   BuildMCSClient();
850   InitializeClient();
851   MCSMessage message(BuildDataMessage(
852       "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
853   mcs_client()->SendMessage(message);
854
855   MCSMessage message2(BuildDataMessage("from",
856                                        "app",
857                                        "message id 2",
858                                        1,
859                                        "2",
860                                        kTTLValue,
861                                        1,
862                                        0,
863                                        "token",
864                                        1));
865   mcs_client()->SendMessage(message2);
866
867   LoginClient(std::vector<std::string>());
868   GetFakeHandler()->ExpectOutgoingMessage(message);
869   GetFakeHandler()->ExpectOutgoingMessage(message2);
870   PumpLoop();
871 }
872
873 } // namespace
874
875 }  // namespace gcm