Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / google_apis / gcm / engine / gcm_store_impl_unittest.cc
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   scoped_ptr<GCMStore> BuildGCMStore();
49
50   std::string GetNextPersistentId();
51
52   void PumpLoop();
53
54   void LoadCallback(scoped_ptr<GCMStore::LoadResult>* result_dst,
55                     scoped_ptr<GCMStore::LoadResult> result);
56   void UpdateCallback(bool success);
57
58  protected:
59   base::MessageLoop message_loop_;
60   base::ScopedTempDir temp_directory_;
61   bool expected_success_;
62   uint64 next_persistent_id_;
63   scoped_ptr<base::RunLoop> run_loop_;
64 };
65
66 GCMStoreImplTest::GCMStoreImplTest()
67     : expected_success_(true),
68       next_persistent_id_(base::Time::Now().ToInternalValue()) {
69   EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
70   run_loop_.reset(new base::RunLoop());
71 }
72
73 GCMStoreImplTest::~GCMStoreImplTest() {}
74
75 scoped_ptr<GCMStore> GCMStoreImplTest::BuildGCMStore() {
76   return scoped_ptr<GCMStore>(new GCMStoreImpl(
77       temp_directory_.path(),
78       message_loop_.message_loop_proxy(),
79       make_scoped_ptr<Encryptor>(new FakeEncryptor)));
80 }
81
82 std::string GCMStoreImplTest::GetNextPersistentId() {
83   return base::Uint64ToString(next_persistent_id_++);
84 }
85
86 void GCMStoreImplTest::PumpLoop() { message_loop_.RunUntilIdle(); }
87
88 void GCMStoreImplTest::LoadCallback(
89     scoped_ptr<GCMStore::LoadResult>* result_dst,
90     scoped_ptr<GCMStore::LoadResult> result) {
91   ASSERT_TRUE(result->success);
92   *result_dst = result.Pass();
93   run_loop_->Quit();
94   run_loop_.reset(new base::RunLoop());
95 }
96
97 void GCMStoreImplTest::UpdateCallback(bool success) {
98   ASSERT_EQ(expected_success_, success);
99 }
100
101 // Verify creating a new database and loading it.
102 TEST_F(GCMStoreImplTest, LoadNew) {
103   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
104   scoped_ptr<GCMStore::LoadResult> load_result;
105   gcm_store->Load(base::Bind(
106       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
107   PumpLoop();
108
109   EXPECT_EQ(0U, load_result->device_android_id);
110   EXPECT_EQ(0U, load_result->device_security_token);
111   EXPECT_TRUE(load_result->incoming_messages.empty());
112   EXPECT_TRUE(load_result->outgoing_messages.empty());
113   EXPECT_TRUE(load_result->gservices_settings.empty());
114   EXPECT_EQ(base::Time::FromInternalValue(0LL), load_result->last_checkin_time);
115 }
116
117 TEST_F(GCMStoreImplTest, DeviceCredentials) {
118   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
119   scoped_ptr<GCMStore::LoadResult> load_result;
120   gcm_store->Load(base::Bind(
121       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
122   PumpLoop();
123
124   gcm_store->SetDeviceCredentials(
125       kDeviceId,
126       kDeviceToken,
127       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
128   PumpLoop();
129
130   gcm_store = BuildGCMStore().Pass();
131   gcm_store->Load(base::Bind(
132       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
133   PumpLoop();
134
135   ASSERT_EQ(kDeviceId, load_result->device_android_id);
136   ASSERT_EQ(kDeviceToken, load_result->device_security_token);
137 }
138
139 TEST_F(GCMStoreImplTest, LastCheckinInfo) {
140   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
141   scoped_ptr<GCMStore::LoadResult> load_result;
142   gcm_store->Load(base::Bind(
143       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
144   PumpLoop();
145
146   base::Time last_checkin_time = base::Time::Now();
147   std::set<std::string> accounts;
148   accounts.insert("test_user1@gmail.com");
149   accounts.insert("test_user2@gmail.com");
150
151   gcm_store->SetLastCheckinInfo(
152       last_checkin_time,
153       accounts,
154       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
155   PumpLoop();
156
157   gcm_store = BuildGCMStore().Pass();
158   gcm_store->Load(base::Bind(
159       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
160   PumpLoop();
161   ASSERT_EQ(last_checkin_time, load_result->last_checkin_time);
162   ASSERT_EQ(accounts, load_result->last_checkin_accounts);
163 }
164
165 TEST_F(GCMStoreImplTest, GServicesSettings_ProtocolV2) {
166   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
167   scoped_ptr<GCMStore::LoadResult> load_result;
168   gcm_store->Load(base::Bind(
169       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
170   PumpLoop();
171
172   std::map<std::string, std::string> settings;
173   settings["checkin_interval"] = "12345";
174   settings["mcs_port"] = "438";
175   settings["checkin_url"] = "http://checkin.google.com";
176   std::string digest = "digest1";
177
178   gcm_store->SetGServicesSettings(
179       settings,
180       digest,
181       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
182   PumpLoop();
183
184   gcm_store = BuildGCMStore().Pass();
185   gcm_store->Load(base::Bind(
186       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
187   PumpLoop();
188
189   ASSERT_EQ(settings, load_result->gservices_settings);
190   ASSERT_EQ(digest, load_result->gservices_digest);
191
192   // Remove some, and add some.
193   settings.clear();
194   settings["checkin_interval"] = "54321";
195   settings["registration_url"] = "http://registration.google.com";
196   digest = "digest2";
197
198   gcm_store->SetGServicesSettings(
199       settings,
200       digest,
201       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
202   PumpLoop();
203
204   gcm_store = BuildGCMStore().Pass();
205   gcm_store->Load(base::Bind(
206       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
207   PumpLoop();
208
209   ASSERT_EQ(settings, load_result->gservices_settings);
210   ASSERT_EQ(digest, load_result->gservices_digest);
211 }
212
213 TEST_F(GCMStoreImplTest, Registrations) {
214   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
215   scoped_ptr<GCMStore::LoadResult> load_result;
216   gcm_store->Load(base::Bind(
217       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
218   PumpLoop();
219
220   // Add one registration with one sender.
221   linked_ptr<RegistrationInfo> registration1(new RegistrationInfo);
222   registration1->sender_ids.push_back("sender1");
223   registration1->registration_id = "registration1";
224   gcm_store->AddRegistration(
225       "app1",
226       registration1,
227       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
228   PumpLoop();
229
230   // Add one registration with multiple senders.
231   linked_ptr<RegistrationInfo> registration2(new RegistrationInfo);
232   registration2->sender_ids.push_back("sender2_1");
233   registration2->sender_ids.push_back("sender2_2");
234   registration2->registration_id = "registration2";
235   gcm_store->AddRegistration(
236       "app2",
237       registration2,
238       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
239   PumpLoop();
240
241   gcm_store = BuildGCMStore().Pass();
242   gcm_store->Load(base::Bind(
243       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
244   PumpLoop();
245
246   ASSERT_EQ(2u, load_result->registrations.size());
247   ASSERT_TRUE(load_result->registrations.find("app1") !=
248               load_result->registrations.end());
249   EXPECT_EQ(registration1->registration_id,
250             load_result->registrations["app1"]->registration_id);
251   ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
252   EXPECT_EQ(registration1->sender_ids[0],
253             load_result->registrations["app1"]->sender_ids[0]);
254   ASSERT_TRUE(load_result->registrations.find("app2") !=
255               load_result->registrations.end());
256   EXPECT_EQ(registration2->registration_id,
257             load_result->registrations["app2"]->registration_id);
258   ASSERT_EQ(2u, load_result->registrations["app2"]->sender_ids.size());
259   EXPECT_EQ(registration2->sender_ids[0],
260             load_result->registrations["app2"]->sender_ids[0]);
261   EXPECT_EQ(registration2->sender_ids[1],
262             load_result->registrations["app2"]->sender_ids[1]);
263
264   gcm_store->RemoveRegistration(
265       "app2",
266       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
267   PumpLoop();
268
269   gcm_store = BuildGCMStore().Pass();
270   gcm_store->Load(base::Bind(
271       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
272   PumpLoop();
273
274   ASSERT_EQ(1u, load_result->registrations.size());
275   ASSERT_TRUE(load_result->registrations.find("app1") !=
276               load_result->registrations.end());
277   EXPECT_EQ(registration1->registration_id,
278             load_result->registrations["app1"]->registration_id);
279   ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
280   EXPECT_EQ(registration1->sender_ids[0],
281             load_result->registrations["app1"]->sender_ids[0]);
282 }
283
284 // Verify saving some incoming messages, reopening the directory, and then
285 // removing those incoming messages.
286 TEST_F(GCMStoreImplTest, IncomingMessages) {
287   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
288   scoped_ptr<GCMStore::LoadResult> load_result;
289   gcm_store->Load(base::Bind(
290       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
291   PumpLoop();
292
293   std::vector<std::string> persistent_ids;
294   for (int i = 0; i < kNumPersistentIds; ++i) {
295     persistent_ids.push_back(GetNextPersistentId());
296     gcm_store->AddIncomingMessage(
297         persistent_ids.back(),
298         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
299     PumpLoop();
300   }
301
302   gcm_store = BuildGCMStore().Pass();
303   gcm_store->Load(base::Bind(
304       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
305   PumpLoop();
306
307   ASSERT_EQ(persistent_ids, load_result->incoming_messages);
308   ASSERT_TRUE(load_result->outgoing_messages.empty());
309
310   gcm_store->RemoveIncomingMessages(
311       persistent_ids,
312       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
313   PumpLoop();
314
315   gcm_store = BuildGCMStore().Pass();
316   load_result->incoming_messages.clear();
317   gcm_store->Load(base::Bind(
318       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
319   PumpLoop();
320
321   ASSERT_TRUE(load_result->incoming_messages.empty());
322   ASSERT_TRUE(load_result->outgoing_messages.empty());
323 }
324
325 // Verify saving some outgoing messages, reopening the directory, and then
326 // removing those outgoing messages.
327 TEST_F(GCMStoreImplTest, OutgoingMessages) {
328   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
329   scoped_ptr<GCMStore::LoadResult> load_result;
330   gcm_store->Load(base::Bind(
331       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
332   PumpLoop();
333
334   std::vector<std::string> persistent_ids;
335   const int kNumPersistentIds = 10;
336   for (int i = 0; i < kNumPersistentIds; ++i) {
337     persistent_ids.push_back(GetNextPersistentId());
338     mcs_proto::DataMessageStanza message;
339     message.set_from(kAppName + persistent_ids.back());
340     message.set_category(kCategoryName + persistent_ids.back());
341     gcm_store->AddOutgoingMessage(
342         persistent_ids.back(),
343         MCSMessage(message),
344         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
345     PumpLoop();
346   }
347
348   gcm_store = BuildGCMStore().Pass();
349   gcm_store->Load(base::Bind(
350       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
351   PumpLoop();
352
353   ASSERT_TRUE(load_result->incoming_messages.empty());
354   ASSERT_EQ(load_result->outgoing_messages.size(), persistent_ids.size());
355   for (int i = 0; i < kNumPersistentIds; ++i) {
356     std::string id = persistent_ids[i];
357     ASSERT_TRUE(load_result->outgoing_messages[id].get());
358     const mcs_proto::DataMessageStanza* message =
359         reinterpret_cast<mcs_proto::DataMessageStanza*>(
360             load_result->outgoing_messages[id].get());
361     ASSERT_EQ(message->from(), kAppName + id);
362     ASSERT_EQ(message->category(), kCategoryName + id);
363   }
364
365   gcm_store->RemoveOutgoingMessages(
366       persistent_ids,
367       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
368   PumpLoop();
369
370   gcm_store = BuildGCMStore().Pass();
371   load_result->outgoing_messages.clear();
372   gcm_store->Load(base::Bind(
373       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
374   PumpLoop();
375
376   ASSERT_TRUE(load_result->incoming_messages.empty());
377   ASSERT_TRUE(load_result->outgoing_messages.empty());
378 }
379
380 // Verify incoming and outgoing messages don't conflict.
381 TEST_F(GCMStoreImplTest, IncomingAndOutgoingMessages) {
382   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
383   scoped_ptr<GCMStore::LoadResult> load_result;
384   gcm_store->Load(base::Bind(
385       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
386   PumpLoop();
387
388   std::vector<std::string> persistent_ids;
389   const int kNumPersistentIds = 10;
390   for (int i = 0; i < kNumPersistentIds; ++i) {
391     persistent_ids.push_back(GetNextPersistentId());
392     gcm_store->AddIncomingMessage(
393         persistent_ids.back(),
394         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
395     PumpLoop();
396
397     mcs_proto::DataMessageStanza message;
398     message.set_from(kAppName + persistent_ids.back());
399     message.set_category(kCategoryName + persistent_ids.back());
400     gcm_store->AddOutgoingMessage(
401         persistent_ids.back(),
402         MCSMessage(message),
403         base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
404     PumpLoop();
405   }
406
407   gcm_store = BuildGCMStore().Pass();
408   gcm_store->Load(base::Bind(
409       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
410   PumpLoop();
411
412   ASSERT_EQ(persistent_ids, load_result->incoming_messages);
413   ASSERT_EQ(load_result->outgoing_messages.size(), persistent_ids.size());
414   for (int i = 0; i < kNumPersistentIds; ++i) {
415     std::string id = persistent_ids[i];
416     ASSERT_TRUE(load_result->outgoing_messages[id].get());
417     const mcs_proto::DataMessageStanza* message =
418         reinterpret_cast<mcs_proto::DataMessageStanza*>(
419             load_result->outgoing_messages[id].get());
420     ASSERT_EQ(message->from(), kAppName + id);
421     ASSERT_EQ(message->category(), kCategoryName + id);
422   }
423
424   gcm_store->RemoveIncomingMessages(
425       persistent_ids,
426       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
427   PumpLoop();
428   gcm_store->RemoveOutgoingMessages(
429       persistent_ids,
430       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
431   PumpLoop();
432
433   gcm_store = BuildGCMStore().Pass();
434   load_result->incoming_messages.clear();
435   load_result->outgoing_messages.clear();
436   gcm_store->Load(base::Bind(
437       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
438   PumpLoop();
439
440   ASSERT_TRUE(load_result->incoming_messages.empty());
441   ASSERT_TRUE(load_result->outgoing_messages.empty());
442 }
443
444 // Test that per-app message limits are enforced, persisted across restarts,
445 // and updated as messages are removed.
446 TEST_F(GCMStoreImplTest, PerAppMessageLimits) {
447   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
448   scoped_ptr<GCMStore::LoadResult> load_result;
449   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
450                              base::Unretained(this),
451                              &load_result));
452
453   // Add the initial (below app limit) messages.
454   for (int i = 0; i < kNumMessagesPerApp; ++i) {
455     mcs_proto::DataMessageStanza message;
456     message.set_from(kAppName);
457     message.set_category(kCategoryName);
458     EXPECT_TRUE(gcm_store->AddOutgoingMessage(
459                     base::IntToString(i),
460                     MCSMessage(message),
461                     base::Bind(&GCMStoreImplTest::UpdateCallback,
462                                base::Unretained(this))));
463     PumpLoop();
464   }
465
466   // Attempting to add some more should fail.
467   for (int i = 0; i < kNumMessagesPerApp; ++i) {
468     mcs_proto::DataMessageStanza message;
469     message.set_from(kAppName);
470     message.set_category(kCategoryName);
471     EXPECT_FALSE(gcm_store->AddOutgoingMessage(
472                      base::IntToString(i + kNumMessagesPerApp),
473                      MCSMessage(message),
474                      base::Bind(&GCMStoreImplTest::UpdateCallback,
475                                 base::Unretained(this))));
476     PumpLoop();
477   }
478
479   // Tear down and restore the database.
480   gcm_store = BuildGCMStore().Pass();
481   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
482                              base::Unretained(this),
483                              &load_result));
484   PumpLoop();
485
486   // Adding more messages should still fail.
487   for (int i = 0; i < kNumMessagesPerApp; ++i) {
488     mcs_proto::DataMessageStanza message;
489     message.set_from(kAppName);
490     message.set_category(kCategoryName);
491     EXPECT_FALSE(gcm_store->AddOutgoingMessage(
492                      base::IntToString(i + kNumMessagesPerApp),
493                      MCSMessage(message),
494                      base::Bind(&GCMStoreImplTest::UpdateCallback,
495                                 base::Unretained(this))));
496     PumpLoop();
497   }
498
499   // Remove the existing messages.
500   for (int i = 0; i < kNumMessagesPerApp; ++i) {
501     gcm_store->RemoveOutgoingMessage(
502         base::IntToString(i),
503         base::Bind(&GCMStoreImplTest::UpdateCallback,
504                    base::Unretained(this)));
505     PumpLoop();
506   }
507
508   // Successfully add new messages.
509   for (int i = 0; i < kNumMessagesPerApp; ++i) {
510     mcs_proto::DataMessageStanza message;
511     message.set_from(kAppName);
512     message.set_category(kCategoryName);
513     EXPECT_TRUE(gcm_store->AddOutgoingMessage(
514                     base::IntToString(i + kNumMessagesPerApp),
515                     MCSMessage(message),
516                     base::Bind(&GCMStoreImplTest::UpdateCallback,
517                                base::Unretained(this))));
518     PumpLoop();
519   }
520 }
521
522 TEST_F(GCMStoreImplTest, AccountMapping) {
523   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
524   scoped_ptr<GCMStore::LoadResult> load_result;
525   gcm_store->Load(base::Bind(
526       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
527
528   // Add account mappings.
529   AccountMapping account_mapping1;
530   account_mapping1.account_id = "account_id_1";
531   account_mapping1.email = "account_id_1@gmail.com";
532   account_mapping1.access_token = "account_token1";
533   account_mapping1.status = AccountMapping::ADDING;
534   account_mapping1.status_change_timestamp = base::Time();
535   account_mapping1.last_message_id = "message_1";
536
537   AccountMapping account_mapping2;
538   account_mapping2.account_id = "account_id_2";
539   account_mapping2.email = "account_id_2@gmail.com";
540   account_mapping2.access_token = "account_token1";
541   account_mapping2.status = AccountMapping::REMOVING;
542   account_mapping2.status_change_timestamp =
543       base::Time::FromInternalValue(1305734521259935LL);
544   account_mapping2.last_message_id = "message_2";
545
546   gcm_store->AddAccountMapping(
547       account_mapping1,
548       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
549   PumpLoop();
550   gcm_store->AddAccountMapping(
551       account_mapping2,
552       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
553   PumpLoop();
554
555   gcm_store = BuildGCMStore().Pass();
556   gcm_store->Load(base::Bind(
557       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
558   PumpLoop();
559
560   EXPECT_EQ(2UL, load_result->account_mappings.size());
561   GCMStore::AccountMappings::iterator iter =
562       load_result->account_mappings.begin();
563   EXPECT_EQ(account_mapping1.account_id, iter->account_id);
564   EXPECT_EQ(account_mapping1.email, iter->email);
565   EXPECT_TRUE(iter->access_token.empty());
566   EXPECT_EQ(AccountMapping::ADDING, iter->status);
567   EXPECT_EQ(account_mapping1.status_change_timestamp,
568             iter->status_change_timestamp);
569   EXPECT_EQ(account_mapping1.last_message_id, iter->last_message_id);
570   ++iter;
571   EXPECT_EQ(account_mapping2.account_id, iter->account_id);
572   EXPECT_EQ(account_mapping2.email, iter->email);
573   EXPECT_TRUE(iter->access_token.empty());
574   EXPECT_EQ(AccountMapping::REMOVING, iter->status);
575   EXPECT_EQ(account_mapping2.status_change_timestamp,
576             iter->status_change_timestamp);
577   EXPECT_EQ(account_mapping2.last_message_id, iter->last_message_id);
578
579   gcm_store->RemoveAccountMapping(
580       account_mapping1.account_id,
581       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
582   PumpLoop();
583
584   gcm_store = BuildGCMStore().Pass();
585   gcm_store->Load(base::Bind(
586       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
587   PumpLoop();
588
589   EXPECT_EQ(1UL, load_result->account_mappings.size());
590   iter = load_result->account_mappings.begin();
591   EXPECT_EQ(account_mapping2.account_id, iter->account_id);
592   EXPECT_EQ(account_mapping2.email, iter->email);
593   EXPECT_TRUE(iter->access_token.empty());
594   EXPECT_EQ(AccountMapping::REMOVING, iter->status);
595   EXPECT_EQ(account_mapping2.status_change_timestamp,
596             iter->status_change_timestamp);
597   EXPECT_EQ(account_mapping2.last_message_id, iter->last_message_id);
598 }
599
600 // When the database is destroyed, all database updates should fail. At the
601 // same time, they per-app message counts should not go up, as failures should
602 // result in decrementing the counts.
603 TEST_F(GCMStoreImplTest, AddMessageAfterDestroy) {
604   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
605   scoped_ptr<GCMStore::LoadResult> load_result;
606   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
607                              base::Unretained(this),
608                              &load_result));
609   PumpLoop();
610   gcm_store->Destroy(base::Bind(&GCMStoreImplTest::UpdateCallback,
611                                base::Unretained(this)));
612   PumpLoop();
613
614   expected_success_ = false;
615   for (int i = 0; i < kNumMessagesPerApp * 2; ++i) {
616     mcs_proto::DataMessageStanza message;
617     message.set_from(kAppName);
618     message.set_category(kCategoryName);
619     // Because all adds are failing, none should hit the per-app message limits.
620     EXPECT_TRUE(gcm_store->AddOutgoingMessage(
621                     base::IntToString(i),
622                     MCSMessage(message),
623                     base::Bind(&GCMStoreImplTest::UpdateCallback,
624                                base::Unretained(this))));
625     PumpLoop();
626   }
627 }
628
629 TEST_F(GCMStoreImplTest, ReloadAfterClose) {
630   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
631   scoped_ptr<GCMStore::LoadResult> load_result;
632   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
633                              base::Unretained(this),
634                              &load_result));
635   PumpLoop();
636
637   gcm_store->Close();
638   PumpLoop();
639
640   gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
641                              base::Unretained(this),
642                              &load_result));
643   PumpLoop();
644 }
645
646 TEST_F(GCMStoreImplTest, LastTokenFetchTime) {
647   scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
648   scoped_ptr<GCMStore::LoadResult> load_result;
649   gcm_store->Load(base::Bind(
650       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
651   PumpLoop();
652   EXPECT_EQ(base::Time(), load_result->last_token_fetch_time);
653
654   base::Time last_token_fetch_time = base::Time::Now();
655   gcm_store->SetLastTokenFetchTime(
656       last_token_fetch_time,
657       base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
658   PumpLoop();
659
660   gcm_store = BuildGCMStore().Pass();
661   gcm_store->Load(base::Bind(
662       &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
663   PumpLoop();
664   EXPECT_EQ(last_token_fetch_time, load_result->last_token_fetch_time);
665 }
666
667 }  // namespace
668
669 }  // namespace gcm