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