Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / sync / internal_api / sync_manager_impl_unittest.cc
blob27791ffe0cec4b770713bbd61289eaa3ddea46ec
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.
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.
9 #include <cstddef>
10 #include <map>
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/run_loop.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/test/values_test_util.h"
24 #include "base/values.h"
25 #include "google_apis/gaia/gaia_constants.h"
26 #include "sync/engine/sync_scheduler.h"
27 #include "sync/internal_api/public/base/attachment_id_proto.h"
28 #include "sync/internal_api/public/base/cancelation_signal.h"
29 #include "sync/internal_api/public/base/model_type_test_util.h"
30 #include "sync/internal_api/public/change_record.h"
31 #include "sync/internal_api/public/engine/model_safe_worker.h"
32 #include "sync/internal_api/public/engine/polling_constants.h"
33 #include "sync/internal_api/public/events/protocol_event.h"
34 #include "sync/internal_api/public/http_post_provider_factory.h"
35 #include "sync/internal_api/public/http_post_provider_interface.h"
36 #include "sync/internal_api/public/read_node.h"
37 #include "sync/internal_api/public/read_transaction.h"
38 #include "sync/internal_api/public/test/test_entry_factory.h"
39 #include "sync/internal_api/public/test/test_internal_components_factory.h"
40 #include "sync/internal_api/public/test/test_user_share.h"
41 #include "sync/internal_api/public/write_node.h"
42 #include "sync/internal_api/public/write_transaction.h"
43 #include "sync/internal_api/sync_encryption_handler_impl.h"
44 #include "sync/internal_api/sync_manager_impl.h"
45 #include "sync/internal_api/syncapi_internal.h"
46 #include "sync/js/js_backend.h"
47 #include "sync/js/js_event_handler.h"
48 #include "sync/js/js_test_util.h"
49 #include "sync/protocol/bookmark_specifics.pb.h"
50 #include "sync/protocol/encryption.pb.h"
51 #include "sync/protocol/extension_specifics.pb.h"
52 #include "sync/protocol/password_specifics.pb.h"
53 #include "sync/protocol/preference_specifics.pb.h"
54 #include "sync/protocol/proto_value_conversions.h"
55 #include "sync/protocol/sync.pb.h"
56 #include "sync/sessions/sync_session.h"
57 #include "sync/syncable/directory.h"
58 #include "sync/syncable/entry.h"
59 #include "sync/syncable/mutable_entry.h"
60 #include "sync/syncable/nigori_util.h"
61 #include "sync/syncable/syncable_id.h"
62 #include "sync/syncable/syncable_read_transaction.h"
63 #include "sync/syncable/syncable_util.h"
64 #include "sync/syncable/syncable_write_transaction.h"
65 #include "sync/test/callback_counter.h"
66 #include "sync/test/engine/fake_model_worker.h"
67 #include "sync/test/engine/fake_sync_scheduler.h"
68 #include "sync/test/engine/test_id_factory.h"
69 #include "sync/test/fake_encryptor.h"
70 #include "sync/util/cryptographer.h"
71 #include "sync/util/extensions_activity.h"
72 #include "sync/util/mock_unrecoverable_error_handler.h"
73 #include "sync/util/time.h"
74 #include "testing/gmock/include/gmock/gmock.h"
75 #include "testing/gtest/include/gtest/gtest.h"
76 #include "url/gurl.h"
78 using base::ExpectDictStringValue;
79 using testing::_;
80 using testing::DoAll;
81 using testing::InSequence;
82 using testing::Return;
83 using testing::SaveArg;
84 using testing::StrictMock;
86 namespace syncer {
88 using sessions::SyncSessionSnapshot;
89 using syncable::GET_BY_HANDLE;
90 using syncable::IS_DEL;
91 using syncable::IS_UNSYNCED;
92 using syncable::NON_UNIQUE_NAME;
93 using syncable::SPECIFICS;
94 using syncable::kEncryptedString;
96 namespace {
98 // Makes a child node under the type root folder. Returns the id of the
99 // newly-created node.
100 int64 MakeNode(UserShare* share,
101 ModelType model_type,
102 const std::string& client_tag) {
103 WriteTransaction trans(FROM_HERE, share);
104 WriteNode node(&trans);
105 WriteNode::InitUniqueByCreationResult result =
106 node.InitUniqueByCreation(model_type, client_tag);
107 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
108 node.SetIsFolder(false);
109 return node.GetId();
112 // Makes a non-folder child of the root node. Returns the id of the
113 // newly-created node.
114 int64 MakeNodeWithRoot(UserShare* share,
115 ModelType model_type,
116 const std::string& client_tag) {
117 WriteTransaction trans(FROM_HERE, share);
118 ReadNode root_node(&trans);
119 root_node.InitByRootLookup();
120 WriteNode node(&trans);
121 WriteNode::InitUniqueByCreationResult result =
122 node.InitUniqueByCreation(model_type, root_node, client_tag);
123 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
124 node.SetIsFolder(false);
125 return node.GetId();
128 // Makes a folder child of a non-root node. Returns the id of the
129 // newly-created node.
130 int64 MakeFolderWithParent(UserShare* share,
131 ModelType model_type,
132 int64 parent_id,
133 BaseNode* predecessor) {
134 WriteTransaction trans(FROM_HERE, share);
135 ReadNode parent_node(&trans);
136 EXPECT_EQ(BaseNode::INIT_OK, parent_node.InitByIdLookup(parent_id));
137 WriteNode node(&trans);
138 EXPECT_TRUE(node.InitBookmarkByCreation(parent_node, predecessor));
139 node.SetIsFolder(true);
140 return node.GetId();
143 int64 MakeBookmarkWithParent(UserShare* share,
144 int64 parent_id,
145 BaseNode* predecessor) {
146 WriteTransaction trans(FROM_HERE, share);
147 ReadNode parent_node(&trans);
148 EXPECT_EQ(BaseNode::INIT_OK, parent_node.InitByIdLookup(parent_id));
149 WriteNode node(&trans);
150 EXPECT_TRUE(node.InitBookmarkByCreation(parent_node, predecessor));
151 return node.GetId();
154 // Creates the "synced" root node for a particular datatype. We use the syncable
155 // methods here so that the syncer treats these nodes as if they were already
156 // received from the server.
157 int64 MakeTypeRoot(UserShare* share, ModelType model_type) {
158 sync_pb::EntitySpecifics specifics;
159 AddDefaultFieldValue(model_type, &specifics);
160 syncable::WriteTransaction trans(
161 FROM_HERE, syncable::UNITTEST, share->directory.get());
162 // Attempt to lookup by nigori tag.
163 std::string type_tag = ModelTypeToRootTag(model_type);
164 syncable::Id node_id = syncable::Id::CreateFromServerId(type_tag);
165 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
166 node_id);
167 EXPECT_TRUE(entry.good());
168 entry.PutBaseVersion(1);
169 entry.PutServerVersion(1);
170 entry.PutIsUnappliedUpdate(false);
171 entry.PutParentId(syncable::Id::GetRoot());
172 entry.PutServerParentId(syncable::Id::GetRoot());
173 entry.PutServerIsDir(true);
174 entry.PutIsDir(true);
175 entry.PutServerSpecifics(specifics);
176 entry.PutSpecifics(specifics);
177 entry.PutUniqueServerTag(type_tag);
178 entry.PutNonUniqueName(type_tag);
179 entry.PutIsDel(false);
180 return entry.GetMetahandle();
183 // Simulates creating a "synced" node as a child of the root datatype node.
184 int64 MakeServerNode(UserShare* share, ModelType model_type,
185 const std::string& client_tag,
186 const std::string& hashed_tag,
187 const sync_pb::EntitySpecifics& specifics) {
188 syncable::WriteTransaction trans(
189 FROM_HERE, syncable::UNITTEST, share->directory.get());
190 syncable::Entry root_entry(&trans, syncable::GET_TYPE_ROOT, model_type);
191 EXPECT_TRUE(root_entry.good());
192 syncable::Id root_id = root_entry.GetId();
193 syncable::Id node_id = syncable::Id::CreateFromServerId(client_tag);
194 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
195 node_id);
196 EXPECT_TRUE(entry.good());
197 entry.PutBaseVersion(1);
198 entry.PutServerVersion(1);
199 entry.PutIsUnappliedUpdate(false);
200 entry.PutServerParentId(root_id);
201 entry.PutParentId(root_id);
202 entry.PutServerIsDir(false);
203 entry.PutIsDir(false);
204 entry.PutServerSpecifics(specifics);
205 entry.PutSpecifics(specifics);
206 entry.PutNonUniqueName(client_tag);
207 entry.PutUniqueClientTag(hashed_tag);
208 entry.PutIsDel(false);
209 return entry.GetMetahandle();
212 int GetTotalNodeCount(UserShare* share, int64 root) {
213 ReadTransaction trans(FROM_HERE, share);
214 ReadNode node(&trans);
215 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(root));
216 return node.GetTotalNodeCount();
219 } // namespace
221 class SyncApiTest : public testing::Test {
222 public:
223 void SetUp() override { test_user_share_.SetUp(); }
225 void TearDown() override { test_user_share_.TearDown(); }
227 protected:
228 // Create an entry with the given |model_type|, |client_tag| and
229 // |attachment_metadata|.
230 void CreateEntryWithAttachmentMetadata(
231 const ModelType& model_type,
232 const std::string& client_tag,
233 const sync_pb::AttachmentMetadata& attachment_metadata);
235 // Attempts to load the entry specified by |model_type| and |client_tag| and
236 // returns the lookup result code.
237 BaseNode::InitByLookupResult LookupEntryByClientTag(
238 const ModelType& model_type,
239 const std::string& client_tag);
241 // Replace the entry specified by |model_type| and |client_tag| with a
242 // tombstone.
243 void ReplaceWithTombstone(const ModelType& model_type,
244 const std::string& client_tag);
246 // Save changes to the Directory, destroy it then reload it.
247 bool ReloadDir();
249 UserShare* user_share();
250 syncable::Directory* dir();
251 SyncEncryptionHandler* encryption_handler();
253 private:
254 base::MessageLoop message_loop_;
255 TestUserShare test_user_share_;
258 UserShare* SyncApiTest::user_share() {
259 return test_user_share_.user_share();
262 syncable::Directory* SyncApiTest::dir() {
263 return test_user_share_.user_share()->directory.get();
266 SyncEncryptionHandler* SyncApiTest::encryption_handler() {
267 return test_user_share_.encryption_handler();
270 bool SyncApiTest::ReloadDir() {
271 return test_user_share_.Reload();
274 void SyncApiTest::CreateEntryWithAttachmentMetadata(
275 const ModelType& model_type,
276 const std::string& client_tag,
277 const sync_pb::AttachmentMetadata& attachment_metadata) {
278 syncer::WriteTransaction trans(FROM_HERE, user_share());
279 syncer::ReadNode root_node(&trans);
280 root_node.InitByRootLookup();
281 syncer::WriteNode node(&trans);
282 ASSERT_EQ(node.InitUniqueByCreation(model_type, root_node, client_tag),
283 syncer::WriteNode::INIT_SUCCESS);
284 node.SetAttachmentMetadata(attachment_metadata);
287 BaseNode::InitByLookupResult SyncApiTest::LookupEntryByClientTag(
288 const ModelType& model_type,
289 const std::string& client_tag) {
290 syncer::ReadTransaction trans(FROM_HERE, user_share());
291 syncer::ReadNode node(&trans);
292 return node.InitByClientTagLookup(model_type, client_tag);
295 void SyncApiTest::ReplaceWithTombstone(const ModelType& model_type,
296 const std::string& client_tag) {
297 syncer::WriteTransaction trans(FROM_HERE, user_share());
298 syncer::WriteNode node(&trans);
299 ASSERT_EQ(node.InitByClientTagLookup(model_type, client_tag),
300 syncer::WriteNode::INIT_OK);
301 node.Tombstone();
304 TEST_F(SyncApiTest, SanityCheckTest) {
306 ReadTransaction trans(FROM_HERE, user_share());
307 EXPECT_TRUE(trans.GetWrappedTrans());
310 WriteTransaction trans(FROM_HERE, user_share());
311 EXPECT_TRUE(trans.GetWrappedTrans());
314 // No entries but root should exist
315 ReadTransaction trans(FROM_HERE, user_share());
316 ReadNode node(&trans);
317 // Metahandle 1 can be root, sanity check 2
318 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD, node.InitByIdLookup(2));
322 TEST_F(SyncApiTest, BasicTagWrite) {
324 ReadTransaction trans(FROM_HERE, user_share());
325 ReadNode root_node(&trans);
326 root_node.InitByRootLookup();
327 EXPECT_EQ(kInvalidId, root_node.GetFirstChildId());
330 ignore_result(MakeNodeWithRoot(user_share(), BOOKMARKS, "testtag"));
333 ReadTransaction trans(FROM_HERE, user_share());
334 ReadNode node(&trans);
335 EXPECT_EQ(BaseNode::INIT_OK,
336 node.InitByClientTagLookup(BOOKMARKS, "testtag"));
337 EXPECT_NE(0, node.GetId());
339 ReadNode root_node(&trans);
340 root_node.InitByRootLookup();
341 EXPECT_EQ(node.GetId(), root_node.GetFirstChildId());
345 TEST_F(SyncApiTest, BasicTagWriteWithImplicitParent) {
346 int64 type_root = MakeTypeRoot(user_share(), PREFERENCES);
349 ReadTransaction trans(FROM_HERE, user_share());
350 ReadNode type_root_node(&trans);
351 EXPECT_EQ(BaseNode::INIT_OK, type_root_node.InitByIdLookup(type_root));
352 EXPECT_EQ(kInvalidId, type_root_node.GetFirstChildId());
355 ignore_result(MakeNode(user_share(), PREFERENCES, "testtag"));
358 ReadTransaction trans(FROM_HERE, user_share());
359 ReadNode node(&trans);
360 EXPECT_EQ(BaseNode::INIT_OK,
361 node.InitByClientTagLookup(PREFERENCES, "testtag"));
362 EXPECT_EQ(kInvalidId, node.GetParentId());
364 ReadNode type_root_node(&trans);
365 EXPECT_EQ(BaseNode::INIT_OK, type_root_node.InitByIdLookup(type_root));
366 EXPECT_EQ(node.GetId(), type_root_node.GetFirstChildId());
370 TEST_F(SyncApiTest, ModelTypesSiloed) {
372 WriteTransaction trans(FROM_HERE, user_share());
373 ReadNode root_node(&trans);
374 root_node.InitByRootLookup();
375 EXPECT_EQ(root_node.GetFirstChildId(), 0);
378 ignore_result(MakeNodeWithRoot(user_share(), BOOKMARKS, "collideme"));
379 ignore_result(MakeNodeWithRoot(user_share(), PREFERENCES, "collideme"));
380 ignore_result(MakeNodeWithRoot(user_share(), AUTOFILL, "collideme"));
383 ReadTransaction trans(FROM_HERE, user_share());
385 ReadNode bookmarknode(&trans);
386 EXPECT_EQ(BaseNode::INIT_OK,
387 bookmarknode.InitByClientTagLookup(BOOKMARKS,
388 "collideme"));
390 ReadNode prefnode(&trans);
391 EXPECT_EQ(BaseNode::INIT_OK,
392 prefnode.InitByClientTagLookup(PREFERENCES,
393 "collideme"));
395 ReadNode autofillnode(&trans);
396 EXPECT_EQ(BaseNode::INIT_OK,
397 autofillnode.InitByClientTagLookup(AUTOFILL,
398 "collideme"));
400 EXPECT_NE(bookmarknode.GetId(), prefnode.GetId());
401 EXPECT_NE(autofillnode.GetId(), prefnode.GetId());
402 EXPECT_NE(bookmarknode.GetId(), autofillnode.GetId());
406 TEST_F(SyncApiTest, ReadMissingTagsFails) {
408 ReadTransaction trans(FROM_HERE, user_share());
409 ReadNode node(&trans);
410 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD,
411 node.InitByClientTagLookup(BOOKMARKS,
412 "testtag"));
415 WriteTransaction trans(FROM_HERE, user_share());
416 WriteNode node(&trans);
417 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD,
418 node.InitByClientTagLookup(BOOKMARKS,
419 "testtag"));
423 // TODO(chron): Hook this all up to the server and write full integration tests
424 // for update->undelete behavior.
425 TEST_F(SyncApiTest, TestDeleteBehavior) {
426 int64 node_id;
427 int64 folder_id;
428 std::string test_title("test1");
431 WriteTransaction trans(FROM_HERE, user_share());
432 ReadNode root_node(&trans);
433 root_node.InitByRootLookup();
435 // we'll use this spare folder later
436 WriteNode folder_node(&trans);
437 EXPECT_TRUE(folder_node.InitBookmarkByCreation(root_node, NULL));
438 folder_id = folder_node.GetId();
440 WriteNode wnode(&trans);
441 WriteNode::InitUniqueByCreationResult result =
442 wnode.InitUniqueByCreation(BOOKMARKS, root_node, "testtag");
443 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
444 wnode.SetIsFolder(false);
445 wnode.SetTitle(test_title);
447 node_id = wnode.GetId();
450 // Ensure we can delete something with a tag.
452 WriteTransaction trans(FROM_HERE, user_share());
453 WriteNode wnode(&trans);
454 EXPECT_EQ(BaseNode::INIT_OK,
455 wnode.InitByClientTagLookup(BOOKMARKS,
456 "testtag"));
457 EXPECT_FALSE(wnode.GetIsFolder());
458 EXPECT_EQ(wnode.GetTitle(), test_title);
460 wnode.Tombstone();
463 // Lookup of a node which was deleted should return failure,
464 // but have found some data about the node.
466 ReadTransaction trans(FROM_HERE, user_share());
467 ReadNode node(&trans);
468 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_IS_DEL,
469 node.InitByClientTagLookup(BOOKMARKS,
470 "testtag"));
471 // Note that for proper function of this API this doesn't need to be
472 // filled, we're checking just to make sure the DB worked in this test.
473 EXPECT_EQ(node.GetTitle(), test_title);
477 WriteTransaction trans(FROM_HERE, user_share());
478 ReadNode folder_node(&trans);
479 EXPECT_EQ(BaseNode::INIT_OK, folder_node.InitByIdLookup(folder_id));
481 WriteNode wnode(&trans);
482 // This will undelete the tag.
483 WriteNode::InitUniqueByCreationResult result =
484 wnode.InitUniqueByCreation(BOOKMARKS, folder_node, "testtag");
485 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
486 EXPECT_EQ(wnode.GetIsFolder(), false);
487 EXPECT_EQ(wnode.GetParentId(), folder_node.GetId());
488 EXPECT_EQ(wnode.GetId(), node_id);
489 EXPECT_NE(wnode.GetTitle(), test_title); // Title should be cleared
490 wnode.SetTitle(test_title);
493 // Now look up should work.
495 ReadTransaction trans(FROM_HERE, user_share());
496 ReadNode node(&trans);
497 EXPECT_EQ(BaseNode::INIT_OK,
498 node.InitByClientTagLookup(BOOKMARKS,
499 "testtag"));
500 EXPECT_EQ(node.GetTitle(), test_title);
501 EXPECT_EQ(node.GetModelType(), BOOKMARKS);
505 TEST_F(SyncApiTest, WriteAndReadPassword) {
506 KeyParams params = {"localhost", "username", "passphrase"};
508 ReadTransaction trans(FROM_HERE, user_share());
509 trans.GetCryptographer()->AddKey(params);
512 WriteTransaction trans(FROM_HERE, user_share());
513 ReadNode root_node(&trans);
514 root_node.InitByRootLookup();
516 WriteNode password_node(&trans);
517 WriteNode::InitUniqueByCreationResult result =
518 password_node.InitUniqueByCreation(PASSWORDS,
519 root_node, "foo");
520 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
521 sync_pb::PasswordSpecificsData data;
522 data.set_password_value("secret");
523 password_node.SetPasswordSpecifics(data);
526 ReadTransaction trans(FROM_HERE, user_share());
528 ReadNode password_node(&trans);
529 EXPECT_EQ(BaseNode::INIT_OK,
530 password_node.InitByClientTagLookup(PASSWORDS, "foo"));
531 const sync_pb::PasswordSpecificsData& data =
532 password_node.GetPasswordSpecifics();
533 EXPECT_EQ("secret", data.password_value());
537 TEST_F(SyncApiTest, WriteEncryptedTitle) {
538 KeyParams params = {"localhost", "username", "passphrase"};
540 ReadTransaction trans(FROM_HERE, user_share());
541 trans.GetCryptographer()->AddKey(params);
543 encryption_handler()->EnableEncryptEverything();
544 int bookmark_id;
546 WriteTransaction trans(FROM_HERE, user_share());
547 ReadNode root_node(&trans);
548 root_node.InitByRootLookup();
550 WriteNode bookmark_node(&trans);
551 ASSERT_TRUE(bookmark_node.InitBookmarkByCreation(root_node, NULL));
552 bookmark_id = bookmark_node.GetId();
553 bookmark_node.SetTitle("foo");
555 WriteNode pref_node(&trans);
556 WriteNode::InitUniqueByCreationResult result =
557 pref_node.InitUniqueByCreation(PREFERENCES, root_node, "bar");
558 ASSERT_EQ(WriteNode::INIT_SUCCESS, result);
559 pref_node.SetTitle("bar");
562 ReadTransaction trans(FROM_HERE, user_share());
564 ReadNode bookmark_node(&trans);
565 ASSERT_EQ(BaseNode::INIT_OK, bookmark_node.InitByIdLookup(bookmark_id));
566 EXPECT_EQ("foo", bookmark_node.GetTitle());
567 EXPECT_EQ(kEncryptedString,
568 bookmark_node.GetEntry()->GetNonUniqueName());
570 ReadNode pref_node(&trans);
571 ASSERT_EQ(BaseNode::INIT_OK,
572 pref_node.InitByClientTagLookup(PREFERENCES,
573 "bar"));
574 EXPECT_EQ(kEncryptedString, pref_node.GetTitle());
578 // Non-unique name should not be empty. For bookmarks non-unique name is copied
579 // from bookmark title. This test verifies that setting bookmark title to ""
580 // results in single space title and non-unique name in internal representation.
581 // GetTitle should still return empty string.
582 TEST_F(SyncApiTest, WriteEmptyBookmarkTitle) {
583 int bookmark_id;
585 WriteTransaction trans(FROM_HERE, user_share());
586 ReadNode root_node(&trans);
587 root_node.InitByRootLookup();
589 WriteNode bookmark_node(&trans);
590 ASSERT_TRUE(bookmark_node.InitBookmarkByCreation(root_node, NULL));
591 bookmark_id = bookmark_node.GetId();
592 bookmark_node.SetTitle("");
595 ReadTransaction trans(FROM_HERE, user_share());
597 ReadNode bookmark_node(&trans);
598 ASSERT_EQ(BaseNode::INIT_OK, bookmark_node.InitByIdLookup(bookmark_id));
599 EXPECT_EQ("", bookmark_node.GetTitle());
600 EXPECT_EQ(" ", bookmark_node.GetEntry()->GetSpecifics().bookmark().title());
601 EXPECT_EQ(" ", bookmark_node.GetEntry()->GetNonUniqueName());
605 TEST_F(SyncApiTest, BaseNodeSetSpecifics) {
606 int64 child_id = MakeNodeWithRoot(user_share(), BOOKMARKS, "testtag");
607 WriteTransaction trans(FROM_HERE, user_share());
608 WriteNode node(&trans);
609 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id));
611 sync_pb::EntitySpecifics entity_specifics;
612 entity_specifics.mutable_bookmark()->set_url("http://www.google.com");
614 EXPECT_NE(entity_specifics.SerializeAsString(),
615 node.GetEntitySpecifics().SerializeAsString());
616 node.SetEntitySpecifics(entity_specifics);
617 EXPECT_EQ(entity_specifics.SerializeAsString(),
618 node.GetEntitySpecifics().SerializeAsString());
621 TEST_F(SyncApiTest, BaseNodeSetSpecificsPreservesUnknownFields) {
622 int64 child_id = MakeNodeWithRoot(user_share(), BOOKMARKS, "testtag");
623 WriteTransaction trans(FROM_HERE, user_share());
624 WriteNode node(&trans);
625 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id));
626 EXPECT_TRUE(node.GetEntitySpecifics().unknown_fields().empty());
628 sync_pb::EntitySpecifics entity_specifics;
629 entity_specifics.mutable_bookmark()->set_url("http://www.google.com");
630 entity_specifics.mutable_unknown_fields()->AddFixed32(5, 100);
631 node.SetEntitySpecifics(entity_specifics);
632 EXPECT_FALSE(node.GetEntitySpecifics().unknown_fields().empty());
634 entity_specifics.mutable_unknown_fields()->Clear();
635 node.SetEntitySpecifics(entity_specifics);
636 EXPECT_FALSE(node.GetEntitySpecifics().unknown_fields().empty());
639 TEST_F(SyncApiTest, EmptyTags) {
640 WriteTransaction trans(FROM_HERE, user_share());
641 ReadNode root_node(&trans);
642 root_node.InitByRootLookup();
643 WriteNode node(&trans);
644 std::string empty_tag;
645 WriteNode::InitUniqueByCreationResult result =
646 node.InitUniqueByCreation(TYPED_URLS, root_node, empty_tag);
647 EXPECT_NE(WriteNode::INIT_SUCCESS, result);
648 EXPECT_EQ(BaseNode::INIT_FAILED_PRECONDITION,
649 node.InitByClientTagLookup(TYPED_URLS, empty_tag));
652 // Test counting nodes when the type's root node has no children.
653 TEST_F(SyncApiTest, GetTotalNodeCountEmpty) {
654 int64 type_root = MakeTypeRoot(user_share(), BOOKMARKS);
655 EXPECT_EQ(1, GetTotalNodeCount(user_share(), type_root));
658 // Test counting nodes when there is one child beneath the type's root.
659 TEST_F(SyncApiTest, GetTotalNodeCountOneChild) {
660 int64 type_root = MakeTypeRoot(user_share(), BOOKMARKS);
661 int64 parent = MakeFolderWithParent(user_share(), BOOKMARKS, type_root, NULL);
662 EXPECT_EQ(2, GetTotalNodeCount(user_share(), type_root));
663 EXPECT_EQ(1, GetTotalNodeCount(user_share(), parent));
666 // Test counting nodes when there are multiple children beneath the type root,
667 // and one of those children has children of its own.
668 TEST_F(SyncApiTest, GetTotalNodeCountMultipleChildren) {
669 int64 type_root = MakeTypeRoot(user_share(), BOOKMARKS);
670 int64 parent = MakeFolderWithParent(user_share(), BOOKMARKS, type_root, NULL);
671 ignore_result(MakeFolderWithParent(user_share(), BOOKMARKS, type_root, NULL));
672 int64 child1 = MakeFolderWithParent(user_share(), BOOKMARKS, parent, NULL);
673 ignore_result(MakeBookmarkWithParent(user_share(), parent, NULL));
674 ignore_result(MakeBookmarkWithParent(user_share(), child1, NULL));
675 EXPECT_EQ(6, GetTotalNodeCount(user_share(), type_root));
676 EXPECT_EQ(4, GetTotalNodeCount(user_share(), parent));
679 // Verify that Directory keeps track of which attachments are referenced by
680 // which entries.
681 TEST_F(SyncApiTest, AttachmentLinking) {
682 // Add an entry with an attachment.
683 std::string tag1("some tag");
684 syncer::AttachmentId attachment_id(syncer::AttachmentId::Create(0, 0));
685 sync_pb::AttachmentMetadata attachment_metadata;
686 sync_pb::AttachmentMetadataRecord* record = attachment_metadata.add_record();
687 *record->mutable_id() = attachment_id.GetProto();
688 ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
689 CreateEntryWithAttachmentMetadata(PREFERENCES, tag1, attachment_metadata);
691 // See that the directory knows it's linked.
692 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
694 // Add a second entry referencing the same attachment.
695 std::string tag2("some other tag");
696 CreateEntryWithAttachmentMetadata(PREFERENCES, tag2, attachment_metadata);
698 // See that the directory knows it's still linked.
699 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
701 // Tombstone the first entry.
702 ReplaceWithTombstone(syncer::PREFERENCES, tag1);
704 // See that the attachment is still considered linked because the entry hasn't
705 // been purged from the Directory.
706 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
708 // Save changes and see that the entry is truly gone.
709 ASSERT_TRUE(dir()->SaveChanges());
710 ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag1),
711 syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD);
713 // However, the attachment is still linked.
714 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
716 // Save, destroy, and recreate the directory. See that it's still linked.
717 ASSERT_TRUE(ReloadDir());
718 ASSERT_TRUE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
720 // Tombstone the second entry, save changes, see that it's truly gone.
721 ReplaceWithTombstone(syncer::PREFERENCES, tag2);
722 ASSERT_TRUE(dir()->SaveChanges());
723 ASSERT_EQ(LookupEntryByClientTag(PREFERENCES, tag2),
724 syncer::WriteNode::INIT_FAILED_ENTRY_NOT_GOOD);
726 // Finally, the attachment is no longer linked.
727 ASSERT_FALSE(dir()->IsAttachmentLinked(attachment_id.GetProto()));
730 // This tests directory integrity in the case of creating a new unique node
731 // with client tag matching that of an existing unapplied node with server only
732 // data. See crbug.com/505761.
733 TEST_F(SyncApiTest, WriteNode_UniqueByCreation_UndeleteCase) {
734 int64 preferences_root = MakeTypeRoot(user_share(), PREFERENCES);
736 // Create a node with server only data.
737 int64 item1 = 0;
739 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST,
740 user_share()->directory.get());
741 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
742 syncable::Id::CreateFromServerId("foo1"));
743 DCHECK(entry.good());
744 entry.PutServerVersion(10);
745 entry.PutIsUnappliedUpdate(true);
746 sync_pb::EntitySpecifics specifics;
747 AddDefaultFieldValue(PREFERENCES, &specifics);
748 entry.PutServerSpecifics(specifics);
749 const std::string hash = syncable::GenerateSyncableHash(PREFERENCES, "foo");
750 entry.PutUniqueClientTag(hash);
751 item1 = entry.GetMetahandle();
754 // Verify that the server-only item is invisible as a child of
755 // of |preferences_root| because at this point it should have the
756 // "deleted" flag set.
757 EXPECT_EQ(1, GetTotalNodeCount(user_share(), preferences_root));
759 // Create a client node with the same tag as the node above.
760 int64 item2 = MakeNode(user_share(), PREFERENCES, "foo");
761 // Expect this to be the same directory entry as |item1|.
762 EXPECT_EQ(item1, item2);
763 // Expect it to be visible as a child of |preferences_root|.
764 EXPECT_EQ(2, GetTotalNodeCount(user_share(), preferences_root));
766 // Tombstone the new item
768 WriteTransaction trans(FROM_HERE, user_share());
769 WriteNode node(&trans);
770 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(item1));
771 node.Tombstone();
774 // Verify that it is gone from the index.
775 EXPECT_EQ(1, GetTotalNodeCount(user_share(), preferences_root));
778 namespace {
780 class TestHttpPostProviderInterface : public HttpPostProviderInterface {
781 public:
782 ~TestHttpPostProviderInterface() override {}
784 void SetExtraRequestHeaders(const char* headers) override {}
785 void SetURL(const char* url, int port) override {}
786 void SetPostPayload(const char* content_type,
787 int content_length,
788 const char* content) override {}
789 bool MakeSynchronousPost(int* error_code, int* response_code) override {
790 return false;
792 int GetResponseContentLength() const override { return 0; }
793 const char* GetResponseContent() const override { return ""; }
794 const std::string GetResponseHeaderValue(
795 const std::string& name) const override {
796 return std::string();
798 void Abort() override {}
801 class TestHttpPostProviderFactory : public HttpPostProviderFactory {
802 public:
803 ~TestHttpPostProviderFactory() override {}
804 void Init(const std::string& user_agent,
805 const BindToTrackerCallback& bind_to_tracker_callback) override {}
806 HttpPostProviderInterface* Create() override {
807 return new TestHttpPostProviderInterface();
809 void Destroy(HttpPostProviderInterface* http) override {
810 delete static_cast<TestHttpPostProviderInterface*>(http);
814 class SyncManagerObserverMock : public SyncManager::Observer {
815 public:
816 MOCK_METHOD1(OnSyncCycleCompleted,
817 void(const SyncSessionSnapshot&)); // NOLINT
818 MOCK_METHOD4(OnInitializationComplete,
819 void(const WeakHandle<JsBackend>&,
820 const WeakHandle<DataTypeDebugInfoListener>&,
821 bool,
822 syncer::ModelTypeSet)); // NOLINT
823 MOCK_METHOD1(OnConnectionStatusChange, void(ConnectionStatus)); // NOLINT
824 MOCK_METHOD1(OnUpdatedToken, void(const std::string&)); // NOLINT
825 MOCK_METHOD1(OnActionableError, void(const SyncProtocolError&)); // NOLINT
826 MOCK_METHOD1(OnMigrationRequested, void(syncer::ModelTypeSet)); // NOLINT
827 MOCK_METHOD1(OnProtocolEvent, void(const ProtocolEvent&)); // NOLINT
830 class SyncEncryptionHandlerObserverMock
831 : public SyncEncryptionHandler::Observer {
832 public:
833 MOCK_METHOD2(OnPassphraseRequired,
834 void(PassphraseRequiredReason,
835 const sync_pb::EncryptedData&)); // NOLINT
836 MOCK_METHOD0(OnPassphraseAccepted, void()); // NOLINT
837 MOCK_METHOD2(OnBootstrapTokenUpdated,
838 void(const std::string&, BootstrapTokenType type)); // NOLINT
839 MOCK_METHOD2(OnEncryptedTypesChanged,
840 void(ModelTypeSet, bool)); // NOLINT
841 MOCK_METHOD0(OnEncryptionComplete, void()); // NOLINT
842 MOCK_METHOD1(OnCryptographerStateChanged, void(Cryptographer*)); // NOLINT
843 MOCK_METHOD2(OnPassphraseTypeChanged, void(PassphraseType,
844 base::Time)); // NOLINT
845 MOCK_METHOD1(OnLocalSetPassphraseEncryption,
846 void(const SyncEncryptionHandler::NigoriState&)); // NOLINT
849 } // namespace
851 class SyncManagerTest : public testing::Test,
852 public SyncManager::ChangeDelegate {
853 protected:
854 enum NigoriStatus {
855 DONT_WRITE_NIGORI,
856 WRITE_TO_NIGORI
859 enum EncryptionStatus {
860 UNINITIALIZED,
861 DEFAULT_ENCRYPTION,
862 FULL_ENCRYPTION
865 SyncManagerTest()
866 : sync_manager_("Test sync manager") {
867 switches_.encryption_method =
868 InternalComponentsFactory::ENCRYPTION_KEYSTORE;
871 virtual ~SyncManagerTest() {
874 // Test implementation.
875 void SetUp() {
876 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
878 extensions_activity_ = new ExtensionsActivity();
880 SyncCredentials credentials;
881 credentials.email = "foo@bar.com";
882 credentials.sync_token = "sometoken";
883 OAuth2TokenService::ScopeSet scope_set;
884 scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope);
885 credentials.scope_set = scope_set;
887 sync_manager_.AddObserver(&manager_observer_);
888 EXPECT_CALL(manager_observer_, OnInitializationComplete(_, _, _, _)).
889 WillOnce(DoAll(SaveArg<0>(&js_backend_),
890 SaveArg<2>(&initialization_succeeded_)));
892 EXPECT_FALSE(js_backend_.IsInitialized());
894 std::vector<scoped_refptr<ModelSafeWorker> > workers;
895 ModelSafeRoutingInfo routing_info;
896 GetModelSafeRoutingInfo(&routing_info);
898 // This works only because all routing info types are GROUP_PASSIVE.
899 // If we had types in other groups, we would need additional workers
900 // to support them.
901 scoped_refptr<ModelSafeWorker> worker = new FakeModelWorker(GROUP_PASSIVE);
902 workers.push_back(worker);
904 SyncManager::InitArgs args;
905 args.database_location = temp_dir_.path();
906 args.service_url = GURL("https://example.com/");
907 args.post_factory =
908 scoped_ptr<HttpPostProviderFactory>(new TestHttpPostProviderFactory());
909 args.workers = workers;
910 args.extensions_activity = extensions_activity_.get(),
911 args.change_delegate = this;
912 args.credentials = credentials;
913 args.invalidator_client_id = "fake_invalidator_client_id";
914 args.internal_components_factory.reset(GetFactory());
915 args.encryptor = &encryptor_;
916 args.unrecoverable_error_handler =
917 MakeWeakHandle(mock_unrecoverable_error_handler_.GetWeakPtr());
918 args.cancelation_signal = &cancelation_signal_;
919 sync_manager_.Init(&args);
921 sync_manager_.GetEncryptionHandler()->AddObserver(&encryption_observer_);
923 EXPECT_TRUE(js_backend_.IsInitialized());
924 EXPECT_EQ(InternalComponentsFactory::STORAGE_ON_DISK,
925 storage_used_);
927 if (initialization_succeeded_) {
928 for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
929 i != routing_info.end(); ++i) {
930 type_roots_[i->first] =
931 MakeTypeRoot(sync_manager_.GetUserShare(), i->first);
935 PumpLoop();
938 void TearDown() {
939 sync_manager_.RemoveObserver(&manager_observer_);
940 sync_manager_.ShutdownOnSyncThread(STOP_SYNC);
941 PumpLoop();
944 void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
945 (*out)[NIGORI] = GROUP_PASSIVE;
946 (*out)[DEVICE_INFO] = GROUP_PASSIVE;
947 (*out)[EXPERIMENTS] = GROUP_PASSIVE;
948 (*out)[BOOKMARKS] = GROUP_PASSIVE;
949 (*out)[THEMES] = GROUP_PASSIVE;
950 (*out)[SESSIONS] = GROUP_PASSIVE;
951 (*out)[PASSWORDS] = GROUP_PASSIVE;
952 (*out)[PREFERENCES] = GROUP_PASSIVE;
953 (*out)[PRIORITY_PREFERENCES] = GROUP_PASSIVE;
954 (*out)[ARTICLES] = GROUP_PASSIVE;
957 ModelTypeSet GetEnabledTypes() {
958 ModelSafeRoutingInfo routing_info;
959 GetModelSafeRoutingInfo(&routing_info);
960 return GetRoutingInfoTypes(routing_info);
963 void OnChangesApplied(
964 ModelType model_type,
965 int64 model_version,
966 const BaseTransaction* trans,
967 const ImmutableChangeRecordList& changes) override {}
969 void OnChangesComplete(ModelType model_type) override {}
971 // Helper methods.
972 bool SetUpEncryption(NigoriStatus nigori_status,
973 EncryptionStatus encryption_status) {
974 UserShare* share = sync_manager_.GetUserShare();
976 // We need to create the nigori node as if it were an applied server update.
977 int64 nigori_id = GetIdForDataType(NIGORI);
978 if (nigori_id == kInvalidId)
979 return false;
981 // Set the nigori cryptographer information.
982 if (encryption_status == FULL_ENCRYPTION)
983 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything();
985 WriteTransaction trans(FROM_HERE, share);
986 Cryptographer* cryptographer = trans.GetCryptographer();
987 if (!cryptographer)
988 return false;
989 if (encryption_status != UNINITIALIZED) {
990 KeyParams params = {"localhost", "dummy", "foobar"};
991 cryptographer->AddKey(params);
992 } else {
993 DCHECK_NE(nigori_status, WRITE_TO_NIGORI);
995 if (nigori_status == WRITE_TO_NIGORI) {
996 sync_pb::NigoriSpecifics nigori;
997 cryptographer->GetKeys(nigori.mutable_encryption_keybag());
998 share->directory->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
999 &nigori,
1000 trans.GetWrappedTrans());
1001 WriteNode node(&trans);
1002 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(nigori_id));
1003 node.SetNigoriSpecifics(nigori);
1005 return cryptographer->is_ready();
1008 int64 GetIdForDataType(ModelType type) {
1009 if (type_roots_.count(type) == 0)
1010 return 0;
1011 return type_roots_[type];
1014 void PumpLoop() {
1015 base::RunLoop().RunUntilIdle();
1018 void SetJsEventHandler(const WeakHandle<JsEventHandler>& event_handler) {
1019 js_backend_.Call(FROM_HERE, &JsBackend::SetJsEventHandler,
1020 event_handler);
1021 PumpLoop();
1024 // Looks up an entry by client tag and resets IS_UNSYNCED value to false.
1025 // Returns true if entry was previously unsynced, false if IS_UNSYNCED was
1026 // already false.
1027 bool ResetUnsyncedEntry(ModelType type,
1028 const std::string& client_tag) {
1029 UserShare* share = sync_manager_.GetUserShare();
1030 syncable::WriteTransaction trans(
1031 FROM_HERE, syncable::UNITTEST, share->directory.get());
1032 const std::string hash = syncable::GenerateSyncableHash(type, client_tag);
1033 syncable::MutableEntry entry(&trans, syncable::GET_BY_CLIENT_TAG,
1034 hash);
1035 EXPECT_TRUE(entry.good());
1036 if (!entry.GetIsUnsynced())
1037 return false;
1038 entry.PutIsUnsynced(false);
1039 return true;
1042 virtual InternalComponentsFactory* GetFactory() {
1043 return new TestInternalComponentsFactory(
1044 GetSwitches(), InternalComponentsFactory::STORAGE_IN_MEMORY,
1045 &storage_used_);
1048 // Returns true if we are currently encrypting all sync data. May
1049 // be called on any thread.
1050 bool IsEncryptEverythingEnabledForTest() {
1051 return sync_manager_.GetEncryptionHandler()->IsEncryptEverythingEnabled();
1054 // Gets the set of encrypted types from the cryptographer
1055 // Note: opens a transaction. May be called from any thread.
1056 ModelTypeSet GetEncryptedTypes() {
1057 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1058 return GetEncryptedTypesWithTrans(&trans);
1061 ModelTypeSet GetEncryptedTypesWithTrans(BaseTransaction* trans) {
1062 return trans->GetDirectory()->GetNigoriHandler()->
1063 GetEncryptedTypes(trans->GetWrappedTrans());
1066 void SimulateInvalidatorEnabledForTest(bool is_enabled) {
1067 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread());
1068 sync_manager_.SetInvalidatorEnabled(is_enabled);
1071 void SetProgressMarkerForType(ModelType type, bool set) {
1072 if (set) {
1073 sync_pb::DataTypeProgressMarker marker;
1074 marker.set_token("token");
1075 marker.set_data_type_id(GetSpecificsFieldNumberFromModelType(type));
1076 sync_manager_.directory()->SetDownloadProgress(type, marker);
1077 } else {
1078 sync_pb::DataTypeProgressMarker marker;
1079 sync_manager_.directory()->SetDownloadProgress(type, marker);
1083 InternalComponentsFactory::Switches GetSwitches() const {
1084 return switches_;
1087 void ExpectPassphraseAcceptance() {
1088 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted());
1089 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1090 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1093 void SetImplicitPassphraseAndCheck(const std::string& passphrase) {
1094 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase(
1095 passphrase,
1096 false);
1097 EXPECT_EQ(IMPLICIT_PASSPHRASE,
1098 sync_manager_.GetEncryptionHandler()->GetPassphraseType());
1101 void SetCustomPassphraseAndCheck(const std::string& passphrase) {
1102 EXPECT_CALL(encryption_observer_,
1103 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _));
1104 sync_manager_.GetEncryptionHandler()->SetEncryptionPassphrase(
1105 passphrase,
1106 true);
1107 EXPECT_EQ(CUSTOM_PASSPHRASE,
1108 sync_manager_.GetEncryptionHandler()->GetPassphraseType());
1111 bool HasUnrecoverableError() {
1112 return mock_unrecoverable_error_handler_.invocation_count() > 0;
1115 private:
1116 // Needed by |sync_manager_|.
1117 base::MessageLoop message_loop_;
1118 // Needed by |sync_manager_|.
1119 base::ScopedTempDir temp_dir_;
1120 // Sync Id's for the roots of the enabled datatypes.
1121 std::map<ModelType, int64> type_roots_;
1122 scoped_refptr<ExtensionsActivity> extensions_activity_;
1124 protected:
1125 FakeEncryptor encryptor_;
1126 SyncManagerImpl sync_manager_;
1127 CancelationSignal cancelation_signal_;
1128 WeakHandle<JsBackend> js_backend_;
1129 bool initialization_succeeded_;
1130 StrictMock<SyncManagerObserverMock> manager_observer_;
1131 StrictMock<SyncEncryptionHandlerObserverMock> encryption_observer_;
1132 InternalComponentsFactory::Switches switches_;
1133 InternalComponentsFactory::StorageOption storage_used_;
1134 MockUnrecoverableErrorHandler mock_unrecoverable_error_handler_;
1137 TEST_F(SyncManagerTest, GetAllNodesForTypeTest) {
1138 ModelSafeRoutingInfo routing_info;
1139 GetModelSafeRoutingInfo(&routing_info);
1140 sync_manager_.StartSyncingNormally(routing_info, base::Time());
1142 scoped_ptr<base::ListValue> node_list(
1143 sync_manager_.GetAllNodesForType(syncer::PREFERENCES));
1145 // Should have one node: the type root node.
1146 ASSERT_EQ(1U, node_list->GetSize());
1148 const base::DictionaryValue* first_result;
1149 ASSERT_TRUE(node_list->GetDictionary(0, &first_result));
1150 EXPECT_TRUE(first_result->HasKey("ID"));
1151 EXPECT_TRUE(first_result->HasKey("NON_UNIQUE_NAME"));
1154 TEST_F(SyncManagerTest, RefreshEncryptionReady) {
1155 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1156 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1157 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1158 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
1160 sync_manager_.GetEncryptionHandler()->Init();
1161 PumpLoop();
1163 const ModelTypeSet encrypted_types = GetEncryptedTypes();
1164 EXPECT_TRUE(encrypted_types.Has(PASSWORDS));
1165 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1168 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1169 ReadNode node(&trans);
1170 EXPECT_EQ(BaseNode::INIT_OK,
1171 node.InitByIdLookup(GetIdForDataType(NIGORI)));
1172 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
1173 EXPECT_TRUE(nigori.has_encryption_keybag());
1174 Cryptographer* cryptographer = trans.GetCryptographer();
1175 EXPECT_TRUE(cryptographer->is_ready());
1176 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag()));
1180 // Attempt to refresh encryption when nigori not downloaded.
1181 TEST_F(SyncManagerTest, RefreshEncryptionNotReady) {
1182 // Don't set up encryption (no nigori node created).
1184 // Should fail. Triggers an OnPassphraseRequired because the cryptographer
1185 // is not ready.
1186 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_, _)).Times(1);
1187 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1188 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
1189 sync_manager_.GetEncryptionHandler()->Init();
1190 PumpLoop();
1192 const ModelTypeSet encrypted_types = GetEncryptedTypes();
1193 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded.
1194 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1197 // Attempt to refresh encryption when nigori is empty.
1198 TEST_F(SyncManagerTest, RefreshEncryptionEmptyNigori) {
1199 EXPECT_TRUE(SetUpEncryption(DONT_WRITE_NIGORI, DEFAULT_ENCRYPTION));
1200 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()).Times(1);
1201 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1202 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
1204 // Should write to nigori.
1205 sync_manager_.GetEncryptionHandler()->Init();
1206 PumpLoop();
1208 const ModelTypeSet encrypted_types = GetEncryptedTypes();
1209 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded.
1210 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1213 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1214 ReadNode node(&trans);
1215 EXPECT_EQ(BaseNode::INIT_OK,
1216 node.InitByIdLookup(GetIdForDataType(NIGORI)));
1217 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
1218 EXPECT_TRUE(nigori.has_encryption_keybag());
1219 Cryptographer* cryptographer = trans.GetCryptographer();
1220 EXPECT_TRUE(cryptographer->is_ready());
1221 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag()));
1225 TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) {
1226 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1227 EXPECT_CALL(encryption_observer_,
1228 OnEncryptedTypesChanged(
1229 HasModelTypes(EncryptableUserTypes()), true));
1230 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1231 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything();
1232 EXPECT_TRUE(IsEncryptEverythingEnabledForTest());
1235 TEST_F(SyncManagerTest, EncryptDataTypesWithData) {
1236 size_t batch_size = 5;
1237 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1239 // Create some unencrypted unsynced data.
1240 int64 folder = MakeFolderWithParent(sync_manager_.GetUserShare(),
1241 BOOKMARKS,
1242 GetIdForDataType(BOOKMARKS),
1243 NULL);
1244 // First batch_size nodes are children of folder.
1245 size_t i;
1246 for (i = 0; i < batch_size; ++i) {
1247 MakeBookmarkWithParent(sync_manager_.GetUserShare(), folder, NULL);
1249 // Next batch_size nodes are a different type and on their own.
1250 for (; i < 2*batch_size; ++i) {
1251 MakeNodeWithRoot(sync_manager_.GetUserShare(), SESSIONS,
1252 base::StringPrintf("%" PRIuS "", i));
1254 // Last batch_size nodes are a third type that will not need encryption.
1255 for (; i < 3*batch_size; ++i) {
1256 MakeNodeWithRoot(sync_manager_.GetUserShare(), THEMES,
1257 base::StringPrintf("%" PRIuS "", i));
1261 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1262 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals(
1263 SyncEncryptionHandler::SensitiveTypes()));
1264 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1265 trans.GetWrappedTrans(),
1266 BOOKMARKS,
1267 false /* not encrypted */));
1268 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1269 trans.GetWrappedTrans(),
1270 SESSIONS,
1271 false /* not encrypted */));
1272 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1273 trans.GetWrappedTrans(),
1274 THEMES,
1275 false /* not encrypted */));
1278 EXPECT_CALL(encryption_observer_,
1279 OnEncryptedTypesChanged(
1280 HasModelTypes(EncryptableUserTypes()), true));
1281 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1282 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything();
1283 EXPECT_TRUE(IsEncryptEverythingEnabledForTest());
1285 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1286 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals(
1287 EncryptableUserTypes()));
1288 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1289 trans.GetWrappedTrans(),
1290 BOOKMARKS,
1291 true /* is encrypted */));
1292 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1293 trans.GetWrappedTrans(),
1294 SESSIONS,
1295 true /* is encrypted */));
1296 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1297 trans.GetWrappedTrans(),
1298 THEMES,
1299 true /* is encrypted */));
1302 // Trigger's a ReEncryptEverything with new passphrase.
1303 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
1304 EXPECT_CALL(encryption_observer_,
1305 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1306 ExpectPassphraseAcceptance();
1307 SetCustomPassphraseAndCheck("new_passphrase");
1308 EXPECT_TRUE(IsEncryptEverythingEnabledForTest());
1310 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1311 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals(
1312 EncryptableUserTypes()));
1313 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1314 trans.GetWrappedTrans(),
1315 BOOKMARKS,
1316 true /* is encrypted */));
1317 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1318 trans.GetWrappedTrans(),
1319 SESSIONS,
1320 true /* is encrypted */));
1321 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1322 trans.GetWrappedTrans(),
1323 THEMES,
1324 true /* is encrypted */));
1326 // Calling EncryptDataTypes with an empty encrypted types should not trigger
1327 // a reencryption and should just notify immediately.
1328 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
1329 EXPECT_CALL(encryption_observer_,
1330 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)).Times(0);
1331 EXPECT_CALL(encryption_observer_, OnPassphraseAccepted()).Times(0);
1332 EXPECT_CALL(encryption_observer_, OnEncryptionComplete()).Times(0);
1333 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything();
1336 // Test that when there are no pending keys and the cryptographer is not
1337 // initialized, we add a key based on the current GAIA password.
1338 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1339 TEST_F(SyncManagerTest, SetInitialGaiaPass) {
1340 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED));
1341 EXPECT_CALL(encryption_observer_,
1342 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1343 ExpectPassphraseAcceptance();
1344 SetImplicitPassphraseAndCheck("new_passphrase");
1345 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1347 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1348 ReadNode node(&trans);
1349 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI));
1350 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
1351 Cryptographer* cryptographer = trans.GetCryptographer();
1352 EXPECT_TRUE(cryptographer->is_ready());
1353 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag()));
1357 // Test that when there are no pending keys and we have on the old GAIA
1358 // password, we update and re-encrypt everything with the new GAIA password.
1359 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1360 TEST_F(SyncManagerTest, UpdateGaiaPass) {
1361 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1362 Cryptographer verifier(&encryptor_);
1364 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1365 Cryptographer* cryptographer = trans.GetCryptographer();
1366 std::string bootstrap_token;
1367 cryptographer->GetBootstrapToken(&bootstrap_token);
1368 verifier.Bootstrap(bootstrap_token);
1370 EXPECT_CALL(encryption_observer_,
1371 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1372 ExpectPassphraseAcceptance();
1373 SetImplicitPassphraseAndCheck("new_passphrase");
1374 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1376 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1377 Cryptographer* cryptographer = trans.GetCryptographer();
1378 EXPECT_TRUE(cryptographer->is_ready());
1379 // Verify the default key has changed.
1380 sync_pb::EncryptedData encrypted;
1381 cryptographer->GetKeys(&encrypted);
1382 EXPECT_FALSE(verifier.CanDecrypt(encrypted));
1386 // Sets a new explicit passphrase. This should update the bootstrap token
1387 // and re-encrypt everything.
1388 // (case 2 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1389 TEST_F(SyncManagerTest, SetPassphraseWithPassword) {
1390 Cryptographer verifier(&encryptor_);
1391 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1393 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1394 // Store the default (soon to be old) key.
1395 Cryptographer* cryptographer = trans.GetCryptographer();
1396 std::string bootstrap_token;
1397 cryptographer->GetBootstrapToken(&bootstrap_token);
1398 verifier.Bootstrap(bootstrap_token);
1400 ReadNode root_node(&trans);
1401 root_node.InitByRootLookup();
1403 WriteNode password_node(&trans);
1404 WriteNode::InitUniqueByCreationResult result =
1405 password_node.InitUniqueByCreation(PASSWORDS,
1406 root_node, "foo");
1407 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
1408 sync_pb::PasswordSpecificsData data;
1409 data.set_password_value("secret");
1410 password_node.SetPasswordSpecifics(data);
1412 EXPECT_CALL(encryption_observer_,
1413 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1414 ExpectPassphraseAcceptance();
1415 SetCustomPassphraseAndCheck("new_passphrase");
1416 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1418 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1419 Cryptographer* cryptographer = trans.GetCryptographer();
1420 EXPECT_TRUE(cryptographer->is_ready());
1421 // Verify the default key has changed.
1422 sync_pb::EncryptedData encrypted;
1423 cryptographer->GetKeys(&encrypted);
1424 EXPECT_FALSE(verifier.CanDecrypt(encrypted));
1426 ReadNode password_node(&trans);
1427 EXPECT_EQ(BaseNode::INIT_OK,
1428 password_node.InitByClientTagLookup(PASSWORDS,
1429 "foo"));
1430 const sync_pb::PasswordSpecificsData& data =
1431 password_node.GetPasswordSpecifics();
1432 EXPECT_EQ("secret", data.password_value());
1436 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1437 // being encrypted with a new (unprovided) GAIA password, then supply the
1438 // password.
1439 // (case 7 in SyncManager::SyncInternal::SetDecryptionPassphrase)
1440 TEST_F(SyncManagerTest, SupplyPendingGAIAPass) {
1441 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1442 Cryptographer other_cryptographer(&encryptor_);
1444 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1445 Cryptographer* cryptographer = trans.GetCryptographer();
1446 std::string bootstrap_token;
1447 cryptographer->GetBootstrapToken(&bootstrap_token);
1448 other_cryptographer.Bootstrap(bootstrap_token);
1450 // Now update the nigori to reflect the new keys, and update the
1451 // cryptographer to have pending keys.
1452 KeyParams params = {"localhost", "dummy", "passphrase2"};
1453 other_cryptographer.AddKey(params);
1454 WriteNode node(&trans);
1455 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI));
1456 sync_pb::NigoriSpecifics nigori;
1457 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
1458 cryptographer->SetPendingKeys(nigori.encryption_keybag());
1459 EXPECT_TRUE(cryptographer->has_pending_keys());
1460 node.SetNigoriSpecifics(nigori);
1462 EXPECT_CALL(encryption_observer_,
1463 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1464 ExpectPassphraseAcceptance();
1465 sync_manager_.GetEncryptionHandler()->SetDecryptionPassphrase("passphrase2");
1466 EXPECT_EQ(IMPLICIT_PASSPHRASE,
1467 sync_manager_.GetEncryptionHandler()->GetPassphraseType());
1468 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1470 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1471 Cryptographer* cryptographer = trans.GetCryptographer();
1472 EXPECT_TRUE(cryptographer->is_ready());
1473 // Verify we're encrypting with the new key.
1474 sync_pb::EncryptedData encrypted;
1475 cryptographer->GetKeys(&encrypted);
1476 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted));
1480 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1481 // being encrypted with an old (unprovided) GAIA password. Attempt to supply
1482 // the current GAIA password and verify the bootstrap token is updated. Then
1483 // supply the old GAIA password, and verify we re-encrypt all data with the
1484 // new GAIA password.
1485 // (cases 4 and 5 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1486 TEST_F(SyncManagerTest, SupplyPendingOldGAIAPass) {
1487 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1488 Cryptographer other_cryptographer(&encryptor_);
1490 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1491 Cryptographer* cryptographer = trans.GetCryptographer();
1492 std::string bootstrap_token;
1493 cryptographer->GetBootstrapToken(&bootstrap_token);
1494 other_cryptographer.Bootstrap(bootstrap_token);
1496 // Now update the nigori to reflect the new keys, and update the
1497 // cryptographer to have pending keys.
1498 KeyParams params = {"localhost", "dummy", "old_gaia"};
1499 other_cryptographer.AddKey(params);
1500 WriteNode node(&trans);
1501 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI));
1502 sync_pb::NigoriSpecifics nigori;
1503 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
1504 node.SetNigoriSpecifics(nigori);
1505 cryptographer->SetPendingKeys(nigori.encryption_keybag());
1507 // other_cryptographer now contains all encryption keys, and is encrypting
1508 // with the newest gaia.
1509 KeyParams new_params = {"localhost", "dummy", "new_gaia"};
1510 other_cryptographer.AddKey(new_params);
1512 // The bootstrap token should have been updated. Save it to ensure it's based
1513 // on the new GAIA password.
1514 std::string bootstrap_token;
1515 EXPECT_CALL(encryption_observer_,
1516 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN))
1517 .WillOnce(SaveArg<0>(&bootstrap_token));
1518 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_,_));
1519 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1520 SetImplicitPassphraseAndCheck("new_gaia");
1521 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1522 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
1524 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1525 Cryptographer* cryptographer = trans.GetCryptographer();
1526 EXPECT_TRUE(cryptographer->is_initialized());
1527 EXPECT_FALSE(cryptographer->is_ready());
1528 // Verify we're encrypting with the new key, even though we have pending
1529 // keys.
1530 sync_pb::EncryptedData encrypted;
1531 other_cryptographer.GetKeys(&encrypted);
1532 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted));
1534 EXPECT_CALL(encryption_observer_,
1535 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1536 ExpectPassphraseAcceptance();
1537 SetImplicitPassphraseAndCheck("old_gaia");
1539 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1540 Cryptographer* cryptographer = trans.GetCryptographer();
1541 EXPECT_TRUE(cryptographer->is_ready());
1543 // Verify we're encrypting with the new key.
1544 sync_pb::EncryptedData encrypted;
1545 other_cryptographer.GetKeys(&encrypted);
1546 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted));
1548 // Verify the saved bootstrap token is based on the new gaia password.
1549 Cryptographer temp_cryptographer(&encryptor_);
1550 temp_cryptographer.Bootstrap(bootstrap_token);
1551 EXPECT_TRUE(temp_cryptographer.CanDecrypt(encrypted));
1555 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1556 // being encrypted with an explicit (unprovided) passphrase, then supply the
1557 // passphrase.
1558 // (case 9 in SyncManager::SyncInternal::SetDecryptionPassphrase)
1559 TEST_F(SyncManagerTest, SupplyPendingExplicitPass) {
1560 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1561 Cryptographer other_cryptographer(&encryptor_);
1563 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1564 Cryptographer* cryptographer = trans.GetCryptographer();
1565 std::string bootstrap_token;
1566 cryptographer->GetBootstrapToken(&bootstrap_token);
1567 other_cryptographer.Bootstrap(bootstrap_token);
1569 // Now update the nigori to reflect the new keys, and update the
1570 // cryptographer to have pending keys.
1571 KeyParams params = {"localhost", "dummy", "explicit"};
1572 other_cryptographer.AddKey(params);
1573 WriteNode node(&trans);
1574 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI));
1575 sync_pb::NigoriSpecifics nigori;
1576 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
1577 cryptographer->SetPendingKeys(nigori.encryption_keybag());
1578 EXPECT_TRUE(cryptographer->has_pending_keys());
1579 nigori.set_keybag_is_frozen(true);
1580 node.SetNigoriSpecifics(nigori);
1582 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1583 EXPECT_CALL(encryption_observer_,
1584 OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _));
1585 EXPECT_CALL(encryption_observer_, OnPassphraseRequired(_, _));
1586 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
1587 sync_manager_.GetEncryptionHandler()->Init();
1588 EXPECT_CALL(encryption_observer_,
1589 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1590 ExpectPassphraseAcceptance();
1591 sync_manager_.GetEncryptionHandler()->SetDecryptionPassphrase("explicit");
1592 EXPECT_EQ(CUSTOM_PASSPHRASE,
1593 sync_manager_.GetEncryptionHandler()->GetPassphraseType());
1594 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1596 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1597 Cryptographer* cryptographer = trans.GetCryptographer();
1598 EXPECT_TRUE(cryptographer->is_ready());
1599 // Verify we're encrypting with the new key.
1600 sync_pb::EncryptedData encrypted;
1601 cryptographer->GetKeys(&encrypted);
1602 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted));
1606 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1607 // being encrypted with a new (unprovided) GAIA password, then supply the
1608 // password as a user-provided password.
1609 // This is the android case 7/8.
1610 TEST_F(SyncManagerTest, SupplyPendingGAIAPassUserProvided) {
1611 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED));
1612 Cryptographer other_cryptographer(&encryptor_);
1614 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1615 Cryptographer* cryptographer = trans.GetCryptographer();
1616 // Now update the nigori to reflect the new keys, and update the
1617 // cryptographer to have pending keys.
1618 KeyParams params = {"localhost", "dummy", "passphrase"};
1619 other_cryptographer.AddKey(params);
1620 WriteNode node(&trans);
1621 EXPECT_EQ(BaseNode::INIT_OK, node.InitTypeRoot(NIGORI));
1622 sync_pb::NigoriSpecifics nigori;
1623 other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
1624 node.SetNigoriSpecifics(nigori);
1625 cryptographer->SetPendingKeys(nigori.encryption_keybag());
1626 EXPECT_FALSE(cryptographer->is_ready());
1628 EXPECT_CALL(encryption_observer_,
1629 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1630 ExpectPassphraseAcceptance();
1631 SetImplicitPassphraseAndCheck("passphrase");
1632 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1634 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1635 Cryptographer* cryptographer = trans.GetCryptographer();
1636 EXPECT_TRUE(cryptographer->is_ready());
1640 TEST_F(SyncManagerTest, SetPassphraseWithEmptyPasswordNode) {
1641 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1642 int64 node_id = 0;
1643 std::string tag = "foo";
1645 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1646 ReadNode root_node(&trans);
1647 root_node.InitByRootLookup();
1649 WriteNode password_node(&trans);
1650 WriteNode::InitUniqueByCreationResult result =
1651 password_node.InitUniqueByCreation(PASSWORDS, root_node, tag);
1652 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
1653 node_id = password_node.GetId();
1655 EXPECT_CALL(encryption_observer_,
1656 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1657 ExpectPassphraseAcceptance();
1658 SetCustomPassphraseAndCheck("new_passphrase");
1659 EXPECT_FALSE(IsEncryptEverythingEnabledForTest());
1661 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1662 ReadNode password_node(&trans);
1663 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY,
1664 password_node.InitByClientTagLookup(PASSWORDS,
1665 tag));
1668 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1669 ReadNode password_node(&trans);
1670 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY,
1671 password_node.InitByIdLookup(node_id));
1675 // Friended by WriteNode, so can't be in an anonymouse namespace.
1676 TEST_F(SyncManagerTest, EncryptBookmarksWithLegacyData) {
1677 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1678 std::string title;
1679 SyncAPINameToServerName("Google", &title);
1680 std::string url = "http://www.google.com";
1681 std::string raw_title2 = ".."; // An invalid cosmo title.
1682 std::string title2;
1683 SyncAPINameToServerName(raw_title2, &title2);
1684 std::string url2 = "http://www.bla.com";
1686 // Create a bookmark using the legacy format.
1687 int64 node_id1 =
1688 MakeNodeWithRoot(sync_manager_.GetUserShare(), BOOKMARKS, "testtag");
1689 int64 node_id2 =
1690 MakeNodeWithRoot(sync_manager_.GetUserShare(), BOOKMARKS, "testtag2");
1692 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1693 WriteNode node(&trans);
1694 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1));
1696 sync_pb::EntitySpecifics entity_specifics;
1697 entity_specifics.mutable_bookmark()->set_url(url);
1698 node.SetEntitySpecifics(entity_specifics);
1700 // Set the old style title.
1701 syncable::MutableEntry* node_entry = node.entry_;
1702 node_entry->PutNonUniqueName(title);
1704 WriteNode node2(&trans);
1705 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2));
1707 sync_pb::EntitySpecifics entity_specifics2;
1708 entity_specifics2.mutable_bookmark()->set_url(url2);
1709 node2.SetEntitySpecifics(entity_specifics2);
1711 // Set the old style title.
1712 syncable::MutableEntry* node_entry2 = node2.entry_;
1713 node_entry2->PutNonUniqueName(title2);
1717 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1718 ReadNode node(&trans);
1719 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1));
1720 EXPECT_EQ(BOOKMARKS, node.GetModelType());
1721 EXPECT_EQ(title, node.GetTitle());
1722 EXPECT_EQ(title, node.GetBookmarkSpecifics().title());
1723 EXPECT_EQ(url, node.GetBookmarkSpecifics().url());
1725 ReadNode node2(&trans);
1726 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2));
1727 EXPECT_EQ(BOOKMARKS, node2.GetModelType());
1728 // We should de-canonicalize the title in GetTitle(), but the title in the
1729 // specifics should be stored in the server legal form.
1730 EXPECT_EQ(raw_title2, node2.GetTitle());
1731 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title());
1732 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url());
1736 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1737 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1738 trans.GetWrappedTrans(),
1739 BOOKMARKS,
1740 false /* not encrypted */));
1743 EXPECT_CALL(encryption_observer_,
1744 OnEncryptedTypesChanged(
1745 HasModelTypes(EncryptableUserTypes()), true));
1746 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1747 sync_manager_.GetEncryptionHandler()->EnableEncryptEverything();
1748 EXPECT_TRUE(IsEncryptEverythingEnabledForTest());
1751 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1752 EXPECT_TRUE(GetEncryptedTypesWithTrans(&trans).Equals(
1753 EncryptableUserTypes()));
1754 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1755 trans.GetWrappedTrans(),
1756 BOOKMARKS,
1757 true /* is encrypted */));
1759 ReadNode node(&trans);
1760 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1));
1761 EXPECT_EQ(BOOKMARKS, node.GetModelType());
1762 EXPECT_EQ(title, node.GetTitle());
1763 EXPECT_EQ(title, node.GetBookmarkSpecifics().title());
1764 EXPECT_EQ(url, node.GetBookmarkSpecifics().url());
1766 ReadNode node2(&trans);
1767 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2));
1768 EXPECT_EQ(BOOKMARKS, node2.GetModelType());
1769 // We should de-canonicalize the title in GetTitle(), but the title in the
1770 // specifics should be stored in the server legal form.
1771 EXPECT_EQ(raw_title2, node2.GetTitle());
1772 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title());
1773 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url());
1777 // Create a bookmark and set the title/url, then verify the data was properly
1778 // set. This replicates the unique way bookmarks have of creating sync nodes.
1779 // See BookmarkChangeProcessor::PlaceSyncNode(..).
1780 TEST_F(SyncManagerTest, CreateLocalBookmark) {
1781 std::string title = "title";
1782 std::string url = "url";
1784 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1785 ReadNode bookmark_root(&trans);
1786 ASSERT_EQ(BaseNode::INIT_OK, bookmark_root.InitTypeRoot(BOOKMARKS));
1787 WriteNode node(&trans);
1788 ASSERT_TRUE(node.InitBookmarkByCreation(bookmark_root, NULL));
1789 node.SetIsFolder(false);
1790 node.SetTitle(title);
1792 sync_pb::BookmarkSpecifics bookmark_specifics(node.GetBookmarkSpecifics());
1793 bookmark_specifics.set_url(url);
1794 node.SetBookmarkSpecifics(bookmark_specifics);
1797 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1798 ReadNode bookmark_root(&trans);
1799 ASSERT_EQ(BaseNode::INIT_OK, bookmark_root.InitTypeRoot(BOOKMARKS));
1800 int64 child_id = bookmark_root.GetFirstChildId();
1802 ReadNode node(&trans);
1803 ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id));
1804 EXPECT_FALSE(node.GetIsFolder());
1805 EXPECT_EQ(title, node.GetTitle());
1806 EXPECT_EQ(url, node.GetBookmarkSpecifics().url());
1810 // Verifies WriteNode::UpdateEntryWithEncryption does not make unnecessary
1811 // changes.
1812 TEST_F(SyncManagerTest, UpdateEntryWithEncryption) {
1813 std::string client_tag = "title";
1814 sync_pb::EntitySpecifics entity_specifics;
1815 entity_specifics.mutable_bookmark()->set_url("url");
1816 entity_specifics.mutable_bookmark()->set_title("title");
1817 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
1818 syncable::GenerateSyncableHash(BOOKMARKS,
1819 client_tag),
1820 entity_specifics);
1821 // New node shouldn't start off unsynced.
1822 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1823 // Manually change to the same data. Should not set is_unsynced.
1825 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1826 WriteNode node(&trans);
1827 EXPECT_EQ(BaseNode::INIT_OK,
1828 node.InitByClientTagLookup(BOOKMARKS, client_tag));
1829 node.SetEntitySpecifics(entity_specifics);
1831 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1833 // Encrypt the datatatype, should set is_unsynced.
1834 EXPECT_CALL(encryption_observer_,
1835 OnEncryptedTypesChanged(
1836 HasModelTypes(EncryptableUserTypes()), true));
1837 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1838 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
1840 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1841 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true));
1842 sync_manager_.GetEncryptionHandler()->Init();
1843 PumpLoop();
1845 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1846 ReadNode node(&trans);
1847 EXPECT_EQ(BaseNode::INIT_OK,
1848 node.InitByClientTagLookup(BOOKMARKS, client_tag));
1849 const syncable::Entry* node_entry = node.GetEntry();
1850 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
1851 EXPECT_TRUE(specifics.has_encrypted());
1852 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
1853 Cryptographer* cryptographer = trans.GetCryptographer();
1854 EXPECT_TRUE(cryptographer->is_ready());
1855 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
1856 specifics.encrypted()));
1858 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1860 // Set a new passphrase. Should set is_unsynced.
1861 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
1862 EXPECT_CALL(encryption_observer_,
1863 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
1864 ExpectPassphraseAcceptance();
1865 SetCustomPassphraseAndCheck("new_passphrase");
1867 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1868 ReadNode node(&trans);
1869 EXPECT_EQ(BaseNode::INIT_OK,
1870 node.InitByClientTagLookup(BOOKMARKS, client_tag));
1871 const syncable::Entry* node_entry = node.GetEntry();
1872 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
1873 EXPECT_TRUE(specifics.has_encrypted());
1874 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
1875 Cryptographer* cryptographer = trans.GetCryptographer();
1876 EXPECT_TRUE(cryptographer->is_ready());
1877 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
1878 specifics.encrypted()));
1880 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1882 // Force a re-encrypt everything. Should not set is_unsynced.
1883 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
1884 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
1885 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
1886 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true));
1888 sync_manager_.GetEncryptionHandler()->Init();
1889 PumpLoop();
1892 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1893 ReadNode node(&trans);
1894 EXPECT_EQ(BaseNode::INIT_OK,
1895 node.InitByClientTagLookup(BOOKMARKS, client_tag));
1896 const syncable::Entry* node_entry = node.GetEntry();
1897 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
1898 EXPECT_TRUE(specifics.has_encrypted());
1899 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
1900 Cryptographer* cryptographer = trans.GetCryptographer();
1901 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
1902 specifics.encrypted()));
1904 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1906 // Manually change to the same data. Should not set is_unsynced.
1908 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1909 WriteNode node(&trans);
1910 EXPECT_EQ(BaseNode::INIT_OK,
1911 node.InitByClientTagLookup(BOOKMARKS, client_tag));
1912 node.SetEntitySpecifics(entity_specifics);
1913 const syncable::Entry* node_entry = node.GetEntry();
1914 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
1915 EXPECT_TRUE(specifics.has_encrypted());
1916 EXPECT_FALSE(node_entry->GetIsUnsynced());
1917 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
1918 Cryptographer* cryptographer = trans.GetCryptographer();
1919 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
1920 specifics.encrypted()));
1922 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1924 // Manually change to different data. Should set is_unsynced.
1926 entity_specifics.mutable_bookmark()->set_url("url2");
1927 entity_specifics.mutable_bookmark()->set_title("title2");
1928 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1929 WriteNode node(&trans);
1930 EXPECT_EQ(BaseNode::INIT_OK,
1931 node.InitByClientTagLookup(BOOKMARKS, client_tag));
1932 node.SetEntitySpecifics(entity_specifics);
1933 const syncable::Entry* node_entry = node.GetEntry();
1934 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
1935 EXPECT_TRUE(specifics.has_encrypted());
1936 EXPECT_TRUE(node_entry->GetIsUnsynced());
1937 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
1938 Cryptographer* cryptographer = trans.GetCryptographer();
1939 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
1940 specifics.encrypted()));
1944 // Passwords have their own handling for encryption. Verify it does not result
1945 // in unnecessary writes via SetEntitySpecifics.
1946 TEST_F(SyncManagerTest, UpdatePasswordSetEntitySpecificsNoChange) {
1947 std::string client_tag = "title";
1948 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1949 sync_pb::EntitySpecifics entity_specifics;
1951 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1952 Cryptographer* cryptographer = trans.GetCryptographer();
1953 sync_pb::PasswordSpecificsData data;
1954 data.set_password_value("secret");
1955 cryptographer->Encrypt(
1956 data,
1957 entity_specifics.mutable_password()->
1958 mutable_encrypted());
1960 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
1961 syncable::GenerateSyncableHash(PASSWORDS,
1962 client_tag),
1963 entity_specifics);
1964 // New node shouldn't start off unsynced.
1965 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
1967 // Manually change to the same data via SetEntitySpecifics. Should not set
1968 // is_unsynced.
1970 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1971 WriteNode node(&trans);
1972 EXPECT_EQ(BaseNode::INIT_OK,
1973 node.InitByClientTagLookup(PASSWORDS, client_tag));
1974 node.SetEntitySpecifics(entity_specifics);
1976 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
1979 // Passwords have their own handling for encryption. Verify it does not result
1980 // in unnecessary writes via SetPasswordSpecifics.
1981 TEST_F(SyncManagerTest, UpdatePasswordSetPasswordSpecifics) {
1982 std::string client_tag = "title";
1983 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1984 sync_pb::EntitySpecifics entity_specifics;
1986 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1987 Cryptographer* cryptographer = trans.GetCryptographer();
1988 sync_pb::PasswordSpecificsData data;
1989 data.set_password_value("secret");
1990 cryptographer->Encrypt(
1991 data,
1992 entity_specifics.mutable_password()->
1993 mutable_encrypted());
1995 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
1996 syncable::GenerateSyncableHash(PASSWORDS,
1997 client_tag),
1998 entity_specifics);
1999 // New node shouldn't start off unsynced.
2000 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2002 // Manually change to the same data via SetPasswordSpecifics. Should not set
2003 // is_unsynced.
2005 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2006 WriteNode node(&trans);
2007 EXPECT_EQ(BaseNode::INIT_OK,
2008 node.InitByClientTagLookup(PASSWORDS, client_tag));
2009 node.SetPasswordSpecifics(node.GetPasswordSpecifics());
2011 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2013 // Manually change to different data. Should set is_unsynced.
2015 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2016 WriteNode node(&trans);
2017 EXPECT_EQ(BaseNode::INIT_OK,
2018 node.InitByClientTagLookup(PASSWORDS, client_tag));
2019 Cryptographer* cryptographer = trans.GetCryptographer();
2020 sync_pb::PasswordSpecificsData data;
2021 data.set_password_value("secret2");
2022 cryptographer->Encrypt(
2023 data,
2024 entity_specifics.mutable_password()->mutable_encrypted());
2025 node.SetPasswordSpecifics(data);
2026 const syncable::Entry* node_entry = node.GetEntry();
2027 EXPECT_TRUE(node_entry->GetIsUnsynced());
2031 // Passwords have their own handling for encryption. Verify setting a new
2032 // passphrase updates the data.
2033 TEST_F(SyncManagerTest, UpdatePasswordNewPassphrase) {
2034 std::string client_tag = "title";
2035 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2036 sync_pb::EntitySpecifics entity_specifics;
2038 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2039 Cryptographer* cryptographer = trans.GetCryptographer();
2040 sync_pb::PasswordSpecificsData data;
2041 data.set_password_value("secret");
2042 cryptographer->Encrypt(
2043 data,
2044 entity_specifics.mutable_password()->mutable_encrypted());
2046 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
2047 syncable::GenerateSyncableHash(PASSWORDS,
2048 client_tag),
2049 entity_specifics);
2050 // New node shouldn't start off unsynced.
2051 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2053 // Set a new passphrase. Should set is_unsynced.
2054 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
2055 EXPECT_CALL(encryption_observer_,
2056 OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
2057 ExpectPassphraseAcceptance();
2058 SetCustomPassphraseAndCheck("new_passphrase");
2059 EXPECT_TRUE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2062 // Passwords have their own handling for encryption. Verify it does not result
2063 // in unnecessary writes via ReencryptEverything.
2064 TEST_F(SyncManagerTest, UpdatePasswordReencryptEverything) {
2065 std::string client_tag = "title";
2066 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2067 sync_pb::EntitySpecifics entity_specifics;
2069 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2070 Cryptographer* cryptographer = trans.GetCryptographer();
2071 sync_pb::PasswordSpecificsData data;
2072 data.set_password_value("secret");
2073 cryptographer->Encrypt(
2074 data,
2075 entity_specifics.mutable_password()->mutable_encrypted());
2077 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
2078 syncable::GenerateSyncableHash(PASSWORDS,
2079 client_tag),
2080 entity_specifics);
2081 // New node shouldn't start off unsynced.
2082 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2084 // Force a re-encrypt everything. Should not set is_unsynced.
2085 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
2086 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
2087 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
2088 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
2089 sync_manager_.GetEncryptionHandler()->Init();
2090 PumpLoop();
2091 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2094 // Test that attempting to start up with corrupted password data triggers
2095 // an unrecoverable error (rather than crashing).
2096 TEST_F(SyncManagerTest, ReencryptEverythingWithUnrecoverableErrorPasswords) {
2097 const char kClientTag[] = "client_tag";
2099 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2100 sync_pb::EntitySpecifics entity_specifics;
2102 // Create a synced bookmark with undecryptable data.
2103 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2105 Cryptographer other_cryptographer(&encryptor_);
2106 KeyParams fake_params = {"localhost", "dummy", "fake_key"};
2107 other_cryptographer.AddKey(fake_params);
2108 sync_pb::PasswordSpecificsData data;
2109 data.set_password_value("secret");
2110 other_cryptographer.Encrypt(
2111 data,
2112 entity_specifics.mutable_password()->mutable_encrypted());
2114 // Set up the real cryptographer with a different key.
2115 KeyParams real_params = {"localhost", "username", "real_key"};
2116 trans.GetCryptographer()->AddKey(real_params);
2118 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, kClientTag,
2119 syncable::GenerateSyncableHash(PASSWORDS,
2120 kClientTag),
2121 entity_specifics);
2122 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, kClientTag));
2124 // Force a re-encrypt everything. Should trigger an unrecoverable error due
2125 // to being unable to decrypt the data that was previously applied.
2126 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
2127 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
2128 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
2129 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
2130 EXPECT_FALSE(HasUnrecoverableError());
2131 sync_manager_.GetEncryptionHandler()->Init();
2132 PumpLoop();
2133 EXPECT_TRUE(HasUnrecoverableError());
2136 // Test that attempting to start up with corrupted bookmark data triggers
2137 // an unrecoverable error (rather than crashing).
2138 TEST_F(SyncManagerTest, ReencryptEverythingWithUnrecoverableErrorBookmarks) {
2139 const char kClientTag[] = "client_tag";
2140 EXPECT_CALL(encryption_observer_,
2141 OnEncryptedTypesChanged(
2142 HasModelTypes(EncryptableUserTypes()), true));
2143 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
2144 sync_pb::EntitySpecifics entity_specifics;
2146 // Create a synced bookmark with undecryptable data.
2147 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2149 Cryptographer other_cryptographer(&encryptor_);
2150 KeyParams fake_params = {"localhost", "dummy", "fake_key"};
2151 other_cryptographer.AddKey(fake_params);
2152 sync_pb::EntitySpecifics bm_specifics;
2153 bm_specifics.mutable_bookmark()->set_title("title");
2154 bm_specifics.mutable_bookmark()->set_url("url");
2155 sync_pb::EncryptedData encrypted;
2156 other_cryptographer.Encrypt(bm_specifics, &encrypted);
2157 entity_specifics.mutable_encrypted()->CopyFrom(encrypted);
2159 // Set up the real cryptographer with a different key.
2160 KeyParams real_params = {"localhost", "username", "real_key"};
2161 trans.GetCryptographer()->AddKey(real_params);
2163 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, kClientTag,
2164 syncable::GenerateSyncableHash(BOOKMARKS,
2165 kClientTag),
2166 entity_specifics);
2167 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, kClientTag));
2169 // Force a re-encrypt everything. Should trigger an unrecoverable error due
2170 // to being unable to decrypt the data that was previously applied.
2171 testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
2172 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
2173 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
2174 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true));
2175 EXPECT_FALSE(HasUnrecoverableError());
2176 sync_manager_.GetEncryptionHandler()->Init();
2177 PumpLoop();
2178 EXPECT_TRUE(HasUnrecoverableError());
2181 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for bookmarks
2182 // when we write the same data, but does set it when we write new data.
2183 TEST_F(SyncManagerTest, SetBookmarkTitle) {
2184 std::string client_tag = "title";
2185 sync_pb::EntitySpecifics entity_specifics;
2186 entity_specifics.mutable_bookmark()->set_url("url");
2187 entity_specifics.mutable_bookmark()->set_title("title");
2188 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2189 syncable::GenerateSyncableHash(BOOKMARKS,
2190 client_tag),
2191 entity_specifics);
2192 // New node shouldn't start off unsynced.
2193 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2195 // Manually change to the same title. Should not set is_unsynced.
2197 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2198 WriteNode node(&trans);
2199 EXPECT_EQ(BaseNode::INIT_OK,
2200 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2201 node.SetTitle(client_tag);
2203 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2205 // Manually change to new title. Should set is_unsynced.
2207 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2208 WriteNode node(&trans);
2209 EXPECT_EQ(BaseNode::INIT_OK,
2210 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2211 node.SetTitle("title2");
2213 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2216 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted
2217 // bookmarks when we write the same data, but does set it when we write new
2218 // data.
2219 TEST_F(SyncManagerTest, SetBookmarkTitleWithEncryption) {
2220 std::string client_tag = "title";
2221 sync_pb::EntitySpecifics entity_specifics;
2222 entity_specifics.mutable_bookmark()->set_url("url");
2223 entity_specifics.mutable_bookmark()->set_title("title");
2224 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2225 syncable::GenerateSyncableHash(BOOKMARKS,
2226 client_tag),
2227 entity_specifics);
2228 // New node shouldn't start off unsynced.
2229 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2231 // Encrypt the datatatype, should set is_unsynced.
2232 EXPECT_CALL(encryption_observer_,
2233 OnEncryptedTypesChanged(
2234 HasModelTypes(EncryptableUserTypes()), true));
2235 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
2236 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
2237 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
2238 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true));
2239 sync_manager_.GetEncryptionHandler()->Init();
2240 PumpLoop();
2241 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2243 // Manually change to the same title. Should not set is_unsynced.
2244 // NON_UNIQUE_NAME should be kEncryptedString.
2246 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2247 WriteNode node(&trans);
2248 EXPECT_EQ(BaseNode::INIT_OK,
2249 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2250 node.SetTitle(client_tag);
2251 const syncable::Entry* node_entry = node.GetEntry();
2252 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
2253 EXPECT_TRUE(specifics.has_encrypted());
2254 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
2256 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2258 // Manually change to new title. Should set is_unsynced. NON_UNIQUE_NAME
2259 // should still be kEncryptedString.
2261 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2262 WriteNode node(&trans);
2263 EXPECT_EQ(BaseNode::INIT_OK,
2264 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2265 node.SetTitle("title2");
2266 const syncable::Entry* node_entry = node.GetEntry();
2267 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
2268 EXPECT_TRUE(specifics.has_encrypted());
2269 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
2271 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2274 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for non-bookmarks
2275 // when we write the same data, but does set it when we write new data.
2276 TEST_F(SyncManagerTest, SetNonBookmarkTitle) {
2277 std::string client_tag = "title";
2278 sync_pb::EntitySpecifics entity_specifics;
2279 entity_specifics.mutable_preference()->set_name("name");
2280 entity_specifics.mutable_preference()->set_value("value");
2281 MakeServerNode(sync_manager_.GetUserShare(),
2282 PREFERENCES,
2283 client_tag,
2284 syncable::GenerateSyncableHash(PREFERENCES,
2285 client_tag),
2286 entity_specifics);
2287 // New node shouldn't start off unsynced.
2288 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2290 // Manually change to the same title. Should not set is_unsynced.
2292 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2293 WriteNode node(&trans);
2294 EXPECT_EQ(BaseNode::INIT_OK,
2295 node.InitByClientTagLookup(PREFERENCES, client_tag));
2296 node.SetTitle(client_tag);
2298 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2300 // Manually change to new title. Should set is_unsynced.
2302 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2303 WriteNode node(&trans);
2304 EXPECT_EQ(BaseNode::INIT_OK,
2305 node.InitByClientTagLookup(PREFERENCES, client_tag));
2306 node.SetTitle("title2");
2308 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2311 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted
2312 // non-bookmarks when we write the same data or when we write new data
2313 // data (should remained kEncryptedString).
2314 TEST_F(SyncManagerTest, SetNonBookmarkTitleWithEncryption) {
2315 std::string client_tag = "title";
2316 sync_pb::EntitySpecifics entity_specifics;
2317 entity_specifics.mutable_preference()->set_name("name");
2318 entity_specifics.mutable_preference()->set_value("value");
2319 MakeServerNode(sync_manager_.GetUserShare(),
2320 PREFERENCES,
2321 client_tag,
2322 syncable::GenerateSyncableHash(PREFERENCES,
2323 client_tag),
2324 entity_specifics);
2325 // New node shouldn't start off unsynced.
2326 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2328 // Encrypt the datatatype, should set is_unsynced.
2329 EXPECT_CALL(encryption_observer_,
2330 OnEncryptedTypesChanged(
2331 HasModelTypes(EncryptableUserTypes()), true));
2332 EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
2333 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
2334 EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
2335 EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true));
2336 sync_manager_.GetEncryptionHandler()->Init();
2337 PumpLoop();
2338 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2340 // Manually change to the same title. Should not set is_unsynced.
2341 // NON_UNIQUE_NAME should be kEncryptedString.
2343 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2344 WriteNode node(&trans);
2345 EXPECT_EQ(BaseNode::INIT_OK,
2346 node.InitByClientTagLookup(PREFERENCES, client_tag));
2347 node.SetTitle(client_tag);
2348 const syncable::Entry* node_entry = node.GetEntry();
2349 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
2350 EXPECT_TRUE(specifics.has_encrypted());
2351 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
2353 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2355 // Manually change to new title. Should not set is_unsynced because the
2356 // NON_UNIQUE_NAME should still be kEncryptedString.
2358 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2359 WriteNode node(&trans);
2360 EXPECT_EQ(BaseNode::INIT_OK,
2361 node.InitByClientTagLookup(PREFERENCES, client_tag));
2362 node.SetTitle("title2");
2363 const syncable::Entry* node_entry = node.GetEntry();
2364 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
2365 EXPECT_TRUE(specifics.has_encrypted());
2366 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
2367 EXPECT_FALSE(node_entry->GetIsUnsynced());
2371 // Ensure that titles are truncated to 255 bytes, and attempting to reset
2372 // them to their longer version does not set IS_UNSYNCED.
2373 TEST_F(SyncManagerTest, SetLongTitle) {
2374 const int kNumChars = 512;
2375 const std::string kClientTag = "tag";
2376 std::string title(kNumChars, '0');
2377 sync_pb::EntitySpecifics entity_specifics;
2378 entity_specifics.mutable_preference()->set_name("name");
2379 entity_specifics.mutable_preference()->set_value("value");
2380 MakeServerNode(sync_manager_.GetUserShare(),
2381 PREFERENCES,
2382 "short_title",
2383 syncable::GenerateSyncableHash(PREFERENCES,
2384 kClientTag),
2385 entity_specifics);
2386 // New node shouldn't start off unsynced.
2387 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, kClientTag));
2389 // Manually change to the long title. Should set is_unsynced.
2391 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2392 WriteNode node(&trans);
2393 EXPECT_EQ(BaseNode::INIT_OK,
2394 node.InitByClientTagLookup(PREFERENCES, kClientTag));
2395 node.SetTitle(title);
2396 EXPECT_EQ(node.GetTitle(), title.substr(0, 255));
2398 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, kClientTag));
2400 // Manually change to the same title. Should not set is_unsynced.
2402 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2403 WriteNode node(&trans);
2404 EXPECT_EQ(BaseNode::INIT_OK,
2405 node.InitByClientTagLookup(PREFERENCES, kClientTag));
2406 node.SetTitle(title);
2407 EXPECT_EQ(node.GetTitle(), title.substr(0, 255));
2409 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, kClientTag));
2411 // Manually change to new title. Should set is_unsynced.
2413 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2414 WriteNode node(&trans);
2415 EXPECT_EQ(BaseNode::INIT_OK,
2416 node.InitByClientTagLookup(PREFERENCES, kClientTag));
2417 node.SetTitle("title2");
2419 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, kClientTag));
2422 // Create an encrypted entry when the cryptographer doesn't think the type is
2423 // marked for encryption. Ensure reads/writes don't break and don't unencrypt
2424 // the data.
2425 TEST_F(SyncManagerTest, SetPreviouslyEncryptedSpecifics) {
2426 std::string client_tag = "tag";
2427 std::string url = "url";
2428 std::string url2 = "new_url";
2429 std::string title = "title";
2430 sync_pb::EntitySpecifics entity_specifics;
2431 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2433 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2434 Cryptographer* crypto = trans.GetCryptographer();
2435 sync_pb::EntitySpecifics bm_specifics;
2436 bm_specifics.mutable_bookmark()->set_title("title");
2437 bm_specifics.mutable_bookmark()->set_url("url");
2438 sync_pb::EncryptedData encrypted;
2439 crypto->Encrypt(bm_specifics, &encrypted);
2440 entity_specifics.mutable_encrypted()->CopyFrom(encrypted);
2441 AddDefaultFieldValue(BOOKMARKS, &entity_specifics);
2443 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2444 syncable::GenerateSyncableHash(BOOKMARKS,
2445 client_tag),
2446 entity_specifics);
2449 // Verify the data.
2450 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2451 ReadNode node(&trans);
2452 EXPECT_EQ(BaseNode::INIT_OK,
2453 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2454 EXPECT_EQ(title, node.GetTitle());
2455 EXPECT_EQ(url, node.GetBookmarkSpecifics().url());
2459 // Overwrite the url (which overwrites the specifics).
2460 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2461 WriteNode node(&trans);
2462 EXPECT_EQ(BaseNode::INIT_OK,
2463 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2465 sync_pb::BookmarkSpecifics bookmark_specifics(node.GetBookmarkSpecifics());
2466 bookmark_specifics.set_url(url2);
2467 node.SetBookmarkSpecifics(bookmark_specifics);
2471 // Verify it's still encrypted and it has the most recent url.
2472 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2473 ReadNode node(&trans);
2474 EXPECT_EQ(BaseNode::INIT_OK,
2475 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2476 EXPECT_EQ(title, node.GetTitle());
2477 EXPECT_EQ(url2, node.GetBookmarkSpecifics().url());
2478 const syncable::Entry* node_entry = node.GetEntry();
2479 EXPECT_EQ(kEncryptedString, node_entry->GetNonUniqueName());
2480 const sync_pb::EntitySpecifics& specifics = node_entry->GetSpecifics();
2481 EXPECT_TRUE(specifics.has_encrypted());
2485 // Verify transaction version of a model type is incremented when node of
2486 // that type is updated.
2487 TEST_F(SyncManagerTest, IncrementTransactionVersion) {
2488 ModelSafeRoutingInfo routing_info;
2489 GetModelSafeRoutingInfo(&routing_info);
2492 ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare());
2493 for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
2494 i != routing_info.end(); ++i) {
2495 // Transaction version is incremented when SyncManagerTest::SetUp()
2496 // creates a node of each type.
2497 EXPECT_EQ(1,
2498 sync_manager_.GetUserShare()->directory->
2499 GetTransactionVersion(i->first));
2503 // Create bookmark node to increment transaction version of bookmark model.
2504 std::string client_tag = "title";
2505 sync_pb::EntitySpecifics entity_specifics;
2506 entity_specifics.mutable_bookmark()->set_url("url");
2507 entity_specifics.mutable_bookmark()->set_title("title");
2508 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2509 syncable::GenerateSyncableHash(BOOKMARKS,
2510 client_tag),
2511 entity_specifics);
2514 ReadTransaction read_trans(FROM_HERE, sync_manager_.GetUserShare());
2515 for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
2516 i != routing_info.end(); ++i) {
2517 EXPECT_EQ(i->first == BOOKMARKS ? 2 : 1,
2518 sync_manager_.GetUserShare()->directory->
2519 GetTransactionVersion(i->first));
2524 class MockSyncScheduler : public FakeSyncScheduler {
2525 public:
2526 MockSyncScheduler() : FakeSyncScheduler() {}
2527 virtual ~MockSyncScheduler() {}
2529 MOCK_METHOD2(Start, void(SyncScheduler::Mode, base::Time));
2530 MOCK_METHOD1(ScheduleConfiguration, void(const ConfigurationParams&));
2533 class ComponentsFactory : public TestInternalComponentsFactory {
2534 public:
2535 ComponentsFactory(const Switches& switches,
2536 SyncScheduler* scheduler_to_use,
2537 sessions::SyncSessionContext** session_context,
2538 InternalComponentsFactory::StorageOption* storage_used)
2539 : TestInternalComponentsFactory(
2540 switches, InternalComponentsFactory::STORAGE_IN_MEMORY, storage_used),
2541 scheduler_to_use_(scheduler_to_use),
2542 session_context_(session_context) {}
2543 ~ComponentsFactory() override {}
2545 scoped_ptr<SyncScheduler> BuildScheduler(
2546 const std::string& name,
2547 sessions::SyncSessionContext* context,
2548 CancelationSignal* stop_handle) override {
2549 *session_context_ = context;
2550 return scheduler_to_use_.Pass();
2553 private:
2554 scoped_ptr<SyncScheduler> scheduler_to_use_;
2555 sessions::SyncSessionContext** session_context_;
2558 class SyncManagerTestWithMockScheduler : public SyncManagerTest {
2559 public:
2560 SyncManagerTestWithMockScheduler() : scheduler_(NULL) {}
2561 InternalComponentsFactory* GetFactory() override {
2562 scheduler_ = new MockSyncScheduler();
2563 return new ComponentsFactory(GetSwitches(), scheduler_, &session_context_,
2564 &storage_used_);
2567 MockSyncScheduler* scheduler() { return scheduler_; }
2568 sessions::SyncSessionContext* session_context() {
2569 return session_context_;
2572 private:
2573 MockSyncScheduler* scheduler_;
2574 sessions::SyncSessionContext* session_context_;
2577 // Test that the configuration params are properly created and sent to
2578 // ScheduleConfigure. No callback should be invoked. Any disabled datatypes
2579 // should be purged.
2580 TEST_F(SyncManagerTestWithMockScheduler, BasicConfiguration) {
2581 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
2582 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
2583 ModelSafeRoutingInfo new_routing_info;
2584 GetModelSafeRoutingInfo(&new_routing_info);
2585 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info);
2586 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
2588 ConfigurationParams params;
2589 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE, _));
2590 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)).
2591 WillOnce(SaveArg<0>(&params));
2593 // Set data for all types.
2594 ModelTypeSet protocol_types = ProtocolTypes();
2595 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
2596 iter.Inc()) {
2597 SetProgressMarkerForType(iter.Get(), true);
2600 CallbackCounter ready_task_counter, retry_task_counter;
2601 sync_manager_.ConfigureSyncer(
2602 reason,
2603 types_to_download,
2604 disabled_types,
2605 ModelTypeSet(),
2606 ModelTypeSet(),
2607 new_routing_info,
2608 base::Bind(&CallbackCounter::Callback,
2609 base::Unretained(&ready_task_counter)),
2610 base::Bind(&CallbackCounter::Callback,
2611 base::Unretained(&retry_task_counter)));
2612 EXPECT_EQ(0, ready_task_counter.times_called());
2613 EXPECT_EQ(0, retry_task_counter.times_called());
2614 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
2615 params.source);
2616 EXPECT_TRUE(types_to_download.Equals(params.types_to_download));
2617 EXPECT_EQ(new_routing_info, params.routing_info);
2619 // Verify all the disabled types were purged.
2620 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().Equals(
2621 enabled_types));
2622 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken(
2623 ModelTypeSet::All()).Equals(disabled_types));
2626 // Test that on a reconfiguration (configuration where the session context
2627 // already has routing info), only those recently disabled types are purged.
2628 TEST_F(SyncManagerTestWithMockScheduler, ReConfiguration) {
2629 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
2630 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
2631 ModelTypeSet disabled_types = ModelTypeSet(THEMES, SESSIONS);
2632 ModelSafeRoutingInfo old_routing_info;
2633 ModelSafeRoutingInfo new_routing_info;
2634 GetModelSafeRoutingInfo(&old_routing_info);
2635 new_routing_info = old_routing_info;
2636 new_routing_info.erase(THEMES);
2637 new_routing_info.erase(SESSIONS);
2638 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info);
2640 ConfigurationParams params;
2641 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE, _));
2642 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)).
2643 WillOnce(SaveArg<0>(&params));
2645 // Set data for all types except those recently disabled (so we can verify
2646 // only those recently disabled are purged) .
2647 ModelTypeSet protocol_types = ProtocolTypes();
2648 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
2649 iter.Inc()) {
2650 if (!disabled_types.Has(iter.Get())) {
2651 SetProgressMarkerForType(iter.Get(), true);
2652 } else {
2653 SetProgressMarkerForType(iter.Get(), false);
2657 // Set the context to have the old routing info.
2658 session_context()->SetRoutingInfo(old_routing_info);
2660 CallbackCounter ready_task_counter, retry_task_counter;
2661 sync_manager_.ConfigureSyncer(
2662 reason,
2663 types_to_download,
2664 ModelTypeSet(),
2665 ModelTypeSet(),
2666 ModelTypeSet(),
2667 new_routing_info,
2668 base::Bind(&CallbackCounter::Callback,
2669 base::Unretained(&ready_task_counter)),
2670 base::Bind(&CallbackCounter::Callback,
2671 base::Unretained(&retry_task_counter)));
2672 EXPECT_EQ(0, ready_task_counter.times_called());
2673 EXPECT_EQ(0, retry_task_counter.times_called());
2674 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
2675 params.source);
2676 EXPECT_TRUE(types_to_download.Equals(params.types_to_download));
2677 EXPECT_EQ(new_routing_info, params.routing_info);
2679 // Verify only the recently disabled types were purged.
2680 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken(
2681 ProtocolTypes()).Equals(disabled_types));
2684 // Test that SyncManager::ClearServerData invokes the scheduler.
2685 TEST_F(SyncManagerTestWithMockScheduler, ClearServerData) {
2686 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, _));
2687 CallbackCounter callback_counter;
2688 sync_manager_.ClearServerData(base::Bind(
2689 &CallbackCounter::Callback, base::Unretained(&callback_counter)));
2690 PumpLoop();
2691 EXPECT_EQ(1, callback_counter.times_called());
2694 // Test that PurgePartiallySyncedTypes purges only those types that have not
2695 // fully completed their initial download and apply.
2696 TEST_F(SyncManagerTest, PurgePartiallySyncedTypes) {
2697 ModelSafeRoutingInfo routing_info;
2698 GetModelSafeRoutingInfo(&routing_info);
2699 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
2701 UserShare* share = sync_manager_.GetUserShare();
2703 // The test harness automatically initializes all types in the routing info.
2704 // Check that autofill is not among them.
2705 ASSERT_FALSE(enabled_types.Has(AUTOFILL));
2707 // Further ensure that the test harness did not create its root node.
2709 syncable::ReadTransaction trans(FROM_HERE, share->directory.get());
2710 syncable::Entry autofill_root_node(&trans,
2711 syncable::GET_TYPE_ROOT,
2712 AUTOFILL);
2713 ASSERT_FALSE(autofill_root_node.good());
2716 // One more redundant check.
2717 ASSERT_FALSE(sync_manager_.InitialSyncEndedTypes().Has(AUTOFILL));
2719 // Give autofill a progress marker.
2720 sync_pb::DataTypeProgressMarker autofill_marker;
2721 autofill_marker.set_data_type_id(
2722 GetSpecificsFieldNumberFromModelType(AUTOFILL));
2723 autofill_marker.set_token("token");
2724 share->directory->SetDownloadProgress(AUTOFILL, autofill_marker);
2726 // Also add a pending autofill root node update from the server.
2727 TestEntryFactory factory_(share->directory.get());
2728 int autofill_meta = factory_.CreateUnappliedRootNode(AUTOFILL);
2730 // Preferences is an enabled type. Check that the harness initialized it.
2731 ASSERT_TRUE(enabled_types.Has(PREFERENCES));
2732 ASSERT_TRUE(sync_manager_.InitialSyncEndedTypes().Has(PREFERENCES));
2734 // Give preferencse a progress marker.
2735 sync_pb::DataTypeProgressMarker prefs_marker;
2736 prefs_marker.set_data_type_id(
2737 GetSpecificsFieldNumberFromModelType(PREFERENCES));
2738 prefs_marker.set_token("token");
2739 share->directory->SetDownloadProgress(PREFERENCES, prefs_marker);
2741 // Add a fully synced preferences node under the root.
2742 std::string pref_client_tag = "prefABC";
2743 std::string pref_hashed_tag = "hashXYZ";
2744 sync_pb::EntitySpecifics pref_specifics;
2745 AddDefaultFieldValue(PREFERENCES, &pref_specifics);
2746 int pref_meta = MakeServerNode(
2747 share, PREFERENCES, pref_client_tag, pref_hashed_tag, pref_specifics);
2749 // And now, the purge.
2750 EXPECT_TRUE(sync_manager_.PurgePartiallySyncedTypes());
2752 // Ensure that autofill lost its progress marker, but preferences did not.
2753 ModelTypeSet empty_tokens =
2754 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All());
2755 EXPECT_TRUE(empty_tokens.Has(AUTOFILL));
2756 EXPECT_FALSE(empty_tokens.Has(PREFERENCES));
2758 // Ensure that autofill lots its node, but preferences did not.
2760 syncable::ReadTransaction trans(FROM_HERE, share->directory.get());
2761 syncable::Entry autofill_node(&trans, GET_BY_HANDLE, autofill_meta);
2762 syncable::Entry pref_node(&trans, GET_BY_HANDLE, pref_meta);
2763 EXPECT_FALSE(autofill_node.good());
2764 EXPECT_TRUE(pref_node.good());
2768 // Test CleanupDisabledTypes properly purges all disabled types as specified
2769 // by the previous and current enabled params.
2770 TEST_F(SyncManagerTest, PurgeDisabledTypes) {
2771 ModelSafeRoutingInfo routing_info;
2772 GetModelSafeRoutingInfo(&routing_info);
2773 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
2774 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
2776 // The harness should have initialized the enabled_types for us.
2777 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes()));
2779 // Set progress markers for all types.
2780 ModelTypeSet protocol_types = ProtocolTypes();
2781 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
2782 iter.Inc()) {
2783 SetProgressMarkerForType(iter.Get(), true);
2786 // Verify all the enabled types remain after cleanup, and all the disabled
2787 // types were purged.
2788 sync_manager_.PurgeDisabledTypes(disabled_types,
2789 ModelTypeSet(),
2790 ModelTypeSet());
2791 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes()));
2792 EXPECT_TRUE(disabled_types.Equals(
2793 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All())));
2795 // Disable some more types.
2796 disabled_types.Put(BOOKMARKS);
2797 disabled_types.Put(PREFERENCES);
2798 ModelTypeSet new_enabled_types =
2799 Difference(ModelTypeSet::All(), disabled_types);
2801 // Verify only the non-disabled types remain after cleanup.
2802 sync_manager_.PurgeDisabledTypes(disabled_types,
2803 ModelTypeSet(),
2804 ModelTypeSet());
2805 EXPECT_TRUE(new_enabled_types.Equals(sync_manager_.InitialSyncEndedTypes()));
2806 EXPECT_TRUE(disabled_types.Equals(
2807 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All())));
2810 // Test PurgeDisabledTypes properly unapplies types by deleting their local data
2811 // and preserving their server data and progress marker.
2812 TEST_F(SyncManagerTest, PurgeUnappliedTypes) {
2813 ModelSafeRoutingInfo routing_info;
2814 GetModelSafeRoutingInfo(&routing_info);
2815 ModelTypeSet unapplied_types = ModelTypeSet(BOOKMARKS, PREFERENCES);
2816 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
2817 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
2819 // The harness should have initialized the enabled_types for us.
2820 EXPECT_TRUE(enabled_types.Equals(sync_manager_.InitialSyncEndedTypes()));
2822 // Set progress markers for all types.
2823 ModelTypeSet protocol_types = ProtocolTypes();
2824 for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
2825 iter.Inc()) {
2826 SetProgressMarkerForType(iter.Get(), true);
2829 // Add the following kinds of items:
2830 // 1. Fully synced preference.
2831 // 2. Locally created preference, server unknown, unsynced
2832 // 3. Locally deleted preference, server known, unsynced
2833 // 4. Server deleted preference, locally known.
2834 // 5. Server created preference, locally unknown, unapplied.
2835 // 6. A fully synced bookmark (no unique_client_tag).
2836 UserShare* share = sync_manager_.GetUserShare();
2837 sync_pb::EntitySpecifics pref_specifics;
2838 AddDefaultFieldValue(PREFERENCES, &pref_specifics);
2839 sync_pb::EntitySpecifics bm_specifics;
2840 AddDefaultFieldValue(BOOKMARKS, &bm_specifics);
2841 int pref1_meta = MakeServerNode(
2842 share, PREFERENCES, "pref1", "hash1", pref_specifics);
2843 int64 pref2_meta = MakeNodeWithRoot(share, PREFERENCES, "pref2");
2844 int pref3_meta = MakeServerNode(
2845 share, PREFERENCES, "pref3", "hash3", pref_specifics);
2846 int pref4_meta = MakeServerNode(
2847 share, PREFERENCES, "pref4", "hash4", pref_specifics);
2848 int pref5_meta = MakeServerNode(
2849 share, PREFERENCES, "pref5", "hash5", pref_specifics);
2850 int bookmark_meta = MakeServerNode(
2851 share, BOOKMARKS, "bookmark", "", bm_specifics);
2854 syncable::WriteTransaction trans(FROM_HERE,
2855 syncable::SYNCER,
2856 share->directory.get());
2857 // Pref's 1 and 2 are already set up properly.
2858 // Locally delete pref 3.
2859 syncable::MutableEntry pref3(&trans, GET_BY_HANDLE, pref3_meta);
2860 pref3.PutIsDel(true);
2861 pref3.PutIsUnsynced(true);
2862 // Delete pref 4 at the server.
2863 syncable::MutableEntry pref4(&trans, GET_BY_HANDLE, pref4_meta);
2864 pref4.PutServerIsDel(true);
2865 pref4.PutIsUnappliedUpdate(true);
2866 pref4.PutServerVersion(2);
2867 // Pref 5 is an new unapplied update.
2868 syncable::MutableEntry pref5(&trans, GET_BY_HANDLE, pref5_meta);
2869 pref5.PutIsUnappliedUpdate(true);
2870 pref5.PutIsDel(true);
2871 pref5.PutBaseVersion(-1);
2872 // Bookmark is already set up properly
2875 // Take a snapshot to clear all the dirty bits.
2876 share->directory.get()->SaveChanges();
2878 // Now request a purge for the unapplied types.
2879 disabled_types.PutAll(unapplied_types);
2880 sync_manager_.PurgeDisabledTypes(disabled_types,
2881 ModelTypeSet(),
2882 unapplied_types);
2884 // Verify the unapplied types still have progress markers and initial sync
2885 // ended after cleanup.
2886 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().HasAll(unapplied_types));
2887 EXPECT_TRUE(
2888 sync_manager_.GetTypesWithEmptyProgressMarkerToken(unapplied_types).
2889 Empty());
2891 // Ensure the items were unapplied as necessary.
2893 syncable::ReadTransaction trans(FROM_HERE, share->directory.get());
2894 syncable::Entry pref_node(&trans, GET_BY_HANDLE, pref1_meta);
2895 ASSERT_TRUE(pref_node.good());
2896 EXPECT_TRUE(pref_node.GetKernelCopy().is_dirty());
2897 EXPECT_FALSE(pref_node.GetIsUnsynced());
2898 EXPECT_TRUE(pref_node.GetIsUnappliedUpdate());
2899 EXPECT_TRUE(pref_node.GetIsDel());
2900 EXPECT_GT(pref_node.GetServerVersion(), 0);
2901 EXPECT_EQ(pref_node.GetBaseVersion(), -1);
2903 // Pref 2 should just be locally deleted.
2904 syncable::Entry pref2_node(&trans, GET_BY_HANDLE, pref2_meta);
2905 ASSERT_TRUE(pref2_node.good());
2906 EXPECT_TRUE(pref2_node.GetKernelCopy().is_dirty());
2907 EXPECT_FALSE(pref2_node.GetIsUnsynced());
2908 EXPECT_TRUE(pref2_node.GetIsDel());
2909 EXPECT_FALSE(pref2_node.GetIsUnappliedUpdate());
2910 EXPECT_TRUE(pref2_node.GetIsDel());
2911 EXPECT_EQ(pref2_node.GetServerVersion(), 0);
2912 EXPECT_EQ(pref2_node.GetBaseVersion(), -1);
2914 syncable::Entry pref3_node(&trans, GET_BY_HANDLE, pref3_meta);
2915 ASSERT_TRUE(pref3_node.good());
2916 EXPECT_TRUE(pref3_node.GetKernelCopy().is_dirty());
2917 EXPECT_FALSE(pref3_node.GetIsUnsynced());
2918 EXPECT_TRUE(pref3_node.GetIsUnappliedUpdate());
2919 EXPECT_TRUE(pref3_node.GetIsDel());
2920 EXPECT_GT(pref3_node.GetServerVersion(), 0);
2921 EXPECT_EQ(pref3_node.GetBaseVersion(), -1);
2923 syncable::Entry pref4_node(&trans, GET_BY_HANDLE, pref4_meta);
2924 ASSERT_TRUE(pref4_node.good());
2925 EXPECT_TRUE(pref4_node.GetKernelCopy().is_dirty());
2926 EXPECT_FALSE(pref4_node.GetIsUnsynced());
2927 EXPECT_TRUE(pref4_node.GetIsUnappliedUpdate());
2928 EXPECT_TRUE(pref4_node.GetIsDel());
2929 EXPECT_GT(pref4_node.GetServerVersion(), 0);
2930 EXPECT_EQ(pref4_node.GetBaseVersion(), -1);
2932 // Pref 5 should remain untouched.
2933 syncable::Entry pref5_node(&trans, GET_BY_HANDLE, pref5_meta);
2934 ASSERT_TRUE(pref5_node.good());
2935 EXPECT_FALSE(pref5_node.GetKernelCopy().is_dirty());
2936 EXPECT_FALSE(pref5_node.GetIsUnsynced());
2937 EXPECT_TRUE(pref5_node.GetIsUnappliedUpdate());
2938 EXPECT_TRUE(pref5_node.GetIsDel());
2939 EXPECT_GT(pref5_node.GetServerVersion(), 0);
2940 EXPECT_EQ(pref5_node.GetBaseVersion(), -1);
2942 syncable::Entry bookmark_node(&trans, GET_BY_HANDLE, bookmark_meta);
2943 ASSERT_TRUE(bookmark_node.good());
2944 EXPECT_TRUE(bookmark_node.GetKernelCopy().is_dirty());
2945 EXPECT_FALSE(bookmark_node.GetIsUnsynced());
2946 EXPECT_TRUE(bookmark_node.GetIsUnappliedUpdate());
2947 EXPECT_TRUE(bookmark_node.GetIsDel());
2948 EXPECT_GT(bookmark_node.GetServerVersion(), 0);
2949 EXPECT_EQ(bookmark_node.GetBaseVersion(), -1);
2953 // A test harness to exercise the code that processes and passes changes from
2954 // the "SYNCER"-WriteTransaction destructor, through the SyncManager, to the
2955 // ChangeProcessor.
2956 class SyncManagerChangeProcessingTest : public SyncManagerTest {
2957 public:
2958 void OnChangesApplied(ModelType model_type,
2959 int64 model_version,
2960 const BaseTransaction* trans,
2961 const ImmutableChangeRecordList& changes) override {
2962 last_changes_ = changes;
2965 void OnChangesComplete(ModelType model_type) override {}
2967 const ImmutableChangeRecordList& GetRecentChangeList() {
2968 return last_changes_;
2971 UserShare* share() {
2972 return sync_manager_.GetUserShare();
2975 // Set some flags so our nodes reasonably approximate the real world scenario
2976 // and can get past CheckTreeInvariants.
2978 // It's never going to be truly accurate, since we're squashing update
2979 // receipt, processing and application into a single transaction.
2980 void SetNodeProperties(syncable::MutableEntry *entry) {
2981 entry->PutId(id_factory_.NewServerId());
2982 entry->PutBaseVersion(10);
2983 entry->PutServerVersion(10);
2986 // Looks for the given change in the list. Returns the index at which it was
2987 // found. Returns -1 on lookup failure.
2988 size_t FindChangeInList(int64 id, ChangeRecord::Action action) {
2989 SCOPED_TRACE(id);
2990 for (size_t i = 0; i < last_changes_.Get().size(); ++i) {
2991 if (last_changes_.Get()[i].id == id
2992 && last_changes_.Get()[i].action == action) {
2993 return i;
2996 ADD_FAILURE() << "Failed to find specified change";
2997 return static_cast<size_t>(-1);
3000 // Returns the current size of the change list.
3002 // Note that spurious changes do not necessarily indicate a problem.
3003 // Assertions on change list size can help detect problems, but it may be
3004 // necessary to reduce their strictness if the implementation changes.
3005 size_t GetChangeListSize() {
3006 return last_changes_.Get().size();
3009 void ClearChangeList() { last_changes_ = ImmutableChangeRecordList(); }
3011 protected:
3012 ImmutableChangeRecordList last_changes_;
3013 TestIdFactory id_factory_;
3016 // Test creation of a folder and a bookmark.
3017 TEST_F(SyncManagerChangeProcessingTest, AddBookmarks) {
3018 int64 type_root = GetIdForDataType(BOOKMARKS);
3019 int64 folder_id = kInvalidId;
3020 int64 child_id = kInvalidId;
3022 // Create a folder and a bookmark under it.
3024 syncable::WriteTransaction trans(
3025 FROM_HERE, syncable::SYNCER, share()->directory.get());
3026 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root);
3027 ASSERT_TRUE(root.good());
3029 syncable::MutableEntry folder(&trans, syncable::CREATE,
3030 BOOKMARKS, root.GetId(), "folder");
3031 ASSERT_TRUE(folder.good());
3032 SetNodeProperties(&folder);
3033 folder.PutIsDir(true);
3034 folder_id = folder.GetMetahandle();
3036 syncable::MutableEntry child(&trans, syncable::CREATE,
3037 BOOKMARKS, folder.GetId(), "child");
3038 ASSERT_TRUE(child.good());
3039 SetNodeProperties(&child);
3040 child_id = child.GetMetahandle();
3043 // The closing of the above scope will delete the transaction. Its processed
3044 // changes should be waiting for us in a member of the test harness.
3045 EXPECT_EQ(2UL, GetChangeListSize());
3047 // We don't need to check these return values here. The function will add a
3048 // non-fatal failure if these changes are not found.
3049 size_t folder_change_pos =
3050 FindChangeInList(folder_id, ChangeRecord::ACTION_ADD);
3051 size_t child_change_pos =
3052 FindChangeInList(child_id, ChangeRecord::ACTION_ADD);
3054 // Parents are delivered before children.
3055 EXPECT_LT(folder_change_pos, child_change_pos);
3058 // Test creation of a preferences (with implicit parent Id)
3059 TEST_F(SyncManagerChangeProcessingTest, AddPreferences) {
3060 int64 item1_id = kInvalidId;
3061 int64 item2_id = kInvalidId;
3063 // Create two preferences.
3065 syncable::WriteTransaction trans(FROM_HERE, syncable::SYNCER,
3066 share()->directory.get());
3068 syncable::MutableEntry item1(&trans, syncable::CREATE, PREFERENCES,
3069 "test_item_1");
3070 ASSERT_TRUE(item1.good());
3071 SetNodeProperties(&item1);
3072 item1_id = item1.GetMetahandle();
3074 // Need at least two items to ensure hitting all possible codepaths in
3075 // ChangeReorderBuffer::Traversal::ExpandToInclude.
3076 syncable::MutableEntry item2(&trans, syncable::CREATE, PREFERENCES,
3077 "test_item_2");
3078 ASSERT_TRUE(item2.good());
3079 SetNodeProperties(&item2);
3080 item2_id = item2.GetMetahandle();
3083 // The closing of the above scope will delete the transaction. Its processed
3084 // changes should be waiting for us in a member of the test harness.
3085 EXPECT_EQ(2UL, GetChangeListSize());
3087 FindChangeInList(item1_id, ChangeRecord::ACTION_ADD);
3088 FindChangeInList(item2_id, ChangeRecord::ACTION_ADD);
3091 // Test moving a bookmark into an empty folder.
3092 TEST_F(SyncManagerChangeProcessingTest, MoveBookmarkIntoEmptyFolder) {
3093 int64 type_root = GetIdForDataType(BOOKMARKS);
3094 int64 folder_b_id = kInvalidId;
3095 int64 child_id = kInvalidId;
3097 // Create two folders. Place a child under folder A.
3099 syncable::WriteTransaction trans(
3100 FROM_HERE, syncable::SYNCER, share()->directory.get());
3101 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root);
3102 ASSERT_TRUE(root.good());
3104 syncable::MutableEntry folder_a(&trans, syncable::CREATE,
3105 BOOKMARKS, root.GetId(), "folderA");
3106 ASSERT_TRUE(folder_a.good());
3107 SetNodeProperties(&folder_a);
3108 folder_a.PutIsDir(true);
3110 syncable::MutableEntry folder_b(&trans, syncable::CREATE,
3111 BOOKMARKS, root.GetId(), "folderB");
3112 ASSERT_TRUE(folder_b.good());
3113 SetNodeProperties(&folder_b);
3114 folder_b.PutIsDir(true);
3115 folder_b_id = folder_b.GetMetahandle();
3117 syncable::MutableEntry child(&trans, syncable::CREATE,
3118 BOOKMARKS, folder_a.GetId(),
3119 "child");
3120 ASSERT_TRUE(child.good());
3121 SetNodeProperties(&child);
3122 child_id = child.GetMetahandle();
3125 // Close that transaction. The above was to setup the initial scenario. The
3126 // real test starts now.
3128 // Move the child from folder A to folder B.
3130 syncable::WriteTransaction trans(
3131 FROM_HERE, syncable::SYNCER, share()->directory.get());
3133 syncable::Entry folder_b(&trans, syncable::GET_BY_HANDLE, folder_b_id);
3134 syncable::MutableEntry child(&trans, syncable::GET_BY_HANDLE, child_id);
3136 child.PutParentId(folder_b.GetId());
3139 EXPECT_EQ(1UL, GetChangeListSize());
3141 // Verify that this was detected as a real change. An early version of the
3142 // UniquePosition code had a bug where moves from one folder to another were
3143 // ignored unless the moved node's UniquePosition value was also changed in
3144 // some way.
3145 FindChangeInList(child_id, ChangeRecord::ACTION_UPDATE);
3148 // Test moving a bookmark into a non-empty folder.
3149 TEST_F(SyncManagerChangeProcessingTest, MoveIntoPopulatedFolder) {
3150 int64 type_root = GetIdForDataType(BOOKMARKS);
3151 int64 child_a_id = kInvalidId;
3152 int64 child_b_id = kInvalidId;
3154 // Create two folders. Place one child each under folder A and folder B.
3156 syncable::WriteTransaction trans(
3157 FROM_HERE, syncable::SYNCER, share()->directory.get());
3158 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root);
3159 ASSERT_TRUE(root.good());
3161 syncable::MutableEntry folder_a(&trans, syncable::CREATE,
3162 BOOKMARKS, root.GetId(), "folderA");
3163 ASSERT_TRUE(folder_a.good());
3164 SetNodeProperties(&folder_a);
3165 folder_a.PutIsDir(true);
3167 syncable::MutableEntry folder_b(&trans, syncable::CREATE,
3168 BOOKMARKS, root.GetId(), "folderB");
3169 ASSERT_TRUE(folder_b.good());
3170 SetNodeProperties(&folder_b);
3171 folder_b.PutIsDir(true);
3173 syncable::MutableEntry child_a(&trans, syncable::CREATE,
3174 BOOKMARKS, folder_a.GetId(),
3175 "childA");
3176 ASSERT_TRUE(child_a.good());
3177 SetNodeProperties(&child_a);
3178 child_a_id = child_a.GetMetahandle();
3180 syncable::MutableEntry child_b(&trans, syncable::CREATE,
3181 BOOKMARKS, folder_b.GetId(),
3182 "childB");
3183 SetNodeProperties(&child_b);
3184 child_b_id = child_b.GetMetahandle();
3187 // Close that transaction. The above was to setup the initial scenario. The
3188 // real test starts now.
3191 syncable::WriteTransaction trans(
3192 FROM_HERE, syncable::SYNCER, share()->directory.get());
3194 syncable::MutableEntry child_a(&trans, syncable::GET_BY_HANDLE, child_a_id);
3195 syncable::MutableEntry child_b(&trans, syncable::GET_BY_HANDLE, child_b_id);
3197 // Move child A from folder A to folder B and update its position.
3198 child_a.PutParentId(child_b.GetParentId());
3199 child_a.PutPredecessor(child_b.GetId());
3202 EXPECT_EQ(1UL, GetChangeListSize());
3204 // Verify that only child a is in the change list.
3205 // (This function will add a failure if the lookup fails.)
3206 FindChangeInList(child_a_id, ChangeRecord::ACTION_UPDATE);
3209 // Tests the ordering of deletion changes.
3210 TEST_F(SyncManagerChangeProcessingTest, DeletionsAndChanges) {
3211 int64 type_root = GetIdForDataType(BOOKMARKS);
3212 int64 folder_a_id = kInvalidId;
3213 int64 folder_b_id = kInvalidId;
3214 int64 child_id = kInvalidId;
3216 // Create two folders. Place a child under folder A.
3218 syncable::WriteTransaction trans(
3219 FROM_HERE, syncable::SYNCER, share()->directory.get());
3220 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root);
3221 ASSERT_TRUE(root.good());
3223 syncable::MutableEntry folder_a(&trans, syncable::CREATE,
3224 BOOKMARKS, root.GetId(), "folderA");
3225 ASSERT_TRUE(folder_a.good());
3226 SetNodeProperties(&folder_a);
3227 folder_a.PutIsDir(true);
3228 folder_a_id = folder_a.GetMetahandle();
3230 syncable::MutableEntry folder_b(&trans, syncable::CREATE,
3231 BOOKMARKS, root.GetId(), "folderB");
3232 ASSERT_TRUE(folder_b.good());
3233 SetNodeProperties(&folder_b);
3234 folder_b.PutIsDir(true);
3235 folder_b_id = folder_b.GetMetahandle();
3237 syncable::MutableEntry child(&trans, syncable::CREATE,
3238 BOOKMARKS, folder_a.GetId(),
3239 "child");
3240 ASSERT_TRUE(child.good());
3241 SetNodeProperties(&child);
3242 child_id = child.GetMetahandle();
3245 // Close that transaction. The above was to setup the initial scenario. The
3246 // real test starts now.
3249 syncable::WriteTransaction trans(
3250 FROM_HERE, syncable::SYNCER, share()->directory.get());
3252 syncable::MutableEntry folder_a(
3253 &trans, syncable::GET_BY_HANDLE, folder_a_id);
3254 syncable::MutableEntry folder_b(
3255 &trans, syncable::GET_BY_HANDLE, folder_b_id);
3256 syncable::MutableEntry child(&trans, syncable::GET_BY_HANDLE, child_id);
3258 // Delete folder B and its child.
3259 child.PutIsDel(true);
3260 folder_b.PutIsDel(true);
3262 // Make an unrelated change to folder A.
3263 folder_a.PutNonUniqueName("NewNameA");
3266 EXPECT_EQ(3UL, GetChangeListSize());
3268 size_t folder_a_pos =
3269 FindChangeInList(folder_a_id, ChangeRecord::ACTION_UPDATE);
3270 size_t folder_b_pos =
3271 FindChangeInList(folder_b_id, ChangeRecord::ACTION_DELETE);
3272 size_t child_pos = FindChangeInList(child_id, ChangeRecord::ACTION_DELETE);
3274 // Deletes should appear before updates.
3275 EXPECT_LT(child_pos, folder_a_pos);
3276 EXPECT_LT(folder_b_pos, folder_a_pos);
3279 // See that attachment metadata changes are not filtered out by
3280 // SyncManagerImpl::VisiblePropertiesDiffer.
3281 TEST_F(SyncManagerChangeProcessingTest, AttachmentMetadataOnlyChanges) {
3282 // Create an article with no attachments. See that a change is generated.
3283 int64 article_id = kInvalidId;
3285 syncable::WriteTransaction trans(
3286 FROM_HERE, syncable::SYNCER, share()->directory.get());
3287 int64 type_root = GetIdForDataType(ARTICLES);
3288 syncable::Entry root(&trans, syncable::GET_BY_HANDLE, type_root);
3289 ASSERT_TRUE(root.good());
3290 syncable::MutableEntry article(
3291 &trans, syncable::CREATE, ARTICLES, root.GetId(), "article");
3292 ASSERT_TRUE(article.good());
3293 SetNodeProperties(&article);
3294 article_id = article.GetMetahandle();
3296 ASSERT_EQ(1UL, GetChangeListSize());
3297 FindChangeInList(article_id, ChangeRecord::ACTION_ADD);
3298 ClearChangeList();
3300 // Modify the article by adding one attachment. Don't touch anything else.
3301 // See that a change is generated.
3303 syncable::WriteTransaction trans(
3304 FROM_HERE, syncable::SYNCER, share()->directory.get());
3305 syncable::MutableEntry article(&trans, syncable::GET_BY_HANDLE, article_id);
3306 sync_pb::AttachmentMetadata metadata;
3307 *metadata.add_record()->mutable_id() = CreateAttachmentIdProto(0, 0);
3308 article.PutAttachmentMetadata(metadata);
3310 ASSERT_EQ(1UL, GetChangeListSize());
3311 FindChangeInList(article_id, ChangeRecord::ACTION_UPDATE);
3312 ClearChangeList();
3314 // Modify the article by replacing its attachment with a different one. See
3315 // that a change is generated.
3317 syncable::WriteTransaction trans(
3318 FROM_HERE, syncable::SYNCER, share()->directory.get());
3319 syncable::MutableEntry article(&trans, syncable::GET_BY_HANDLE, article_id);
3320 sync_pb::AttachmentMetadata metadata = article.GetAttachmentMetadata();
3321 *metadata.add_record()->mutable_id() = CreateAttachmentIdProto(0, 0);
3322 article.PutAttachmentMetadata(metadata);
3324 ASSERT_EQ(1UL, GetChangeListSize());
3325 FindChangeInList(article_id, ChangeRecord::ACTION_UPDATE);
3326 ClearChangeList();
3328 // Modify the article by replacing its attachment metadata with the same
3329 // attachment metadata. No change should be generated.
3331 syncable::WriteTransaction trans(
3332 FROM_HERE, syncable::SYNCER, share()->directory.get());
3333 syncable::MutableEntry article(&trans, syncable::GET_BY_HANDLE, article_id);
3334 article.PutAttachmentMetadata(article.GetAttachmentMetadata());
3336 ASSERT_EQ(0UL, GetChangeListSize());
3339 // During initialization SyncManagerImpl loads sqlite database. If it fails to
3340 // do so it should fail initialization. This test verifies this behavior.
3341 // Test reuses SyncManagerImpl initialization from SyncManagerTest but overrides
3342 // InternalComponentsFactory to return DirectoryBackingStore that always fails
3343 // to load.
3344 class SyncManagerInitInvalidStorageTest : public SyncManagerTest {
3345 public:
3346 SyncManagerInitInvalidStorageTest() {
3349 InternalComponentsFactory* GetFactory() override {
3350 return new TestInternalComponentsFactory(
3351 GetSwitches(), InternalComponentsFactory::STORAGE_INVALID,
3352 &storage_used_);
3356 // SyncManagerInitInvalidStorageTest::GetFactory will return
3357 // DirectoryBackingStore that ensures that SyncManagerImpl::OpenDirectory fails.
3358 // SyncManagerImpl initialization is done in SyncManagerTest::SetUp. This test's
3359 // task is to ensure that SyncManagerImpl reported initialization failure in
3360 // OnInitializationComplete callback.
3361 TEST_F(SyncManagerInitInvalidStorageTest, FailToOpenDatabase) {
3362 EXPECT_FALSE(initialization_succeeded_);
3365 } // namespace syncer