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/strings/string_number_conversions.h" 21 #include "base/strings/stringprintf.h" 22 #include "base/strings/utf_string_conversions.h" 23 #include "base/test/values_test_util.h" 24 #include "base/values.h" 25 #include "google_apis/gaia/gaia_constants.h" 26 #include "sync/engine/sync_scheduler.h" 27 #include "sync/internal_api/public/base/attachment_id_proto.h" 28 #include "sync/internal_api/public/base/cancelation_signal.h" 29 #include "sync/internal_api/public/base/model_type_test_util.h" 30 #include "sync/internal_api/public/change_record.h" 31 #include "sync/internal_api/public/engine/model_safe_worker.h" 32 #include "sync/internal_api/public/engine/polling_constants.h" 33 #include "sync/internal_api/public/events/protocol_event.h" 34 #include "sync/internal_api/public/http_post_provider_factory.h" 35 #include "sync/internal_api/public/http_post_provider_interface.h" 36 #include "sync/internal_api/public/read_node.h" 37 #include "sync/internal_api/public/read_transaction.h" 38 #include "sync/internal_api/public/test/test_entry_factory.h" 39 #include "sync/internal_api/public/test/test_internal_components_factory.h" 40 #include "sync/internal_api/public/test/test_user_share.h" 41 #include "sync/internal_api/public/write_node.h" 42 #include "sync/internal_api/public/write_transaction.h" 43 #include "sync/internal_api/sync_encryption_handler_impl.h" 44 #include "sync/internal_api/sync_manager_impl.h" 45 #include "sync/internal_api/syncapi_internal.h" 46 #include "sync/js/js_backend.h" 47 #include "sync/js/js_event_handler.h" 48 #include "sync/js/js_test_util.h" 49 #include "sync/protocol/bookmark_specifics.pb.h" 50 #include "sync/protocol/encryption.pb.h" 51 #include "sync/protocol/extension_specifics.pb.h" 52 #include "sync/protocol/password_specifics.pb.h" 53 #include "sync/protocol/preference_specifics.pb.h" 54 #include "sync/protocol/proto_value_conversions.h" 55 #include "sync/protocol/sync.pb.h" 56 #include "sync/sessions/sync_session.h" 57 #include "sync/syncable/directory.h" 58 #include "sync/syncable/entry.h" 59 #include "sync/syncable/mutable_entry.h" 60 #include "sync/syncable/nigori_util.h" 61 #include "sync/syncable/syncable_id.h" 62 #include "sync/syncable/syncable_read_transaction.h" 63 #include "sync/syncable/syncable_util.h" 64 #include "sync/syncable/syncable_write_transaction.h" 65 #include "sync/test/callback_counter.h" 66 #include "sync/test/engine/fake_model_worker.h" 67 #include "sync/test/engine/fake_sync_scheduler.h" 68 #include "sync/test/engine/test_id_factory.h" 69 #include "sync/test/fake_encryptor.h" 70 #include "sync/util/cryptographer.h" 71 #include "sync/util/extensions_activity.h" 72 #include "sync/util/test_unrecoverable_error_handler.h" 73 #include "sync/util/time.h" 74 #include "testing/gmock/include/gmock/gmock.h" 75 #include "testing/gtest/include/gtest/gtest.h" 76 #include "url/gurl.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 OAuth2TokenService::ScopeSet scope_set; 798 scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope); 799 credentials.scope_set = scope_set; 800 801 sync_manager_.AddObserver(&manager_observer_); 802 EXPECT_CALL(manager_observer_, OnInitializationComplete(_, _, _, _)). 803 WillOnce(DoAll(SaveArg<0>(&js_backend_), 804 SaveArg<2>(&initialization_succeeded_))); 805 806 EXPECT_FALSE(js_backend_.IsInitialized()); 807 808 std::vector<scoped_refptr<ModelSafeWorker> > workers; 809 ModelSafeRoutingInfo routing_info; 810 GetModelSafeRoutingInfo(&routing_info); 811 812 // This works only because all routing info types are GROUP_PASSIVE. 813 // If we had types in other groups, we would need additional workers 814 // to support them. 815 scoped_refptr<ModelSafeWorker> worker = new FakeModelWorker(GROUP_PASSIVE); 816 workers.push_back(worker); 817 818 SyncManager::InitArgs args; 819 args.database_location = temp_dir_.path(); 820 args.service_url = GURL("https://example.com/"); 821 args.post_factory = 822 scoped_ptr<HttpPostProviderFactory>(new TestHttpPostProviderFactory()); 823 args.workers = workers; 824 args.extensions_activity = extensions_activity_.get(), 825 args.change_delegate = this; 826 args.credentials = credentials; 827 args.invalidator_client_id = "fake_invalidator_client_id"; 828 args.internal_components_factory.reset(GetFactory()); 829 args.encryptor = &encryptor_; 830 args.unrecoverable_error_handler.reset(new TestUnrecoverableErrorHandler); 831 args.cancelation_signal = &cancelation_signal_; 832 sync_manager_.Init(&args); 833 834 sync_manager_.GetEncryptionHandler()->AddObserver(&encryption_observer_); 835 836 EXPECT_TRUE(js_backend_.IsInitialized()); 837 EXPECT_EQ(InternalComponentsFactory::STORAGE_ON_DISK, 838 storage_used_); 839 840 if (initialization_succeeded_) { 841 for (ModelSafeRoutingInfo::iterator i = routing_info.begin(); 842 i != routing_info.end(); ++i) { 843 type_roots_[i->first] = MakeServerNodeForType( 844 sync_manager_.GetUserShare(), i->first); 845 } 846 } 847 848 PumpLoop(); 849 } 850 851 void TearDown() { 852 sync_manager_.RemoveObserver(&manager_observer_); 853 sync_manager_.ShutdownOnSyncThread(STOP_SYNC); 854 PumpLoop(); 855 } 856 857 void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) { 858 (*out)[NIGORI] = GROUP_PASSIVE; 859 (*out)[DEVICE_INFO] = GROUP_PASSIVE; 860 (*out)[EXPERIMENTS] = GROUP_PASSIVE; 861 (*out)[BOOKMARKS] = GROUP_PASSIVE; 862 (*out)[THEMES] = GROUP_PASSIVE; 863 (*out)[SESSIONS] = GROUP_PASSIVE; 864 (*out)[PASSWORDS] = GROUP_PASSIVE; 865 (*out)[PREFERENCES] = GROUP_PASSIVE; 866 (*out)[PRIORITY_PREFERENCES] = GROUP_PASSIVE; 867 (*out)[ARTICLES] = 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( 957 GetSwitches(), InternalComponentsFactory::STORAGE_IN_MEMORY, 958 &storage_used_); 959 } 960 961 // Returns true if we are currently encrypting all sync data. May 962 // be called on any thread. 963 bool EncryptEverythingEnabledForTest() { 964 return sync_manager_.GetEncryptionHandler()->EncryptEverythingEnabled(); 965 } 966 967 // Gets the set of encrypted types from the cryptographer 968 // Note: opens a transaction. May be called from any thread. 969 ModelTypeSet GetEncryptedTypes() { 970 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 971 return GetEncryptedTypesWithTrans(&trans); 972 } 973 974 ModelTypeSet GetEncryptedTypesWithTrans(BaseTransaction* trans) { 975 return trans->GetDirectory()->GetNigoriHandler()-> 976 GetEncryptedTypes(trans->GetWrappedTrans()); 977 } 978 979 void SimulateInvalidatorEnabledForTest(bool is_enabled) { 980 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread()); 981 sync_manager_.SetInvalidatorEnabled(is_enabled); 982 } 983 984 void SetProgressMarkerForType(ModelType type, bool set) { 985 if (set) { 986 sync_pb::DataTypeProgressMarker marker; 987 marker.set_token("token"); 988 marker.set_data_type_id(GetSpecificsFieldNumberFromModelType(type)); 989 sync_manager_.directory()->SetDownloadProgress(type, marker); 990 } else { 991 sync_pb::DataTypeProgressMarker marker; 992 sync_manager_.directory()->SetDownloadProgress(type, marker); 993 } 994 } 995 996 InternalComponentsFactory::Switches GetSwitches() const { 997 return switches_; 998 } 999 1000 private: 1001 // Needed by |sync_manager_|. 1002 base::MessageLoop message_loop_; 1003 // Needed by |sync_manager_|. 1004 base::ScopedTempDir temp_dir_; 1005 // Sync Id's for the roots of the enabled datatypes. 1006 std::map<ModelType, int64> type_roots_; 1007 scoped_refptr<ExtensionsActivity> extensions_activity_; 1008 1009 protected: 1010 FakeEncryptor encryptor_; 1011 SyncManagerImpl sync_manager_; 1012 CancelationSignal cancelation_signal_; 1013 WeakHandle<JsBackend> js_backend_; 1014 bool initialization_succeeded_; 1015 StrictMock<SyncManagerObserverMock> manager_observer_; 1016 StrictMock<SyncEncryptionHandlerObserverMock> encryption_observer_; 1017 InternalComponentsFactory::Switches switches_; 1018 InternalComponentsFactory::StorageOption storage_used_; 1019 }; 1020 1021 TEST_F(SyncManagerTest, GetAllNodesForTypeTest) { 1022 ModelSafeRoutingInfo routing_info; 1023 GetModelSafeRoutingInfo(&routing_info); 1024 sync_manager_.StartSyncingNormally(routing_info); 1025 1026 scoped_ptr<base::ListValue> node_list( 1027 sync_manager_.GetAllNodesForType(syncer::PREFERENCES)); 1028 1029 // Should have one node: the type root node. 1030 ASSERT_EQ(1U, node_list->GetSize()); 1031 1032 const base::DictionaryValue* first_result; 1033 ASSERT_TRUE(node_list->GetDictionary(0, &first_result)); 1034 EXPECT_TRUE(first_result->HasKey("ID")); 1035 EXPECT_TRUE(first_result->HasKey("NON_UNIQUE_NAME")); 1036 } 1037 1038 TEST_F(SyncManagerTest, RefreshEncryptionReady) { 1039 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1040 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1041 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1042 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1043 1044 sync_manager_.GetEncryptionHandler()->Init(); 1045 PumpLoop(); 1046 1047 const ModelTypeSet encrypted_types = GetEncryptedTypes(); 1048 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); 1049 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1050 1051 { 1052 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1053 ReadNode node(&trans); 1054 EXPECT_EQ(BaseNode::INIT_OK, 1055 node.InitByIdLookup(GetIdForDataType(NIGORI))); 1056 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); 1057 EXPECT_TRUE(nigori.has_encryption_keybag()); 1058 Cryptographer* cryptographer = trans.GetCryptographer(); 1059 EXPECT_TRUE(cryptographer->is_ready()); 1060 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); 1061 } 1062 } 1063 1064 // Attempt to refresh encryption when nigori not downloaded. 1065 TEST_F(SyncManagerTest, RefreshEncryptionNotReady) { 1066 // Don't set up encryption (no nigori node created). 1067 1068 // Should fail. Triggers an OnPassphraseRequired because the cryptographer 1069 // is not ready. 1070 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_, _)).Times(1); 1071 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1072 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1073 sync_manager_.GetEncryptionHandler()->Init(); 1074 PumpLoop(); 1075 1076 const ModelTypeSet encrypted_types = GetEncryptedTypes(); 1077 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded. 1078 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1079 } 1080 1081 // Attempt to refresh encryption when nigori is empty. 1082 TEST_F(SyncManagerTest, RefreshEncryptionEmptyNigori) { 1083 EXPECT_TRUE(SetUpEncryption(DONT_WRITE_NIGORI, DEFAULT_ENCRYPTION)); 1084 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()).Times(1); 1085 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1086 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1087 1088 // Should write to nigori. 1089 sync_manager_.GetEncryptionHandler()->Init(); 1090 PumpLoop(); 1091 1092 const ModelTypeSet encrypted_types = GetEncryptedTypes(); 1093 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded. 1094 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1095 1096 { 1097 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1098 ReadNode node(&trans); 1099 EXPECT_EQ(BaseNode::INIT_OK, 1100 node.InitByIdLookup(GetIdForDataType(NIGORI))); 1101 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); 1102 EXPECT_TRUE(nigori.has_encryption_keybag()); 1103 Cryptographer* cryptographer = trans.GetCryptographer(); 1104 EXPECT_TRUE(cryptographer->is_ready()); 1105 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); 1106 } 1107 } 1108 1109 TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) { 1110 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1111 EXPECT_CALL(encryption_observer_, 1112 OnEncryptedTypesChanged( 1113 HasModelTypes(EncryptableUserTypes()), true)); 1114 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1115 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1116 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1117 } 1118 1119 TEST_F(SyncManagerTest, EncryptDataTypesWithData) { 1120 size_t batch_size = 5; 1121 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1122 1123 // Create some unencrypted unsynced data. 1124 int64 folder = MakeFolderWithParent(sync_manager_.GetUserShare(), 1125 BOOKMARKS, 1126 GetIdForDataType(BOOKMARKS), 1127 NULL); 1128 // First batch_size nodes are children of folder. 1129 size_t i; 1130 for (i = 0; i < batch_size; ++i) { 1131 MakeBookmarkWithParent(sync_manager_.GetUserShare(), folder, NULL); 1132 } 1133 // Next batch_size nodes are a different type and on their own. 1134 for (; i < 2*batch_size; ++i) { 1135 MakeNode(sync_manager_.GetUserShare(), SESSIONS, 1136 base::StringPrintf("%" PRIuS "", i)); 1137 } 1138 // Last batch_size nodes are a third type that will not need encryption. 1139 for (; i < 3*batch_size; ++i) { 1140 MakeNode(sync_manager_.GetUserShare(), THEMES, 1141 base::StringPrintf("%" PRIuS "", i)); 1142 } 1143 1144 { 1145 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1146 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1147 SyncEncryptionHandler::SensitiveTypes())); 1148 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1149 trans.GetWrappedTrans(), 1150 BOOKMARKS, 1151 false /* not encrypted */)); 1152 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1153 trans.GetWrappedTrans(), 1154 SESSIONS, 1155 false /* not encrypted */)); 1156 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1157 trans.GetWrappedTrans(), 1158 THEMES, 1159 false /* not encrypted */)); 1160 } 1161 1162 EXPECT_CALL(encryption_observer_, 1163 OnEncryptedTypesChanged( 1164 HasModelTypes(EncryptableUserTypes()), true)); 1165 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1166 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1167 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1168 { 1169 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1170 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1171 EncryptableUserTypes())); 1172 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1173 trans.GetWrappedTrans(), 1174 BOOKMARKS, 1175 true /* is encrypted */)); 1176 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1177 trans.GetWrappedTrans(), 1178 SESSIONS, 1179 true /* is encrypted */)); 1180 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1181 trans.GetWrappedTrans(), 1182 THEMES, 1183 true /* is encrypted */)); 1184 } 1185 1186 // Trigger's a ReEncryptEverything with new passphrase. 1187 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1188 EXPECT_CALL(encryption_observer_, 1189 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1190 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1191 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1192 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1193 EXPECT_CALL(encryption_observer_, 1194 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1195 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1196 "new_passphrase", true); 1197 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1198 { 1199 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1200 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1201 EncryptableUserTypes())); 1202 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1203 trans.GetWrappedTrans(), 1204 BOOKMARKS, 1205 true /* is encrypted */)); 1206 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1207 trans.GetWrappedTrans(), 1208 SESSIONS, 1209 true /* is encrypted */)); 1210 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1211 trans.GetWrappedTrans(), 1212 THEMES, 1213 true /* is encrypted */)); 1214 } 1215 // Calling EncryptDataTypes with an empty encrypted types should not trigger 1216 // a reencryption and should just notify immediately. 1217 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1218 EXPECT_CALL(encryption_observer_, 1219 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)).Times(0); 1220 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()).Times(0); 1221 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()).Times(0); 1222 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1223 } 1224 1225 // Test that when there are no pending keys and the cryptographer is not 1226 // initialized, we add a key based on the current GAIA password. 1227 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1228 TEST_F(SyncManagerTest, SetInitialGaiaPass) { 1229 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED)); 1230 EXPECT_CALL(encryption_observer_, 1231 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1232 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1233 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1234 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1235 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1236 "new_passphrase", 1237 false); 1238 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1239 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1240 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1241 { 1242 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1243 ReadNode node(&trans); 1244 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1245 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); 1246 Cryptographer* cryptographer = trans.GetCryptographer(); 1247 EXPECT_TRUE(cryptographer->is_ready()); 1248 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); 1249 } 1250 } 1251 1252 // Test that when there are no pending keys and we have on the old GAIA 1253 // password, we update and re-encrypt everything with the new GAIA password. 1254 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1255 TEST_F(SyncManagerTest, UpdateGaiaPass) { 1256 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1257 Cryptographer verifier(&encryptor_); 1258 { 1259 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1260 Cryptographer* cryptographer = trans.GetCryptographer(); 1261 std::string bootstrap_token; 1262 cryptographer->GetBootstrapToken(&bootstrap_token); 1263 verifier.Bootstrap(bootstrap_token); 1264 } 1265 EXPECT_CALL(encryption_observer_, 1266 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1267 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1268 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1269 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1270 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1271 "new_passphrase", 1272 false); 1273 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1274 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1275 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1276 { 1277 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1278 Cryptographer* cryptographer = trans.GetCryptographer(); 1279 EXPECT_TRUE(cryptographer->is_ready()); 1280 // Verify the default key has changed. 1281 sync_pb::EncryptedData encrypted; 1282 cryptographer->GetKeys(&encrypted); 1283 EXPECT_FALSE(verifier.CanDecrypt(encrypted)); 1284 } 1285 } 1286 1287 // Sets a new explicit passphrase. This should update the bootstrap token 1288 // and re-encrypt everything. 1289 // (case 2 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1290 TEST_F(SyncManagerTest, SetPassphraseWithPassword) { 1291 Cryptographer verifier(&encryptor_); 1292 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1293 { 1294 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1295 // Store the default (soon to be old) key. 1296 Cryptographer* cryptographer = trans.GetCryptographer(); 1297 std::string bootstrap_token; 1298 cryptographer->GetBootstrapToken(&bootstrap_token); 1299 verifier.Bootstrap(bootstrap_token); 1300 1301 ReadNode root_node(&trans); 1302 root_node.InitByRootLookup(); 1303 1304 WriteNode password_node(&trans); 1305 WriteNode::InitUniqueByCreationResult result = 1306 password_node.InitUniqueByCreation(PASSWORDS, 1307 root_node, "foo"); 1308 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 1309 sync_pb::PasswordSpecificsData data; 1310 data.set_password_value("secret"); 1311 password_node.SetPasswordSpecifics(data); 1312 } 1313 EXPECT_CALL(encryption_observer_, 1314 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1315 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1316 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1317 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1318 EXPECT_CALL(encryption_observer_, 1319 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1320 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1321 "new_passphrase", 1322 true); 1323 EXPECT_EQ(CUSTOM_PASSPHRASE, 1324 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1325 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1326 { 1327 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1328 Cryptographer* cryptographer = trans.GetCryptographer(); 1329 EXPECT_TRUE(cryptographer->is_ready()); 1330 // Verify the default key has changed. 1331 sync_pb::EncryptedData encrypted; 1332 cryptographer->GetKeys(&encrypted); 1333 EXPECT_FALSE(verifier.CanDecrypt(encrypted)); 1334 1335 ReadNode password_node(&trans); 1336 EXPECT_EQ(BaseNode::INIT_OK, 1337 password_node.InitByClientTagLookup(PASSWORDS, 1338 "foo")); 1339 const sync_pb::PasswordSpecificsData& data = 1340 password_node.GetPasswordSpecifics(); 1341 EXPECT_EQ("secret", data.password_value()); 1342 } 1343 } 1344 1345 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1346 // being encrypted with a new (unprovided) GAIA password, then supply the 1347 // password. 1348 // (case 7 in SyncManager::SyncInternal::SetDecryptionPassphrase) 1349 TEST_F(SyncManagerTest, SupplyPendingGAIAPass) { 1350 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1351 Cryptographer other_cryptographer(&encryptor_); 1352 { 1353 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1354 Cryptographer* cryptographer = trans.GetCryptographer(); 1355 std::string bootstrap_token; 1356 cryptographer->GetBootstrapToken(&bootstrap_token); 1357 other_cryptographer.Bootstrap(bootstrap_token); 1358 1359 // Now update the nigori to reflect the new keys, and update the 1360 // cryptographer to have pending keys. 1361 KeyParams params = {"localhost", "dummy", "passphrase2"}; 1362 other_cryptographer.AddKey(params); 1363 WriteNode node(&trans); 1364 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1365 sync_pb::NigoriSpecifics nigori; 1366 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1367 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1368 EXPECT_TRUE(cryptographer->has_pending_keys()); 1369 node.SetNigoriSpecifics(nigori); 1370 } 1371 EXPECT_CALL(encryption_observer_, 1372 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1373 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1374 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1375 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1376 sync_manager_.GetEncryptionHandler()->SetDecryptionPassphrase("passphrase2"); 1377 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1378 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1379 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1380 { 1381 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1382 Cryptographer* cryptographer = trans.GetCryptographer(); 1383 EXPECT_TRUE(cryptographer->is_ready()); 1384 // Verify we're encrypting with the new key. 1385 sync_pb::EncryptedData encrypted; 1386 cryptographer->GetKeys(&encrypted); 1387 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted)); 1388 } 1389 } 1390 1391 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1392 // being encrypted with an old (unprovided) GAIA password. Attempt to supply 1393 // the current GAIA password and verify the bootstrap token is updated. Then 1394 // supply the old GAIA password, and verify we re-encrypt all data with the 1395 // new GAIA password. 1396 // (cases 4 and 5 in SyncManager::SyncInternal::SetEncryptionPassphrase) 1397 TEST_F(SyncManagerTest, SupplyPendingOldGAIAPass) { 1398 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1399 Cryptographer other_cryptographer(&encryptor_); 1400 { 1401 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1402 Cryptographer* cryptographer = trans.GetCryptographer(); 1403 std::string bootstrap_token; 1404 cryptographer->GetBootstrapToken(&bootstrap_token); 1405 other_cryptographer.Bootstrap(bootstrap_token); 1406 1407 // Now update the nigori to reflect the new keys, and update the 1408 // cryptographer to have pending keys. 1409 KeyParams params = {"localhost", "dummy", "old_gaia"}; 1410 other_cryptographer.AddKey(params); 1411 WriteNode node(&trans); 1412 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1413 sync_pb::NigoriSpecifics nigori; 1414 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1415 node.SetNigoriSpecifics(nigori); 1416 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1417 1418 // other_cryptographer now contains all encryption keys, and is encrypting 1419 // with the newest gaia. 1420 KeyParams new_params = {"localhost", "dummy", "new_gaia"}; 1421 other_cryptographer.AddKey(new_params); 1422 } 1423 // The bootstrap token should have been updated. Save it to ensure it's based 1424 // on the new GAIA password. 1425 std::string bootstrap_token; 1426 EXPECT_CALL(encryption_observer_, 1427 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) 1428 .WillOnce(SaveArg<0>(&bootstrap_token)); 1429 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_,_)); 1430 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1431 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1432 "new_gaia", 1433 false); 1434 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1435 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1436 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1437 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1438 { 1439 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1440 Cryptographer* cryptographer = trans.GetCryptographer(); 1441 EXPECT_TRUE(cryptographer->is_initialized()); 1442 EXPECT_FALSE(cryptographer->is_ready()); 1443 // Verify we're encrypting with the new key, even though we have pending 1444 // keys. 1445 sync_pb::EncryptedData encrypted; 1446 other_cryptographer.GetKeys(&encrypted); 1447 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted)); 1448 } 1449 EXPECT_CALL(encryption_observer_, 1450 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1451 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1452 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1453 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1454 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1455 "old_gaia", 1456 false); 1457 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1458 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1459 { 1460 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1461 Cryptographer* cryptographer = trans.GetCryptographer(); 1462 EXPECT_TRUE(cryptographer->is_ready()); 1463 1464 // Verify we're encrypting with the new key. 1465 sync_pb::EncryptedData encrypted; 1466 other_cryptographer.GetKeys(&encrypted); 1467 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted)); 1468 1469 // Verify the saved bootstrap token is based on the new gaia password. 1470 Cryptographer temp_cryptographer(&encryptor_); 1471 temp_cryptographer.Bootstrap(bootstrap_token); 1472 EXPECT_TRUE(temp_cryptographer.CanDecrypt(encrypted)); 1473 } 1474 } 1475 1476 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1477 // being encrypted with an explicit (unprovided) passphrase, then supply the 1478 // passphrase. 1479 // (case 9 in SyncManager::SyncInternal::SetDecryptionPassphrase) 1480 TEST_F(SyncManagerTest, SupplyPendingExplicitPass) { 1481 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1482 Cryptographer other_cryptographer(&encryptor_); 1483 { 1484 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1485 Cryptographer* cryptographer = trans.GetCryptographer(); 1486 std::string bootstrap_token; 1487 cryptographer->GetBootstrapToken(&bootstrap_token); 1488 other_cryptographer.Bootstrap(bootstrap_token); 1489 1490 // Now update the nigori to reflect the new keys, and update the 1491 // cryptographer to have pending keys. 1492 KeyParams params = {"localhost", "dummy", "explicit"}; 1493 other_cryptographer.AddKey(params); 1494 WriteNode node(&trans); 1495 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1496 sync_pb::NigoriSpecifics nigori; 1497 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1498 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1499 EXPECT_TRUE(cryptographer->has_pending_keys()); 1500 nigori.set_keybag_is_frozen(true); 1501 node.SetNigoriSpecifics(nigori); 1502 } 1503 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1504 EXPECT_CALL(encryption_observer_, 1505 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1506 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_, _)); 1507 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 1508 sync_manager_.GetEncryptionHandler()->Init(); 1509 EXPECT_CALL(encryption_observer_, 1510 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1511 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1512 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1513 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1514 sync_manager_.GetEncryptionHandler()->SetDecryptionPassphrase("explicit"); 1515 EXPECT_EQ(CUSTOM_PASSPHRASE, 1516 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1517 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1518 { 1519 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1520 Cryptographer* cryptographer = trans.GetCryptographer(); 1521 EXPECT_TRUE(cryptographer->is_ready()); 1522 // Verify we're encrypting with the new key. 1523 sync_pb::EncryptedData encrypted; 1524 cryptographer->GetKeys(&encrypted); 1525 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted)); 1526 } 1527 } 1528 1529 // Manually set the pending keys in the cryptographer/nigori to reflect the data 1530 // being encrypted with a new (unprovided) GAIA password, then supply the 1531 // password as a user-provided password. 1532 // This is the android case 7/8. 1533 TEST_F(SyncManagerTest, SupplyPendingGAIAPassUserProvided) { 1534 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED)); 1535 Cryptographer other_cryptographer(&encryptor_); 1536 { 1537 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1538 Cryptographer* cryptographer = trans.GetCryptographer(); 1539 // Now update the nigori to reflect the new keys, and update the 1540 // cryptographer to have pending keys. 1541 KeyParams params = {"localhost", "dummy", "passphrase"}; 1542 other_cryptographer.AddKey(params); 1543 WriteNode node(&trans); 1544 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI)); 1545 sync_pb::NigoriSpecifics nigori; 1546 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); 1547 node.SetNigoriSpecifics(nigori); 1548 cryptographer->SetPendingKeys(nigori.encryption_keybag()); 1549 EXPECT_FALSE(cryptographer->is_ready()); 1550 } 1551 EXPECT_CALL(encryption_observer_, 1552 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1553 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1554 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1555 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1556 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1557 "passphrase", 1558 false); 1559 EXPECT_EQ(IMPLICIT_PASSPHRASE, 1560 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1561 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1562 { 1563 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1564 Cryptographer* cryptographer = trans.GetCryptographer(); 1565 EXPECT_TRUE(cryptographer->is_ready()); 1566 } 1567 } 1568 1569 TEST_F(SyncManagerTest, SetPassphraseWithEmptyPasswordNode) { 1570 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1571 int64 node_id = 0; 1572 std::string tag = "foo"; 1573 { 1574 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1575 ReadNode root_node(&trans); 1576 root_node.InitByRootLookup(); 1577 1578 WriteNode password_node(&trans); 1579 WriteNode::InitUniqueByCreationResult result = 1580 password_node.InitUniqueByCreation(PASSWORDS, root_node, tag); 1581 EXPECT_EQ(WriteNode::INIT_SUCCESS, result); 1582 node_id = password_node.GetId(); 1583 } 1584 EXPECT_CALL(encryption_observer_, 1585 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1586 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1587 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1588 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1589 EXPECT_CALL(encryption_observer_, 1590 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1591 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1592 "new_passphrase", 1593 true); 1594 EXPECT_EQ(CUSTOM_PASSPHRASE, 1595 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 1596 EXPECT_FALSE(EncryptEverythingEnabledForTest()); 1597 { 1598 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1599 ReadNode password_node(&trans); 1600 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY, 1601 password_node.InitByClientTagLookup(PASSWORDS, 1602 tag)); 1603 } 1604 { 1605 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1606 ReadNode password_node(&trans); 1607 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY, 1608 password_node.InitByIdLookup(node_id)); 1609 } 1610 } 1611 1612 // Friended by WriteNode, so can't be in an anonymouse namespace. 1613 TEST_F(SyncManagerTest, EncryptBookmarksWithLegacyData) { 1614 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1615 std::string title; 1616 SyncAPINameToServerName("Google", &title); 1617 std::string url = "http://www.google.com"; 1618 std::string raw_title2 = ".."; // An invalid cosmo title. 1619 std::string title2; 1620 SyncAPINameToServerName(raw_title2, &title2); 1621 std::string url2 = "http://www.bla.com"; 1622 1623 // Create a bookmark using the legacy format. 1624 int64 node_id1 = MakeNode(sync_manager_.GetUserShare(), 1625 BOOKMARKS, 1626 "testtag"); 1627 int64 node_id2 = MakeNode(sync_manager_.GetUserShare(), 1628 BOOKMARKS, 1629 "testtag2"); 1630 { 1631 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1632 WriteNode node(&trans); 1633 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1)); 1634 1635 sync_pb::EntitySpecifics entity_specifics; 1636 entity_specifics.mutable_bookmark()->set_url(url); 1637 node.SetEntitySpecifics(entity_specifics); 1638 1639 // Set the old style title. 1640 syncable::MutableEntry* node_entry = node.entry_; 1641 node_entry->PutNonUniqueName(title); 1642 1643 WriteNode node2(&trans); 1644 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2)); 1645 1646 sync_pb::EntitySpecifics entity_specifics2; 1647 entity_specifics2.mutable_bookmark()->set_url(url2); 1648 node2.SetEntitySpecifics(entity_specifics2); 1649 1650 // Set the old style title. 1651 syncable::MutableEntry* node_entry2 = node2.entry_; 1652 node_entry2->PutNonUniqueName(title2); 1653 } 1654 1655 { 1656 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1657 ReadNode node(&trans); 1658 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1)); 1659 EXPECT_EQ(BOOKMARKS, node.GetModelType()); 1660 EXPECT_EQ(title, node.GetTitle()); 1661 EXPECT_EQ(title, node.GetBookmarkSpecifics().title()); 1662 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 1663 1664 ReadNode node2(&trans); 1665 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2)); 1666 EXPECT_EQ(BOOKMARKS, node2.GetModelType()); 1667 // We should de-canonicalize the title in GetTitle(), but the title in the 1668 // specifics should be stored in the server legal form. 1669 EXPECT_EQ(raw_title2, node2.GetTitle()); 1670 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title()); 1671 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url()); 1672 } 1673 1674 { 1675 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1676 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1677 trans.GetWrappedTrans(), 1678 BOOKMARKS, 1679 false /* not encrypted */)); 1680 } 1681 1682 EXPECT_CALL(encryption_observer_, 1683 OnEncryptedTypesChanged( 1684 HasModelTypes(EncryptableUserTypes()), true)); 1685 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1686 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything(); 1687 EXPECT_TRUE(EncryptEverythingEnabledForTest()); 1688 1689 { 1690 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1691 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals( 1692 EncryptableUserTypes())); 1693 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest( 1694 trans.GetWrappedTrans(), 1695 BOOKMARKS, 1696 true /* is encrypted */)); 1697 1698 ReadNode node(&trans); 1699 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1)); 1700 EXPECT_EQ(BOOKMARKS, node.GetModelType()); 1701 EXPECT_EQ(title, node.GetTitle()); 1702 EXPECT_EQ(title, node.GetBookmarkSpecifics().title()); 1703 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 1704 1705 ReadNode node2(&trans); 1706 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2)); 1707 EXPECT_EQ(BOOKMARKS, node2.GetModelType()); 1708 // We should de-canonicalize the title in GetTitle(), but the title in the 1709 // specifics should be stored in the server legal form. 1710 EXPECT_EQ(raw_title2, node2.GetTitle()); 1711 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title()); 1712 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url()); 1713 } 1714 } 1715 1716 // Create a bookmark and set the title/url, then verify the data was properly 1717 // set. This replicates the unique way bookmarks have of creating sync nodes. 1718 // See BookmarkChangeProcessor::PlaceSyncNode(..). 1719 TEST_F(SyncManagerTest, CreateLocalBookmark) { 1720 std::string title = "title"; 1721 std::string url = "url"; 1722 { 1723 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1724 ReadNode bookmark_root(&trans); 1725 ASSERT_EQ(BaseNode::INIT_OK, bookmark_root.InitTypeRoot(BOOKMARKS)); 1726 WriteNode node(&trans); 1727 ASSERT_TRUE(node.InitBookmarkByCreation(bookmark_root, NULL)); 1728 node.SetIsFolder(false); 1729 node.SetTitle(title); 1730 1731 sync_pb::BookmarkSpecifics bookmark_specifics(node.GetBookmarkSpecifics()); 1732 bookmark_specifics.set_url(url); 1733 node.SetBookmarkSpecifics(bookmark_specifics); 1734 } 1735 { 1736 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1737 ReadNode bookmark_root(&trans); 1738 ASSERT_EQ(BaseNode::INIT_OK, bookmark_root.InitTypeRoot(BOOKMARKS)); 1739 int64 child_id = bookmark_root.GetFirstChildId(); 1740 1741 ReadNode node(&trans); 1742 ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id)); 1743 EXPECT_FALSE(node.GetIsFolder()); 1744 EXPECT_EQ(title, node.GetTitle()); 1745 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 1746 } 1747 } 1748 1749 // Verifies WriteNode::UpdateEntryWithEncryption does not make unnecessary 1750 // changes. 1751 TEST_F(SyncManagerTest, UpdateEntryWithEncryption) { 1752 std::string client_tag = "title"; 1753 sync_pb::EntitySpecifics entity_specifics; 1754 entity_specifics.mutable_bookmark()->set_url("url"); 1755 entity_specifics.mutable_bookmark()->set_title("title"); 1756 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 1757 syncable::GenerateSyncableHash(BOOKMARKS, 1758 client_tag), 1759 entity_specifics); 1760 // New node shouldn't start off unsynced. 1761 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1762 // Manually change to the same data. Should not set is_unsynced. 1763 { 1764 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1765 WriteNode node(&trans); 1766 EXPECT_EQ(BaseNode::INIT_OK, 1767 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1768 node.SetEntitySpecifics(entity_specifics); 1769 } 1770 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1771 1772 // Encrypt the datatatype, should set is_unsynced. 1773 EXPECT_CALL(encryption_observer_, 1774 OnEncryptedTypesChanged( 1775 HasModelTypes(EncryptableUserTypes()), true)); 1776 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1777 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION)); 1778 1779 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1780 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 1781 sync_manager_.GetEncryptionHandler()->Init(); 1782 PumpLoop(); 1783 { 1784 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1785 ReadNode node(&trans); 1786 EXPECT_EQ(BaseNode::INIT_OK, 1787 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1788 const syncable::Entry* node_entry = node.GetEntry(); 1789 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1790 EXPECT_TRUE(specifics.has_encrypted()); 1791 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1792 Cryptographer* cryptographer = trans.GetCryptographer(); 1793 EXPECT_TRUE(cryptographer->is_ready()); 1794 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1795 specifics.encrypted())); 1796 } 1797 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1798 1799 // Set a new passphrase. Should set is_unsynced. 1800 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1801 EXPECT_CALL(encryption_observer_, 1802 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 1803 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 1804 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1805 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1806 EXPECT_CALL(encryption_observer_, 1807 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 1808 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 1809 "new_passphrase", 1810 true); 1811 { 1812 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1813 ReadNode node(&trans); 1814 EXPECT_EQ(BaseNode::INIT_OK, 1815 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1816 const syncable::Entry* node_entry = node.GetEntry(); 1817 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1818 EXPECT_TRUE(specifics.has_encrypted()); 1819 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1820 Cryptographer* cryptographer = trans.GetCryptographer(); 1821 EXPECT_TRUE(cryptographer->is_ready()); 1822 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1823 specifics.encrypted())); 1824 } 1825 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1826 1827 // Force a re-encrypt everything. Should not set is_unsynced. 1828 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 1829 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 1830 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 1831 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 1832 1833 sync_manager_.GetEncryptionHandler()->Init(); 1834 PumpLoop(); 1835 1836 { 1837 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1838 ReadNode node(&trans); 1839 EXPECT_EQ(BaseNode::INIT_OK, 1840 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1841 const syncable::Entry* node_entry = node.GetEntry(); 1842 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1843 EXPECT_TRUE(specifics.has_encrypted()); 1844 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1845 Cryptographer* cryptographer = trans.GetCryptographer(); 1846 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1847 specifics.encrypted())); 1848 } 1849 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1850 1851 // Manually change to the same data. Should not set is_unsynced. 1852 { 1853 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1854 WriteNode node(&trans); 1855 EXPECT_EQ(BaseNode::INIT_OK, 1856 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1857 node.SetEntitySpecifics(entity_specifics); 1858 const syncable::Entry* node_entry = node.GetEntry(); 1859 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1860 EXPECT_TRUE(specifics.has_encrypted()); 1861 EXPECT_FALSE(node_entry->GetIsUnsynced()); 1862 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1863 Cryptographer* cryptographer = trans.GetCryptographer(); 1864 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1865 specifics.encrypted())); 1866 } 1867 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 1868 1869 // Manually change to different data. Should set is_unsynced. 1870 { 1871 entity_specifics.mutable_bookmark()->set_url("url2"); 1872 entity_specifics.mutable_bookmark()->set_title("title2"); 1873 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1874 WriteNode node(&trans); 1875 EXPECT_EQ(BaseNode::INIT_OK, 1876 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 1877 node.SetEntitySpecifics(entity_specifics); 1878 const syncable::Entry* node_entry = node.GetEntry(); 1879 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 1880 EXPECT_TRUE(specifics.has_encrypted()); 1881 EXPECT_TRUE(node_entry->GetIsUnsynced()); 1882 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 1883 Cryptographer* cryptographer = trans.GetCryptographer(); 1884 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey( 1885 specifics.encrypted())); 1886 } 1887 } 1888 1889 // Passwords have their own handling for encryption. Verify it does not result 1890 // in unnecessary writes via SetEntitySpecifics. 1891 TEST_F(SyncManagerTest, UpdatePasswordSetEntitySpecificsNoChange) { 1892 std::string client_tag = "title"; 1893 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1894 sync_pb::EntitySpecifics entity_specifics; 1895 { 1896 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1897 Cryptographer* cryptographer = trans.GetCryptographer(); 1898 sync_pb::PasswordSpecificsData data; 1899 data.set_password_value("secret"); 1900 cryptographer->Encrypt( 1901 data, 1902 entity_specifics.mutable_password()-> 1903 mutable_encrypted()); 1904 } 1905 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 1906 syncable::GenerateSyncableHash(PASSWORDS, 1907 client_tag), 1908 entity_specifics); 1909 // New node shouldn't start off unsynced. 1910 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1911 1912 // Manually change to the same data via SetEntitySpecifics. Should not set 1913 // is_unsynced. 1914 { 1915 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1916 WriteNode node(&trans); 1917 EXPECT_EQ(BaseNode::INIT_OK, 1918 node.InitByClientTagLookup(PASSWORDS, client_tag)); 1919 node.SetEntitySpecifics(entity_specifics); 1920 } 1921 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1922 } 1923 1924 // Passwords have their own handling for encryption. Verify it does not result 1925 // in unnecessary writes via SetPasswordSpecifics. 1926 TEST_F(SyncManagerTest, UpdatePasswordSetPasswordSpecifics) { 1927 std::string client_tag = "title"; 1928 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1929 sync_pb::EntitySpecifics entity_specifics; 1930 { 1931 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1932 Cryptographer* cryptographer = trans.GetCryptographer(); 1933 sync_pb::PasswordSpecificsData data; 1934 data.set_password_value("secret"); 1935 cryptographer->Encrypt( 1936 data, 1937 entity_specifics.mutable_password()-> 1938 mutable_encrypted()); 1939 } 1940 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 1941 syncable::GenerateSyncableHash(PASSWORDS, 1942 client_tag), 1943 entity_specifics); 1944 // New node shouldn't start off unsynced. 1945 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1946 1947 // Manually change to the same data via SetPasswordSpecifics. Should not set 1948 // is_unsynced. 1949 { 1950 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1951 WriteNode node(&trans); 1952 EXPECT_EQ(BaseNode::INIT_OK, 1953 node.InitByClientTagLookup(PASSWORDS, client_tag)); 1954 node.SetPasswordSpecifics(node.GetPasswordSpecifics()); 1955 } 1956 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1957 1958 // Manually change to different data. Should set is_unsynced. 1959 { 1960 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1961 WriteNode node(&trans); 1962 EXPECT_EQ(BaseNode::INIT_OK, 1963 node.InitByClientTagLookup(PASSWORDS, client_tag)); 1964 Cryptographer* cryptographer = trans.GetCryptographer(); 1965 sync_pb::PasswordSpecificsData data; 1966 data.set_password_value("secret2"); 1967 cryptographer->Encrypt( 1968 data, 1969 entity_specifics.mutable_password()->mutable_encrypted()); 1970 node.SetPasswordSpecifics(data); 1971 const syncable::Entry* node_entry = node.GetEntry(); 1972 EXPECT_TRUE(node_entry->GetIsUnsynced()); 1973 } 1974 } 1975 1976 // Passwords have their own handling for encryption. Verify setting a new 1977 // passphrase updates the data. 1978 TEST_F(SyncManagerTest, UpdatePasswordNewPassphrase) { 1979 std::string client_tag = "title"; 1980 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 1981 sync_pb::EntitySpecifics entity_specifics; 1982 { 1983 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 1984 Cryptographer* cryptographer = trans.GetCryptographer(); 1985 sync_pb::PasswordSpecificsData data; 1986 data.set_password_value("secret"); 1987 cryptographer->Encrypt( 1988 data, 1989 entity_specifics.mutable_password()->mutable_encrypted()); 1990 } 1991 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 1992 syncable::GenerateSyncableHash(PASSWORDS, 1993 client_tag), 1994 entity_specifics); 1995 // New node shouldn't start off unsynced. 1996 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 1997 1998 // Set a new passphrase. Should set is_unsynced. 1999 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 2000 EXPECT_CALL(encryption_observer_, 2001 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); 2002 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()); 2003 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2004 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2005 EXPECT_CALL(encryption_observer_, 2006 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); 2007 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase( 2008 "new_passphrase", 2009 true); 2010 EXPECT_EQ(CUSTOM_PASSPHRASE, 2011 sync_manager_.GetEncryptionHandler()->GetPassphraseType()); 2012 EXPECT_TRUE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2013 } 2014 2015 // Passwords have their own handling for encryption. Verify it does not result 2016 // in unnecessary writes via ReencryptEverything. 2017 TEST_F(SyncManagerTest, UpdatePasswordReencryptEverything) { 2018 std::string client_tag = "title"; 2019 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 2020 sync_pb::EntitySpecifics entity_specifics; 2021 { 2022 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2023 Cryptographer* cryptographer = trans.GetCryptographer(); 2024 sync_pb::PasswordSpecificsData data; 2025 data.set_password_value("secret"); 2026 cryptographer->Encrypt( 2027 data, 2028 entity_specifics.mutable_password()->mutable_encrypted()); 2029 } 2030 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag, 2031 syncable::GenerateSyncableHash(PASSWORDS, 2032 client_tag), 2033 entity_specifics); 2034 // New node shouldn't start off unsynced. 2035 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2036 2037 // Force a re-encrypt everything. Should not set is_unsynced. 2038 testing::Mock::VerifyAndClearExpectations(&encryption_observer_); 2039 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2040 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2041 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); 2042 sync_manager_.GetEncryptionHandler()->Init(); 2043 PumpLoop(); 2044 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag)); 2045 } 2046 2047 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for bookmarks 2048 // when we write the same data, but does set it when we write new data. 2049 TEST_F(SyncManagerTest, SetBookmarkTitle) { 2050 std::string client_tag = "title"; 2051 sync_pb::EntitySpecifics entity_specifics; 2052 entity_specifics.mutable_bookmark()->set_url("url"); 2053 entity_specifics.mutable_bookmark()->set_title("title"); 2054 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2055 syncable::GenerateSyncableHash(BOOKMARKS, 2056 client_tag), 2057 entity_specifics); 2058 // New node shouldn't start off unsynced. 2059 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2060 2061 // Manually change to the same title. Should not set is_unsynced. 2062 { 2063 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2064 WriteNode node(&trans); 2065 EXPECT_EQ(BaseNode::INIT_OK, 2066 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2067 node.SetTitle(client_tag); 2068 } 2069 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2070 2071 // Manually change to new title. Should set is_unsynced. 2072 { 2073 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2074 WriteNode node(&trans); 2075 EXPECT_EQ(BaseNode::INIT_OK, 2076 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2077 node.SetTitle("title2"); 2078 } 2079 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2080 } 2081 2082 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted 2083 // bookmarks when we write the same data, but does set it when we write new 2084 // data. 2085 TEST_F(SyncManagerTest, SetBookmarkTitleWithEncryption) { 2086 std::string client_tag = "title"; 2087 sync_pb::EntitySpecifics entity_specifics; 2088 entity_specifics.mutable_bookmark()->set_url("url"); 2089 entity_specifics.mutable_bookmark()->set_title("title"); 2090 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2091 syncable::GenerateSyncableHash(BOOKMARKS, 2092 client_tag), 2093 entity_specifics); 2094 // New node shouldn't start off unsynced. 2095 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2096 2097 // Encrypt the datatatype, should set is_unsynced. 2098 EXPECT_CALL(encryption_observer_, 2099 OnEncryptedTypesChanged( 2100 HasModelTypes(EncryptableUserTypes()), true)); 2101 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2102 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION)); 2103 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2104 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 2105 sync_manager_.GetEncryptionHandler()->Init(); 2106 PumpLoop(); 2107 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2108 2109 // Manually change to the same title. Should not set is_unsynced. 2110 // NON_UNIQUE_NAME should be kEncryptedString. 2111 { 2112 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2113 WriteNode node(&trans); 2114 EXPECT_EQ(BaseNode::INIT_OK, 2115 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2116 node.SetTitle(client_tag); 2117 const syncable::Entry* node_entry = node.GetEntry(); 2118 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2119 EXPECT_TRUE(specifics.has_encrypted()); 2120 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2121 } 2122 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2123 2124 // Manually change to new title. Should set is_unsynced. NON_UNIQUE_NAME 2125 // should still be kEncryptedString. 2126 { 2127 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2128 WriteNode node(&trans); 2129 EXPECT_EQ(BaseNode::INIT_OK, 2130 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2131 node.SetTitle("title2"); 2132 const syncable::Entry* node_entry = node.GetEntry(); 2133 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2134 EXPECT_TRUE(specifics.has_encrypted()); 2135 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2136 } 2137 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag)); 2138 } 2139 2140 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for non-bookmarks 2141 // when we write the same data, but does set it when we write new data. 2142 TEST_F(SyncManagerTest, SetNonBookmarkTitle) { 2143 std::string client_tag = "title"; 2144 sync_pb::EntitySpecifics entity_specifics; 2145 entity_specifics.mutable_preference()->set_name("name"); 2146 entity_specifics.mutable_preference()->set_value("value"); 2147 MakeServerNode(sync_manager_.GetUserShare(), 2148 PREFERENCES, 2149 client_tag, 2150 syncable::GenerateSyncableHash(PREFERENCES, 2151 client_tag), 2152 entity_specifics); 2153 // New node shouldn't start off unsynced. 2154 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2155 2156 // Manually change to the same title. Should not set is_unsynced. 2157 { 2158 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2159 WriteNode node(&trans); 2160 EXPECT_EQ(BaseNode::INIT_OK, 2161 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2162 node.SetTitle(client_tag); 2163 } 2164 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2165 2166 // Manually change to new title. Should set is_unsynced. 2167 { 2168 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2169 WriteNode node(&trans); 2170 EXPECT_EQ(BaseNode::INIT_OK, 2171 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2172 node.SetTitle("title2"); 2173 } 2174 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2175 } 2176 2177 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted 2178 // non-bookmarks when we write the same data or when we write new data 2179 // data (should remained kEncryptedString). 2180 TEST_F(SyncManagerTest, SetNonBookmarkTitleWithEncryption) { 2181 std::string client_tag = "title"; 2182 sync_pb::EntitySpecifics entity_specifics; 2183 entity_specifics.mutable_preference()->set_name("name"); 2184 entity_specifics.mutable_preference()->set_value("value"); 2185 MakeServerNode(sync_manager_.GetUserShare(), 2186 PREFERENCES, 2187 client_tag, 2188 syncable::GenerateSyncableHash(PREFERENCES, 2189 client_tag), 2190 entity_specifics); 2191 // New node shouldn't start off unsynced. 2192 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2193 2194 // Encrypt the datatatype, should set is_unsynced. 2195 EXPECT_CALL(encryption_observer_, 2196 OnEncryptedTypesChanged( 2197 HasModelTypes(EncryptableUserTypes()), true)); 2198 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); 2199 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION)); 2200 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); 2201 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true)); 2202 sync_manager_.GetEncryptionHandler()->Init(); 2203 PumpLoop(); 2204 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2205 2206 // Manually change to the same title. Should not set is_unsynced. 2207 // NON_UNIQUE_NAME should be kEncryptedString. 2208 { 2209 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2210 WriteNode node(&trans); 2211 EXPECT_EQ(BaseNode::INIT_OK, 2212 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2213 node.SetTitle(client_tag); 2214 const syncable::Entry* node_entry = node.GetEntry(); 2215 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2216 EXPECT_TRUE(specifics.has_encrypted()); 2217 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2218 } 2219 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag)); 2220 2221 // Manually change to new title. Should not set is_unsynced because the 2222 // NON_UNIQUE_NAME should still be kEncryptedString. 2223 { 2224 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2225 WriteNode node(&trans); 2226 EXPECT_EQ(BaseNode::INIT_OK, 2227 node.InitByClientTagLookup(PREFERENCES, client_tag)); 2228 node.SetTitle("title2"); 2229 const syncable::Entry* node_entry = node.GetEntry(); 2230 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2231 EXPECT_TRUE(specifics.has_encrypted()); 2232 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2233 EXPECT_FALSE(node_entry->GetIsUnsynced()); 2234 } 2235 } 2236 2237 // Ensure that titles are truncated to 255 bytes, and attempting to reset 2238 // them to their longer version does not set IS_UNSYNCED. 2239 TEST_F(SyncManagerTest, SetLongTitle) { 2240 const int kNumChars = 512; 2241 const std::string kClientTag = "tag"; 2242 std::string title(kNumChars, '0'); 2243 sync_pb::EntitySpecifics entity_specifics; 2244 entity_specifics.mutable_preference()->set_name("name"); 2245 entity_specifics.mutable_preference()->set_value("value"); 2246 MakeServerNode(sync_manager_.GetUserShare(), 2247 PREFERENCES, 2248 "short_title", 2249 syncable::GenerateSyncableHash(PREFERENCES, 2250 kClientTag), 2251 entity_specifics); 2252 // New node shouldn't start off unsynced. 2253 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2254 2255 // Manually change to the long title. Should set is_unsynced. 2256 { 2257 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2258 WriteNode node(&trans); 2259 EXPECT_EQ(BaseNode::INIT_OK, 2260 node.InitByClientTagLookup(PREFERENCES, kClientTag)); 2261 node.SetTitle(title); 2262 EXPECT_EQ(node.GetTitle(), title.substr(0, 255)); 2263 } 2264 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2265 2266 // Manually change to the same title. Should not set is_unsynced. 2267 { 2268 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2269 WriteNode node(&trans); 2270 EXPECT_EQ(BaseNode::INIT_OK, 2271 node.InitByClientTagLookup(PREFERENCES, kClientTag)); 2272 node.SetTitle(title); 2273 EXPECT_EQ(node.GetTitle(), title.substr(0, 255)); 2274 } 2275 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2276 2277 // Manually change to new title. Should set is_unsynced. 2278 { 2279 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2280 WriteNode node(&trans); 2281 EXPECT_EQ(BaseNode::INIT_OK, 2282 node.InitByClientTagLookup(PREFERENCES, kClientTag)); 2283 node.SetTitle("title2"); 2284 } 2285 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, kClientTag)); 2286 } 2287 2288 // Create an encrypted entry when the cryptographer doesn't think the type is 2289 // marked for encryption. Ensure reads/writes don't break and don't unencrypt 2290 // the data. 2291 TEST_F(SyncManagerTest, SetPreviouslyEncryptedSpecifics) { 2292 std::string client_tag = "tag"; 2293 std::string url = "url"; 2294 std::string url2 = "new_url"; 2295 std::string title = "title"; 2296 sync_pb::EntitySpecifics entity_specifics; 2297 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); 2298 { 2299 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2300 Cryptographer* crypto = trans.GetCryptographer(); 2301 sync_pb::EntitySpecifics bm_specifics; 2302 bm_specifics.mutable_bookmark()->set_title("title"); 2303 bm_specifics.mutable_bookmark()->set_url("url"); 2304 sync_pb::EncryptedData encrypted; 2305 crypto->Encrypt(bm_specifics, &encrypted); 2306 entity_specifics.mutable_encrypted()->CopyFrom(encrypted); 2307 AddDefaultFieldValue(BOOKMARKS, &entity_specifics); 2308 } 2309 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2310 syncable::GenerateSyncableHash(BOOKMARKS, 2311 client_tag), 2312 entity_specifics); 2313 2314 { 2315 // Verify the data. 2316 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2317 ReadNode node(&trans); 2318 EXPECT_EQ(BaseNode::INIT_OK, 2319 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2320 EXPECT_EQ(title, node.GetTitle()); 2321 EXPECT_EQ(url, node.GetBookmarkSpecifics().url()); 2322 } 2323 2324 { 2325 // Overwrite the url (which overwrites the specifics). 2326 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2327 WriteNode node(&trans); 2328 EXPECT_EQ(BaseNode::INIT_OK, 2329 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2330 2331 sync_pb::BookmarkSpecifics bookmark_specifics(node.GetBookmarkSpecifics()); 2332 bookmark_specifics.set_url(url2); 2333 node.SetBookmarkSpecifics(bookmark_specifics); 2334 } 2335 2336 { 2337 // Verify it's still encrypted and it has the most recent url. 2338 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); 2339 ReadNode node(&trans); 2340 EXPECT_EQ(BaseNode::INIT_OK, 2341 node.InitByClientTagLookup(BOOKMARKS, client_tag)); 2342 EXPECT_EQ(title, node.GetTitle()); 2343 EXPECT_EQ(url2, node.GetBookmarkSpecifics().url()); 2344 const syncable::Entry* node_entry = node.GetEntry(); 2345 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName()); 2346 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics(); 2347 EXPECT_TRUE(specifics.has_encrypted()); 2348 } 2349 } 2350 2351 // Verify transaction version of a model type is incremented when node of 2352 // that type is updated. 2353 TEST_F(SyncManagerTest, IncrementTransactionVersion) { 2354 ModelSafeRoutingInfo routing_info; 2355 GetModelSafeRoutingInfo(&routing_info); 2356 2357 { 2358 ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare()); 2359 for (ModelSafeRoutingInfo::iterator i = routing_info.begin(); 2360 i != routing_info.end(); ++i) { 2361 // Transaction version is incremented when SyncManagerTest::SetUp() 2362 // creates a node of each type. 2363 EXPECT_EQ(1, 2364 sync_manager_.GetUserShare()->directory-> 2365 GetTransactionVersion(i->first)); 2366 } 2367 } 2368 2369 // Create bookmark node to increment transaction version of bookmark model. 2370 std::string client_tag = "title"; 2371 sync_pb::EntitySpecifics entity_specifics; 2372 entity_specifics.mutable_bookmark()->set_url("url"); 2373 entity_specifics.mutable_bookmark()->set_title("title"); 2374 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag, 2375 syncable::GenerateSyncableHash(BOOKMARKS, 2376 client_tag), 2377 entity_specifics); 2378 2379 { 2380 ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare()); 2381 for (ModelSafeRoutingInfo::iterator i = routing_info.begin(); 2382 i != routing_info.end(); ++i) { 2383 EXPECT_EQ(i->first == BOOKMARKS ? 2 : 1, 2384 sync_manager_.GetUserShare()->directory-> 2385 GetTransactionVersion(i->first)); 2386 } 2387 } 2388 } 2389 2390 class MockSyncScheduler : public FakeSyncScheduler { 2391 public: 2392 MockSyncScheduler() : FakeSyncScheduler() {} 2393 virtual ~MockSyncScheduler() {} 2394 2395 MOCK_METHOD1(Start, void(SyncScheduler::Mode)); 2396 MOCK_METHOD1(ScheduleConfiguration, void(const ConfigurationParams&)); 2397 }; 2398 2399 class ComponentsFactory : public TestInternalComponentsFactory { 2400 public: 2401 ComponentsFactory(const Switches& switches, 2402 SyncScheduler* scheduler_to_use, 2403 sessions::SyncSessionContext** session_context, 2404 InternalComponentsFactory::StorageOption* storage_used) 2405 : TestInternalComponentsFactory( 2406 switches, InternalComponentsFactory::STORAGE_IN_MEMORY, storage_used), 2407 scheduler_to_use_(scheduler_to_use), 2408 session_context_(session_context) {} 2409 virtual ~ComponentsFactory() {} 2410 2411 virtual scoped_ptr<SyncScheduler> BuildScheduler( 2412 const std::string& name, 2413 sessions::SyncSessionContext* context, 2414 CancelationSignal* stop_handle) OVERRIDE { 2415 *session_context_ = context; 2416 return scheduler_to_use_.Pass(); 2417 } 2418 2419 private: 2420 scoped_ptr<SyncScheduler> scheduler_to_use_; 2421 sessions::SyncSessionContext** session_context_; 2422 }; 2423 2424 class SyncManagerTestWithMockScheduler : public SyncManagerTest { 2425 public: 2426 SyncManagerTestWithMockScheduler() : scheduler_(NULL) {} 2427 virtual InternalComponentsFactory* GetFactory() OVERRIDE { 2428 scheduler_ = new MockSyncScheduler(); 2429 return new ComponentsFactory(GetSwitches(), scheduler_, &session_context_, 2430 &storage_used_); 2431 } 2432 2433 MockSyncScheduler* scheduler() { return scheduler_; } 2434 sessions::SyncSessionContext* session_context() { 2435 return session_context_; 2436 } 2437 2438 private: 2439 MockSyncScheduler* scheduler_; 2440 sessions::SyncSessionContext* session_context_; 2441 }; 2442 2443 // Test that the configuration params are properly created and sent to 2444 // ScheduleConfigure. No callback should be invoked. Any disabled datatypes 2445 // should be purged. 2446 TEST_F(SyncManagerTestWithMockScheduler, BasicConfiguration) { 2447 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION; 2448 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES); 2449 ModelSafeRoutingInfo new_routing_info; 2450 GetModelSafeRoutingInfo(&new_routing_info); 2451 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info); 2452 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types); 2453 2454 ConfigurationParams params; 2455 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE)); 2456 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)). 2457 WillOnce(SaveArg<0>(¶ms)); 2458 2459 // Set data for all types. 2460 ModelTypeSet protocol_types = ProtocolTypes(); 2461 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2462 iter.Inc()) { 2463 SetProgressMarkerForType(iter.Get(), true); 2464 } 2465 2466 CallbackCounter ready_task_counter, retry_task_counter; 2467 sync_manager_.ConfigureSyncer( 2468 reason, 2469 types_to_download, 2470 disabled_types, 2471 ModelTypeSet(), 2472 ModelTypeSet(), 2473 new_routing_info, 2474 base::Bind(&CallbackCounter::Callback, 2475 base::Unretained(&ready_task_counter)), 2476 base::Bind(&CallbackCounter::Callback, 2477 base::Unretained(&retry_task_counter))); 2478 EXPECT_EQ(0, ready_task_counter.times_called()); 2479 EXPECT_EQ(0, retry_task_counter.times_called()); 2480 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, 2481 params.source); 2482 EXPECT_TRUE(types_to_download.Equals(params.types_to_download)); 2483 EXPECT_EQ(new_routing_info, params.routing_info); 2484 2485 // Verify all the disabled types were purged. 2486 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().Equals( 2487 enabled_types)); 2488 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken( 2489 ModelTypeSet::All()).Equals(disabled_types)); 2490 } 2491 2492 // Test that on a reconfiguration (configuration where the session context 2493 // already has routing info), only those recently disabled types are purged. 2494 TEST_F(SyncManagerTestWithMockScheduler, ReConfiguration) { 2495 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION; 2496 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES); 2497 ModelTypeSet disabled_types = ModelTypeSet(THEMES, SESSIONS); 2498 ModelSafeRoutingInfo old_routing_info; 2499 ModelSafeRoutingInfo new_routing_info; 2500 GetModelSafeRoutingInfo(&old_routing_info); 2501 new_routing_info = old_routing_info; 2502 new_routing_info.erase(THEMES); 2503 new_routing_info.erase(SESSIONS); 2504 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info); 2505 2506 ConfigurationParams params; 2507 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE)); 2508 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)). 2509 WillOnce(SaveArg<0>(¶ms)); 2510 2511 // Set data for all types except those recently disabled (so we can verify 2512 // only those recently disabled are purged) . 2513 ModelTypeSet protocol_types = ProtocolTypes(); 2514 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2515 iter.Inc()) { 2516 if (!disabled_types.Has(iter.Get())) { 2517 SetProgressMarkerForType(iter.Get(), true); 2518 } else { 2519 SetProgressMarkerForType(iter.Get(), false); 2520 } 2521 } 2522 2523 // Set the context to have the old routing info. 2524 session_context()->SetRoutingInfo(old_routing_info); 2525 2526 CallbackCounter ready_task_counter, retry_task_counter; 2527 sync_manager_.ConfigureSyncer( 2528 reason, 2529 types_to_download, 2530 ModelTypeSet(), 2531 ModelTypeSet(), 2532 ModelTypeSet(), 2533 new_routing_info, 2534 base::Bind(&CallbackCounter::Callback, 2535 base::Unretained(&ready_task_counter)), 2536 base::Bind(&CallbackCounter::Callback, 2537 base::Unretained(&retry_task_counter))); 2538 EXPECT_EQ(0, ready_task_counter.times_called()); 2539 EXPECT_EQ(0, retry_task_counter.times_called()); 2540 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, 2541 params.source); 2542 EXPECT_TRUE(types_to_download.Equals(params.types_to_download)); 2543 EXPECT_EQ(new_routing_info, params.routing_info); 2544 2545 // Verify only the recently disabled types were purged. 2546 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken( 2547 ProtocolTypes()).Equals(disabled_types)); 2548 } 2549 2550 // Test that PurgePartiallySyncedTypes purges only those types that have not 2551 // fully completed their initial download and apply. 2552 TEST_F(SyncManagerTest, PurgePartiallySyncedTypes) { 2553 ModelSafeRoutingInfo routing_info; 2554 GetModelSafeRoutingInfo(&routing_info); 2555 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); 2556 2557 UserShare* share = sync_manager_.GetUserShare(); 2558 2559 // The test harness automatically initializes all types in the routing info. 2560 // Check that autofill is not among them. 2561 ASSERT_FALSE(enabled_types.Has(AUTOFILL)); 2562 2563 // Further ensure that the test harness did not create its root node. 2564 { 2565 syncable::ReadTransaction trans(FROM_HERE, share->directory.get()); 2566 syncable::Entry autofill_root_node(&trans, 2567 syncable::GET_TYPE_ROOT, 2568 AUTOFILL); 2569 ASSERT_FALSE(autofill_root_node.good()); 2570 } 2571 2572 // One more redundant check. 2573 ASSERT_FALSE(sync_manager_.InitialSyncEndedTypes().Has(AUTOFILL)); 2574 2575 // Give autofill a progress marker. 2576 sync_pb::DataTypeProgressMarker autofill_marker; 2577 autofill_marker.set_data_type_id( 2578 GetSpecificsFieldNumberFromModelType(AUTOFILL)); 2579 autofill_marker.set_token("token"); 2580 share->directory->SetDownloadProgress(AUTOFILL, autofill_marker); 2581 2582 // Also add a pending autofill root node update from the server. 2583 TestEntryFactory factory_(share->directory.get()); 2584 int autofill_meta = factory_.CreateUnappliedRootNode(AUTOFILL); 2585 2586 // Preferences is an enabled type. Check that the harness initialized it. 2587 ASSERT_TRUE(enabled_types.Has(PREFERENCES)); 2588 ASSERT_TRUE(sync_manager_.InitialSyncEndedTypes().Has(PREFERENCES)); 2589 2590 // Give preferencse a progress marker. 2591 sync_pb::DataTypeProgressMarker prefs_marker; 2592 prefs_marker.set_data_type_id( 2593 GetSpecificsFieldNumberFromModelType(PREFERENCES)); 2594 prefs_marker.set_token("token"); 2595 share->directory->SetDownloadProgress(PREFERENCES, prefs_marker); 2596 2597 // Add a fully synced preferences node under the root. 2598 std::string pref_client_tag = "prefABC"; 2599 std::string pref_hashed_tag = "hashXYZ"; 2600 sync_pb::EntitySpecifics pref_specifics; 2601 AddDefaultFieldValue(PREFERENCES, &pref_specifics); 2602 int pref_meta = MakeServerNode( 2603 share, PREFERENCES, pref_client_tag, pref_hashed_tag, pref_specifics); 2604 2605 // And now, the purge. 2606 EXPECT_TRUE(sync_manager_.PurgePartiallySyncedTypes()); 2607 2608 // Ensure that autofill lost its progress marker, but preferences did not. 2609 ModelTypeSet empty_tokens = 2610 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All()); 2611 EXPECT_TRUE(empty_tokens.Has(AUTOFILL)); 2612 EXPECT_FALSE(empty_tokens.Has(PREFERENCES)); 2613 2614 // Ensure that autofill lots its node, but preferences did not. 2615 { 2616 syncable::ReadTransaction trans(FROM_HERE, share->directory.get()); 2617 syncable::Entry autofill_node(&trans, GET_BY_HANDLE, autofill_meta); 2618 syncable::Entry pref_node(&trans, GET_BY_HANDLE, pref_meta); 2619 EXPECT_FALSE(autofill_node.good()); 2620 EXPECT_TRUE(pref_node.good()); 2621 } 2622 } 2623 2624 // Test CleanupDisabledTypes properly purges all disabled types as specified 2625 // by the previous and current enabled params. 2626 TEST_F(SyncManagerTest, PurgeDisabledTypes) { 2627 ModelSafeRoutingInfo routing_info; 2628 GetModelSafeRoutingInfo(&routing_info); 2629 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); 2630 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types); 2631 2632 // The harness should have initialized the enabled_types for us. 2633 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2634 2635 // Set progress markers for all types. 2636 ModelTypeSet protocol_types = ProtocolTypes(); 2637 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2638 iter.Inc()) { 2639 SetProgressMarkerForType(iter.Get(), true); 2640 } 2641 2642 // Verify all the enabled types remain after cleanup, and all the disabled 2643 // types were purged. 2644 sync_manager_.PurgeDisabledTypes(disabled_types, 2645 ModelTypeSet(), 2646 ModelTypeSet()); 2647 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2648 EXPECT_TRUE(disabled_types.Equals( 2649 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All()))); 2650 2651 // Disable some more types. 2652 disabled_types.Put(BOOKMARKS); 2653 disabled_types.Put(PREFERENCES); 2654 ModelTypeSet new_enabled_types = 2655 Difference(ModelTypeSet::All(), disabled_types); 2656 2657 // Verify only the non-disabled types remain after cleanup. 2658 sync_manager_.PurgeDisabledTypes(disabled_types, 2659 ModelTypeSet(), 2660 ModelTypeSet()); 2661 EXPECT_TRUE(new_enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2662 EXPECT_TRUE(disabled_types.Equals( 2663 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All()))); 2664 } 2665 2666 // Test PurgeDisabledTypes properly unapplies types by deleting their local data 2667 // and preserving their server data and progress marker. 2668 TEST_F(SyncManagerTest, PurgeUnappliedTypes) { 2669 ModelSafeRoutingInfo routing_info; 2670 GetModelSafeRoutingInfo(&routing_info); 2671 ModelTypeSet unapplied_types = ModelTypeSet(BOOKMARKS, PREFERENCES); 2672 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); 2673 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types); 2674 2675 // The harness should have initialized the enabled_types for us. 2676 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes())); 2677 2678 // Set progress markers for all types. 2679 ModelTypeSet protocol_types = ProtocolTypes(); 2680 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good(); 2681 iter.Inc()) { 2682 SetProgressMarkerForType(iter.Get(), true); 2683 } 2684 2685 // Add the following kinds of items: 2686 // 1. Fully synced preference. 2687 // 2. Locally created preference, server unknown, unsynced 2688 // 3. Locally deleted preference, server known, unsynced 2689 // 4. Server deleted preference, locally known. 2690 // 5. Server created preference, locally unknown, unapplied. 2691 // 6. A fully synced bookmark (no unique_client_tag). 2692 UserShare* share = sync_manager_.GetUserShare(); 2693 sync_pb::EntitySpecifics pref_specifics; 2694 AddDefaultFieldValue(PREFERENCES, &pref_specifics); 2695 sync_pb::EntitySpecifics bm_specifics; 2696 AddDefaultFieldValue(BOOKMARKS, &bm_specifics); 2697 int pref1_meta = MakeServerNode( 2698 share, PREFERENCES, "pref1", "hash1", pref_specifics); 2699 int64 pref2_meta = MakeNode(share, PREFERENCES, "pref2"); 2700 int pref3_meta = MakeServerNode( 2701 share, PREFERENCES, "pref3", "hash3", pref_specifics); 2702 int pref4_meta = MakeServerNode( 2703 share, PREFERENCES, "pref4", "hash4", pref_specifics); 2704 int pref5_meta = MakeServerNode( 2705 share, PREFERENCES, "pref5", "hash5", pref_specifics); 2706 int bookmark_meta = MakeServerNode( 2707 share, BOOKMARKS, "bookmark", "", bm_specifics); 2708 2709 { 2710 syncable::WriteTransaction trans(FROM_HERE, 2711 syncable::SYNCER, 2712 share->directory.get()); 2713 // Pref's 1 and 2 are already set up properly. 2714 // Locally delete pref 3. 2715 syncable::MutableEntry pref3(&trans, GET_BY_HANDLE, pref3_meta); 2716 pref3.PutIsDel(true); 2717 pref3.PutIsUnsynced(true); 2718 // Delete pref 4 at the server. 2719 syncable::MutableEntry pref4(&trans, GET_BY_HANDLE, pref4_meta); 2720 pref4.PutServerIsDel(true); 2721 pref4.PutIsUnappliedUpdate(true); 2722 pref4.PutServerVersion(2); 2723 // Pref 5 is an new unapplied update. 2724 syncable::MutableEntry pref5(&trans, GET_BY_HANDLE, pref5_meta); 2725 pref5.PutIsUnappliedUpdate(true); 2726 pref5.PutIsDel(true); 2727 pref5.PutBaseVersion(-1); 2728 // Bookmark is already set up properly 2729 } 2730 2731 // Take a snapshot to clear all the dirty bits. 2732 share->directory.get()->SaveChanges(); 2733 2734 // Now request a purge for the unapplied types. 2735 disabled_types.PutAll(unapplied_types); 2736 sync_manager_.PurgeDisabledTypes(disabled_types, 2737 ModelTypeSet(), 2738 unapplied_types); 2739 2740 // Verify the unapplied types still have progress markers and initial sync 2741 // ended after cleanup. 2742 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().HasAll(unapplied_types)); 2743 EXPECT_TRUE( 2744 sync_manager_.GetTypesWithEmptyProgressMarkerToken(unapplied_types). 2745 Empty()); 2746 2747 // Ensure the items were unapplied as necessary. 2748 { 2749 syncable::ReadTransaction trans(FROM_HERE, share->directory.get()); 2750 syncable::Entry pref_node(&trans, GET_BY_HANDLE, pref1_meta); 2751 ASSERT_TRUE(pref_node.good()); 2752 EXPECT_TRUE(pref_node.GetKernelCopy().is_dirty()); 2753 EXPECT_FALSE(pref_node.GetIsUnsynced()); 2754 EXPECT_TRUE(pref_node.GetIsUnappliedUpdate()); 2755 EXPECT_TRUE(pref_node.GetIsDel()); 2756 EXPECT_GT(pref_node.GetServerVersion(), 0); 2757 EXPECT_EQ(pref_node.GetBaseVersion(), -1); 2758 2759 // Pref 2 should just be locally deleted. 2760 syncable::Entry pref2_node(&trans, GET_BY_HANDLE, pref2_meta); 2761 ASSERT_TRUE(pref2_node.good()); 2762 EXPECT_TRUE(pref2_node.GetKernelCopy().is_dirty()); 2763 EXPECT_FALSE(pref2_node.GetIsUnsynced()); 2764 EXPECT_TRUE(pref2_node.GetIsDel()); 2765 EXPECT_FALSE(pref2_node.GetIsUnappliedUpdate()); 2766 EXPECT_TRUE(pref2_node.GetIsDel()); 2767 EXPECT_EQ(pref2_node.GetServerVersion(), 0); 2768 EXPECT_EQ(pref2_node.GetBaseVersion(), -1); 2769 2770 syncable::Entry pref3_node(&trans, GET_BY_HANDLE, pref3_meta); 2771 ASSERT_TRUE(pref3_node.good()); 2772 EXPECT_TRUE(pref3_node.GetKernelCopy().is_dirty()); 2773 EXPECT_FALSE(pref3_node.GetIsUnsynced()); 2774 EXPECT_TRUE(pref3_node.GetIsUnappliedUpdate()); 2775 EXPECT_TRUE(pref3_node.GetIsDel()); 2776 EXPECT_GT(pref3_node.GetServerVersion(), 0); 2777 EXPECT_EQ(pref3_node.GetBaseVersion(), -1); 2778 2779 syncable::Entry pref4_node(&trans, GET_BY_HANDLE, pref4_meta); 2780 ASSERT_TRUE(pref4_node.good()); 2781 EXPECT_TRUE(pref4_node.GetKernelCopy().is_dirty()); 2782 EXPECT_FALSE(pref4_node.GetIsUnsynced()); 2783 EXPECT_TRUE(pref4_node.GetIsUnappliedUpdate()); 2784 EXPECT_TRUE(pref4_node.GetIsDel()); 2785 EXPECT_GT(pref4_node.GetServerVersion(), 0); 2786 EXPECT_EQ(pref4_node.GetBaseVersion(), -1); 2787 2788 // Pref 5 should remain untouched. 2789 syncable::Entry pref5_node(&trans, GET_BY_HANDLE, pref5_meta); 2790 ASSERT_TRUE(pref5_node.good()); 2791 EXPECT_FALSE(pref5_node.GetKernelCopy().is_dirty()); 2792 EXPECT_FALSE(pref5_node.GetIsUnsynced()); 2793 EXPECT_TRUE(pref5_node.GetIsUnappliedUpdate()); 2794 EXPECT_TRUE(pref5_node.GetIsDel()); 2795 EXPECT_GT(pref5_node.GetServerVersion(), 0); 2796 EXPECT_EQ(pref5_node.GetBaseVersion(), -1); 2797 2798 syncable::Entry bookmark_node(&trans, GET_BY_HANDLE, bookmark_meta); 2799 ASSERT_TRUE(bookmark_node.good()); 2800 EXPECT_TRUE(bookmark_node.GetKernelCopy().is_dirty()); 2801 EXPECT_FALSE(bookmark_node.GetIsUnsynced()); 2802 EXPECT_TRUE(bookmark_node.GetIsUnappliedUpdate()); 2803 EXPECT_TRUE(bookmark_node.GetIsDel()); 2804 EXPECT_GT(bookmark_node.GetServerVersion(), 0); 2805 EXPECT_EQ(bookmark_node.GetBaseVersion(), -1); 2806 } 2807 } 2808 2809 // A test harness to exercise the code that processes and passes changes from 2810 // the "SYNCER"-WriteTransaction destructor, through the SyncManager, to the 2811 // ChangeProcessor. 2812 class SyncManagerChangeProcessingTest : public SyncManagerTest { 2813 public: 2814 virtual void OnChangesApplied( 2815 ModelType model_type, 2816 int64 model_version, 2817 const BaseTransaction* trans, 2818 const ImmutableChangeRecordList& changes) OVERRIDE { 2819 last_changes_ = changes; 2820 } 2821 2822 virtual void OnChangesComplete(ModelType model_type) OVERRIDE {} 2823 2824 const ImmutableChangeRecordList& GetRecentChangeList() { 2825 return last_changes_; 2826 } 2827 2828 UserShare* share() { 2829 return sync_manager_.GetUserShare(); 2830 } 2831 2832 // Set some flags so our nodes reasonably approximate the real world scenario 2833 // and can get past CheckTreeInvariants. 2834 // 2835 // It's never going to be truly accurate, since we're squashing update 2836 // receipt, processing and application into a single transaction. 2837 void SetNodeProperties(syncable::MutableEntry *entry) { 2838 entry->PutId(id_factory_.NewServerId()); 2839 entry->PutBaseVersion(10); 2840 entry->PutServerVersion(10); 2841 } 2842 2843 // Looks for the given change in the list. Returns the index at which it was 2844 // found. Returns -1 on lookup failure. 2845 size_t FindChangeInList(int64 id, ChangeRecord::Action action) { 2846 SCOPED_TRACE(id); 2847 for (size_t i = 0; i < last_changes_.Get().size(); ++i) { 2848 if (last_changes_.Get()[i].id == id 2849 && last_changes_.Get()[i].action == action) { 2850 return i; 2851 } 2852 } 2853 ADD_FAILURE() << "Failed to find specified change"; 2854 return static_cast<size_t>(-1); 2855 } 2856 2857 // Returns the current size of the change list. 2858 // 2859 // Note that spurious changes do not necessarily indicate a problem. 2860 // Assertions on change list size can help detect problems, but it may be 2861 // necessary to reduce their strictness if the implementation changes. 2862 size_t GetChangeListSize() { 2863 return last_changes_.Get().size(); 2864 } 2865 2866 void ClearChangeList() { last_changes_ = ImmutableChangeRecordList(); } 2867 2868 protected: 2869 ImmutableChangeRecordList last_changes_; 2870 TestIdFactory id_factory_; 2871 }; 2872 2873 // Test creation of a folder and a bookmark. 2874 TEST_F(SyncManagerChangeProcessingTest, AddBookmarks) { 2875 int64 type_root = GetIdForDataType(BOOKMARKS); 2876 int64 folder_id = kInvalidId; 2877 int64 child_id = kInvalidId; 2878 2879 // Create a folder and a bookmark under it. 2880 { 2881 syncable::WriteTransaction trans( 2882 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2883 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 2884 ASSERT_TRUE(root.good()); 2885 2886 syncable::MutableEntry folder(&trans, syncable::CREATE, 2887 BOOKMARKS, root.GetId(), "folder"); 2888 ASSERT_TRUE(folder.good()); 2889 SetNodeProperties(&folder); 2890 folder.PutIsDir(true); 2891 folder_id = folder.GetMetahandle(); 2892 2893 syncable::MutableEntry child(&trans, syncable::CREATE, 2894 BOOKMARKS, folder.GetId(), "child"); 2895 ASSERT_TRUE(child.good()); 2896 SetNodeProperties(&child); 2897 child_id = child.GetMetahandle(); 2898 } 2899 2900 // The closing of the above scope will delete the transaction. Its processed 2901 // changes should be waiting for us in a member of the test harness. 2902 EXPECT_EQ(2UL, GetChangeListSize()); 2903 2904 // We don't need to check these return values here. The function will add a 2905 // non-fatal failure if these changes are not found. 2906 size_t folder_change_pos = 2907 FindChangeInList(folder_id, ChangeRecord::ACTION_ADD); 2908 size_t child_change_pos = 2909 FindChangeInList(child_id, ChangeRecord::ACTION_ADD); 2910 2911 // Parents are delivered before children. 2912 EXPECT_LT(folder_change_pos, child_change_pos); 2913 } 2914 2915 // Test moving a bookmark into an empty folder. 2916 TEST_F(SyncManagerChangeProcessingTest, MoveBookmarkIntoEmptyFolder) { 2917 int64 type_root = GetIdForDataType(BOOKMARKS); 2918 int64 folder_b_id = kInvalidId; 2919 int64 child_id = kInvalidId; 2920 2921 // Create two folders. Place a child under folder A. 2922 { 2923 syncable::WriteTransaction trans( 2924 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2925 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 2926 ASSERT_TRUE(root.good()); 2927 2928 syncable::MutableEntry folder_a(&trans, syncable::CREATE, 2929 BOOKMARKS, root.GetId(), "folderA"); 2930 ASSERT_TRUE(folder_a.good()); 2931 SetNodeProperties(&folder_a); 2932 folder_a.PutIsDir(true); 2933 2934 syncable::MutableEntry folder_b(&trans, syncable::CREATE, 2935 BOOKMARKS, root.GetId(), "folderB"); 2936 ASSERT_TRUE(folder_b.good()); 2937 SetNodeProperties(&folder_b); 2938 folder_b.PutIsDir(true); 2939 folder_b_id = folder_b.GetMetahandle(); 2940 2941 syncable::MutableEntry child(&trans, syncable::CREATE, 2942 BOOKMARKS, folder_a.GetId(), 2943 "child"); 2944 ASSERT_TRUE(child.good()); 2945 SetNodeProperties(&child); 2946 child_id = child.GetMetahandle(); 2947 } 2948 2949 // Close that transaction. The above was to setup the initial scenario. The 2950 // real test starts now. 2951 2952 // Move the child from folder A to folder B. 2953 { 2954 syncable::WriteTransaction trans( 2955 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2956 2957 syncable::Entry folder_b(&trans, syncable::GET_BY_HANDLE, folder_b_id); 2958 syncable::MutableEntry child(&trans, syncable::GET_BY_HANDLE, child_id); 2959 2960 child.PutParentId(folder_b.GetId()); 2961 } 2962 2963 EXPECT_EQ(1UL, GetChangeListSize()); 2964 2965 // Verify that this was detected as a real change. An early version of the 2966 // UniquePosition code had a bug where moves from one folder to another were 2967 // ignored unless the moved node's UniquePosition value was also changed in 2968 // some way. 2969 FindChangeInList(child_id, ChangeRecord::ACTION_UPDATE); 2970 } 2971 2972 // Test moving a bookmark into a non-empty folder. 2973 TEST_F(SyncManagerChangeProcessingTest, MoveIntoPopulatedFolder) { 2974 int64 type_root = GetIdForDataType(BOOKMARKS); 2975 int64 child_a_id = kInvalidId; 2976 int64 child_b_id = kInvalidId; 2977 2978 // Create two folders. Place one child each under folder A and folder B. 2979 { 2980 syncable::WriteTransaction trans( 2981 FROM_HERE, syncable::SYNCER, share()->directory.get()); 2982 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 2983 ASSERT_TRUE(root.good()); 2984 2985 syncable::MutableEntry folder_a(&trans, syncable::CREATE, 2986 BOOKMARKS, root.GetId(), "folderA"); 2987 ASSERT_TRUE(folder_a.good()); 2988 SetNodeProperties(&folder_a); 2989 folder_a.PutIsDir(true); 2990 2991 syncable::MutableEntry folder_b(&trans, syncable::CREATE, 2992 BOOKMARKS, root.GetId(), "folderB"); 2993 ASSERT_TRUE(folder_b.good()); 2994 SetNodeProperties(&folder_b); 2995 folder_b.PutIsDir(true); 2996 2997 syncable::MutableEntry child_a(&trans, syncable::CREATE, 2998 BOOKMARKS, folder_a.GetId(), 2999 "childA"); 3000 ASSERT_TRUE(child_a.good()); 3001 SetNodeProperties(&child_a); 3002 child_a_id = child_a.GetMetahandle(); 3003 3004 syncable::MutableEntry child_b(&trans, syncable::CREATE, 3005 BOOKMARKS, folder_b.GetId(), 3006 "childB"); 3007 SetNodeProperties(&child_b); 3008 child_b_id = child_b.GetMetahandle(); 3009 } 3010 3011 // Close that transaction. The above was to setup the initial scenario. The 3012 // real test starts now. 3013 3014 { 3015 syncable::WriteTransaction trans( 3016 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3017 3018 syncable::MutableEntry child_a(&trans, syncable::GET_BY_HANDLE, child_a_id); 3019 syncable::MutableEntry child_b(&trans, syncable::GET_BY_HANDLE, child_b_id); 3020 3021 // Move child A from folder A to folder B and update its position. 3022 child_a.PutParentId(child_b.GetParentId()); 3023 child_a.PutPredecessor(child_b.GetId()); 3024 } 3025 3026 EXPECT_EQ(1UL, GetChangeListSize()); 3027 3028 // Verify that only child a is in the change list. 3029 // (This function will add a failure if the lookup fails.) 3030 FindChangeInList(child_a_id, ChangeRecord::ACTION_UPDATE); 3031 } 3032 3033 // Tests the ordering of deletion changes. 3034 TEST_F(SyncManagerChangeProcessingTest, DeletionsAndChanges) { 3035 int64 type_root = GetIdForDataType(BOOKMARKS); 3036 int64 folder_a_id = kInvalidId; 3037 int64 folder_b_id = kInvalidId; 3038 int64 child_id = kInvalidId; 3039 3040 // Create two folders. Place a child under folder A. 3041 { 3042 syncable::WriteTransaction trans( 3043 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3044 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 3045 ASSERT_TRUE(root.good()); 3046 3047 syncable::MutableEntry folder_a(&trans, syncable::CREATE, 3048 BOOKMARKS, root.GetId(), "folderA"); 3049 ASSERT_TRUE(folder_a.good()); 3050 SetNodeProperties(&folder_a); 3051 folder_a.PutIsDir(true); 3052 folder_a_id = folder_a.GetMetahandle(); 3053 3054 syncable::MutableEntry folder_b(&trans, syncable::CREATE, 3055 BOOKMARKS, root.GetId(), "folderB"); 3056 ASSERT_TRUE(folder_b.good()); 3057 SetNodeProperties(&folder_b); 3058 folder_b.PutIsDir(true); 3059 folder_b_id = folder_b.GetMetahandle(); 3060 3061 syncable::MutableEntry child(&trans, syncable::CREATE, 3062 BOOKMARKS, folder_a.GetId(), 3063 "child"); 3064 ASSERT_TRUE(child.good()); 3065 SetNodeProperties(&child); 3066 child_id = child.GetMetahandle(); 3067 } 3068 3069 // Close that transaction. The above was to setup the initial scenario. The 3070 // real test starts now. 3071 3072 { 3073 syncable::WriteTransaction trans( 3074 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3075 3076 syncable::MutableEntry folder_a( 3077 &trans, syncable::GET_BY_HANDLE, folder_a_id); 3078 syncable::MutableEntry folder_b( 3079 &trans, syncable::GET_BY_HANDLE, folder_b_id); 3080 syncable::MutableEntry child(&trans, syncable::GET_BY_HANDLE, child_id); 3081 3082 // Delete folder B and its child. 3083 child.PutIsDel(true); 3084 folder_b.PutIsDel(true); 3085 3086 // Make an unrelated change to folder A. 3087 folder_a.PutNonUniqueName("NewNameA"); 3088 } 3089 3090 EXPECT_EQ(3UL, GetChangeListSize()); 3091 3092 size_t folder_a_pos = 3093 FindChangeInList(folder_a_id, ChangeRecord::ACTION_UPDATE); 3094 size_t folder_b_pos = 3095 FindChangeInList(folder_b_id, ChangeRecord::ACTION_DELETE); 3096 size_t child_pos = FindChangeInList(child_id, ChangeRecord::ACTION_DELETE); 3097 3098 // Deletes should appear before updates. 3099 EXPECT_LT(child_pos, folder_a_pos); 3100 EXPECT_LT(folder_b_pos, folder_a_pos); 3101 } 3102 3103 // See that attachment metadata changes are not filtered out by 3104 // SyncManagerImpl::VisiblePropertiesDiffer. 3105 TEST_F(SyncManagerChangeProcessingTest, AttachmentMetadataOnlyChanges) { 3106 // Create an article with no attachments. See that a change is generated. 3107 int64 article_id = kInvalidId; 3108 { 3109 syncable::WriteTransaction trans( 3110 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3111 int64 type_root = GetIdForDataType(ARTICLES); 3112 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root); 3113 ASSERT_TRUE(root.good()); 3114 syncable::MutableEntry article( 3115 &trans, syncable::CREATE, ARTICLES, root.GetId(), "article"); 3116 ASSERT_TRUE(article.good()); 3117 SetNodeProperties(&article); 3118 article_id = article.GetMetahandle(); 3119 } 3120 ASSERT_EQ(1UL, GetChangeListSize()); 3121 FindChangeInList(article_id, ChangeRecord::ACTION_ADD); 3122 ClearChangeList(); 3123 3124 // Modify the article by adding one attachment. Don't touch anything else. 3125 // See that a change is generated. 3126 { 3127 syncable::WriteTransaction trans( 3128 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3129 syncable::MutableEntry article(&trans, syncable::GET_BY_HANDLE, article_id); 3130 sync_pb::AttachmentMetadata metadata; 3131 *metadata.add_record()->mutable_id() = CreateAttachmentIdProto(); 3132 article.PutAttachmentMetadata(metadata); 3133 } 3134 ASSERT_EQ(1UL, GetChangeListSize()); 3135 FindChangeInList(article_id, ChangeRecord::ACTION_UPDATE); 3136 ClearChangeList(); 3137 3138 // Modify the article by replacing its attachment with a different one. See 3139 // that a change is generated. 3140 { 3141 syncable::WriteTransaction trans( 3142 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3143 syncable::MutableEntry article(&trans, syncable::GET_BY_HANDLE, article_id); 3144 sync_pb::AttachmentMetadata metadata = article.GetAttachmentMetadata(); 3145 *metadata.add_record()->mutable_id() = CreateAttachmentIdProto(); 3146 article.PutAttachmentMetadata(metadata); 3147 } 3148 ASSERT_EQ(1UL, GetChangeListSize()); 3149 FindChangeInList(article_id, ChangeRecord::ACTION_UPDATE); 3150 ClearChangeList(); 3151 3152 // Modify the article by replacing its attachment metadata with the same 3153 // attachment metadata. No change should be generated. 3154 { 3155 syncable::WriteTransaction trans( 3156 FROM_HERE, syncable::SYNCER, share()->directory.get()); 3157 syncable::MutableEntry article(&trans, syncable::GET_BY_HANDLE, article_id); 3158 article.PutAttachmentMetadata(article.GetAttachmentMetadata()); 3159 } 3160 ASSERT_EQ(0UL, GetChangeListSize()); 3161 } 3162 3163 // During initialization SyncManagerImpl loads sqlite database. If it fails to 3164 // do so it should fail initialization. This test verifies this behavior. 3165 // Test reuses SyncManagerImpl initialization from SyncManagerTest but overrides 3166 // InternalComponentsFactory to return DirectoryBackingStore that always fails 3167 // to load. 3168 class SyncManagerInitInvalidStorageTest : public SyncManagerTest { 3169 public: 3170 SyncManagerInitInvalidStorageTest() { 3171 } 3172 3173 virtual InternalComponentsFactory* GetFactory() OVERRIDE { 3174 return new TestInternalComponentsFactory( 3175 GetSwitches(), InternalComponentsFactory::STORAGE_INVALID, 3176 &storage_used_); 3177 } 3178 }; 3179 3180 // SyncManagerInitInvalidStorageTest::GetFactory will return 3181 // DirectoryBackingStore that ensures that SyncManagerImpl::OpenDirectory fails. 3182 // SyncManagerImpl initialization is done in SyncManagerTest::SetUp. This test's 3183 // task is to ensure that SyncManagerImpl reported initialization failure in 3184 // OnInitializationComplete callback. 3185 TEST_F(SyncManagerInitInvalidStorageTest, FailToOpenDatabase) { 3186 EXPECT_FALSE(initialization_succeeded_); 3187 } 3188 3189 } // namespace syncer 3190