1 // Copyright 2012 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 // Unit tests for the SyncApi. Note that a lot of the underlying 6 // functionality is provided by the Syncable layer, which has its own 7 // unit tests. We'll test SyncApi specific things in this harness. 8 9 #include <cstddef> 10 #include <map> 11 12 #include "base/basictypes.h" 13 #include "base/callback.h" 14 #include "base/compiler_specific.h" 15 #include "base/files/scoped_temp_dir.h" 16 #include "base/format_macros.h" 17 #include "base/location.h" 18 #include "base/memory/scoped_ptr.h" 19 #include "base/message_loop/message_loop.h" 20 #include "base/message_loop/message_loop_proxy.h" 21 #include "base/strings/string_number_conversions.h" 22 #include "base/strings/stringprintf.h" 23 #include "base/strings/utf_string_conversions.h" 24 #include "base/test/values_test_util.h" 25 #include "base/values.h" 26 #include "sync/engine/sync_scheduler.h" 27 #include "sync/internal_api/public/base/cancelation_signal.h" 28 #include "sync/internal_api/public/base/model_type_test_util.h" 29 #include "sync/internal_api/public/change_record.h" 30 #include "sync/internal_api/public/engine/model_safe_worker.h" 31 #include "sync/internal_api/public/engine/polling_constants.h" 32 #include "sync/internal_api/public/events/protocol_event.h" 33 #include "sync/internal_api/public/http_post_provider_factory.h" 34 #include "sync/internal_api/public/http_post_provider_interface.h" 35 #include "sync/internal_api/public/read_node.h" 36 #include "sync/internal_api/public/read_transaction.h" 37 #include "sync/internal_api/public/test/test_entry_factory.h" 38 #include "sync/internal_api/public/test/test_internal_components_factory.h" 39 #include "sync/internal_api/public/test/test_user_share.h" 40 #include "sync/internal_api/public/write_node.h" 41 #include "sync/internal_api/public/write_transaction.h" 42 #include "sync/internal_api/sync_encryption_handler_impl.h" 43 #include "sync/internal_api/sync_manager_impl.h" 44 #include "sync/internal_api/syncapi_internal.h" 45 #include "sync/js/js_backend.h" 46 #include "sync/js/js_event_handler.h" 47 #include "sync/js/js_test_util.h" 48 #include "sync/notifier/invalidation_handler.h" 49 #include "sync/notifier/invalidator.h" 50 #include "sync/protocol/bookmark_specifics.pb.h" 51 #include "sync/protocol/encryption.pb.h" 52 #include "sync/protocol/extension_specifics.pb.h" 53 #include "sync/protocol/password_specifics.pb.h" 54 #include "sync/protocol/preference_specifics.pb.h" 55 #include "sync/protocol/proto_value_conversions.h" 56 #include "sync/protocol/sync.pb.h" 57 #include "sync/sessions/sync_session.h" 58 #include "sync/syncable/directory.h" 59 #include "sync/syncable/entry.h" 60 #include "sync/syncable/mutable_entry.h" 61 #include "sync/syncable/nigori_util.h" 62 #include "sync/syncable/syncable_id.h" 63 #include "sync/syncable/syncable_read_transaction.h" 64 #include "sync/syncable/syncable_util.h" 65 #include "sync/syncable/syncable_write_transaction.h" 66 #include "sync/test/callback_counter.h" 67 #include "sync/test/engine/fake_model_worker.h" 68 #include "sync/test/engine/fake_sync_scheduler.h" 69 #include "sync/test/engine/test_id_factory.h" 70 #include "sync/test/fake_encryptor.h" 71 #include "sync/util/cryptographer.h" 72 #include "sync/util/extensions_activity.h" 73 #include "sync/util/test_unrecoverable_error_handler.h" 74 #include "sync/util/time.h" 75 #include "testing/gmock/include/gmock/gmock.h" 76 #include "testing/gtest/include/gtest/gtest.h" 77 78 using base::ExpectDictStringValue; 79 using testing::_; 80 using testing::DoAll; 81 using testing::InSequence; 82 using testing::Return; 83 using testing::SaveArg; 84 using testing::StrictMock; 85 86 namespace syncer { 87 88 using sessions::SyncSessionSnapshot; 89 using syncable::GET_BY_HANDLE; 90 using syncable::IS_DEL; 91 using syncable::IS_UNSYNCED; 92 using syncable::NON_UNIQUE_NAME; 93 using syncable::SPECIFICS; 94 using syncable::kEncryptedString; 95 96 namespace { 97 98 // Makes a non-folder child of the root node. Returns the id of the 99 // newly-created node. 100 int64 MakeNode(UserShare* share, 101 ModelType model_type, 102 const std::string& client_tag) { 103 WriteTransaction trans(FROM_HERE, share); 104 ReadNode root_node(&trans); 105 root_node.InitByRootLookup(); 106 WriteNode node(&trans); 107 WriteNode::InitUniqueByCreationResult result = 108 node.InitUniqueByCreation(model_type, root_node, client_tag); 109 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 110 node.SetIsFolder(false); 111 return node.GetId(); 112 } 113 114 // Makes a folder child of a non-root node. Returns the id of the 115 // newly-created node. 116 int64 MakeFolderWithParent(UserShare* share, 117 ModelType model_type, 118 int64 parent_id, 119 BaseNode* predecessor) { 120 WriteTransaction trans(FROM_HERE, share); 121 ReadNode parent_node(&trans); 122 EXPECT_EQ(BaseNode::INIT_OK, parent_node.InitByIdLookup(parent_id)); 123 WriteNode node(&trans); 124 EXPECT_TRUE(node.InitBookmarkByCreation(parent_node, predecessor)); 125 node.SetIsFolder(true); 126 return node.GetId(); 127 } 128 129 int64 MakeBookmarkWithParent(UserShare* share, 130 int64 parent_id, 131 BaseNode* predecessor) { 132 WriteTransaction trans(FROM_HERE, share); 133 ReadNode parent_node(&trans); 134 EXPECT_EQ(BaseNode::INIT_OK, parent_node.InitByIdLookup(parent_id)); 135 WriteNode node(&trans); 136 EXPECT_TRUE(node.InitBookmarkByCreation(parent_node, predecessor)); 137 return node.GetId(); 138 } 139 140 // Creates the "synced" root node for a particular datatype. We use the syncable 141 // methods here so that the syncer treats these nodes as if they were already 142 // received from the server. 143 int64 MakeServerNodeForType(UserShare* share, 144 ModelType model_type) { 145 sync_pb::EntitySpecifics specifics; 146 AddDefaultFieldValue(model_type, &specifics); 147 syncable::WriteTransaction trans( 148 FROM_HERE, syncable::UNITTEST, share->directory.get()); 149 // Attempt to lookup by nigori tag. 150 std::string type_tag = ModelTypeToRootTag(model_type); 151 syncable::Id node_id = syncable::Id::CreateFromServerId(type_tag); 152 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, 153 node_id); 154 EXPECT_TRUE(entry.good()); 155 entry.PutBaseVersion(1); 156 entry.PutServerVersion(1); 157 entry.PutIsUnappliedUpdate(false); 158 entry.PutServerParentId(syncable::GetNullId()); 159 entry.PutServerIsDir(true); 160 entry.PutIsDir(true); 161 entry.PutServerSpecifics(specifics); 162 entry.PutUniqueServerTag(type_tag); 163 entry.PutNonUniqueName(type_tag); 164 entry.PutIsDel(false); 165 entry.PutSpecifics(specifics); 166 return entry.GetMetahandle(); 167 } 168 169 // Simulates creating a "synced" node as a child of the root datatype node. 170 int64 MakeServerNode(UserShare* share, ModelType model_type, 171 const std::string& client_tag, 172 const std::string& hashed_tag, 173 const sync_pb::EntitySpecifics& specifics) { 174 syncable::WriteTransaction trans( 175 FROM_HERE, syncable::UNITTEST, share->directory.get()); 176 syncable::Entry root_entry(&trans, syncable::GET_TYPE_ROOT, model_type); 177 EXPECT_TRUE(root_entry.good()); 178 syncable::Id root_id = root_entry.GetId(); 179 syncable::Id node_id = syncable::Id::CreateFromServerId(client_tag); 180 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM, 181 node_id); 182 EXPECT_TRUE(entry.good()); 183 entry.PutBaseVersion(1); 184 entry.PutServerVersion(1); 185 entry.PutIsUnappliedUpdate(false); 186 entry.PutServerParentId(root_id); 187 entry.PutParentId(root_id); 188 entry.PutServerIsDir(false); 189 entry.PutIsDir(false); 190 entry.PutServerSpecifics(specifics); 191 entry.PutNonUniqueName(client_tag); 192 entry.PutUniqueClientTag(hashed_tag); 193 entry.PutIsDel(false); 194 entry.PutSpecifics(specifics); 195 return entry.GetMetahandle(); 196 } 197 198 } // namespace 199 200 class SyncApiTest : public testing::Test { 201 public: 202 virtual void SetUp() { 203 test_user_share_.SetUp(); 204 } 205 206 virtual void TearDown() { 207 test_user_share_.TearDown(); 208 } 209 210 protected: 211 // Create an entry with the given |model_type|, |client_tag| and 212 // |attachment_metadata|. 213 void CreateEntryWithAttachmentMetadata( 214 const ModelType& model_type, 215 const std::string& client_tag, 216 const sync_pb::AttachmentMetadata& attachment_metadata); 217 218 // Attempts to load the entry specified by |model_type| and |client_tag| and 219 // returns the lookup result code. 220 BaseNode::InitByLookupResult LookupEntryByClientTag( 221 const ModelType& model_type, 222 const std::string& client_tag); 223 224 // Replace the entry specified by |model_type| and |client_tag| with a 225 // tombstone. 226 void ReplaceWithTombstone(const ModelType& model_type, 227 const std::string& client_tag); 228 229 // Save changes to the Directory, destroy it then reload it. 230 bool ReloadDir(); 231 232 UserShare* user_share(); 233 syncable::Directory* dir(); 234 SyncEncryptionHandler* encryption_handler(); 235 236 private: 237 base::MessageLoop message_loop_; 238 TestUserShare test_user_share_; 239 }; 240 241 UserShare* SyncApiTest::user_share() { 242 return test_user_share_.user_share(); 243 } 244 245 syncable::Directory* SyncApiTest::dir() { 246 return test_user_share_.user_share()->directory.get(); 247 } 248 249 SyncEncryptionHandler* SyncApiTest::encryption_handler() { 250 return test_user_share_.encryption_handler(); 251 } 252 253 bool SyncApiTest::ReloadDir() { 254 return test_user_share_.Reload(); 255 } 256 257 void SyncApiTest::CreateEntryWithAttachmentMetadata( 258 const ModelType& model_type, 259 const std::string& client_tag, 260 const sync_pb::AttachmentMetadata& attachment_metadata) { 261 syncer::WriteTransaction trans(FROM_HERE, user_share()); 262 syncer::ReadNode root_node(&trans); 263 root_node.InitByRootLookup(); 264 syncer::WriteNode node(&trans); 265 ASSERT_EQ(node.InitUniqueByCreation(model_type, root_node, client_tag), 266 syncer::WriteNode::INIT_SUCCESS); 267 node.SetAttachmentMetadata(attachment_metadata); 268 } 269 270 BaseNode::InitByLookupResult SyncApiTest::LookupEntryByClientTag( 271 const ModelType& model_type, 272 const std::string& client_tag) { 273 syncer::ReadTransaction trans(FROM_HERE, user_share()); 274 syncer::ReadNode node(&trans); 275 return node.InitByClientTagLookup(model_type, client_tag); 276 } 277 278 void SyncApiTest::ReplaceWithTombstone(const ModelType& model_type, 279 const std::string& client_tag) { 280 syncer::WriteTransaction trans(FROM_HERE, user_share()); 281 syncer::WriteNode node(&trans); 282 ASSERT_EQ(node.InitByClientTagLookup(model_type, client_tag), 283 syncer::WriteNode::INIT_OK); 284 node.Tombstone(); 285 } 286 287 TEST_F(SyncApiTest, SanityCheckTest) { 288 { 289 ReadTransaction trans(FROM_HERE, user_share()); 290 EXPECT_TRUE(trans.GetWrappedTrans()); 291 } 292 { 293 WriteTransaction trans(FROM_HERE, user_share()); 294 EXPECT_TRUE(trans.GetWrappedTrans()); 295 } 296 { 297 // No entries but root should exist 298 ReadTransaction trans(FROM_HERE, user_share()); 299 ReadNode node(&trans); 300 // Metahandle 1 can be root, sanity check 2 301 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD, node.InitByIdLookup(2)); 302 } 303 } 304 305 TEST_F(SyncApiTest, BasicTagWrite) { 306 { 307 ReadTransaction trans(FROM_HERE, user_share()); 308 ReadNode root_node(&trans); 309 root_node.InitByRootLookup(); 310 EXPECT_EQ(root_node.GetFirstChildId(), 0); 311 } 312 313 ignore_result(MakeNode(user_share(), BOOKMARKS, "testtag")); 314 315 { 316 ReadTransaction trans(FROM_HERE, user_share()); 317 ReadNode node(&trans); 318 EXPECT_EQ(BaseNode::INIT_OK, 319 node.InitByClientTagLookup(BOOKMARKS, "testtag")); 320 321 ReadNode root_node(&trans); 322 root_node.InitByRootLookup(); 323 EXPECT_NE(node.GetId(), 0); 324 EXPECT_EQ(node.GetId(), root_node.GetFirstChildId()); 325 } 326 } 327 328 TEST_F(SyncApiTest, ModelTypesSiloed) { 329 { 330 WriteTransaction trans(FROM_HERE, user_share()); 331 ReadNode root_node(&trans); 332 root_node.InitByRootLookup(); 333 EXPECT_EQ(root_node.GetFirstChildId(), 0); 334 } 335 336 ignore_result(MakeNode(user_share(), BOOKMARKS, "collideme")); 337 ignore_result(MakeNode(user_share(), PREFERENCES, "collideme")); 338 ignore_result(MakeNode(user_share(), AUTOFILL, "collideme")); 339 340 { 341 ReadTransaction trans(FROM_HERE, user_share()); 342 343 ReadNode bookmarknode(&trans); 344 EXPECT_EQ(BaseNode::INIT_OK, 345 bookmarknode.InitByClientTagLookup(BOOKMARKS, 346 "collideme")); 347 348 ReadNode prefnode(&trans); 349 EXPECT_EQ(BaseNode::INIT_OK, 350 prefnode.InitByClientTagLookup(PREFERENCES, 351 "collideme")); 352 353 ReadNode autofillnode(&trans); 354 EXPECT_EQ(BaseNode::INIT_OK, 355 autofillnode.InitByClientTagLookup(AUTOFILL, 356 "collideme")); 357 358 EXPECT_NE(bookmarknode.GetId(), prefnode.GetId()); 359 EXPECT_NE(autofillnode.GetId(), prefnode.GetId()); 360 EXPECT_NE(bookmarknode.GetId(), autofillnode.GetId()); 361 } 362 } 363 364 TEST_F(SyncApiTest, ReadMissingTagsFails) { 365 { 366 ReadTransaction trans(FROM_HERE, user_share()); 367 ReadNode node(&trans); 368 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD, 369 node.InitByClientTagLookup(BOOKMARKS, 370 "testtag")); 371 } 372 { 373 WriteTransaction trans(FROM_HERE, user_share()); 374 WriteNode node(&trans); 375 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD, 376 node.InitByClientTagLookup(BOOKMARKS, 377 "testtag")); 378 } 379 } 380 381 // TODO(chron): Hook this all up to the server and write full integration tests 382 // for update->undelete behavior. 383 TEST_F(SyncApiTest, TestDeleteBehavior) { 384 int64 node_id; 385 int64 folder_id; 386 std::string test_title("test1"); 387 388 { 389 WriteTransaction trans(FROM_HERE, user_share()); 390 ReadNode root_node(&trans); 391 root_node.InitByRootLookup(); 392 393 // we'll use this spare folder later 394 WriteNode folder_node(&trans); 395 EXPECT_TRUE(folder_node.InitBookmarkByCreation(root_node, NULL)); 396 folder_id = folder_node.GetId(); 397 398 WriteNode wnode(&trans); 399 WriteNode::InitUniqueByCreationResult result = 400 wnode.InitUniqueByCreation(BOOKMARKS, root_node, "testtag"); 401 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 402 wnode.SetIsFolder(false); 403 wnode.SetTitle(test_title); 404 405 node_id = wnode.GetId(); 406 } 407 408 // Ensure we can delete something with a tag. 409 { 410 WriteTransaction trans(FROM_HERE, user_share()); 411 WriteNode wnode(&trans); 412 EXPECT_EQ(BaseNode::INIT_OK, 413 wnode.InitByClientTagLookup(BOOKMARKS, 414 "testtag")); 415 EXPECT_FALSE(wnode.GetIsFolder()); 416 EXPECT_EQ(wnode.GetTitle(), test_title); 417 418 wnode.Tombstone(); 419 } 420 421 // Lookup of a node which was deleted should return failure, 422 // but have found some data about the node. 423 { 424 ReadTransaction trans(FROM_HERE, user_share()); 425 ReadNode node(&trans); 426 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_IS_DEL, 427 node.InitByClientTagLookup(BOOKMARKS, 428 "testtag")); 429 // Note that for proper function of this API this doesn't need to be 430 // filled, we're checking just to make sure the DB worked in this test. 431 EXPECT_EQ(node.GetTitle(), test_title); 432 } 433 434 { 435 WriteTransaction trans(FROM_HERE, user_share()); 436 ReadNode folder_node(&trans); 437 EXPECT_EQ(BaseNode::INIT_OK, folder_node.InitByIdLookup(folder_id)); 438 439 WriteNode wnode(&trans); 440 // This will undelete the tag. 441 WriteNode::InitUniqueByCreationResult result = 442 wnode.InitUniqueByCreation(BOOKMARKS, folder_node, "testtag"); 443 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 444 EXPECT_EQ(wnode.GetIsFolder(), false); 445 EXPECT_EQ(wnode.GetParentId(), folder_node.GetId()); 446 EXPECT_EQ(wnode.GetId(), node_id); 447 EXPECT_NE(wnode.GetTitle(), test_title); // Title should be cleared 448 wnode.SetTitle(test_title); 449 } 450 451 // Now look up should work. 452 { 453 ReadTransaction trans(FROM_HERE, user_share()); 454 ReadNode node(&trans); 455 EXPECT_EQ(BaseNode::INIT_OK, 456 node.InitByClientTagLookup(BOOKMARKS, 457 "testtag")); 458 EXPECT_EQ(node.GetTitle(), test_title); 459 EXPECT_EQ(node.GetModelType(), BOOKMARKS); 460 } 461 } 462 463 TEST_F(SyncApiTest, WriteAndReadPassword) { 464 KeyParams params = {"localhost", "username", "passphrase"}; 465 { 466 ReadTransaction trans(FROM_HERE, user_share()); 467 trans.GetCryptographer()->AddKey(params); 468 } 469 { 470 WriteTransaction trans(FROM_HERE, user_share()); 471 ReadNode root_node(&trans); 472 root_node.InitByRootLookup(); 473 474 WriteNode password_node(&trans); 475 WriteNode::InitUniqueByCreationResult result = 476 password_node.InitUniqueByCreation(PASSWORDS, 477 root_node, "foo"); 478 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 479 sync_pb::PasswordSpecificsData data; 480 data.set_password_value("secret"); 481 password_node.SetPasswordSpecifics(data); 482 } 483 { 484 ReadTransaction trans(FROM_HERE, user_share()); 485 ReadNode root_node(&trans); 486 root_node.InitByRootLookup(); 487 488 ReadNode password_node(&trans); 489 EXPECT_EQ(BaseNode::INIT_OK, 490 password_node.InitByClientTagLookup(PASSWORDS, "foo")); 491 const sync_pb::PasswordSpecificsData& data = 492 password_node.GetPasswordSpecifics(); 493 EXPECT_EQ("secret", data.password_value()); 494 } 495 } 496 497 TEST_F(SyncApiTest, WriteEncryptedTitle) { 498 KeyParams params = {"localhost", "username", "passphrase"}; 499 { 500 ReadTransaction trans(FROM_HERE, user_share()); 501 trans.GetCryptographer()->AddKey(params); 502 } 503 encryption_handler()->EnableEncryptEverything(); 504 int bookmark_id; 505 { 506 WriteTransaction trans(FROM_HERE, user_share()); 507 ReadNode root_node(&trans); 508 root_node.InitByRootLookup(); 509 510 WriteNode bookmark_node(&trans); 511 ASSERT_TRUE(bookmark_node.InitBookmarkByCreation(root_node, NULL)); 512 bookmark_id = bookmark_node.GetId(); 513 bookmark_node.SetTitle("foo"); 514 515 WriteNode pref_node(&trans); 516 WriteNode::InitUniqueByCreationResult result = 517 pref_node.InitUniqueByCreation(PREFERENCES, root_node, "bar"); 518 ASSERT_EQ(WriteNode::INIT_SUCCESS, result); 519 pref_node.SetTitle("bar"); 520 } 521 { 522 ReadTransaction trans(FROM_HERE, user_share()); 523 ReadNode root_node(&trans); 524 root_node.InitByRootLookup(); 525 526 ReadNode bookmark_node(&trans); 527 ASSERT_EQ(BaseNode::INIT_OK, bookmark_node.InitByIdLookup(bookmark_id)); 528 EXPECT_EQ("foo", bookmark_node.GetTitle()); 529 EXPECT_EQ(kEncryptedString, 530 bookmark_node.GetEntry()->GetNonUniqueName()); 531 532 ReadNode pref_node(&trans); 533 ASSERT_EQ(BaseNode::INIT_OK, 534 pref_node.InitByClientTagLookup(PREFERENCES, 535 "bar")); 536 EXPECT_EQ(kEncryptedString, pref_node.GetTitle()); 537 } 538 } 539 540 TEST_F(SyncApiTest, BaseNodeSetSpecifics) { 541 int64 child_id = MakeNode(user_share(), BOOKMARKS, "testtag"); 542 WriteTransaction trans(FROM_HERE, user_share()); 543 WriteNode node(&trans); 544 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id)); 545 546 sync_pb::EntitySpecifics entity_specifics; 547 entity_specifics.mutable_bookmark()->set_url("http://www.google.com"); 548 549 EXPECT_NE(entity_specifics.SerializeAsString(), 550 node.GetEntitySpecifics().SerializeAsString()); 551 node.SetEntitySpecifics(entity_specifics); 552 EXPECT_EQ(entity_specifics.SerializeAsString(), 553 node.GetEntitySpecifics().SerializeAsString()); 554 } 555 556 TEST_F(SyncApiTest, BaseNodeSetSpecificsPreservesUnknownFields) { 557 int64 child_id = MakeNode(user_share(), BOOKMARKS, "testtag"); 558 WriteTransaction trans(FROM_HERE, user_share()); 559 WriteNode node(&trans); 560 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id)); 561 EXPECT_TRUE(node.GetEntitySpecifics().unknown_fields().empty()); 562 563 sync_pb::EntitySpecifics entity_specifics; 564 entity_specifics.mutable_bookmark()->set_url("http://www.google.com"); 565 entity_specifics.mutable_unknown_fields()->AddFixed32(5, 100); 566 node.SetEntitySpecifics(entity_specifics); 567 EXPECT_FALSE(node.GetEntitySpecifics().unknown_fields().empty()); 568 569 entity_specifics.mutable_unknown_fields()->Clear(); 570 node.SetEntitySpecifics(entity_specifics); 571 EXPECT_FALSE(node.GetEntitySpecifics().unknown_fields().empty()); 572 } 573 574 TEST_F(SyncApiTest, EmptyTags) { 575 WriteTransaction trans(FROM_HERE, user_share()); 576 ReadNode root_node(&trans); 577 root_node.InitByRootLookup(); 578 WriteNode node(&trans); 579 std::string empty_tag; 580 WriteNode::InitUniqueByCreationResult result = 581 node.InitUniqueByCreation(TYPED_URLS, root_node, empty_tag); 582 EXPECT_NE(WriteNode::INIT_SUCCESS, result); 583 EXPECT_EQ(BaseNode::INIT_FAILED_PRECONDITION, 584 node.InitByClientTagLookup(TYPED_URLS, empty_tag)); 585 } 586 587 // Test counting nodes when the type's root node has no children. 588 TEST_F(SyncApiTest, GetTotalNodeCountEmpty) { 589 int64 type_root = MakeServerNodeForType(user_share(), BOOKMARKS); 590 { 591 ReadTransaction trans(FROM_HERE, user_share()); 592 ReadNode type_root_node(&trans); 593 EXPECT_EQ(BaseNode::INIT_OK, 594 type_root_node.InitByIdLookup(type_root)); 595 EXPECT_EQ(1, type_root_node.GetTotalNodeCount()); 596 } 597 } 598 599 // Test counting nodes when there is one child beneath the type's root. 600 TEST_F(SyncApiTest, GetTotalNodeCountOneChild) { 601 int64 type_root = MakeServerNodeForType(user_share(), BOOKMARKS); 602 int64 parent = MakeFolderWithParent(user_share(), BOOKMARKS, type_root, NULL); 603 { 604 ReadTransaction trans(FROM_HERE, user_share()); 605 ReadNode type_root_node(&trans); 606 EXPECT_EQ(BaseNode::INIT_OK, 607 type_root_node.InitByIdLookup(type_root)); 608 EXPECT_EQ(2, type_root_node.GetTotalNodeCount()); 609 ReadNode parent_node(&trans); 610 EXPECT_EQ(BaseNode::INIT_OK, 611 parent_node.InitByIdLookup(parent)); 612 EXPECT_EQ(1, parent_node.GetTotalNodeCount()); 613 } 614 } 615 616 // Test counting nodes when there are multiple children beneath the type root, 617 // and one of those children has children of its own. 618 TEST_F(SyncApiTest, GetTotalNodeCountMultipleChildren) { 619 int64 type_root = MakeServerNodeForType(user_share(), BOOKMARKS); 620 int64 parent = MakeFolderWithParent(user_share(), BOOKMARKS, type_root, NULL); 621 ignore_result(MakeFolderWithParent(user_share(), BOOKMARKS, type_root, NULL)); 622 int64 child1 = MakeFolderWithParent(user_share(), BOOKMARKS, parent, NULL); 623 ignore_result(MakeBookmarkWithParent(user_share(), parent, NULL)); 624 ignore_result(MakeBookmarkWithParent(user_share(), child1, NULL)); 625 626 { 627 ReadTransaction trans(FROM_HERE, user_share()); 628 ReadNode type_root_node(&trans); 629 EXPECT_EQ(BaseNode::INIT_OK, 630 type_root_node.InitByIdLookup(type_root)); 631 EXPECT_EQ(6, type_root_node.GetTotalNodeCount()); 632 ReadNode node(&trans); 633 EXPECT_EQ(BaseNode::INIT_OK, 634 node.InitByIdLookup(parent)); 635 EXPECT_EQ(4, node.GetTotalNodeCount()); 636 } 637 } 638 639 // Verify that Directory keeps track of which attachments are referenced by 640 // which entries. 641 TEST_F(SyncApiTest, AttachmentLinking) { 642 // Add an entry with an attachment. 643 std::string tag1("some tag"); 644 syncer::AttachmentId attachment_id(syncer::AttachmentId::Create()); 645 sync_pb::AttachmentMetadata attachment_metadata; 646 sync_pb::AttachmentMetadataRecord* record = attachment_metadata.add_record(); 647 *record->mutable_id() = attachment_id.GetProto(); 648 ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 649 CreateEntryWithAttachmentMetadata(PREFERENCES, tag1, attachment_metadata); 650 651 // See that the directory knows it's linked. 652 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 653 654 // Add a second entry referencing the same attachment. 655 std::string tag2("some other tag"); 656 CreateEntryWithAttachmentMetadata(PREFERENCES, tag2, attachment_metadata); 657 658 // See that the directory knows it's still linked. 659 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 660 661 // Tombstone the first entry. 662 ReplaceWithTombstone(syncer::PREFERENCES, tag1); 663 664 // See that the attachment is still considered linked because the entry hasn't 665 // been purged from the Directory. 666 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 667 668 // Save changes and see that the entry is truly gone. 669 ASSERT_TRUE(dir()->SaveChanges()); 670 ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag1), 671 syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD); 672 673 // However, the attachment is still linked. 674 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 675 676 // Save, destroy, and recreate the directory. See that it's still linked. 677 ASSERT_TRUE(ReloadDir()); 678 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 679 680 // Tombstone the second entry, save changes, see that it's truly gone. 681 ReplaceWithTombstone(syncer::PREFERENCES, tag2); 682 ASSERT_TRUE(dir()->SaveChanges()); 683 ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag2), 684 syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD); 685 686 // Finally, the attachment is no longer linked. 687 ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id.GetProto())); 688 } 689 690 namespace { 691 692 class TestHttpPostProviderInterface : public HttpPostProviderInterface { 693 public: 694 virtual ~TestHttpPostProviderInterface() {} 695 696 virtual void SetExtraRequestHeaders(const char* headers) OVERRIDE {} 697 virtual void SetURL(const char* url, int port) OVERRIDE {} 698 virtual void SetPostPayload(const char* content_type, 699 int content_length, 700 const char* content) OVERRIDE {} 701 virtual bool MakeSynchronousPost(int* error_code, int* response_code) 702 OVERRIDE { 703 return false; 704 } 705 virtual int GetResponseContentLength() const OVERRIDE { 706 return 0; 707 } 708 virtual const char* GetResponseContent() const OVERRIDE { 709 return ""; 710 } 711 virtual const std::string GetResponseHeaderValue( 712 const std::string& name) const OVERRIDE { 713 return std::string(); 714 } 715 virtual void Abort() OVERRIDE {} 716 }; 717 718 class TestHttpPostProviderFactory : public HttpPostProviderFactory { 719 public: 720 virtual ~TestHttpPostProviderFactory() {} 721 virtual void Init(const std::string& user_agent) OVERRIDE { } 722 virtual HttpPostProviderInterface* Create() OVERRIDE { 723 return new TestHttpPostProviderInterface(); 724 } 725 virtual void Destroy(HttpPostProviderInterface* http) OVERRIDE { 726 delete static_cast<TestHttpPostProviderInterface*>(http); 727 } 728 }; 729 730 class SyncManagerObserverMock : public SyncManager::Observer { 731 public: 732 MOCK_METHOD1(OnSyncCycleCompleted, 733 void(const SyncSessionSnapshot&)); // NOLINT 734 MOCK_METHOD4(OnInitializationComplete, 735 void(const WeakHandle<JsBackend>&, 736 const WeakHandle<DataTypeDebugInfoListener>&, 737 bool, 738 syncer::ModelTypeSet)); // NOLINT 739 MOCK_METHOD1(OnConnectionStatusChange, void(ConnectionStatus)); // NOLINT 740 MOCK_METHOD1(OnUpdatedToken, void(const std::string&)); // NOLINT 741 MOCK_METHOD1(OnActionableError, void(const SyncProtocolError&)); // NOLINT 742 MOCK_METHOD1(OnMigrationRequested, void(syncer::ModelTypeSet)); // NOLINT 743 MOCK_METHOD1(OnProtocolEvent, void(const ProtocolEvent&)); // NOLINT 744 }; 745 746 class SyncEncryptionHandlerObserverMock 747 : public SyncEncryptionHandler::Observer { 748 public: 749 MOCK_METHOD2(OnPassphraseRequired, 750 void(PassphraseRequiredReason, 751 const sync_pb::EncryptedData&)); // NOLINT 752 MOCK_METHOD0(OnPassphraseAccepted, void()); // NOLINT 753 MOCK_METHOD2(OnBootstrapTokenUpdated, 754 void(const std::string&, BootstrapTokenType type)); // NOLINT 755 MOCK_METHOD2(OnEncryptedTypesChanged, 756 void(ModelTypeSet, bool)); // NOLINT 757 MOCK_METHOD0(OnEncryptionComplete, void()); // NOLINT 758 MOCK_METHOD1(OnCryptographerStateChanged, void(Cryptographer*)); // NOLINT 759 MOCK_METHOD2(OnPassphraseTypeChanged, void(PassphraseType, 760 base::Time)); // NOLINT 761 }; 762 763 } // namespace 764 765 class SyncManagerTest : public testing::Test, 766 public SyncManager::ChangeDelegate { 767 protected: 768 enum NigoriStatus { 769 DONT_WRITE_NIGORI, 770 WRITE_TO_NIGORI 771 }; 772 773 enum EncryptionStatus { 774 UNINITIALIZED, 775 DEFAULT_ENCRYPTION, 776 FULL_ENCRYPTION 777 }; 778 779 SyncManagerTest() 780 : sync_manager_("Test sync manager") { 781 switches_.encryption_method = 782 InternalComponentsFactory::ENCRYPTION_KEYSTORE; 783 } 784 785 virtual ~SyncManagerTest() { 786 } 787 788 // Test implementation. 789 void SetUp() { 790 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 791 792 extensions_activity_ = new ExtensionsActivity(); 793 794 SyncCredentials credentials; 795 credentials.email = "foo (at) bar.com"; 796 credentials.sync_token = "sometoken"; 797 798 sync_manager_.AddObserver(&manager_observer_); 799 EXPECT_CALL(manager_observer_, OnInitializationComplete(_, _, _, _)). 800 WillOnce(DoAll(SaveArg<0>(&js_backend_), 801 SaveArg<2>(&initialization_succeeded_))); 802 803 EXPECT_FALSE(js_backend_.IsInitialized()); 804 805 std::vector<scoped_refptr<ModelSafeWorker> > workers; 806 ModelSafeRoutingInfo routing_info; 807 GetModelSafeRoutingInfo(&routing_info); 808 809 // This works only because all routing info types are GROUP_PASSIVE. 810 // If we had types in other groups, we would need additional workers 811 // to support them. 812 scoped_refptr<ModelSafeWorker> worker = new FakeModelWorker(GROUP_PASSIVE); 813 workers.push_back(worker); 814 815 // Takes ownership of |fake_invalidator_|. 816 sync_manager_.Init( 817 temp_dir_.path(), 818 WeakHandle<JsEventHandler>(), 819 "bogus", 820 0, 821 false, 822 scoped_ptr<HttpPostProviderFactory>(new TestHttpPostProviderFactory()), 823 workers, 824 extensions_activity_.get(), 825 this, 826 credentials, 827 "fake_invalidator_client_id", 828 std::string(), 829 std::string(), // bootstrap tokens 830 scoped_ptr<InternalComponentsFactory>(GetFactory()).get(), 831 &encryptor_, 832 scoped_ptr<UnrecoverableErrorHandler>( 833 new TestUnrecoverableErrorHandler).Pass(), 834 NULL, 835 &cancelation_signal_); 836 837 sync_manager_.GetEncryptionHandler()->AddObserver(&encryption_observer_); 838 839 EXPECT_TRUE(js_backend_.IsInitialized()); 840 841 if (initialization_succeeded_) { 842 for (ModelSafeRoutingInfo::iterator i = routing_info.begin(); 843 i != routing_info.end(); ++i) { 844 type_roots_[i->first] = MakeServerNodeForType( 845 sync_manager_.GetUserShare(), i->first); 846 } 847 } 848 849 PumpLoop(); 850 } 851 852 void TearDown() { 853 sync_manager_.RemoveObserver(&manager_observer_); 854 sync_manager_.ShutdownOnSyncThread(); 855 PumpLoop(); 856 } 857 858 void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) { 859 (*out)[NIGORI] = GROUP_PASSIVE; 860 (*out)[DEVICE_INFO] = GROUP_PASSIVE; 861 (*out)[EXPERIMENTS] = GROUP_PASSIVE; 862 (*out)[BOOKMARKS] = GROUP_PASSIVE; 863 (*out)[THEMES] = GROUP_PASSIVE; 864 (*out)[SESSIONS] = GROUP_PASSIVE; 865 (*out)[PASSWORDS] = GROUP_PASSIVE; 866 (*out)[PREFERENCES] = GROUP_PASSIVE; 867 (*out)[PRIORITY_PREFERENCES] = GROUP_PASSIVE; 868 } 869 870 ModelTypeSet GetEnabledTypes() { 871 ModelSafeRoutingInfo routing_info; 872 GetModelSafeRoutingInfo(&routing_info); 873 return GetRoutingInfoTypes(routing_info); 874 } 875 876 virtual void OnChangesApplied( 877 ModelType model_type, 878 int64 model_version, 879 const BaseTransaction* trans, 880 const ImmutableChangeRecordList& changes) OVERRIDE {} 881 882 virtual void OnChangesComplete(ModelType model_type) OVERRIDE {} 883 884 // Helper methods. 885 bool SetUpEncryption(NigoriStatus nigori_status, 886 EncryptionStatus encryption_status) { 887 UserShare* share = sync_manager_.GetUserShare(); 888 889 // We need to create the nigori node as if it were an applied server update. 890 int64 nigori_id = GetIdForDataType(NIGORI); 891 if (nigori_id == kInvalidId) 892 return false; 893 894 // Set the nigori cryptographer information. 895 if (encryption_status == FULL_ENCRYPTION) 896 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 897 898 WriteTransaction trans(FROM_HERE, share); 899 Cryptographer* cryptographer = trans.GetCryptographer(); 900 if (!cryptographer) 901 return false; 902 if (encryption_status != UNINITIALIZED) { 903 KeyParams params = {"localhost", "dummy", "foobar"}; 904 cryptographer->AddKey(params); 905 } else { 906 DCHECK_NE(nigori_status, WRITE_TO_NIGORI); 907 } 908 if (nigori_status == WRITE_TO_NIGORI) { 909 sync_pb::NigoriSpecifics nigori; 910 cryptographer->GetKeys(nigori.mutable_encryption_keybag()); 911 share->directory->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes( 912 &nigori, 913 trans.GetWrappedTrans()); 914 WriteNode node(&trans); 915 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(nigori_id)); 916 node.SetNigoriSpecifics(nigori); 917 } 918 return cryptographer->is_ready(); 919 } 920 921 int64 GetIdForDataType(ModelType type) { 922 if (type_roots_.count(type) == 0) 923 return 0; 924 return type_roots_[type]; 925 } 926 927 void PumpLoop() { 928 message_loop_.RunUntilIdle(); 929 } 930 931 void SetJsEventHandler(const WeakHandle<JsEventHandler>& event_handler) { 932 js_backend_.Call(FROM_HERE, &JsBackend::SetJsEventHandler, 933 event_handler); 934 PumpLoop(); 935 } 936 937 // Looks up an entry by client tag and resets IS_UNSYNCED value to false. 938 // Returns true if entry was previously unsynced, false if IS_UNSYNCED was 939 // already false. 940 bool ResetUnsyncedEntry(ModelType type, 941 const std::string& client_tag) { 942 UserShare* share = sync_manager_.GetUserShare(); 943 syncable::WriteTransaction trans( 944 FROM_HERE, syncable::UNITTEST, share->directory.get()); 945 const std::string hash = syncable::GenerateSyncableHash(type, client_tag); 946 syncable::MutableEntry entry(&trans, syncable::GET_BY_CLIENT_TAG, 947 hash); 948 EXPECT_TRUE(entry.good()); 949 if (!entry.GetIsUnsynced()) 950 return false; 951 entry.PutIsUnsynced(false); 952 return true; 953 } 954 955 virtual InternalComponentsFactory* GetFactory() { 956 return new TestInternalComponentsFactory(GetSwitches(), STORAGE_IN_MEMORY); 957 } 958 959 // Returns true if we are currently encrypting all sync data. May 960 // be called on any thread. 961 bool EncryptEverythingEnabledForTest() { 962 return sync_manager_.GetEncryptionHandler()->EncryptEverythingEnabled(); 963 } 964 965 // Gets the set of encrypted types from the cryptographer 966 // Note: opens a transaction. May be called from any thread. 967 ModelTypeSet GetEncryptedTypes() { 968 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 969 return GetEncryptedTypesWithTrans(&trans); 970 } 971 972 ModelTypeSet GetEncryptedTypesWithTrans(BaseTransaction* trans) { 973 return trans->GetDirectory()->GetNigoriHandler()-> 974 GetEncryptedTypes(trans->GetWrappedTrans()); 975 } 976 977 void SimulateInvalidatorStateChangeForTest(InvalidatorState state) { 978 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread()); 979 sync_manager_.OnInvalidatorStateChange(state); 980 } 981 982 void TriggerOnIncomingNotificationForTest(ModelTypeSet model_types) { 983 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread()); 984 ObjectIdSet id_set = ModelTypeSetToObjectIdSet(model_types); 985 ObjectIdInvalidationMap invalidation_map = 986 ObjectIdInvalidationMap::InvalidateAll(id_set); 987 sync_manager_.OnIncomingInvalidation(invalidation_map); 988 } 989 990 void SetProgressMarkerForType(ModelType type, bool set) { 991 if (set) { 992 sync_pb::DataTypeProgressMarker marker; 993 marker.set_token("token"); 994 marker.set_data_type_id(GetSpecificsFieldNumberFromModelType(type)); 995 sync_manager_.directory()->SetDownloadProgress(type, marker); 996 } else { 997 sync_pb::DataTypeProgressMarker marker; 998 sync_manager_.directory()->SetDownloadProgress(type, marker); 999 } 1000 } 1001 1002 InternalComponentsFactory::Switches GetSwitches() const { 1003 return switches_; 1004 } 1005 1006 private: 1007 // Needed by |sync_manager_|. 1008 base::MessageLoop message_loop_; 1009 // Needed by |sync_manager_|. 1010 base::ScopedTempDir temp_dir_; 1011 // Sync Id's for the roots of the enabled datatypes. 1012 std::map<ModelType, int64> type_roots_; 1013 scoped_refptr<ExtensionsActivity> extensions_activity_; 1014 1015 protected: 1016 FakeEncryptor encryptor_; 1017 SyncManagerImpl sync_manager_; 1018 CancelationSignal cancelation_signal_; 1019 WeakHandle<JsBackend> js_backend_; 1020 bool initialization_succeeded_; 1021 StrictMock<SyncManagerObserverMock> manager_observer_; 1022 StrictMock<SyncEncryptionHandlerObserverMock> encryption_observer_; 1023 InternalComponentsFactory::Switches switches_; 1024 }; 1025 1026 TEST_F(SyncManagerTest, GetAllNodesForTypeTest) { 1027 ModelSafeRoutingInfo routing_info; 1028 GetModelSafeRoutingInfo(&routing_info); 1029 sync_manager_.StartSyncingNormally(routing_info); 1030 1031 scoped_ptr<base::ListValue> node_list( 1032 sync_manager_.GetAllNodesForType(syncer::PREFERENCES)); 1033 1034 // Should have one node: the type root node. 1035 ASSERT_EQ(1U, node_list->GetSize()); 1036 1037 const base::DictionaryValue* first_result; 1038 ASSERT_TRUE(node_list->GetDictionary(0, &first_result)); 1039 EXPECT_TRUE(first_result->HasKey("ID")); 1040 EXPECT_TRUE(first_result->HasKey("NON_UNIQUE_NAME")); 1041 } 1042 1043 TEST_F(SyncManagerTest, RefreshEncryptionReady) { 1044 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1045 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1046 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1047 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1048 1049 sync_manager_.GetEncryptionHandler()->Init(); 1050 PumpLoop(); 1051 1052 const ModelTypeSet encrypted_types = GetEncryptedTypes(); 1053 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); 1054 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1055 1056 { 1057 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1058 ReadNode node(&trans); 1059 EXPECT_EQ(BaseNode::INIT_OK, 1060 node.InitByIdLookup(GetIdForDataType(NIGORI))); 1061 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); 1062 EXPECT_TRUE(nigori.has_encryption_keybag()); 1063 Cryptographer* cryptographer = trans.GetCryptographer(); 1064 EXPECT_TRUE(cryptographer->is_ready()); 1065 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); 1066 } 1067 } 1068 1069 // Attempt to refresh encryption when nigori not downloaded. 1070 TEST_F(SyncManagerTest, RefreshEncryptionNotReady) { 1071 // Don't set up encryption (no nigori node created). 1072 1073 // Should fail. Triggers an OnPassphraseRequired because the cryptographer 1074 // is not ready. 1075 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_, _)).Times(1); 1076 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1077 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1078 sync_manager_.GetEncryptionHandler()->Init(); 1079 PumpLoop(); 1080 1081 const ModelTypeSet encrypted_types = GetEncryptedTypes(); 1082 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded. 1083 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1084 } 1085 1086 // Attempt to refresh encryption when nigori is empty. 1087 TEST_F(SyncManagerTest, RefreshEncryptionEmptyNigori) { 1088 EXPECT_TRUE(SetUpEncryption(DONT_WRITE_NIGORI, DEFAULT_ENCRYPTION)); 1089 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()).Times(1); 1090 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1091 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1092 1093 // Should write to nigori. 1094 sync_manager_.GetEncryptionHandler()->Init(); 1095 PumpLoop(); 1096 1097 const ModelTypeSet encrypted_types = GetEncryptedTypes(); 1098 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded. 1099 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1100 1101 { 1102 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1103 ReadNode node(&trans); 1104 EXPECT_EQ(BaseNode::INIT_OK, 1105 node.InitByIdLookup(GetIdForDataType(NIGORI))); 1106 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); 1107 EXPECT_TRUE(nigori.has_encryption_keybag()); 1108 Cryptographer* cryptographer = trans.GetCryptographer(); 1109 EXPECT_TRUE(cryptographer->is_ready()); 1110 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); 1111 } 1112 } 1113 1114 TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) { 1115 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1116 EXPECT_CALL(encryption_observer_, 1117 OnEncryptedTypesChanged( 1118 HasModelTypes(EncryptableUserTypes()), true)); 1119 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1120 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1121 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1122 } 1123 1124 TEST_F(SyncManagerTest, EncryptDataTypesWithData) { 1125 size_t batch_size = 5; 1126 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1127 1128 // Create some unencrypted unsynced data. 1129 int64 folder = MakeFolderWithParent(sync_manager_.GetUserShare(), 1130 BOOKMARKS, 1131 GetIdForDataType(BOOKMARKS), 1132 NULL); 1133 // First batch_size nodes are children of folder. 1134 size_t i; 1135 for (i = 0; i < batch_size; ++i) { 1136 MakeBookmarkWithParent(sync_manager_.GetUserShare(), folder, NULL); 1137 } 1138 // Next batch_size nodes are a different type and on their own. 1139 for (; i < 2*batch_size; ++i) { 1140 MakeNode(sync_manager_.GetUserShare(), SESSIONS, 1141 base::StringPrintf("%" PRIuS "", i)); 1142 } 1143 // Last batch_size nodes are a third type that will not need encryption. 1144 for (; i < 3*batch_size; ++i) { 1145 MakeNode(sync_manager_.GetUserShare(), THEMES, 1146 base::StringPrintf("%" PRIuS "", i)); 1147 } 1148 1149 { 1150 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1151 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1152 SyncEncryptionHandler::SensitiveTypes())); 1153 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1154 trans.GetWrappedTrans(), 1155 BOOKMARKS, 1156 false /* not encrypted */)); 1157 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1158 trans.GetWrappedTrans(), 1159 SESSIONS, 1160 false /* not encrypted */)); 1161 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1162 trans.GetWrappedTrans(), 1163 THEMES, 1164 false /* not encrypted */)); 1165 } 1166 1167 EXPECT_CALL(encryption_observer_, 1168 OnEncryptedTypesChanged( 1169 HasModelTypes(EncryptableUserTypes()), true)); 1170 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1171 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1172 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1173 { 1174 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1175 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1176 EncryptableUserTypes())); 1177 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1178 trans.GetWrappedTrans(), 1179 BOOKMARKS, 1180 true /* is encrypted */)); 1181 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1182 trans.GetWrappedTrans(), 1183 SESSIONS, 1184 true /* is encrypted */)); 1185 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1186 trans.GetWrappedTrans(), 1187 THEMES, 1188 true /* is encrypted */)); 1189 } 1190 1191 // Trigger's a ReEncryptEverything with new passphrase. 1192 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1193 EXPECT_CALL(encryption_observer_, 1194 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1195 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1196 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1197 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1198 EXPECT_CALL(encryption_observer_, 1199 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1200 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1201 "new_passphrase", true); 1202 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1203 { 1204 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1205 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1206 EncryptableUserTypes())); 1207 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1208 trans.GetWrappedTrans(), 1209 BOOKMARKS, 1210 true /* is encrypted */)); 1211 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1212 trans.GetWrappedTrans(), 1213 SESSIONS, 1214 true /* is encrypted */)); 1215 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1216 trans.GetWrappedTrans(), 1217 THEMES, 1218 true /* is encrypted */)); 1219 } 1220 // Calling EncryptDataTypes with an empty encrypted types should not trigger 1221 // a reencryption and should just notify immediately. 1222 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1223 EXPECT_CALL(encryption_observer_, 1224 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)).Times(0); 1225 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()).Times(0); 1226 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()).Times(0); 1227 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1228 } 1229 1230 // Test that when there are no pending keys and the cryptographer is not 1231 // initialized, we add a key based on the current GAIA password. 1232 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1233 TEST_F(SyncManagerTest, SetInitialGaiaPass) { 1234 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED)); 1235 EXPECT_CALL(encryption_observer_, 1236 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1237 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1238 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1239 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1240 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1241 "new_passphrase", 1242 false); 1243 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1244 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1245 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1246 { 1247 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1248 ReadNode node(&trans); 1249 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1250 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); 1251 Cryptographer* cryptographer = trans.GetCryptographer(); 1252 EXPECT_TRUE(cryptographer->is_ready()); 1253 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); 1254 } 1255 } 1256 1257 // Test that when there are no pending keys and we have on the old GAIA 1258 // password, we update and re-encrypt everything with the new GAIA password. 1259 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1260 TEST_F(SyncManagerTest, UpdateGaiaPass) { 1261 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1262 Cryptographer verifier(&encryptor_); 1263 { 1264 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1265 Cryptographer* cryptographer = trans.GetCryptographer(); 1266 std::string bootstrap_token; 1267 cryptographer->GetBootstrapToken(&bootstrap_token); 1268 verifier.Bootstrap(bootstrap_token); 1269 } 1270 EXPECT_CALL(encryption_observer_, 1271 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1272 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1273 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1274 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1275 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1276 "new_passphrase", 1277 false); 1278 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1279 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1280 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1281 { 1282 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1283 Cryptographer* cryptographer = trans.GetCryptographer(); 1284 EXPECT_TRUE(cryptographer->is_ready()); 1285 // Verify the default key has changed. 1286 sync_pb::EncryptedData encrypted; 1287 cryptographer->GetKeys(&encrypted); 1288 EXPECT_FALSE(verifier.CanDecrypt(encrypted)); 1289 } 1290 } 1291 1292 // Sets a new explicit passphrase. This should update the bootstrap token 1293 // and re-encrypt everything. 1294 // (case 2 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1295 TEST_F(SyncManagerTest, SetPassphraseWithPassword) { 1296 Cryptographer verifier(&encryptor_); 1297 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1298 { 1299 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1300 // Store the default (soon to be old) key. 1301 Cryptographer* cryptographer = trans.GetCryptographer(); 1302 std::string bootstrap_token; 1303 cryptographer->GetBootstrapToken(&bootstrap_token); 1304 verifier.Bootstrap(bootstrap_token); 1305 1306 ReadNode root_node(&trans); 1307 root_node.InitByRootLookup(); 1308 1309 WriteNode password_node(&trans); 1310 WriteNode::InitUniqueByCreationResult result = 1311 password_node.InitUniqueByCreation(PASSWORDS, 1312 root_node, "foo"); 1313 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 1314 sync_pb::PasswordSpecificsData data; 1315 data.set_password_value("secret"); 1316 password_node.SetPasswordSpecifics(data); 1317 } 1318 EXPECT_CALL(encryption_observer_, 1319 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1320 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1321 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1322 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1323 EXPECT_CALL(encryption_observer_, 1324 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1325 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1326 "new_passphrase", 1327 true); 1328 EXPECT_EQ(CUSTOM_PASSPHRASE, 1329 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1330 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1331 { 1332 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1333 Cryptographer* cryptographer = trans.GetCryptographer(); 1334 EXPECT_TRUE(cryptographer->is_ready()); 1335 // Verify the default key has changed. 1336 sync_pb::EncryptedData encrypted; 1337 cryptographer->GetKeys(&encrypted); 1338 EXPECT_FALSE(verifier.CanDecrypt(encrypted)); 1339 1340 ReadNode password_node(&trans); 1341 EXPECT_EQ(BaseNode::INIT_OK, 1342 password_node.InitByClientTagLookup(PASSWORDS, 1343 "foo")); 1344 const sync_pb::PasswordSpecificsData& data = 1345 password_node.GetPasswordSpecifics(); 1346 EXPECT_EQ("secret", data.password_value()); 1347 } 1348 } 1349 1350 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1351 // being encrypted with a new (unprovided) GAIA password, then supply the 1352 // password. 1353 // (case 7 in SyncManager::SyncInternal::SetDecryptionPassphrase) 1354 TEST_F(SyncManagerTest, SupplyPendingGAIAPass) { 1355 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1356 Cryptographer other_cryptographer(&encryptor_); 1357 { 1358 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1359 Cryptographer* cryptographer = trans.GetCryptographer(); 1360 std::string bootstrap_token; 1361 cryptographer->GetBootstrapToken(&bootstrap_token); 1362 other_cryptographer.Bootstrap(bootstrap_token); 1363 1364 // Now update the nigori to reflect the new keys, and update the 1365 // cryptographer to have pending keys. 1366 KeyParams params = {"localhost", "dummy", "passphrase2"}; 1367 other_cryptographer.AddKey(params); 1368 WriteNode node(&trans); 1369 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1370 sync_pb::NigoriSpecifics nigori; 1371 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1372 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1373 EXPECT_TRUE(cryptographer->has_pending_keys()); 1374 node.SetNigoriSpecifics(nigori); 1375 } 1376 EXPECT_CALL(encryption_observer_, 1377 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1378 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1379 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1380 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1381 sync_manager_.GetEncryptionHandler()->SetDecryptionPassphrase("passphrase2"); 1382 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1383 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1384 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1385 { 1386 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1387 Cryptographer* cryptographer = trans.GetCryptographer(); 1388 EXPECT_TRUE(cryptographer->is_ready()); 1389 // Verify we're encrypting with the new key. 1390 sync_pb::EncryptedData encrypted; 1391 cryptographer->GetKeys(&encrypted); 1392 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted)); 1393 } 1394 } 1395 1396 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1397 // being encrypted with an old (unprovided) GAIA password. Attempt to supply 1398 // the current GAIA password and verify the bootstrap token is updated. Then 1399 // supply the old GAIA password, and verify we re-encrypt all data with the 1400 // new GAIA password. 1401 // (cases 4 and 5 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1402 TEST_F(SyncManagerTest, SupplyPendingOldGAIAPass) { 1403 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1404 Cryptographer other_cryptographer(&encryptor_); 1405 { 1406 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1407 Cryptographer* cryptographer = trans.GetCryptographer(); 1408 std::string bootstrap_token; 1409 cryptographer->GetBootstrapToken(&bootstrap_token); 1410 other_cryptographer.Bootstrap(bootstrap_token); 1411 1412 // Now update the nigori to reflect the new keys, and update the 1413 // cryptographer to have pending keys. 1414 KeyParams params = {"localhost", "dummy", "old_gaia"}; 1415 other_cryptographer.AddKey(params); 1416 WriteNode node(&trans); 1417 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1418 sync_pb::NigoriSpecifics nigori; 1419 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1420 node.SetNigoriSpecifics(nigori); 1421 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1422 1423 // other_cryptographer now contains all encryption keys, and is encrypting 1424 // with the newest gaia. 1425 KeyParams new_params = {"localhost", "dummy", "new_gaia"}; 1426 other_cryptographer.AddKey(new_params); 1427 } 1428 // The bootstrap token should have been updated. Save it to ensure it's based 1429 // on the new GAIA password. 1430 std::string bootstrap_token; 1431 EXPECT_CALL(encryption_observer_, 1432 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) 1433 .WillOnce(SaveArg<0>(&bootstrap_token)); 1434 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_,_)); 1435 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1436 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1437 "new_gaia", 1438 false); 1439 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1440 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1441 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1442 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1443 { 1444 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1445 Cryptographer* cryptographer = trans.GetCryptographer(); 1446 EXPECT_TRUE(cryptographer->is_initialized()); 1447 EXPECT_FALSE(cryptographer->is_ready()); 1448 // Verify we're encrypting with the new key, even though we have pending 1449 // keys. 1450 sync_pb::EncryptedData encrypted; 1451 other_cryptographer.GetKeys(&encrypted); 1452 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted)); 1453 } 1454 EXPECT_CALL(encryption_observer_, 1455 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1456 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1457 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1458 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1459 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1460 "old_gaia", 1461 false); 1462 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1463 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1464 { 1465 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1466 Cryptographer* cryptographer = trans.GetCryptographer(); 1467 EXPECT_TRUE(cryptographer->is_ready()); 1468 1469 // Verify we're encrypting with the new key. 1470 sync_pb::EncryptedData encrypted; 1471 other_cryptographer.GetKeys(&encrypted); 1472 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted)); 1473 1474 // Verify the saved bootstrap token is based on the new gaia password. 1475 Cryptographer temp_cryptographer(&encryptor_); 1476 temp_cryptographer.Bootstrap(bootstrap_token); 1477 EXPECT_TRUE(temp_cryptographer.CanDecrypt(encrypted)); 1478 } 1479 } 1480 1481 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1482 // being encrypted with an explicit (unprovided) passphrase, then supply the 1483 // passphrase. 1484 // (case 9 in SyncManager::SyncInternal::SetDecryptionPassphrase) 1485 TEST_F(SyncManagerTest, SupplyPendingExplicitPass) { 1486 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1487 Cryptographer other_cryptographer(&encryptor_); 1488 { 1489 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1490 Cryptographer* cryptographer = trans.GetCryptographer(); 1491 std::string bootstrap_token; 1492 cryptographer->GetBootstrapToken(&bootstrap_token); 1493 other_cryptographer.Bootstrap(bootstrap_token); 1494 1495 // Now update the nigori to reflect the new keys, and update the 1496 // cryptographer to have pending keys. 1497 KeyParams params = {"localhost", "dummy", "explicit"}; 1498 other_cryptographer.AddKey(params); 1499 WriteNode node(&trans); 1500 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1501 sync_pb::NigoriSpecifics nigori; 1502 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1503 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1504 EXPECT_TRUE(cryptographer->has_pending_keys()); 1505 nigori.set_keybag_is_frozen(true); 1506 node.SetNigoriSpecifics(nigori); 1507 } 1508 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1509 EXPECT_CALL(encryption_observer_, 1510 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1511 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_, _)); 1512 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1513 sync_manager_.GetEncryptionHandler()->Init(); 1514 EXPECT_CALL(encryption_observer_, 1515 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1516 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1517 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1518 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1519 sync_manager_.GetEncryptionHandler()->SetDecryptionPassphrase("explicit"); 1520 EXPECT_EQ(CUSTOM_PASSPHRASE, 1521 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1522 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1523 { 1524 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1525 Cryptographer* cryptographer = trans.GetCryptographer(); 1526 EXPECT_TRUE(cryptographer->is_ready()); 1527 // Verify we're encrypting with the new key. 1528 sync_pb::EncryptedData encrypted; 1529 cryptographer->GetKeys(&encrypted); 1530 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted)); 1531 } 1532 } 1533 1534 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1535 // being encrypted with a new (unprovided) GAIA password, then supply the 1536 // password as a user-provided password. 1537 // This is the android case 7/8. 1538 TEST_F(SyncManagerTest, SupplyPendingGAIAPassUserProvided) { 1539 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED)); 1540 Cryptographer other_cryptographer(&encryptor_); 1541 { 1542 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1543 Cryptographer* cryptographer = trans.GetCryptographer(); 1544 // Now update the nigori to reflect the new keys, and update the 1545 // cryptographer to have pending keys. 1546 KeyParams params = {"localhost", "dummy", "passphrase"}; 1547 other_cryptographer.AddKey(params); 1548 WriteNode node(&trans); 1549 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1550 sync_pb::NigoriSpecifics nigori; 1551 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1552 node.SetNigoriSpecifics(nigori); 1553 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1554 EXPECT_FALSE(cryptographer->is_ready()); 1555 } 1556 EXPECT_CALL(encryption_observer_, 1557 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1558 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1559 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1560 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1561 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1562 "passphrase", 1563 false); 1564 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1565 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1566 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1567 { 1568 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1569 Cryptographer* cryptographer = trans.GetCryptographer(); 1570 EXPECT_TRUE(cryptographer->is_ready()); 1571 } 1572 } 1573 1574 TEST_F(SyncManagerTest, SetPassphraseWithEmptyPasswordNode) { 1575 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1576 int64 node_id = 0; 1577 std::string tag = "foo"; 1578 { 1579 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1580 ReadNode root_node(&trans); 1581 root_node.InitByRootLookup(); 1582 1583 WriteNode password_node(&trans); 1584 WriteNode::InitUniqueByCreationResult result = 1585 password_node.InitUniqueByCreation(PASSWORDS, root_node, tag); 1586 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 1587 node_id = password_node.GetId(); 1588 } 1589 EXPECT_CALL(encryption_observer_, 1590 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1591 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1592 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1593 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1594 EXPECT_CALL(encryption_observer_, 1595 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1596 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1597 "new_passphrase", 1598 true); 1599 EXPECT_EQ(CUSTOM_PASSPHRASE, 1600 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1601 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1602 { 1603 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1604 ReadNode password_node(&trans); 1605 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY, 1606 password_node.InitByClientTagLookup(PASSWORDS, 1607 tag)); 1608 } 1609 { 1610 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1611 ReadNode password_node(&trans); 1612 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY, 1613 password_node.InitByIdLookup(node_id)); 1614 } 1615 } 1616 1617 TEST_F(SyncManagerTest, NudgeDelayTest) { 1618 EXPECT_EQ(sync_manager_.GetNudgeDelayTimeDelta(BOOKMARKS), 1619 base::TimeDelta::FromMilliseconds( 1620 SyncManagerImpl::GetDefaultNudgeDelay())); 1621 1622 EXPECT_EQ(sync_manager_.GetNudgeDelayTimeDelta(AUTOFILL), 1623 base::TimeDelta::FromSeconds( 1624 kDefaultShortPollIntervalSeconds)); 1625 1626 EXPECT_EQ(sync_manager_.GetNudgeDelayTimeDelta(PREFERENCES), 1627 base::TimeDelta::FromMilliseconds( 1628 SyncManagerImpl::GetPreferencesNudgeDelay())); 1629 } 1630 1631 // Friended by WriteNode, so can't be in an anonymouse namespace. 1632 TEST_F(SyncManagerTest, EncryptBookmarksWithLegacyData) { 1633 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1634 std::string title; 1635 SyncAPINameToServerName("Google", &title); 1636 std::string url = "http://www.google.com"; 1637 std::string raw_title2 = ".."; // An invalid cosmo title. 1638 std::string title2; 1639 SyncAPINameToServerName(raw_title2, &title2); 1640 std::string url2 = "http://www.bla.com"; 1641 1642 // Create a bookmark using the legacy format. 1643 int64 node_id1 = MakeNode(sync_manager_.GetUserShare(), 1644 BOOKMARKS, 1645 "testtag"); 1646 int64 node_id2 = MakeNode(sync_manager_.GetUserShare(), 1647 BOOKMARKS, 1648 "testtag2"); 1649 { 1650 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1651 WriteNode node(&trans); 1652 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1)); 1653 1654 sync_pb::EntitySpecifics entity_specifics; 1655 entity_specifics.mutable_bookmark()->set_url(url); 1656 node.SetEntitySpecifics(entity_specifics); 1657 1658 // Set the old style title. 1659 syncable::MutableEntry* node_entry = node.entry_; 1660 node_entry->PutNonUniqueName(title); 1661 1662 WriteNode node2(&trans); 1663 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2)); 1664 1665 sync_pb::EntitySpecifics entity_specifics2; 1666 entity_specifics2.mutable_bookmark()->set_url(url2); 1667 node2.SetEntitySpecifics(entity_specifics2); 1668 1669 // Set the old style title. 1670 syncable::MutableEntry* node_entry2 = node2.entry_; 1671 node_entry2->PutNonUniqueName(title2); 1672 } 1673 1674 { 1675 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1676 ReadNode node(&trans); 1677 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1)); 1678 EXPECT_EQ(BOOKMARKS, node.GetModelType()); 1679 EXPECT_EQ(title, node.GetTitle()); 1680 EXPECT_EQ(title, node.GetBookmarkSpecifics().title()); 1681 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 1682 1683 ReadNode node2(&trans); 1684 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2)); 1685 EXPECT_EQ(BOOKMARKS, node2.GetModelType()); 1686 // We should de-canonicalize the title in GetTitle(), but the title in the 1687 // specifics should be stored in the server legal form. 1688 EXPECT_EQ(raw_title2, node2.GetTitle()); 1689 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title()); 1690 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url()); 1691 } 1692 1693 { 1694 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1695 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1696 trans.GetWrappedTrans(), 1697 BOOKMARKS, 1698 false /* not encrypted */)); 1699 } 1700 1701 EXPECT_CALL(encryption_observer_, 1702 OnEncryptedTypesChanged( 1703 HasModelTypes(EncryptableUserTypes()), true)); 1704 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1705 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1706 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1707 1708 { 1709 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1710 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1711 EncryptableUserTypes())); 1712 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1713 trans.GetWrappedTrans(), 1714 BOOKMARKS, 1715 true /* is encrypted */)); 1716 1717 ReadNode node(&trans); 1718 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1)); 1719 EXPECT_EQ(BOOKMARKS, node.GetModelType()); 1720 EXPECT_EQ(title, node.GetTitle()); 1721 EXPECT_EQ(title, node.GetBookmarkSpecifics().title()); 1722 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 1723 1724 ReadNode node2(&trans); 1725 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2)); 1726 EXPECT_EQ(BOOKMARKS, node2.GetModelType()); 1727 // We should de-canonicalize the title in GetTitle(), but the title in the 1728 // specifics should be stored in the server legal form. 1729 EXPECT_EQ(raw_title2, node2.GetTitle()); 1730 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title()); 1731 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url()); 1732 } 1733 } 1734 1735 // Create a bookmark and set the title/url, then verify the data was properly 1736 // set. This replicates the unique way bookmarks have of creating sync nodes. 1737 // See BookmarkChangeProcessor::PlaceSyncNode(..). 1738 TEST_F(SyncManagerTest, CreateLocalBookmark) { 1739 std::string title = "title"; 1740 std::string url = "url"; 1741 { 1742 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1743 ReadNode bookmark_root(&trans); 1744 ASSERT_EQ(BaseNode::INIT_OK, bookmark_root.InitTypeRoot(BOOKMARKS)); 1745 WriteNode node(&trans); 1746 ASSERT_TRUE(node.InitBookmarkByCreation(bookmark_root, NULL)); 1747 node.SetIsFolder(false); 1748 node.SetTitle(title); 1749 1750 sync_pb::BookmarkSpecifics bookmark_specifics(node.GetBookmarkSpecifics()); 1751 bookmark_specifics.set_url(url); 1752 node.SetBookmarkSpecifics(bookmark_specifics); 1753 } 1754 { 1755 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1756 ReadNode bookmark_root(&trans); 1757 ASSERT_EQ(BaseNode::INIT_OK, bookmark_root.InitTypeRoot(BOOKMARKS)); 1758 int64 child_id = bookmark_root.GetFirstChildId(); 1759 1760 ReadNode node(&trans); 1761 ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id)); 1762 EXPECT_FALSE(node.GetIsFolder()); 1763 EXPECT_EQ(title, node.GetTitle()); 1764 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 1765 } 1766 } 1767 1768 // Verifies WriteNode::UpdateEntryWithEncryption does not make unnecessary 1769 // changes. 1770 TEST_F(SyncManagerTest, UpdateEntryWithEncryption) { 1771 std::string client_tag = "title"; 1772 sync_pb::EntitySpecifics entity_specifics; 1773 entity_specifics.mutable_bookmark()->set_url("url"); 1774 entity_specifics.mutable_bookmark()->set_title("title"); 1775 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 1776 syncable::GenerateSyncableHash(BOOKMARKS, 1777 client_tag), 1778 entity_specifics); 1779 // New node shouldn't start off unsynced. 1780 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1781 // Manually change to the same data. Should not set is_unsynced. 1782 { 1783 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1784 WriteNode node(&trans); 1785 EXPECT_EQ(BaseNode::INIT_OK, 1786 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1787 node.SetEntitySpecifics(entity_specifics); 1788 } 1789 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1790 1791 // Encrypt the datatatype, should set is_unsynced. 1792 EXPECT_CALL(encryption_observer_, 1793 OnEncryptedTypesChanged( 1794 HasModelTypes(EncryptableUserTypes()), true)); 1795 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1796 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION)); 1797 1798 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1799 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 1800 sync_manager_.GetEncryptionHandler()->Init(); 1801 PumpLoop(); 1802 { 1803 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1804 ReadNode node(&trans); 1805 EXPECT_EQ(BaseNode::INIT_OK, 1806 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1807 const syncable::Entry* node_entry = node.GetEntry(); 1808 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1809 EXPECT_TRUE(specifics.has_encrypted()); 1810 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1811 Cryptographer* cryptographer = trans.GetCryptographer(); 1812 EXPECT_TRUE(cryptographer->is_ready()); 1813 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1814 specifics.encrypted())); 1815 } 1816 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1817 1818 // Set a new passphrase. Should set is_unsynced. 1819 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1820 EXPECT_CALL(encryption_observer_, 1821 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1822 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1823 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1824 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1825 EXPECT_CALL(encryption_observer_, 1826 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1827 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1828 "new_passphrase", 1829 true); 1830 { 1831 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1832 ReadNode node(&trans); 1833 EXPECT_EQ(BaseNode::INIT_OK, 1834 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1835 const syncable::Entry* node_entry = node.GetEntry(); 1836 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1837 EXPECT_TRUE(specifics.has_encrypted()); 1838 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1839 Cryptographer* cryptographer = trans.GetCryptographer(); 1840 EXPECT_TRUE(cryptographer->is_ready()); 1841 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1842 specifics.encrypted())); 1843 } 1844 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1845 1846 // Force a re-encrypt everything. Should not set is_unsynced. 1847 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1848 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1849 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1850 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 1851 1852 sync_manager_.GetEncryptionHandler()->Init(); 1853 PumpLoop(); 1854 1855 { 1856 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1857 ReadNode node(&trans); 1858 EXPECT_EQ(BaseNode::INIT_OK, 1859 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1860 const syncable::Entry* node_entry = node.GetEntry(); 1861 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1862 EXPECT_TRUE(specifics.has_encrypted()); 1863 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1864 Cryptographer* cryptographer = trans.GetCryptographer(); 1865 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1866 specifics.encrypted())); 1867 } 1868 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1869 1870 // Manually change to the same data. Should not set is_unsynced. 1871 { 1872 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1873 WriteNode node(&trans); 1874 EXPECT_EQ(BaseNode::INIT_OK, 1875 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1876 node.SetEntitySpecifics(entity_specifics); 1877 const syncable::Entry* node_entry = node.GetEntry(); 1878 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1879 EXPECT_TRUE(specifics.has_encrypted()); 1880 EXPECT_FALSE(node_entry->GetIsUnsynced()); 1881 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1882 Cryptographer* cryptographer = trans.GetCryptographer(); 1883 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1884 specifics.encrypted())); 1885 } 1886 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1887 1888 // Manually change to different data. Should set is_unsynced. 1889 { 1890 entity_specifics.mutable_bookmark()->set_url("url2"); 1891 entity_specifics.mutable_bookmark()->set_title("title2"); 1892 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1893 WriteNode node(&trans); 1894 EXPECT_EQ(BaseNode::INIT_OK, 1895 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1896 node.SetEntitySpecifics(entity_specifics); 1897 const syncable::Entry* node_entry = node.GetEntry(); 1898 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1899 EXPECT_TRUE(specifics.has_encrypted()); 1900 EXPECT_TRUE(node_entry->GetIsUnsynced()); 1901 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1902 Cryptographer* cryptographer = trans.GetCryptographer(); 1903 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1904 specifics.encrypted())); 1905 } 1906 } 1907 1908 // Passwords have their own handling for encryption. Verify it does not result 1909 // in unnecessary writes via SetEntitySpecifics. 1910 TEST_F(SyncManagerTest, UpdatePasswordSetEntitySpecificsNoChange) { 1911 std::string client_tag = "title"; 1912 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1913 sync_pb::EntitySpecifics entity_specifics; 1914 { 1915 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1916 Cryptographer* cryptographer = trans.GetCryptographer(); 1917 sync_pb::PasswordSpecificsData data; 1918 data.set_password_value("secret"); 1919 cryptographer->Encrypt( 1920 data, 1921 entity_specifics.mutable_password()-> 1922 mutable_encrypted()); 1923 } 1924 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 1925 syncable::GenerateSyncableHash(PASSWORDS, 1926 client_tag), 1927 entity_specifics); 1928 // New node shouldn't start off unsynced. 1929 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1930 1931 // Manually change to the same data via SetEntitySpecifics. Should not set 1932 // is_unsynced. 1933 { 1934 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1935 WriteNode node(&trans); 1936 EXPECT_EQ(BaseNode::INIT_OK, 1937 node.InitByClientTagLookup(PASSWORDS, client_tag)); 1938 node.SetEntitySpecifics(entity_specifics); 1939 } 1940 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1941 } 1942 1943 // Passwords have their own handling for encryption. Verify it does not result 1944 // in unnecessary writes via SetPasswordSpecifics. 1945 TEST_F(SyncManagerTest, UpdatePasswordSetPasswordSpecifics) { 1946 std::string client_tag = "title"; 1947 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1948 sync_pb::EntitySpecifics entity_specifics; 1949 { 1950 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1951 Cryptographer* cryptographer = trans.GetCryptographer(); 1952 sync_pb::PasswordSpecificsData data; 1953 data.set_password_value("secret"); 1954 cryptographer->Encrypt( 1955 data, 1956 entity_specifics.mutable_password()-> 1957 mutable_encrypted()); 1958 } 1959 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 1960 syncable::GenerateSyncableHash(PASSWORDS, 1961 client_tag), 1962 entity_specifics); 1963 // New node shouldn't start off unsynced. 1964 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1965 1966 // Manually change to the same data via SetPasswordSpecifics. Should not set 1967 // is_unsynced. 1968 { 1969 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1970 WriteNode node(&trans); 1971 EXPECT_EQ(BaseNode::INIT_OK, 1972 node.InitByClientTagLookup(PASSWORDS, client_tag)); 1973 node.SetPasswordSpecifics(node.GetPasswordSpecifics()); 1974 } 1975 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1976 1977 // Manually change to different data. Should set is_unsynced. 1978 { 1979 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1980 WriteNode node(&trans); 1981 EXPECT_EQ(BaseNode::INIT_OK, 1982 node.InitByClientTagLookup(PASSWORDS, client_tag)); 1983 Cryptographer* cryptographer = trans.GetCryptographer(); 1984 sync_pb::PasswordSpecificsData data; 1985 data.set_password_value("secret2"); 1986 cryptographer->Encrypt( 1987 data, 1988 entity_specifics.mutable_password()->mutable_encrypted()); 1989 node.SetPasswordSpecifics(data); 1990 const syncable::Entry* node_entry = node.GetEntry(); 1991 EXPECT_TRUE(node_entry->GetIsUnsynced()); 1992 } 1993 } 1994 1995 // Passwords have their own handling for encryption. Verify setting a new 1996 // passphrase updates the data. 1997 TEST_F(SyncManagerTest, UpdatePasswordNewPassphrase) { 1998 std::string client_tag = "title"; 1999 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 2000 sync_pb::EntitySpecifics entity_specifics; 2001 { 2002 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2003 Cryptographer* cryptographer = trans.GetCryptographer(); 2004 sync_pb::PasswordSpecificsData data; 2005 data.set_password_value("secret"); 2006 cryptographer->Encrypt( 2007 data, 2008 entity_specifics.mutable_password()->mutable_encrypted()); 2009 } 2010 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 2011 syncable::GenerateSyncableHash(PASSWORDS, 2012 client_tag), 2013 entity_specifics); 2014 // New node shouldn't start off unsynced. 2015 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2016 2017 // Set a new passphrase. Should set is_unsynced. 2018 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 2019 EXPECT_CALL(encryption_observer_, 2020 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 2021 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 2022 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2023 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2024 EXPECT_CALL(encryption_observer_, 2025 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 2026 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 2027 "new_passphrase", 2028 true); 2029 EXPECT_EQ(CUSTOM_PASSPHRASE, 2030 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 2031 EXPECT_TRUE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2032 } 2033 2034 // Passwords have their own handling for encryption. Verify it does not result 2035 // in unnecessary writes via ReencryptEverything. 2036 TEST_F(SyncManagerTest, UpdatePasswordReencryptEverything) { 2037 std::string client_tag = "title"; 2038 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 2039 sync_pb::EntitySpecifics entity_specifics; 2040 { 2041 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2042 Cryptographer* cryptographer = trans.GetCryptographer(); 2043 sync_pb::PasswordSpecificsData data; 2044 data.set_password_value("secret"); 2045 cryptographer->Encrypt( 2046 data, 2047 entity_specifics.mutable_password()->mutable_encrypted()); 2048 } 2049 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 2050 syncable::GenerateSyncableHash(PASSWORDS, 2051 client_tag), 2052 entity_specifics); 2053 // New node shouldn't start off unsynced. 2054 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2055 2056 // Force a re-encrypt everything. Should not set is_unsynced. 2057 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 2058 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2059 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2060 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 2061 sync_manager_.GetEncryptionHandler()->Init(); 2062 PumpLoop(); 2063 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2064 } 2065 2066 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for bookmarks 2067 // when we write the same data, but does set it when we write new data. 2068 TEST_F(SyncManagerTest, SetBookmarkTitle) { 2069 std::string client_tag = "title"; 2070 sync_pb::EntitySpecifics entity_specifics; 2071 entity_specifics.mutable_bookmark()->set_url("url"); 2072 entity_specifics.mutable_bookmark()->set_title("title"); 2073 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2074 syncable::GenerateSyncableHash(BOOKMARKS, 2075 client_tag), 2076 entity_specifics); 2077 // New node shouldn't start off unsynced. 2078 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2079 2080 // Manually change to the same title. Should not set is_unsynced. 2081 { 2082 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2083 WriteNode node(&trans); 2084 EXPECT_EQ(BaseNode::INIT_OK, 2085 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2086 node.SetTitle(client_tag); 2087 } 2088 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2089 2090 // Manually change to new title. Should set is_unsynced. 2091 { 2092 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2093 WriteNode node(&trans); 2094 EXPECT_EQ(BaseNode::INIT_OK, 2095 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2096 node.SetTitle("title2"); 2097 } 2098 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2099 } 2100 2101 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted 2102 // bookmarks when we write the same data, but does set it when we write new 2103 // data. 2104 TEST_F(SyncManagerTest, SetBookmarkTitleWithEncryption) { 2105 std::string client_tag = "title"; 2106 sync_pb::EntitySpecifics entity_specifics; 2107 entity_specifics.mutable_bookmark()->set_url("url"); 2108 entity_specifics.mutable_bookmark()->set_title("title"); 2109 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2110 syncable::GenerateSyncableHash(BOOKMARKS, 2111 client_tag), 2112 entity_specifics); 2113 // New node shouldn't start off unsynced. 2114 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2115 2116 // Encrypt the datatatype, should set is_unsynced. 2117 EXPECT_CALL(encryption_observer_, 2118 OnEncryptedTypesChanged( 2119 HasModelTypes(EncryptableUserTypes()), true)); 2120 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2121 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION)); 2122 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2123 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 2124 sync_manager_.GetEncryptionHandler()->Init(); 2125 PumpLoop(); 2126 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2127 2128 // Manually change to the same title. Should not set is_unsynced. 2129 // NON_UNIQUE_NAME should be kEncryptedString. 2130 { 2131 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2132 WriteNode node(&trans); 2133 EXPECT_EQ(BaseNode::INIT_OK, 2134 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2135 node.SetTitle(client_tag); 2136 const syncable::Entry* node_entry = node.GetEntry(); 2137 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2138 EXPECT_TRUE(specifics.has_encrypted()); 2139 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2140 } 2141 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2142 2143 // Manually change to new title. Should set is_unsynced. NON_UNIQUE_NAME 2144 // should still be kEncryptedString. 2145 { 2146 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2147 WriteNode node(&trans); 2148 EXPECT_EQ(BaseNode::INIT_OK, 2149 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2150 node.SetTitle("title2"); 2151 const syncable::Entry* node_entry = node.GetEntry(); 2152 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2153 EXPECT_TRUE(specifics.has_encrypted()); 2154 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2155 } 2156 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2157 } 2158 2159 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for non-bookmarks 2160 // when we write the same data, but does set it when we write new data. 2161 TEST_F(SyncManagerTest, SetNonBookmarkTitle) { 2162 std::string client_tag = "title"; 2163 sync_pb::EntitySpecifics entity_specifics; 2164 entity_specifics.mutable_preference()->set_name("name"); 2165 entity_specifics.mutable_preference()->set_value("value"); 2166 MakeServerNode(sync_manager_.GetUserShare(), 2167 PREFERENCES, 2168 client_tag, 2169 syncable::GenerateSyncableHash(PREFERENCES, 2170 client_tag), 2171 entity_specifics); 2172 // New node shouldn't start off unsynced. 2173 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2174 2175 // Manually change to the same title. Should not set is_unsynced. 2176 { 2177 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2178 WriteNode node(&trans); 2179 EXPECT_EQ(BaseNode::INIT_OK, 2180 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2181 node.SetTitle(client_tag); 2182 } 2183 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2184 2185 // Manually change to new title. Should set is_unsynced. 2186 { 2187 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2188 WriteNode node(&trans); 2189 EXPECT_EQ(BaseNode::INIT_OK, 2190 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2191 node.SetTitle("title2"); 2192 } 2193 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2194 } 2195 2196 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted 2197 // non-bookmarks when we write the same data or when we write new data 2198 // data (should remained kEncryptedString). 2199 TEST_F(SyncManagerTest, SetNonBookmarkTitleWithEncryption) { 2200 std::string client_tag = "title"; 2201 sync_pb::EntitySpecifics entity_specifics; 2202 entity_specifics.mutable_preference()->set_name("name"); 2203 entity_specifics.mutable_preference()->set_value("value"); 2204 MakeServerNode(sync_manager_.GetUserShare(), 2205 PREFERENCES, 2206 client_tag, 2207 syncable::GenerateSyncableHash(PREFERENCES, 2208 client_tag), 2209 entity_specifics); 2210 // New node shouldn't start off unsynced. 2211 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2212 2213 // Encrypt the datatatype, should set is_unsynced. 2214 EXPECT_CALL(encryption_observer_, 2215 OnEncryptedTypesChanged( 2216 HasModelTypes(EncryptableUserTypes()), true)); 2217 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2218 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION)); 2219 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2220 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 2221 sync_manager_.GetEncryptionHandler()->Init(); 2222 PumpLoop(); 2223 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2224 2225 // Manually change to the same title. Should not set is_unsynced. 2226 // NON_UNIQUE_NAME should be kEncryptedString. 2227 { 2228 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2229 WriteNode node(&trans); 2230 EXPECT_EQ(BaseNode::INIT_OK, 2231 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2232 node.SetTitle(client_tag); 2233 const syncable::Entry* node_entry = node.GetEntry(); 2234 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2235 EXPECT_TRUE(specifics.has_encrypted()); 2236 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2237 } 2238 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2239 2240 // Manually change to new title. Should not set is_unsynced because the 2241 // NON_UNIQUE_NAME should still be kEncryptedString. 2242 { 2243 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2244 WriteNode node(&trans); 2245 EXPECT_EQ(BaseNode::INIT_OK, 2246 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2247 node.SetTitle("title2"); 2248 const syncable::Entry* node_entry = node.GetEntry(); 2249 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2250 EXPECT_TRUE(specifics.has_encrypted()); 2251 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2252 EXPECT_FALSE(node_entry->GetIsUnsynced()); 2253 } 2254 } 2255 2256 // Ensure that titles are truncated to 255 bytes, and attempting to reset 2257 // them to their longer version does not set IS_UNSYNCED. 2258 TEST_F(SyncManagerTest, SetLongTitle) { 2259 const int kNumChars = 512; 2260 const std::string kClientTag = "tag"; 2261 std::string title(kNumChars, '0'); 2262 sync_pb::EntitySpecifics entity_specifics; 2263 entity_specifics.mutable_preference()->set_name("name"); 2264 entity_specifics.mutable_preference()->set_value("value"); 2265 MakeServerNode(sync_manager_.GetUserShare(), 2266 PREFERENCES, 2267 "short_title", 2268 syncable::GenerateSyncableHash(PREFERENCES, 2269 kClientTag), 2270 entity_specifics); 2271 // New node shouldn't start off unsynced. 2272 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2273 2274 // Manually change to the long title. Should set is_unsynced. 2275 { 2276 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2277 WriteNode node(&trans); 2278 EXPECT_EQ(BaseNode::INIT_OK, 2279 node.InitByClientTagLookup(PREFERENCES, kClientTag)); 2280 node.SetTitle(title); 2281 EXPECT_EQ(node.GetTitle(), title.substr(0, 255)); 2282 } 2283 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2284 2285 // Manually change to the same title. Should not set is_unsynced. 2286 { 2287 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2288 WriteNode node(&trans); 2289 EXPECT_EQ(BaseNode::INIT_OK, 2290 node.InitByClientTagLookup(PREFERENCES, kClientTag)); 2291 node.SetTitle(title); 2292 EXPECT_EQ(node.GetTitle(), title.substr(0, 255)); 2293 } 2294 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2295 2296 // Manually change to new title. Should set is_unsynced. 2297 { 2298 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2299 WriteNode node(&trans); 2300 EXPECT_EQ(BaseNode::INIT_OK, 2301 node.InitByClientTagLookup(PREFERENCES, kClientTag)); 2302 node.SetTitle("title2"); 2303 } 2304 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2305 } 2306 2307 // Create an encrypted entry when the cryptographer doesn't think the type is 2308 // marked for encryption. Ensure reads/writes don't break and don't unencrypt 2309 // the data. 2310 TEST_F(SyncManagerTest, SetPreviouslyEncryptedSpecifics) { 2311 std::string client_tag = "tag"; 2312 std::string url = "url"; 2313 std::string url2 = "new_url"; 2314 std::string title = "title"; 2315 sync_pb::EntitySpecifics entity_specifics; 2316 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 2317 { 2318 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2319 Cryptographer* crypto = trans.GetCryptographer(); 2320 sync_pb::EntitySpecifics bm_specifics; 2321 bm_specifics.mutable_bookmark()->set_title("title"); 2322 bm_specifics.mutable_bookmark()->set_url("url"); 2323 sync_pb::EncryptedData encrypted; 2324 crypto->Encrypt(bm_specifics, &encrypted); 2325 entity_specifics.mutable_encrypted()->CopyFrom(encrypted); 2326 AddDefaultFieldValue(BOOKMARKS, &entity_specifics); 2327 } 2328 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2329 syncable::GenerateSyncableHash(BOOKMARKS, 2330 client_tag), 2331 entity_specifics); 2332 2333 { 2334 // Verify the data. 2335 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2336 ReadNode node(&trans); 2337 EXPECT_EQ(BaseNode::INIT_OK, 2338 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2339 EXPECT_EQ(title, node.GetTitle()); 2340 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 2341 } 2342 2343 { 2344 // Overwrite the url (which overwrites the specifics). 2345 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2346 WriteNode node(&trans); 2347 EXPECT_EQ(BaseNode::INIT_OK, 2348 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2349 2350 sync_pb::BookmarkSpecifics bookmark_specifics(node.GetBookmarkSpecifics()); 2351 bookmark_specifics.set_url(url2); 2352 node.SetBookmarkSpecifics(bookmark_specifics); 2353 } 2354 2355 { 2356 // Verify it's still encrypted and it has the most recent url. 2357 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2358 ReadNode node(&trans); 2359 EXPECT_EQ(BaseNode::INIT_OK, 2360 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2361 EXPECT_EQ(title, node.GetTitle()); 2362 EXPECT_EQ(url2, node.GetBookmarkSpecifics().url()); 2363 const syncable::Entry* node_entry = node.GetEntry(); 2364 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2365 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2366 EXPECT_TRUE(specifics.has_encrypted()); 2367 } 2368 } 2369 2370 // Verify transaction version of a model type is incremented when node of 2371 // that type is updated. 2372 TEST_F(SyncManagerTest, IncrementTransactionVersion) { 2373 ModelSafeRoutingInfo routing_info; 2374 GetModelSafeRoutingInfo(&routing_info); 2375 2376 { 2377 ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare()); 2378 for (ModelSafeRoutingInfo::iterator i = routing_info.begin(); 2379 i != routing_info.end(); ++i) { 2380 // Transaction version is incremented when SyncManagerTest::SetUp() 2381 // creates a node of each type. 2382 EXPECT_EQ(1, 2383 sync_manager_.GetUserShare()->directory-> 2384 GetTransactionVersion(i->first)); 2385 } 2386 } 2387 2388 // Create bookmark node to increment transaction version of bookmark model. 2389 std::string client_tag = "title"; 2390 sync_pb::EntitySpecifics entity_specifics; 2391 entity_specifics.mutable_bookmark()->set_url("url"); 2392 entity_specifics.mutable_bookmark()->set_title("title"); 2393 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2394 syncable::GenerateSyncableHash(BOOKMARKS, 2395 client_tag), 2396 entity_specifics); 2397 2398 { 2399 ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare()); 2400 for (ModelSafeRoutingInfo::iterator i = routing_info.begin(); 2401 i != routing_info.end(); ++i) { 2402 EXPECT_EQ(i->first == BOOKMARKS ? 2 : 1, 2403 sync_manager_.GetUserShare()->directory-> 2404 GetTransactionVersion(i->first)); 2405 } 2406 } 2407 } 2408 2409 class MockSyncScheduler : public FakeSyncScheduler { 2410 public: 2411 MockSyncScheduler() : FakeSyncScheduler() {} 2412 virtual ~MockSyncScheduler() {} 2413 2414 MOCK_METHOD1(Start, void(SyncScheduler::Mode)); 2415 MOCK_METHOD1(ScheduleConfiguration, void(const ConfigurationParams&)); 2416 }; 2417 2418 class ComponentsFactory : public TestInternalComponentsFactory { 2419 public: 2420 ComponentsFactory(const Switches& switches, 2421 SyncScheduler* scheduler_to_use, 2422 sessions::SyncSessionContext** session_context) 2423 : TestInternalComponentsFactory(switches, syncer::STORAGE_IN_MEMORY), 2424 scheduler_to_use_(scheduler_to_use), 2425 session_context_(session_context) {} 2426 virtual ~ComponentsFactory() {} 2427 2428 virtual scoped_ptr<SyncScheduler> BuildScheduler( 2429 const std::string& name, 2430 sessions::SyncSessionContext* context, 2431 CancelationSignal* stop_handle) OVERRIDE { 2432 *session_context_ = context; 2433 return scheduler_to_use_.Pass(); 2434 } 2435 2436 private: 2437 scoped_ptr<SyncScheduler> scheduler_to_use_; 2438 sessions::SyncSessionContext** session_context_; 2439 }; 2440 2441 class SyncManagerTestWithMockScheduler : public SyncManagerTest { 2442 public: 2443 SyncManagerTestWithMockScheduler() : scheduler_(NULL) {} 2444 virtual InternalComponentsFactory* GetFactory() OVERRIDE { 2445 scheduler_ = new MockSyncScheduler(); 2446 return new ComponentsFactory(GetSwitches(), scheduler_, &session_context_); 2447 } 2448 2449 MockSyncScheduler* scheduler() { return scheduler_; } 2450 sessions::SyncSessionContext* session_context() { 2451 return session_context_; 2452 } 2453 2454 private: 2455 MockSyncScheduler* scheduler_; 2456 sessions::SyncSessionContext* session_context_; 2457 }; 2458 2459 // Test that the configuration params are properly created and sent to 2460 // ScheduleConfigure. No callback should be invoked. Any disabled datatypes 2461 // should be purged. 2462 TEST_F(SyncManagerTestWithMockScheduler, BasicConfiguration) { 2463 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION; 2464 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES); 2465 ModelSafeRoutingInfo new_routing_info; 2466 GetModelSafeRoutingInfo(&new_routing_info); 2467 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info); 2468 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types); 2469 2470 ConfigurationParams params; 2471 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE)); 2472 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)). 2473 WillOnce(SaveArg<0>(¶ms)); 2474 2475 // Set data for all types. 2476 ModelTypeSet protocol_types = ProtocolTypes(); 2477 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2478 iter.Inc()) { 2479 SetProgressMarkerForType(iter.Get(), true); 2480 } 2481 2482 CallbackCounter ready_task_counter, retry_task_counter; 2483 sync_manager_.ConfigureSyncer( 2484 reason, 2485 types_to_download, 2486 disabled_types, 2487 ModelTypeSet(), 2488 ModelTypeSet(), 2489 new_routing_info, 2490 base::Bind(&CallbackCounter::Callback, 2491 base::Unretained(&ready_task_counter)), 2492 base::Bind(&CallbackCounter::Callback, 2493 base::Unretained(&retry_task_counter))); 2494 EXPECT_EQ(0, ready_task_counter.times_called()); 2495 EXPECT_EQ(0, retry_task_counter.times_called()); 2496 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, 2497 params.source); 2498 EXPECT_TRUE(types_to_download.Equals(params.types_to_download)); 2499 EXPECT_EQ(new_routing_info, params.routing_info); 2500 2501 // Verify all the disabled types were purged. 2502 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().Equals( 2503 enabled_types)); 2504 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken( 2505 ModelTypeSet::All()).Equals(disabled_types)); 2506 } 2507 2508 // Test that on a reconfiguration (configuration where the session context 2509 // already has routing info), only those recently disabled types are purged. 2510 TEST_F(SyncManagerTestWithMockScheduler, ReConfiguration) { 2511 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION; 2512 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES); 2513 ModelTypeSet disabled_types = ModelTypeSet(THEMES, SESSIONS); 2514 ModelSafeRoutingInfo old_routing_info; 2515 ModelSafeRoutingInfo new_routing_info; 2516 GetModelSafeRoutingInfo(&old_routing_info); 2517 new_routing_info = old_routing_info; 2518 new_routing_info.erase(THEMES); 2519 new_routing_info.erase(SESSIONS); 2520 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info); 2521 2522 ConfigurationParams params; 2523 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE)); 2524 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)). 2525 WillOnce(SaveArg<0>(¶ms)); 2526 2527 // Set data for all types except those recently disabled (so we can verify 2528 // only those recently disabled are purged) . 2529 ModelTypeSet protocol_types = ProtocolTypes(); 2530 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2531 iter.Inc()) { 2532 if (!disabled_types.Has(iter.Get())) { 2533 SetProgressMarkerForType(iter.Get(), true); 2534 } else { 2535 SetProgressMarkerForType(iter.Get(), false); 2536 } 2537 } 2538 2539 // Set the context to have the old routing info. 2540 session_context()->SetRoutingInfo(old_routing_info); 2541 2542 CallbackCounter ready_task_counter, retry_task_counter; 2543 sync_manager_.ConfigureSyncer( 2544 reason, 2545 types_to_download, 2546 ModelTypeSet(), 2547 ModelTypeSet(), 2548 ModelTypeSet(), 2549 new_routing_info, 2550 base::Bind(&CallbackCounter::Callback, 2551 base::Unretained(&ready_task_counter)), 2552 base::Bind(&CallbackCounter::Callback, 2553 base::Unretained(&retry_task_counter))); 2554 EXPECT_EQ(0, ready_task_counter.times_called()); 2555 EXPECT_EQ(0, retry_task_counter.times_called()); 2556 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, 2557 params.source); 2558 EXPECT_TRUE(types_to_download.Equals(params.types_to_download)); 2559 EXPECT_EQ(new_routing_info, params.routing_info); 2560 2561 // Verify only the recently disabled types were purged. 2562 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken( 2563 ProtocolTypes()).Equals(disabled_types)); 2564 } 2565 2566 // Test that PurgePartiallySyncedTypes purges only those types that have not 2567 // fully completed their initial download and apply. 2568 TEST_F(SyncManagerTest, PurgePartiallySyncedTypes) { 2569 ModelSafeRoutingInfo routing_info; 2570 GetModelSafeRoutingInfo(&routing_info); 2571 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); 2572 2573 UserShare* share = sync_manager_.GetUserShare(); 2574 2575 // The test harness automatically initializes all types in the routing info. 2576 // Check that autofill is not among them. 2577 ASSERT_FALSE(enabled_types.Has(AUTOFILL)); 2578 2579 // Further ensure that the test harness did not create its root node. 2580 { 2581 syncable::ReadTransaction trans(FROM_HERE, share->directory.get()); 2582 syncable::Entry autofill_root_node(&trans, 2583 syncable::GET_TYPE_ROOT, 2584 AUTOFILL); 2585 ASSERT_FALSE(autofill_root_node.good()); 2586 } 2587 2588 // One more redundant check. 2589 ASSERT_FALSE(sync_manager_.InitialSyncEndedTypes().Has(AUTOFILL)); 2590 2591 // Give autofill a progress marker. 2592 sync_pb::DataTypeProgressMarker autofill_marker; 2593 autofill_marker.set_data_type_id( 2594 GetSpecificsFieldNumberFromModelType(AUTOFILL)); 2595 autofill_marker.set_token("token"); 2596 share->directory->SetDownloadProgress(AUTOFILL, autofill_marker); 2597 2598 // Also add a pending autofill root node update from the server. 2599 TestEntryFactory factory_(share->directory.get()); 2600 int autofill_meta = factory_.CreateUnappliedRootNode(AUTOFILL); 2601 2602 // Preferences is an enabled type. Check that the harness initialized it. 2603 ASSERT_TRUE(enabled_types.Has(PREFERENCES)); 2604 ASSERT_TRUE(sync_manager_.InitialSyncEndedTypes().Has(PREFERENCES)); 2605 2606 // Give preferencse a progress marker. 2607 sync_pb::DataTypeProgressMarker prefs_marker; 2608 prefs_marker.set_data_type_id( 2609 GetSpecificsFieldNumberFromModelType(PREFERENCES)); 2610 prefs_marker.set_token("token"); 2611 share->directory->SetDownloadProgress(PREFERENCES, prefs_marker); 2612 2613 // Add a fully synced preferences node under the root. 2614 std::string pref_client_tag = "prefABC"; 2615 std::string pref_hashed_tag = "hashXYZ"; 2616 sync_pb::EntitySpecifics pref_specifics; 2617 AddDefaultFieldValue(PREFERENCES, &pref_specifics); 2618 int pref_meta = MakeServerNode( 2619 share, PREFERENCES, pref_client_tag, pref_hashed_tag, pref_specifics); 2620 2621 // And now, the purge. 2622 EXPECT_TRUE(sync_manager_.PurgePartiallySyncedTypes()); 2623 2624 // Ensure that autofill lost its progress marker, but preferences did not. 2625 ModelTypeSet empty_tokens = 2626 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All()); 2627 EXPECT_TRUE(empty_tokens.Has(AUTOFILL)); 2628 EXPECT_FALSE(empty_tokens.Has(PREFERENCES)); 2629 2630 // Ensure that autofill lots its node, but preferences did not. 2631 { 2632 syncable::ReadTransaction trans(FROM_HERE, share->directory.get()); 2633 syncable::Entry autofill_node(&trans, GET_BY_HANDLE, autofill_meta); 2634 syncable::Entry pref_node(&trans, GET_BY_HANDLE, pref_meta); 2635 EXPECT_FALSE(autofill_node.good()); 2636 EXPECT_TRUE(pref_node.good()); 2637 } 2638 } 2639 2640 // Test CleanupDisabledTypes properly purges all disabled types as specified 2641 // by the previous and current enabled params. 2642 TEST_F(SyncManagerTest, PurgeDisabledTypes) { 2643 ModelSafeRoutingInfo routing_info; 2644 GetModelSafeRoutingInfo(&routing_info); 2645 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); 2646 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types); 2647 2648 // The harness should have initialized the enabled_types for us. 2649 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2650 2651 // Set progress markers for all types. 2652 ModelTypeSet protocol_types = ProtocolTypes(); 2653 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2654 iter.Inc()) { 2655 SetProgressMarkerForType(iter.Get(), true); 2656 } 2657 2658 // Verify all the enabled types remain after cleanup, and all the disabled 2659 // types were purged. 2660 sync_manager_.PurgeDisabledTypes(disabled_types, 2661 ModelTypeSet(), 2662 ModelTypeSet()); 2663 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2664 EXPECT_TRUE(disabled_types.Equals( 2665 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All()))); 2666 2667 // Disable some more types. 2668 disabled_types.Put(BOOKMARKS); 2669 disabled_types.Put(PREFERENCES); 2670 ModelTypeSet new_enabled_types = 2671 Difference(ModelTypeSet::All(), disabled_types); 2672 2673 // Verify only the non-disabled types remain after cleanup. 2674 sync_manager_.PurgeDisabledTypes(disabled_types, 2675 ModelTypeSet(), 2676 ModelTypeSet()); 2677 EXPECT_TRUE(new_enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2678 EXPECT_TRUE(disabled_types.Equals( 2679 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All()))); 2680 } 2681 2682 // Test PurgeDisabledTypes properly unapplies types by deleting their local data 2683 // and preserving their server data and progress marker. 2684 TEST_F(SyncManagerTest, PurgeUnappliedTypes) { 2685 ModelSafeRoutingInfo routing_info; 2686 GetModelSafeRoutingInfo(&routing_info); 2687 ModelTypeSet unapplied_types = ModelTypeSet(BOOKMARKS, PREFERENCES); 2688 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); 2689 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types); 2690 2691 // The harness should have initialized the enabled_types for us. 2692 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2693 2694 // Set progress markers for all types. 2695 ModelTypeSet protocol_types = ProtocolTypes(); 2696 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2697 iter.Inc()) { 2698 SetProgressMarkerForType(iter.Get(), true); 2699 } 2700 2701 // Add the following kinds of items: 2702 // 1. Fully synced preference. 2703 // 2. Locally created preference, server unknown, unsynced 2704 // 3. Locally deleted preference, server known, unsynced 2705 // 4. Server deleted preference, locally known. 2706 // 5. Server created preference, locally unknown, unapplied. 2707 // 6. A fully synced bookmark (no unique_client_tag). 2708 UserShare* share = sync_manager_.GetUserShare(); 2709 sync_pb::EntitySpecifics pref_specifics; 2710 AddDefaultFieldValue(PREFERENCES, &pref_specifics); 2711 sync_pb::EntitySpecifics bm_specifics; 2712 AddDefaultFieldValue(BOOKMARKS, &bm_specifics); 2713 int pref1_meta = MakeServerNode( 2714 share, PREFERENCES, "pref1", "hash1", pref_specifics); 2715 int64 pref2_meta = MakeNode(share, PREFERENCES, "pref2"); 2716 int pref3_meta = MakeServerNode( 2717 share, PREFERENCES, "pref3", "hash3", pref_specifics); 2718 int pref4_meta = MakeServerNode( 2719 share, PREFERENCES, "pref4", "hash4", pref_specifics); 2720 int pref5_meta = MakeServerNode( 2721 share, PREFERENCES, "pref5", "hash5", pref_specifics); 2722 int bookmark_meta = MakeServerNode( 2723 share, BOOKMARKS, "bookmark", "", bm_specifics); 2724 2725 { 2726 syncable::WriteTransaction trans(FROM_HERE, 2727 syncable::SYNCER, 2728 share->directory.get()); 2729 // Pref's 1 and 2 are already set up properly. 2730 // Locally delete pref 3. 2731 syncable::MutableEntry pref3(&trans, GET_BY_HANDLE, pref3_meta); 2732 pref3.PutIsDel(true); 2733 pref3.PutIsUnsynced(true); 2734 // Delete pref 4 at the server. 2735 syncable::MutableEntry pref4(&trans, GET_BY_HANDLE, pref4_meta); 2736 pref4.PutServerIsDel(true); 2737 pref4.PutIsUnappliedUpdate(true); 2738 pref4.PutServerVersion(2); 2739 // Pref 5 is an new unapplied update. 2740 syncable::MutableEntry pref5(&trans, GET_BY_HANDLE, pref5_meta); 2741 pref5.PutIsUnappliedUpdate(true); 2742 pref5.PutIsDel(true); 2743 pref5.PutBaseVersion(-1); 2744 // Bookmark is already set up properly 2745 } 2746 2747 // Take a snapshot to clear all the dirty bits. 2748 share->directory.get()->SaveChanges(); 2749 2750 // Now request a purge for the unapplied types. 2751 disabled_types.PutAll(unapplied_types); 2752 sync_manager_.PurgeDisabledTypes(disabled_types, 2753 ModelTypeSet(), 2754 unapplied_types); 2755 2756 // Verify the unapplied types still have progress markers and initial sync 2757 // ended after cleanup. 2758 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().HasAll(unapplied_types)); 2759 EXPECT_TRUE( 2760 sync_manager_.GetTypesWithEmptyProgressMarkerToken(unapplied_types). 2761 Empty()); 2762 2763 // Ensure the items were unapplied as necessary. 2764 { 2765 syncable::ReadTransaction trans(FROM_HERE, share->directory.get()); 2766 syncable::Entry pref_node(&trans, GET_BY_HANDLE, pref1_meta); 2767 ASSERT_TRUE(pref_node.good()); 2768 EXPECT_TRUE(pref_node.GetKernelCopy().is_dirty()); 2769 EXPECT_FALSE(pref_node.GetIsUnsynced()); 2770 EXPECT_TRUE(pref_node.GetIsUnappliedUpdate()); 2771 EXPECT_TRUE(pref_node.GetIsDel()); 2772 EXPECT_GT(pref_node.GetServerVersion(), 0); 2773 EXPECT_EQ(pref_node.GetBaseVersion(), -1); 2774 2775 // Pref 2 should just be locally deleted. 2776 syncable::Entry pref2_node(&trans, GET_BY_HANDLE, pref2_meta); 2777 ASSERT_TRUE(pref2_node.good()); 2778 EXPECT_TRUE(pref2_node.GetKernelCopy().is_dirty()); 2779 EXPECT_FALSE(pref2_node.GetIsUnsynced()); 2780 EXPECT_TRUE(pref2_node.GetIsDel()); 2781 EXPECT_FALSE(pref2_node.GetIsUnappliedUpdate()); 2782 EXPECT_TRUE(pref2_node.GetIsDel()); 2783 EXPECT_EQ(pref2_node.GetServerVersion(), 0); 2784 EXPECT_EQ(pref2_node.GetBaseVersion(), -1); 2785 2786 syncable::Entry pref3_node(&trans, GET_BY_HANDLE, pref3_meta); 2787 ASSERT_TRUE(pref3_node.good()); 2788 EXPECT_TRUE(pref3_node.GetKernelCopy().is_dirty()); 2789 EXPECT_FALSE(pref3_node.GetIsUnsynced()); 2790 EXPECT_TRUE(pref3_node.GetIsUnappliedUpdate()); 2791 EXPECT_TRUE(pref3_node.GetIsDel()); 2792 EXPECT_GT(pref3_node.GetServerVersion(), 0); 2793 EXPECT_EQ(pref3_node.GetBaseVersion(), -1); 2794 2795 syncable::Entry pref4_node(&trans, GET_BY_HANDLE, pref4_meta); 2796 ASSERT_TRUE(pref4_node.good()); 2797 EXPECT_TRUE(pref4_node.GetKernelCopy().is_dirty()); 2798 EXPECT_FALSE(pref4_node.GetIsUnsynced()); 2799 EXPECT_TRUE(pref4_node.GetIsUnappliedUpdate()); 2800 EXPECT_TRUE(pref4_node.GetIsDel()); 2801 EXPECT_GT(pref4_node.GetServerVersion(), 0); 2802 EXPECT_EQ(pref4_node.GetBaseVersion(), -1); 2803 2804 // Pref 5 should remain untouched. 2805 syncable::Entry pref5_node(&trans, GET_BY_HANDLE, pref5_meta); 2806 ASSERT_TRUE(pref5_node.good()); 2807 EXPECT_FALSE(pref5_node.GetKernelCopy().is_dirty()); 2808 EXPECT_FALSE(pref5_node.GetIsUnsynced()); 2809 EXPECT_TRUE(pref5_node.GetIsUnappliedUpdate()); 2810 EXPECT_TRUE(pref5_node.GetIsDel()); 2811 EXPECT_GT(pref5_node.GetServerVersion(), 0); 2812 EXPECT_EQ(pref5_node.GetBaseVersion(), -1); 2813 2814 syncable::Entry bookmark_node(&trans, GET_BY_HANDLE, bookmark_meta); 2815 ASSERT_TRUE(bookmark_node.good()); 2816 EXPECT_TRUE(bookmark_node.GetKernelCopy().is_dirty()); 2817 EXPECT_FALSE(bookmark_node.GetIsUnsynced()); 2818 EXPECT_TRUE(bookmark_node.GetIsUnappliedUpdate()); 2819 EXPECT_TRUE(bookmark_node.GetIsDel()); 2820 EXPECT_GT(bookmark_node.GetServerVersion(), 0); 2821 EXPECT_EQ(bookmark_node.GetBaseVersion(), -1); 2822 } 2823 } 2824 2825 // A test harness to exercise the code that processes and passes changes from 2826 // the "SYNCER"-WriteTransaction destructor, through the SyncManager, to the 2827 // ChangeProcessor. 2828 class SyncManagerChangeProcessingTest : public SyncManagerTest { 2829 public: 2830 virtual void OnChangesApplied( 2831 ModelType model_type, 2832 int64 model_version, 2833 const BaseTransaction* trans, 2834 const ImmutableChangeRecordList& changes) OVERRIDE { 2835 last_changes_ = changes; 2836 } 2837 2838 virtual void OnChangesComplete(ModelType model_type) OVERRIDE {} 2839 2840 const ImmutableChangeRecordList& GetRecentChangeList() { 2841 return last_changes_; 2842 } 2843 2844 UserShare* share() { 2845 return sync_manager_.GetUserShare(); 2846 } 2847 2848 // Set some flags so our nodes reasonably approximate the real world scenario 2849 // and can get past CheckTreeInvariants. 2850 // 2851 // It's never going to be truly accurate, since we're squashing update 2852 // receipt, processing and application into a single transaction. 2853 void SetNodeProperties(syncable::MutableEntry *entry) { 2854 entry->PutId(id_factory_.NewServerId()); 2855 entry->PutBaseVersion(10); 2856 entry->PutServerVersion(10); 2857 } 2858 2859 // Looks for the given change in the list. Returns the index at which it was 2860 // found. Returns -1 on lookup failure. 2861 size_t FindChangeInList(int64 id, ChangeRecord::Action action) { 2862 SCOPED_TRACE(id); 2863 for (size_t i = 0; i < last_changes_.Get().size(); ++i) { 2864 if (last_changes_.Get()[i].id == id 2865 && last_changes_.Get()[i].action == action) { 2866 return i; 2867 } 2868 } 2869 ADD_FAILURE() << "Failed to find specified change"; 2870 return -1; 2871 } 2872 2873 // Returns the current size of the change list. 2874 // 2875 // Note that spurious changes do not necessarily indicate a problem. 2876 // Assertions on change list size can help detect problems, but it may be 2877 // necessary to reduce their strictness if the implementation changes. 2878 size_t GetChangeListSize() { 2879 return last_changes_.Get().size(); 2880 } 2881 2882 protected: 2883 ImmutableChangeRecordList last_changes_; 2884 TestIdFactory id_factory_; 2885 }; 2886 2887 // Test creation of a folder and a bookmark. 2888 TEST_F(SyncManagerChangeProcessingTest, AddBookmarks) { 2889 int64 type_root = GetIdForDataType(BOOKMARKS); 2890 int64 folder_id = kInvalidId; 2891 int64 child_id = kInvalidId; 2892 2893 // Create a folder and a bookmark under it. 2894 { 2895 syncable::WriteTransaction trans( 2896 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2897 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 2898 ASSERT_TRUE(root.good()); 2899 2900 syncable::MutableEntry folder(&trans, syncable::CREATE, 2901 BOOKMARKS, root.GetId(), "folder"); 2902 ASSERT_TRUE(folder.good()); 2903 SetNodeProperties(&folder); 2904 folder.PutIsDir(true); 2905 folder_id = folder.GetMetahandle(); 2906 2907 syncable::MutableEntry child(&trans, syncable::CREATE, 2908 BOOKMARKS, folder.GetId(), "child"); 2909 ASSERT_TRUE(child.good()); 2910 SetNodeProperties(&child); 2911 child_id = child.GetMetahandle(); 2912 } 2913 2914 // The closing of the above scope will delete the transaction. Its processed 2915 // changes should be waiting for us in a member of the test harness. 2916 EXPECT_EQ(2UL, GetChangeListSize()); 2917 2918 // We don't need to check these return values here. The function will add a 2919 // non-fatal failure if these changes are not found. 2920 size_t folder_change_pos = 2921 FindChangeInList(folder_id, ChangeRecord::ACTION_ADD); 2922 size_t child_change_pos = 2923 FindChangeInList(child_id, ChangeRecord::ACTION_ADD); 2924 2925 // Parents are delivered before children. 2926 EXPECT_LT(folder_change_pos, child_change_pos); 2927 } 2928 2929 // Test moving a bookmark into an empty folder. 2930 TEST_F(SyncManagerChangeProcessingTest, MoveBookmarkIntoEmptyFolder) { 2931 int64 type_root = GetIdForDataType(BOOKMARKS); 2932 int64 folder_b_id = kInvalidId; 2933 int64 child_id = kInvalidId; 2934 2935 // Create two folders. Place a child under folder A. 2936 { 2937 syncable::WriteTransaction trans( 2938 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2939 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 2940 ASSERT_TRUE(root.good()); 2941 2942 syncable::MutableEntry folder_a(&trans, syncable::CREATE, 2943 BOOKMARKS, root.GetId(), "folderA"); 2944 ASSERT_TRUE(folder_a.good()); 2945 SetNodeProperties(&folder_a); 2946 folder_a.PutIsDir(true); 2947 2948 syncable::MutableEntry folder_b(&trans, syncable::CREATE, 2949 BOOKMARKS, root.GetId(), "folderB"); 2950 ASSERT_TRUE(folder_b.good()); 2951 SetNodeProperties(&folder_b); 2952 folder_b.PutIsDir(true); 2953 folder_b_id = folder_b.GetMetahandle(); 2954 2955 syncable::MutableEntry child(&trans, syncable::CREATE, 2956 BOOKMARKS, folder_a.GetId(), 2957 "child"); 2958 ASSERT_TRUE(child.good()); 2959 SetNodeProperties(&child); 2960 child_id = child.GetMetahandle(); 2961 } 2962 2963 // Close that transaction. The above was to setup the initial scenario. The 2964 // real test starts now. 2965 2966 // Move the child from folder A to folder B. 2967 { 2968 syncable::WriteTransaction trans( 2969 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2970 2971 syncable::Entry folder_b(&trans, syncable::GET_BY_HANDLE, folder_b_id); 2972 syncable::MutableEntry child(&trans, syncable::GET_BY_HANDLE, child_id); 2973 2974 child.PutParentId(folder_b.GetId()); 2975 } 2976 2977 EXPECT_EQ(1UL, GetChangeListSize()); 2978 2979 // Verify that this was detected as a real change. An early version of the 2980 // UniquePosition code had a bug where moves from one folder to another were 2981 // ignored unless the moved node's UniquePosition value was also changed in 2982 // some way. 2983 FindChangeInList(child_id, ChangeRecord::ACTION_UPDATE); 2984 } 2985 2986 // Test moving a bookmark into a non-empty folder. 2987 TEST_F(SyncManagerChangeProcessingTest, MoveIntoPopulatedFolder) { 2988 int64 type_root = GetIdForDataType(BOOKMARKS); 2989 int64 child_a_id = kInvalidId; 2990 int64 child_b_id = kInvalidId; 2991 2992 // Create two folders. Place one child each under folder A and folder B. 2993 { 2994 syncable::WriteTransaction trans( 2995 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2996 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 2997 ASSERT_TRUE(root.good()); 2998 2999 syncable::MutableEntry folder_a(&trans, syncable::CREATE, 3000 BOOKMARKS, root.GetId(), "folderA"); 3001 ASSERT_TRUE(folder_a.good()); 3002 SetNodeProperties(&folder_a); 3003 folder_a.PutIsDir(true); 3004 3005 syncable::MutableEntry folder_b(&trans, syncable::CREATE, 3006 BOOKMARKS, root.GetId(), "folderB"); 3007 ASSERT_TRUE(folder_b.good()); 3008 SetNodeProperties(&folder_b); 3009 folder_b.PutIsDir(true); 3010 3011 syncable::MutableEntry child_a(&trans, syncable::CREATE, 3012 BOOKMARKS, folder_a.GetId(), 3013 "childA"); 3014 ASSERT_TRUE(child_a.good()); 3015 SetNodeProperties(&child_a); 3016 child_a_id = child_a.GetMetahandle(); 3017 3018 syncable::MutableEntry child_b(&trans, syncable::CREATE, 3019 BOOKMARKS, folder_b.GetId(), 3020 "childB"); 3021 SetNodeProperties(&child_b); 3022 child_b_id = child_b.GetMetahandle(); 3023 } 3024 3025 // Close that transaction. The above was to setup the initial scenario. The 3026 // real test starts now. 3027 3028 { 3029 syncable::WriteTransaction trans( 3030 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3031 3032 syncable::MutableEntry child_a(&trans, syncable::GET_BY_HANDLE, child_a_id); 3033 syncable::MutableEntry child_b(&trans, syncable::GET_BY_HANDLE, child_b_id); 3034 3035 // Move child A from folder A to folder B and update its position. 3036 child_a.PutParentId(child_b.GetParentId()); 3037 child_a.PutPredecessor(child_b.GetId()); 3038 } 3039 3040 EXPECT_EQ(1UL, GetChangeListSize()); 3041 3042 // Verify that only child a is in the change list. 3043 // (This function will add a failure if the lookup fails.) 3044 FindChangeInList(child_a_id, ChangeRecord::ACTION_UPDATE); 3045 } 3046 3047 // Tests the ordering of deletion changes. 3048 TEST_F(SyncManagerChangeProcessingTest, DeletionsAndChanges) { 3049 int64 type_root = GetIdForDataType(BOOKMARKS); 3050 int64 folder_a_id = kInvalidId; 3051 int64 folder_b_id = kInvalidId; 3052 int64 child_id = kInvalidId; 3053 3054 // Create two folders. Place a child under folder A. 3055 { 3056 syncable::WriteTransaction trans( 3057 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3058 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 3059 ASSERT_TRUE(root.good()); 3060 3061 syncable::MutableEntry folder_a(&trans, syncable::CREATE, 3062 BOOKMARKS, root.GetId(), "folderA"); 3063 ASSERT_TRUE(folder_a.good()); 3064 SetNodeProperties(&folder_a); 3065 folder_a.PutIsDir(true); 3066 folder_a_id = folder_a.GetMetahandle(); 3067 3068 syncable::MutableEntry folder_b(&trans, syncable::CREATE, 3069 BOOKMARKS, root.GetId(), "folderB"); 3070 ASSERT_TRUE(folder_b.good()); 3071 SetNodeProperties(&folder_b); 3072 folder_b.PutIsDir(true); 3073 folder_b_id = folder_b.GetMetahandle(); 3074 3075 syncable::MutableEntry child(&trans, syncable::CREATE, 3076 BOOKMARKS, folder_a.GetId(), 3077 "child"); 3078 ASSERT_TRUE(child.good()); 3079 SetNodeProperties(&child); 3080 child_id = child.GetMetahandle(); 3081 } 3082 3083 // Close that transaction. The above was to setup the initial scenario. The 3084 // real test starts now. 3085 3086 { 3087 syncable::WriteTransaction trans( 3088 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3089 3090 syncable::MutableEntry folder_a( 3091 &trans, syncable::GET_BY_HANDLE, folder_a_id); 3092 syncable::MutableEntry folder_b( 3093 &trans, syncable::GET_BY_HANDLE, folder_b_id); 3094 syncable::MutableEntry child(&trans, syncable::GET_BY_HANDLE, child_id); 3095 3096 // Delete folder B and its child. 3097 child.PutIsDel(true); 3098 folder_b.PutIsDel(true); 3099 3100 // Make an unrelated change to folder A. 3101 folder_a.PutNonUniqueName("NewNameA"); 3102 } 3103 3104 EXPECT_EQ(3UL, GetChangeListSize()); 3105 3106 size_t folder_a_pos = 3107 FindChangeInList(folder_a_id, ChangeRecord::ACTION_UPDATE); 3108 size_t folder_b_pos = 3109 FindChangeInList(folder_b_id, ChangeRecord::ACTION_DELETE); 3110 size_t child_pos = FindChangeInList(child_id, ChangeRecord::ACTION_DELETE); 3111 3112 // Deletes should appear before updates. 3113 EXPECT_LT(child_pos, folder_a_pos); 3114 EXPECT_LT(folder_b_pos, folder_a_pos); 3115 } 3116 3117 // During initialization SyncManagerImpl loads sqlite database. If it fails to 3118 // do so it should fail initialization. This test verifies this behavior. 3119 // Test reuses SyncManagerImpl initialization from SyncManagerTest but overrides 3120 // InternalComponentsFactory to return DirectoryBackingStore that always fails 3121 // to load. 3122 class SyncManagerInitInvalidStorageTest : public SyncManagerTest { 3123 public: 3124 SyncManagerInitInvalidStorageTest() { 3125 } 3126 3127 virtual InternalComponentsFactory* GetFactory() OVERRIDE { 3128 return new TestInternalComponentsFactory(GetSwitches(), STORAGE_INVALID); 3129 } 3130 }; 3131 3132 // SyncManagerInitInvalidStorageTest::GetFactory will return 3133 // DirectoryBackingStore that ensures that SyncManagerImpl::OpenDirectory fails. 3134 // SyncManagerImpl initialization is done in SyncManagerTest::SetUp. This test's 3135 // task is to ensure that SyncManagerImpl reported initialization failure in 3136 // OnInitializationComplete callback. 3137 TEST_F(SyncManagerInitInvalidStorageTest, FailToOpenDatabase) { 3138 EXPECT_FALSE(initialization_succeeded_); 3139 } 3140 3141 } // namespace syncer 3142