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