Home | History | Annotate | Download | only in engine
      1 // Copyright 2014 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/gcm_store_impl.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/files/file_path.h"
     13 #include "base/files/scoped_temp_dir.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/run_loop.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "google_apis/gcm/base/fake_encryptor.h"
     19 #include "google_apis/gcm/base/mcs_message.h"
     20 #include "google_apis/gcm/base/mcs_util.h"
     21 #include "google_apis/gcm/protocol/mcs.pb.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 
     24 namespace gcm {
     25 
     26 namespace {
     27 
     28 // Number of persistent ids to use in tests.
     29 const int kNumPersistentIds = 10;
     30 
     31 // Number of per-app messages in tests.
     32 const int kNumMessagesPerApp = 20;
     33 
     34 // App name for testing.
     35 const char kAppName[] = "my_app";
     36 
     37 // Category name for testing.
     38 const char kCategoryName[] = "my_category";
     39 
     40 const uint64 kDeviceId = 22;
     41 const uint64 kDeviceToken = 55;
     42 
     43 class GCMStoreImplTest : public testing::Test {
     44  public:
     45   GCMStoreImplTest();
     46   virtual ~GCMStoreImplTest();
     47 
     48   virtual void SetUp() OVERRIDE;
     49 
     50   scoped_ptr<GCMStore> BuildGCMStore();
     51 
     52   std::string GetNextPersistentId();
     53 
     54   void PumpLoop();
     55 
     56   void LoadCallback(scoped_ptr<GCMStore::LoadResult>* result_dst,
     57                     scoped_ptr<GCMStore::LoadResult> result);
     58   void UpdateCallback(bool success);
     59 
     60  protected:
     61   base::MessageLoop message_loop_;
     62   base::ScopedTempDir temp_directory_;
     63   bool expected_success_;
     64   uint64 next_persistent_id_;
     65   scoped_ptr<base::RunLoop> run_loop_;
     66 };
     67 
     68 GCMStoreImplTest::GCMStoreImplTest()
     69     : expected_success_(true),
     70       next_persistent_id_(base::Time::Now().ToInternalValue()) {
     71   EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
     72   run_loop_.reset(new base::RunLoop());
     73 }
     74 
     75 GCMStoreImplTest::~GCMStoreImplTest() {}
     76 
     77 void GCMStoreImplTest::SetUp() {
     78   testing::Test::SetUp();
     79 }
     80 
     81 scoped_ptr<GCMStore> GCMStoreImplTest::BuildGCMStore() {
     82   return scoped_ptr<GCMStore>(new GCMStoreImpl(
     83       temp_directory_.path(),
     84       message_loop_.message_loop_proxy(),
     85       make_scoped_ptr<Encryptor>(new FakeEncryptor)));
     86 }
     87 
     88 std::string GCMStoreImplTest::GetNextPersistentId() {
     89   return base::Uint64ToString(next_persistent_id_++);
     90 }
     91 
     92 void GCMStoreImplTest::PumpLoop() { message_loop_.RunUntilIdle(); }
     93 
     94 void GCMStoreImplTest::LoadCallback(
     95     scoped_ptr<GCMStore::LoadResult>* result_dst,
     96     scoped_ptr<GCMStore::LoadResult> result) {
     97   ASSERT_TRUE(result->success);
     98   *result_dst = result.Pass();
     99   run_loop_->Quit();
    100   run_loop_.reset(new base::RunLoop());
    101 }
    102 
    103 void GCMStoreImplTest::UpdateCallback(bool success) {
    104   ASSERT_EQ(expected_success_, success);
    105 }
    106 
    107 // Verify creating a new database and loading it.
    108 TEST_F(GCMStoreImplTest, LoadNew) {
    109   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    110   scoped_ptr<GCMStore::LoadResult> load_result;
    111   gcm_store->Load(base::Bind(
    112       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    113   PumpLoop();
    114 
    115   EXPECT_EQ(0U, load_result->device_android_id);
    116   EXPECT_EQ(0U, load_result->device_security_token);
    117   EXPECT_TRUE(load_result->incoming_messages.empty());
    118   EXPECT_TRUE(load_result->outgoing_messages.empty());
    119   EXPECT_TRUE(load_result->gservices_settings.empty());
    120   EXPECT_EQ(base::Time::FromInternalValue(0LL), load_result->last_checkin_time);
    121 }
    122 
    123 TEST_F(GCMStoreImplTest, DeviceCredentials) {
    124   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    125   scoped_ptr<GCMStore::LoadResult> load_result;
    126   gcm_store->Load(base::Bind(
    127       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    128   PumpLoop();
    129 
    130   gcm_store->SetDeviceCredentials(
    131       kDeviceId,
    132       kDeviceToken,
    133       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    134   PumpLoop();
    135 
    136   gcm_store = BuildGCMStore().Pass();
    137   gcm_store->Load(base::Bind(
    138       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    139   PumpLoop();
    140 
    141   ASSERT_EQ(kDeviceId, load_result->device_android_id);
    142   ASSERT_EQ(kDeviceToken, load_result->device_security_token);
    143 }
    144 
    145 TEST_F(GCMStoreImplTest, LastCheckinTime) {
    146   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    147   scoped_ptr<GCMStore::LoadResult> load_result;
    148   gcm_store->Load(base::Bind(
    149       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    150   PumpLoop();
    151 
    152   base::Time last_checkin_time = base::Time::Now();
    153 
    154   gcm_store->SetLastCheckinTime(
    155       last_checkin_time,
    156       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    157   PumpLoop();
    158 
    159   gcm_store = BuildGCMStore().Pass();
    160   gcm_store->Load(base::Bind(
    161       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    162   PumpLoop();
    163   ASSERT_EQ(last_checkin_time, load_result->last_checkin_time);
    164 }
    165 
    166 TEST_F(GCMStoreImplTest, GServicesSettings_ProtocolV2) {
    167   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    168   scoped_ptr<GCMStore::LoadResult> load_result;
    169   gcm_store->Load(base::Bind(
    170       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    171   PumpLoop();
    172 
    173   std::map<std::string, std::string> settings;
    174   settings["checkin_interval"] = "12345";
    175   settings["mcs_port"] = "438";
    176   settings["checkin_url"] = "http://checkin.google.com";
    177   std::string digest = "digest1";
    178 
    179   gcm_store->SetGServicesSettings(
    180       settings,
    181       digest,
    182       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    183   PumpLoop();
    184 
    185   gcm_store = BuildGCMStore().Pass();
    186   gcm_store->Load(base::Bind(
    187       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    188   PumpLoop();
    189 
    190   ASSERT_EQ(settings, load_result->gservices_settings);
    191   ASSERT_EQ(digest, load_result->gservices_digest);
    192 
    193   // Remove some, and add some.
    194   settings.clear();
    195   settings["checkin_interval"] = "54321";
    196   settings["registration_url"] = "http://registration.google.com";
    197   digest = "digest2";
    198 
    199   gcm_store->SetGServicesSettings(
    200       settings,
    201       digest,
    202       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    203   PumpLoop();
    204 
    205   gcm_store = BuildGCMStore().Pass();
    206   gcm_store->Load(base::Bind(
    207       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    208   PumpLoop();
    209 
    210   ASSERT_EQ(settings, load_result->gservices_settings);
    211   ASSERT_EQ(digest, load_result->gservices_digest);
    212 }
    213 
    214 TEST_F(GCMStoreImplTest, Registrations) {
    215   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    216   scoped_ptr<GCMStore::LoadResult> load_result;
    217   gcm_store->Load(base::Bind(
    218       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    219   PumpLoop();
    220 
    221   // Add one registration with one sender.
    222   linked_ptr<RegistrationInfo> registration1(new RegistrationInfo);
    223   registration1->sender_ids.push_back("sender1");
    224   registration1->registration_id = "registration1";
    225   gcm_store->AddRegistration(
    226       "app1",
    227       registration1,
    228       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    229   PumpLoop();
    230 
    231   // Add one registration with multiple senders.
    232   linked_ptr<RegistrationInfo> registration2(new RegistrationInfo);
    233   registration2->sender_ids.push_back("sender2_1");
    234   registration2->sender_ids.push_back("sender2_2");
    235   registration2->registration_id = "registration2";
    236   gcm_store->AddRegistration(
    237       "app2",
    238       registration2,
    239       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    240   PumpLoop();
    241 
    242   gcm_store = BuildGCMStore().Pass();
    243   gcm_store->Load(base::Bind(
    244       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    245   PumpLoop();
    246 
    247   ASSERT_EQ(2u, load_result->registrations.size());
    248   ASSERT_TRUE(load_result->registrations.find("app1") !=
    249               load_result->registrations.end());
    250   EXPECT_EQ(registration1->registration_id,
    251             load_result->registrations["app1"]->registration_id);
    252   ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
    253   EXPECT_EQ(registration1->sender_ids[0],
    254             load_result->registrations["app1"]->sender_ids[0]);
    255   ASSERT_TRUE(load_result->registrations.find("app2") !=
    256               load_result->registrations.end());
    257   EXPECT_EQ(registration2->registration_id,
    258             load_result->registrations["app2"]->registration_id);
    259   ASSERT_EQ(2u, load_result->registrations["app2"]->sender_ids.size());
    260   EXPECT_EQ(registration2->sender_ids[0],
    261             load_result->registrations["app2"]->sender_ids[0]);
    262   EXPECT_EQ(registration2->sender_ids[1],
    263             load_result->registrations["app2"]->sender_ids[1]);
    264 
    265   gcm_store->RemoveRegistration(
    266       "app2",
    267       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    268   PumpLoop();
    269 
    270   gcm_store = BuildGCMStore().Pass();
    271   gcm_store->Load(base::Bind(
    272       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    273   PumpLoop();
    274 
    275   ASSERT_EQ(1u, load_result->registrations.size());
    276   ASSERT_TRUE(load_result->registrations.find("app1") !=
    277               load_result->registrations.end());
    278   EXPECT_EQ(registration1->registration_id,
    279             load_result->registrations["app1"]->registration_id);
    280   ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
    281   EXPECT_EQ(registration1->sender_ids[0],
    282             load_result->registrations["app1"]->sender_ids[0]);
    283 }
    284 
    285 // Verify saving some incoming messages, reopening the directory, and then
    286 // removing those incoming messages.
    287 TEST_F(GCMStoreImplTest, IncomingMessages) {
    288   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    289   scoped_ptr<GCMStore::LoadResult> load_result;
    290   gcm_store->Load(base::Bind(
    291       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    292   PumpLoop();
    293 
    294   std::vector<std::string> persistent_ids;
    295   for (int i = 0; i < kNumPersistentIds; ++i) {
    296     persistent_ids.push_back(GetNextPersistentId());
    297     gcm_store->AddIncomingMessage(
    298         persistent_ids.back(),
    299         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    300     PumpLoop();
    301   }
    302 
    303   gcm_store = BuildGCMStore().Pass();
    304   gcm_store->Load(base::Bind(
    305       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    306   PumpLoop();
    307 
    308   ASSERT_EQ(persistent_ids, load_result->incoming_messages);
    309   ASSERT_TRUE(load_result->outgoing_messages.empty());
    310 
    311   gcm_store->RemoveIncomingMessages(
    312       persistent_ids,
    313       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    314   PumpLoop();
    315 
    316   gcm_store = BuildGCMStore().Pass();
    317   load_result->incoming_messages.clear();
    318   gcm_store->Load(base::Bind(
    319       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    320   PumpLoop();
    321 
    322   ASSERT_TRUE(load_result->incoming_messages.empty());
    323   ASSERT_TRUE(load_result->outgoing_messages.empty());
    324 }
    325 
    326 // Verify saving some outgoing messages, reopening the directory, and then
    327 // removing those outgoing messages.
    328 TEST_F(GCMStoreImplTest, OutgoingMessages) {
    329   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    330   scoped_ptr<GCMStore::LoadResult> load_result;
    331   gcm_store->Load(base::Bind(
    332       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    333   PumpLoop();
    334 
    335   std::vector<std::string> persistent_ids;
    336   const int kNumPersistentIds = 10;
    337   for (int i = 0; i < kNumPersistentIds; ++i) {
    338     persistent_ids.push_back(GetNextPersistentId());
    339     mcs_proto::DataMessageStanza message;
    340     message.set_from(kAppName + persistent_ids.back());
    341     message.set_category(kCategoryName + persistent_ids.back());
    342     gcm_store->AddOutgoingMessage(
    343         persistent_ids.back(),
    344         MCSMessage(message),
    345         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    346     PumpLoop();
    347   }
    348 
    349   gcm_store = BuildGCMStore().Pass();
    350   gcm_store->Load(base::Bind(
    351       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    352   PumpLoop();
    353 
    354   ASSERT_TRUE(load_result->incoming_messages.empty());
    355   ASSERT_EQ(load_result->outgoing_messages.size(), persistent_ids.size());
    356   for (int i = 0; i < kNumPersistentIds; ++i) {
    357     std::string id = persistent_ids[i];
    358     ASSERT_TRUE(load_result->outgoing_messages[id].get());
    359     const mcs_proto::DataMessageStanza* message =
    360         reinterpret_cast<mcs_proto::DataMessageStanza*>(
    361             load_result->outgoing_messages[id].get());
    362     ASSERT_EQ(message->from(), kAppName + id);
    363     ASSERT_EQ(message->category(), kCategoryName + id);
    364   }
    365 
    366   gcm_store->RemoveOutgoingMessages(
    367       persistent_ids,
    368       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    369   PumpLoop();
    370 
    371   gcm_store = BuildGCMStore().Pass();
    372   load_result->outgoing_messages.clear();
    373   gcm_store->Load(base::Bind(
    374       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    375   PumpLoop();
    376 
    377   ASSERT_TRUE(load_result->incoming_messages.empty());
    378   ASSERT_TRUE(load_result->outgoing_messages.empty());
    379 }
    380 
    381 // Verify incoming and outgoing messages don't conflict.
    382 TEST_F(GCMStoreImplTest, IncomingAndOutgoingMessages) {
    383   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    384   scoped_ptr<GCMStore::LoadResult> load_result;
    385   gcm_store->Load(base::Bind(
    386       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    387   PumpLoop();
    388 
    389   std::vector<std::string> persistent_ids;
    390   const int kNumPersistentIds = 10;
    391   for (int i = 0; i < kNumPersistentIds; ++i) {
    392     persistent_ids.push_back(GetNextPersistentId());
    393     gcm_store->AddIncomingMessage(
    394         persistent_ids.back(),
    395         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    396     PumpLoop();
    397 
    398     mcs_proto::DataMessageStanza message;
    399     message.set_from(kAppName + persistent_ids.back());
    400     message.set_category(kCategoryName + persistent_ids.back());
    401     gcm_store->AddOutgoingMessage(
    402         persistent_ids.back(),
    403         MCSMessage(message),
    404         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    405     PumpLoop();
    406   }
    407 
    408   gcm_store = BuildGCMStore().Pass();
    409   gcm_store->Load(base::Bind(
    410       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    411   PumpLoop();
    412 
    413   ASSERT_EQ(persistent_ids, load_result->incoming_messages);
    414   ASSERT_EQ(load_result->outgoing_messages.size(), persistent_ids.size());
    415   for (int i = 0; i < kNumPersistentIds; ++i) {
    416     std::string id = persistent_ids[i];
    417     ASSERT_TRUE(load_result->outgoing_messages[id].get());
    418     const mcs_proto::DataMessageStanza* message =
    419         reinterpret_cast<mcs_proto::DataMessageStanza*>(
    420             load_result->outgoing_messages[id].get());
    421     ASSERT_EQ(message->from(), kAppName + id);
    422     ASSERT_EQ(message->category(), kCategoryName + id);
    423   }
    424 
    425   gcm_store->RemoveIncomingMessages(
    426       persistent_ids,
    427       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    428   PumpLoop();
    429   gcm_store->RemoveOutgoingMessages(
    430       persistent_ids,
    431       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
    432   PumpLoop();
    433 
    434   gcm_store = BuildGCMStore().Pass();
    435   load_result->incoming_messages.clear();
    436   load_result->outgoing_messages.clear();
    437   gcm_store->Load(base::Bind(
    438       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
    439   PumpLoop();
    440 
    441   ASSERT_TRUE(load_result->incoming_messages.empty());
    442   ASSERT_TRUE(load_result->outgoing_messages.empty());
    443 }
    444 
    445 // Test that per-app message limits are enforced, persisted across restarts,
    446 // and updated as messages are removed.
    447 TEST_F(GCMStoreImplTest, PerAppMessageLimits) {
    448   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    449   scoped_ptr<GCMStore::LoadResult> load_result;
    450   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
    451                              base::Unretained(this),
    452                              &load_result));
    453 
    454   // Add the initial (below app limit) messages.
    455   for (int i = 0; i < kNumMessagesPerApp; ++i) {
    456     mcs_proto::DataMessageStanza message;
    457     message.set_from(kAppName);
    458     message.set_category(kCategoryName);
    459     EXPECT_TRUE(gcm_store->AddOutgoingMessage(
    460                     base::IntToString(i),
    461                     MCSMessage(message),
    462                     base::Bind(&GCMStoreImplTest::UpdateCallback,
    463                                base::Unretained(this))));
    464     PumpLoop();
    465   }
    466 
    467   // Attempting to add some more should fail.
    468   for (int i = 0; i < kNumMessagesPerApp; ++i) {
    469     mcs_proto::DataMessageStanza message;
    470     message.set_from(kAppName);
    471     message.set_category(kCategoryName);
    472     EXPECT_FALSE(gcm_store->AddOutgoingMessage(
    473                      base::IntToString(i + kNumMessagesPerApp),
    474                      MCSMessage(message),
    475                      base::Bind(&GCMStoreImplTest::UpdateCallback,
    476                                 base::Unretained(this))));
    477     PumpLoop();
    478   }
    479 
    480   // Tear down and restore the database.
    481   gcm_store = BuildGCMStore().Pass();
    482   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
    483                              base::Unretained(this),
    484                              &load_result));
    485   PumpLoop();
    486 
    487   // Adding more messages should still fail.
    488   for (int i = 0; i < kNumMessagesPerApp; ++i) {
    489     mcs_proto::DataMessageStanza message;
    490     message.set_from(kAppName);
    491     message.set_category(kCategoryName);
    492     EXPECT_FALSE(gcm_store->AddOutgoingMessage(
    493                      base::IntToString(i + kNumMessagesPerApp),
    494                      MCSMessage(message),
    495                      base::Bind(&GCMStoreImplTest::UpdateCallback,
    496                                 base::Unretained(this))));
    497     PumpLoop();
    498   }
    499 
    500   // Remove the existing messages.
    501   for (int i = 0; i < kNumMessagesPerApp; ++i) {
    502     gcm_store->RemoveOutgoingMessage(
    503         base::IntToString(i),
    504         base::Bind(&GCMStoreImplTest::UpdateCallback,
    505                    base::Unretained(this)));
    506     PumpLoop();
    507   }
    508 
    509   // Successfully add new messages.
    510   for (int i = 0; i < kNumMessagesPerApp; ++i) {
    511     mcs_proto::DataMessageStanza message;
    512     message.set_from(kAppName);
    513     message.set_category(kCategoryName);
    514     EXPECT_TRUE(gcm_store->AddOutgoingMessage(
    515                     base::IntToString(i + kNumMessagesPerApp),
    516                     MCSMessage(message),
    517                     base::Bind(&GCMStoreImplTest::UpdateCallback,
    518                                base::Unretained(this))));
    519     PumpLoop();
    520   }
    521 }
    522 
    523 // When the database is destroyed, all database updates should fail. At the
    524 // same time, they per-app message counts should not go up, as failures should
    525 // result in decrementing the counts.
    526 TEST_F(GCMStoreImplTest, AddMessageAfterDestroy) {
    527   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    528   scoped_ptr<GCMStore::LoadResult> load_result;
    529   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
    530                              base::Unretained(this),
    531                              &load_result));
    532   PumpLoop();
    533   gcm_store->Destroy(base::Bind(&GCMStoreImplTest::UpdateCallback,
    534                                base::Unretained(this)));
    535   PumpLoop();
    536 
    537   expected_success_ = false;
    538   for (int i = 0; i < kNumMessagesPerApp * 2; ++i) {
    539     mcs_proto::DataMessageStanza message;
    540     message.set_from(kAppName);
    541     message.set_category(kCategoryName);
    542     // Because all adds are failing, none should hit the per-app message limits.
    543     EXPECT_TRUE(gcm_store->AddOutgoingMessage(
    544                     base::IntToString(i),
    545                     MCSMessage(message),
    546                     base::Bind(&GCMStoreImplTest::UpdateCallback,
    547                                base::Unretained(this))));
    548     PumpLoop();
    549   }
    550 }
    551 
    552 TEST_F(GCMStoreImplTest, ReloadAfterClose) {
    553   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
    554   scoped_ptr<GCMStore::LoadResult> load_result;
    555   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
    556                              base::Unretained(this),
    557                              &load_result));
    558   PumpLoop();
    559 
    560   gcm_store->Close();
    561   PumpLoop();
    562 
    563   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
    564                              base::Unretained(this),
    565                              &load_result));
    566   PumpLoop();
    567 }
    568 
    569 }  // namespace
    570 
    571 }  // namespace gcm
    572