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 (at) gmail.com"); 149 accounts.insert("test_user2 (at) 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 (at) 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 (at) 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 } // namespace 647 648 } // namespace gcm 649