1 // Copyright (c) 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.
12 #include "base/basictypes.h"
13 #include "base/callback.h"
14 #include "base/compiler_specific.h"
15 #include "base/format_macros.h"
16 #include "base/location.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop.h"
19 #include "base/message_loop_proxy.h"
20 #include "base/scoped_temp_dir.h"
21 #include "base/string_number_conversions.h"
22 #include "base/stringprintf.h"
23 #include "base/test/values_test_util.h"
24 #include "base/utf_string_conversions.h"
25 #include "base/values.h"
26 #include "sync/internal_api/public/base/model_type_test_util.h"
27 #include "sync/internal_api/public/change_record.h"
28 #include "sync/internal_api/public/engine/model_safe_worker.h"
29 #include "sync/internal_api/public/engine/polling_constants.h"
30 #include "sync/internal_api/public/http_post_provider_factory.h"
31 #include "sync/internal_api/public/http_post_provider_interface.h"
32 #include "sync/internal_api/public/read_node.h"
33 #include "sync/internal_api/public/read_transaction.h"
34 #include "sync/internal_api/public/sync_manager.h"
35 #include "sync/internal_api/public/test/test_user_share.h"
36 #include "sync/internal_api/public/write_node.h"
37 #include "sync/internal_api/public/write_transaction.h"
38 #include "sync/internal_api/syncapi_internal.h"
39 #include "sync/js/js_arg_list.h"
40 #include "sync/js/js_backend.h"
41 #include "sync/js/js_event_handler.h"
42 #include "sync/js/js_reply_handler.h"
43 #include "sync/js/js_test_util.h"
44 #include "sync/notifier/sync_notifier.h"
45 #include "sync/notifier/sync_notifier_observer.h"
46 #include "sync/protocol/bookmark_specifics.pb.h"
47 #include "sync/protocol/encryption.pb.h"
48 #include "sync/protocol/extension_specifics.pb.h"
49 #include "sync/protocol/password_specifics.pb.h"
50 #include "sync/protocol/preference_specifics.pb.h"
51 #include "sync/protocol/proto_value_conversions.h"
52 #include "sync/protocol/sync.pb.h"
53 #include "sync/sessions/sync_session.h"
54 #include "sync/syncable/directory.h"
55 #include "sync/syncable/entry.h"
56 #include "sync/syncable/mutable_entry.h"
57 #include "sync/syncable/nigori_util.h"
58 #include "sync/syncable/syncable_id.h"
59 #include "sync/syncable/write_transaction.h"
60 #include "sync/test/fake_encryptor.h"
61 #include "sync/test/fake_extensions_activity_monitor.h"
62 #include "sync/util/cryptographer.h"
63 #include "sync/util/extensions_activity_monitor.h"
64 #include "sync/util/test_unrecoverable_error_handler.h"
65 #include "sync/util/time.h"
66 #include "testing/gmock/include/gmock/gmock.h"
67 #include "testing/gtest/include/gtest/gtest.h"
69 using base::ExpectDictStringValue
;
71 using testing::AnyNumber
;
72 using testing::AtLeast
;
73 using testing::InSequence
;
74 using testing::Invoke
;
75 using testing::SaveArg
;
76 using testing::StrictMock
;
80 using sessions::SyncSessionSnapshot
;
81 using syncable::IS_DEL
;
82 using syncable::IS_UNSYNCED
;
83 using syncable::kEncryptedString
;
84 using syncable::NON_UNIQUE_NAME
;
85 using syncable::SPECIFICS
;
89 const char kTestChromeVersion
[] = "test chrome version";
93 void ExpectInt64Value(int64 expected_value
,
94 const DictionaryValue
& value
, const std::string
& key
) {
95 std::string int64_str
;
96 EXPECT_TRUE(value
.GetString(key
, &int64_str
));
98 EXPECT_TRUE(base::StringToInt64(int64_str
, &val
));
99 EXPECT_EQ(expected_value
, val
);
102 void ExpectTimeValue(const base::Time
& expected_value
,
103 const DictionaryValue
& value
, const std::string
& key
) {
104 std::string time_str
;
105 EXPECT_TRUE(value
.GetString(key
, &time_str
));
106 EXPECT_EQ(syncer::GetTimeDebugString(expected_value
), time_str
);
109 // Makes a non-folder child of the root node. Returns the id of the
110 // newly-created node.
111 int64
MakeNode(UserShare
* share
,
112 ModelType model_type
,
113 const std::string
& client_tag
) {
114 WriteTransaction
trans(FROM_HERE
, share
);
115 ReadNode
root_node(&trans
);
116 root_node
.InitByRootLookup();
117 WriteNode
node(&trans
);
118 syncer::WriteNode::InitUniqueByCreationResult result
=
119 node
.InitUniqueByCreation(model_type
, root_node
, client_tag
);
120 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
121 node
.SetIsFolder(false);
125 // Makes a non-folder child of a non-root node. Returns the id of the
126 // newly-created node.
127 int64
MakeNodeWithParent(UserShare
* share
,
128 ModelType model_type
,
129 const std::string
& client_tag
,
131 WriteTransaction
trans(FROM_HERE
, share
);
132 ReadNode
parent_node(&trans
);
133 EXPECT_EQ(BaseNode::INIT_OK
, parent_node
.InitByIdLookup(parent_id
));
134 WriteNode
node(&trans
);
135 syncer::WriteNode::InitUniqueByCreationResult result
=
136 node
.InitUniqueByCreation(model_type
, parent_node
, client_tag
);
137 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
138 node
.SetIsFolder(false);
142 // Makes a folder child of a non-root node. Returns the id of the
143 // newly-created node.
144 int64
MakeFolderWithParent(UserShare
* share
,
145 ModelType model_type
,
147 BaseNode
* predecessor
) {
148 WriteTransaction
trans(FROM_HERE
, share
);
149 ReadNode
parent_node(&trans
);
150 EXPECT_EQ(BaseNode::INIT_OK
, parent_node
.InitByIdLookup(parent_id
));
151 WriteNode
node(&trans
);
152 EXPECT_TRUE(node
.InitByCreation(model_type
, parent_node
, predecessor
));
153 node
.SetIsFolder(true);
157 // Creates the "synced" root node for a particular datatype. We use the syncable
158 // methods here so that the syncer treats these nodes as if they were already
159 // received from the server.
160 int64
MakeServerNodeForType(UserShare
* share
,
161 ModelType model_type
) {
162 sync_pb::EntitySpecifics specifics
;
163 syncer::AddDefaultFieldValue(model_type
, &specifics
);
164 syncable::WriteTransaction
trans(
165 FROM_HERE
, syncable::UNITTEST
, share
->directory
.get());
166 // Attempt to lookup by nigori tag.
167 std::string type_tag
= syncer::ModelTypeToRootTag(model_type
);
168 syncable::Id node_id
= syncable::Id::CreateFromServerId(type_tag
);
169 syncable::MutableEntry
entry(&trans
, syncable::CREATE_NEW_UPDATE_ITEM
,
171 EXPECT_TRUE(entry
.good());
172 entry
.Put(syncable::BASE_VERSION
, 1);
173 entry
.Put(syncable::SERVER_VERSION
, 1);
174 entry
.Put(syncable::IS_UNAPPLIED_UPDATE
, false);
175 entry
.Put(syncable::SERVER_PARENT_ID
, syncable::GetNullId());
176 entry
.Put(syncable::SERVER_IS_DIR
, true);
177 entry
.Put(syncable::IS_DIR
, true);
178 entry
.Put(syncable::SERVER_SPECIFICS
, specifics
);
179 entry
.Put(syncable::UNIQUE_SERVER_TAG
, type_tag
);
180 entry
.Put(syncable::NON_UNIQUE_NAME
, type_tag
);
181 entry
.Put(syncable::IS_DEL
, false);
182 entry
.Put(syncable::SPECIFICS
, specifics
);
183 return entry
.Get(syncable::META_HANDLE
);
186 // Simulates creating a "synced" node as a child of the root datatype node.
187 int64
MakeServerNode(UserShare
* share
, ModelType model_type
,
188 const std::string
& client_tag
,
189 const std::string
& hashed_tag
,
190 const sync_pb::EntitySpecifics
& specifics
) {
191 syncable::WriteTransaction
trans(
192 FROM_HERE
, syncable::UNITTEST
, share
->directory
.get());
193 syncable::Entry
root_entry(&trans
, syncable::GET_BY_SERVER_TAG
,
194 syncer::ModelTypeToRootTag(model_type
));
195 EXPECT_TRUE(root_entry
.good());
196 syncable::Id root_id
= root_entry
.Get(syncable::ID
);
197 syncable::Id node_id
= syncable::Id::CreateFromServerId(client_tag
);
198 syncable::MutableEntry
entry(&trans
, syncable::CREATE_NEW_UPDATE_ITEM
,
200 EXPECT_TRUE(entry
.good());
201 entry
.Put(syncable::BASE_VERSION
, 1);
202 entry
.Put(syncable::SERVER_VERSION
, 1);
203 entry
.Put(syncable::IS_UNAPPLIED_UPDATE
, false);
204 entry
.Put(syncable::SERVER_PARENT_ID
, root_id
);
205 entry
.Put(syncable::PARENT_ID
, root_id
);
206 entry
.Put(syncable::SERVER_IS_DIR
, false);
207 entry
.Put(syncable::IS_DIR
, false);
208 entry
.Put(syncable::SERVER_SPECIFICS
, specifics
);
209 entry
.Put(syncable::NON_UNIQUE_NAME
, client_tag
);
210 entry
.Put(syncable::UNIQUE_CLIENT_TAG
, hashed_tag
);
211 entry
.Put(syncable::IS_DEL
, false);
212 entry
.Put(syncable::SPECIFICS
, specifics
);
213 return entry
.Get(syncable::META_HANDLE
);
218 class SyncApiTest
: public testing::Test
{
220 virtual void SetUp() {
221 test_user_share_
.SetUp();
224 virtual void TearDown() {
225 test_user_share_
.TearDown();
229 MessageLoop message_loop_
;
230 syncer::TestUserShare test_user_share_
;
233 TEST_F(SyncApiTest
, SanityCheckTest
) {
235 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
236 EXPECT_TRUE(trans
.GetWrappedTrans() != NULL
);
239 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
240 EXPECT_TRUE(trans
.GetWrappedTrans() != NULL
);
243 // No entries but root should exist
244 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
245 ReadNode
node(&trans
);
246 // Metahandle 1 can be root, sanity check 2
247 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
, node
.InitByIdLookup(2));
251 TEST_F(SyncApiTest
, BasicTagWrite
) {
253 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
254 ReadNode
root_node(&trans
);
255 root_node
.InitByRootLookup();
256 EXPECT_EQ(root_node
.GetFirstChildId(), 0);
259 ignore_result(MakeNode(test_user_share_
.user_share(),
260 syncer::BOOKMARKS
, "testtag"));
263 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
264 ReadNode
node(&trans
);
265 EXPECT_EQ(BaseNode::INIT_OK
,
266 node
.InitByClientTagLookup(syncer::BOOKMARKS
, "testtag"));
268 ReadNode
root_node(&trans
);
269 root_node
.InitByRootLookup();
270 EXPECT_NE(node
.GetId(), 0);
271 EXPECT_EQ(node
.GetId(), root_node
.GetFirstChildId());
275 TEST_F(SyncApiTest
, GenerateSyncableHash
) {
276 EXPECT_EQ("OyaXV5mEzrPS4wbogmtKvRfekAI=",
277 BaseNode::GenerateSyncableHash(syncer::BOOKMARKS
, "tag1"));
278 EXPECT_EQ("iNFQtRFQb+IZcn1kKUJEZDDkLs4=",
279 BaseNode::GenerateSyncableHash(syncer::PREFERENCES
, "tag1"));
280 EXPECT_EQ("gO1cPZQXaM73sHOvSA+tKCKFs58=",
281 BaseNode::GenerateSyncableHash(syncer::AUTOFILL
, "tag1"));
283 EXPECT_EQ("A0eYIHXM1/jVwKDDp12Up20IkKY=",
284 BaseNode::GenerateSyncableHash(syncer::BOOKMARKS
, "tag2"));
285 EXPECT_EQ("XYxkF7bhS4eItStFgiOIAU23swI=",
286 BaseNode::GenerateSyncableHash(syncer::PREFERENCES
, "tag2"));
287 EXPECT_EQ("GFiWzo5NGhjLlN+OyCfhy28DJTQ=",
288 BaseNode::GenerateSyncableHash(syncer::AUTOFILL
, "tag2"));
291 TEST_F(SyncApiTest
, ModelTypesSiloed
) {
293 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
294 ReadNode
root_node(&trans
);
295 root_node
.InitByRootLookup();
296 EXPECT_EQ(root_node
.GetFirstChildId(), 0);
299 ignore_result(MakeNode(test_user_share_
.user_share(),
300 syncer::BOOKMARKS
, "collideme"));
301 ignore_result(MakeNode(test_user_share_
.user_share(),
302 syncer::PREFERENCES
, "collideme"));
303 ignore_result(MakeNode(test_user_share_
.user_share(),
304 syncer::AUTOFILL
, "collideme"));
307 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
309 ReadNode
bookmarknode(&trans
);
310 EXPECT_EQ(BaseNode::INIT_OK
,
311 bookmarknode
.InitByClientTagLookup(syncer::BOOKMARKS
,
314 ReadNode
prefnode(&trans
);
315 EXPECT_EQ(BaseNode::INIT_OK
,
316 prefnode
.InitByClientTagLookup(syncer::PREFERENCES
,
319 ReadNode
autofillnode(&trans
);
320 EXPECT_EQ(BaseNode::INIT_OK
,
321 autofillnode
.InitByClientTagLookup(syncer::AUTOFILL
,
324 EXPECT_NE(bookmarknode
.GetId(), prefnode
.GetId());
325 EXPECT_NE(autofillnode
.GetId(), prefnode
.GetId());
326 EXPECT_NE(bookmarknode
.GetId(), autofillnode
.GetId());
330 TEST_F(SyncApiTest
, ReadMissingTagsFails
) {
332 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
333 ReadNode
node(&trans
);
334 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
,
335 node
.InitByClientTagLookup(syncer::BOOKMARKS
,
339 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
340 WriteNode
node(&trans
);
341 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD
,
342 node
.InitByClientTagLookup(syncer::BOOKMARKS
,
347 // TODO(chron): Hook this all up to the server and write full integration tests
348 // for update->undelete behavior.
349 TEST_F(SyncApiTest
, TestDeleteBehavior
) {
352 std::string
test_title("test1");
355 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
356 ReadNode
root_node(&trans
);
357 root_node
.InitByRootLookup();
359 // we'll use this spare folder later
360 WriteNode
folder_node(&trans
);
361 EXPECT_TRUE(folder_node
.InitByCreation(syncer::BOOKMARKS
,
363 folder_id
= folder_node
.GetId();
365 WriteNode
wnode(&trans
);
366 syncer::WriteNode::InitUniqueByCreationResult result
=
367 wnode
.InitUniqueByCreation(syncer::BOOKMARKS
, root_node
, "testtag");
368 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
369 wnode
.SetIsFolder(false);
370 wnode
.SetTitle(UTF8ToWide(test_title
));
372 node_id
= wnode
.GetId();
375 // Ensure we can delete something with a tag.
377 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
378 WriteNode
wnode(&trans
);
379 EXPECT_EQ(BaseNode::INIT_OK
,
380 wnode
.InitByClientTagLookup(syncer::BOOKMARKS
,
382 EXPECT_FALSE(wnode
.GetIsFolder());
383 EXPECT_EQ(wnode
.GetTitle(), test_title
);
388 // Lookup of a node which was deleted should return failure,
389 // but have found some data about the node.
391 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
392 ReadNode
node(&trans
);
393 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_IS_DEL
,
394 node
.InitByClientTagLookup(syncer::BOOKMARKS
,
396 // Note that for proper function of this API this doesn't need to be
397 // filled, we're checking just to make sure the DB worked in this test.
398 EXPECT_EQ(node
.GetTitle(), test_title
);
402 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
403 ReadNode
folder_node(&trans
);
404 EXPECT_EQ(BaseNode::INIT_OK
, folder_node
.InitByIdLookup(folder_id
));
406 WriteNode
wnode(&trans
);
407 // This will undelete the tag.
408 syncer::WriteNode::InitUniqueByCreationResult result
=
409 wnode
.InitUniqueByCreation(syncer::BOOKMARKS
, folder_node
, "testtag");
410 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
411 EXPECT_EQ(wnode
.GetIsFolder(), false);
412 EXPECT_EQ(wnode
.GetParentId(), folder_node
.GetId());
413 EXPECT_EQ(wnode
.GetId(), node_id
);
414 EXPECT_NE(wnode
.GetTitle(), test_title
); // Title should be cleared
415 wnode
.SetTitle(UTF8ToWide(test_title
));
418 // Now look up should work.
420 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
421 ReadNode
node(&trans
);
422 EXPECT_EQ(BaseNode::INIT_OK
,
423 node
.InitByClientTagLookup(syncer::BOOKMARKS
,
425 EXPECT_EQ(node
.GetTitle(), test_title
);
426 EXPECT_EQ(node
.GetModelType(), syncer::BOOKMARKS
);
430 TEST_F(SyncApiTest
, WriteAndReadPassword
) {
431 KeyParams params
= {"localhost", "username", "passphrase"};
433 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
434 trans
.GetCryptographer()->AddKey(params
);
437 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
438 ReadNode
root_node(&trans
);
439 root_node
.InitByRootLookup();
441 WriteNode
password_node(&trans
);
442 syncer::WriteNode::InitUniqueByCreationResult result
=
443 password_node
.InitUniqueByCreation(syncer::PASSWORDS
,
445 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
446 sync_pb::PasswordSpecificsData data
;
447 data
.set_password_value("secret");
448 password_node
.SetPasswordSpecifics(data
);
451 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
452 ReadNode
root_node(&trans
);
453 root_node
.InitByRootLookup();
455 ReadNode
password_node(&trans
);
456 EXPECT_EQ(BaseNode::INIT_OK
,
457 password_node
.InitByClientTagLookup(syncer::PASSWORDS
,
459 const sync_pb::PasswordSpecificsData
& data
=
460 password_node
.GetPasswordSpecifics();
461 EXPECT_EQ("secret", data
.password_value());
465 TEST_F(SyncApiTest
, WriteEncryptedTitle
) {
466 KeyParams params
= {"localhost", "username", "passphrase"};
468 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
469 trans
.GetCryptographer()->AddKey(params
);
470 trans
.GetCryptographer()->set_encrypt_everything();
473 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
474 ReadNode
root_node(&trans
);
475 root_node
.InitByRootLookup();
477 WriteNode
bookmark_node(&trans
);
478 syncer::WriteNode::InitUniqueByCreationResult result
=
479 bookmark_node
.InitUniqueByCreation(syncer::BOOKMARKS
,
481 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
482 bookmark_node
.SetTitle(UTF8ToWide("foo"));
484 WriteNode
pref_node(&trans
);
486 pref_node
.InitUniqueByCreation(syncer::PREFERENCES
, root_node
, "bar");
487 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
488 pref_node
.SetTitle(UTF8ToWide("bar"));
491 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
492 ReadNode
root_node(&trans
);
493 root_node
.InitByRootLookup();
495 ReadNode
bookmark_node(&trans
);
496 EXPECT_EQ(BaseNode::INIT_OK
,
497 bookmark_node
.InitByClientTagLookup(syncer::BOOKMARKS
,
499 EXPECT_EQ("foo", bookmark_node
.GetTitle());
500 EXPECT_EQ(kEncryptedString
,
501 bookmark_node
.GetEntry()->Get(syncable::NON_UNIQUE_NAME
));
503 ReadNode
pref_node(&trans
);
504 EXPECT_EQ(BaseNode::INIT_OK
,
505 pref_node
.InitByClientTagLookup(syncer::PREFERENCES
,
507 EXPECT_EQ(kEncryptedString
, pref_node
.GetTitle());
511 TEST_F(SyncApiTest
, BaseNodeSetSpecifics
) {
512 int64 child_id
= MakeNode(test_user_share_
.user_share(),
513 syncer::BOOKMARKS
, "testtag");
514 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
515 WriteNode
node(&trans
);
516 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(child_id
));
518 sync_pb::EntitySpecifics entity_specifics
;
519 entity_specifics
.mutable_bookmark()->set_url("http://www.google.com");
521 EXPECT_NE(entity_specifics
.SerializeAsString(),
522 node
.GetEntitySpecifics().SerializeAsString());
523 node
.SetEntitySpecifics(entity_specifics
);
524 EXPECT_EQ(entity_specifics
.SerializeAsString(),
525 node
.GetEntitySpecifics().SerializeAsString());
528 TEST_F(SyncApiTest
, BaseNodeSetSpecificsPreservesUnknownFields
) {
529 int64 child_id
= MakeNode(test_user_share_
.user_share(),
530 syncer::BOOKMARKS
, "testtag");
531 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
532 WriteNode
node(&trans
);
533 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(child_id
));
534 EXPECT_TRUE(node
.GetEntitySpecifics().unknown_fields().empty());
536 sync_pb::EntitySpecifics entity_specifics
;
537 entity_specifics
.mutable_bookmark()->set_url("http://www.google.com");
538 entity_specifics
.mutable_unknown_fields()->AddFixed32(5, 100);
539 node
.SetEntitySpecifics(entity_specifics
);
540 EXPECT_FALSE(node
.GetEntitySpecifics().unknown_fields().empty());
542 entity_specifics
.mutable_unknown_fields()->Clear();
543 node
.SetEntitySpecifics(entity_specifics
);
544 EXPECT_FALSE(node
.GetEntitySpecifics().unknown_fields().empty());
549 void CheckNodeValue(const BaseNode
& node
, const DictionaryValue
& value
,
551 ExpectInt64Value(node
.GetId(), value
, "id");
553 bool is_folder
= false;
554 EXPECT_TRUE(value
.GetBoolean("isFolder", &is_folder
));
555 EXPECT_EQ(node
.GetIsFolder(), is_folder
);
557 ExpectDictStringValue(node
.GetTitle(), value
, "title");
559 ModelType expected_model_type
= node
.GetModelType();
560 std::string type_str
;
561 EXPECT_TRUE(value
.GetString("type", &type_str
));
562 if (expected_model_type
>= syncer::FIRST_REAL_MODEL_TYPE
) {
563 ModelType model_type
= syncer::ModelTypeFromString(type_str
);
564 EXPECT_EQ(expected_model_type
, model_type
);
565 } else if (expected_model_type
== syncer::TOP_LEVEL_FOLDER
) {
566 EXPECT_EQ("Top-level folder", type_str
);
567 } else if (expected_model_type
== syncer::UNSPECIFIED
) {
568 EXPECT_EQ("Unspecified", type_str
);
574 ExpectInt64Value(node
.GetParentId(), value
, "parentId");
575 ExpectTimeValue(node
.GetModificationTime(), value
, "modificationTime");
576 ExpectInt64Value(node
.GetExternalId(), value
, "externalId");
577 ExpectInt64Value(node
.GetPredecessorId(), value
, "predecessorId");
578 ExpectInt64Value(node
.GetSuccessorId(), value
, "successorId");
579 ExpectInt64Value(node
.GetFirstChildId(), value
, "firstChildId");
581 scoped_ptr
<DictionaryValue
> expected_entry(node
.GetEntry()->ToValue());
583 EXPECT_TRUE(value
.Get("entry", &entry
));
584 EXPECT_TRUE(Value::Equals(entry
, expected_entry
.get()));
586 EXPECT_EQ(11u, value
.size());
588 EXPECT_EQ(4u, value
.size());
594 TEST_F(SyncApiTest
, BaseNodeGetSummaryAsValue
) {
595 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
596 ReadNode
node(&trans
);
597 node
.InitByRootLookup();
598 scoped_ptr
<DictionaryValue
> details(node
.GetSummaryAsValue());
600 CheckNodeValue(node
, *details
, false);
606 TEST_F(SyncApiTest
, BaseNodeGetDetailsAsValue
) {
607 ReadTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
608 ReadNode
node(&trans
);
609 node
.InitByRootLookup();
610 scoped_ptr
<DictionaryValue
> details(node
.GetDetailsAsValue());
612 CheckNodeValue(node
, *details
, true);
618 TEST_F(SyncApiTest
, EmptyTags
) {
619 WriteTransaction
trans(FROM_HERE
, test_user_share_
.user_share());
620 ReadNode
root_node(&trans
);
621 root_node
.InitByRootLookup();
622 WriteNode
node(&trans
);
623 std::string empty_tag
;
624 syncer::WriteNode::InitUniqueByCreationResult result
=
625 node
.InitUniqueByCreation(syncer::TYPED_URLS
, root_node
, empty_tag
);
626 EXPECT_NE(syncer::WriteNode::INIT_SUCCESS
, result
);
627 EXPECT_EQ(BaseNode::INIT_FAILED_PRECONDITION
,
628 node
.InitByTagLookup(empty_tag
));
633 class TestHttpPostProviderInterface
: public HttpPostProviderInterface
{
635 virtual ~TestHttpPostProviderInterface() {}
637 virtual void SetExtraRequestHeaders(const char* headers
) OVERRIDE
{}
638 virtual void SetURL(const char* url
, int port
) OVERRIDE
{}
639 virtual void SetPostPayload(const char* content_type
,
641 const char* content
) OVERRIDE
{}
642 virtual bool MakeSynchronousPost(int* error_code
, int* response_code
)
646 virtual int GetResponseContentLength() const OVERRIDE
{
649 virtual const char* GetResponseContent() const OVERRIDE
{
652 virtual const std::string
GetResponseHeaderValue(
653 const std::string
& name
) const OVERRIDE
{
656 virtual void Abort() OVERRIDE
{}
659 class TestHttpPostProviderFactory
: public HttpPostProviderFactory
{
661 virtual ~TestHttpPostProviderFactory() {}
662 virtual HttpPostProviderInterface
* Create() OVERRIDE
{
663 return new TestHttpPostProviderInterface();
665 virtual void Destroy(HttpPostProviderInterface
* http
) OVERRIDE
{
666 delete static_cast<TestHttpPostProviderInterface
*>(http
);
670 class SyncManagerObserverMock
: public SyncManager::Observer
{
672 MOCK_METHOD1(OnSyncCycleCompleted
,
673 void(const SyncSessionSnapshot
&)); // NOLINT
674 MOCK_METHOD2(OnInitializationComplete
,
675 void(const WeakHandle
<JsBackend
>&, bool)); // NOLINT
676 MOCK_METHOD1(OnConnectionStatusChange
, void(ConnectionStatus
)); // NOLINT
677 MOCK_METHOD2(OnPassphraseRequired
,
678 void(syncer::PassphraseRequiredReason
,
679 const sync_pb::EncryptedData
&)); // NOLINT
680 MOCK_METHOD0(OnPassphraseAccepted
, void()); // NOLINT
681 MOCK_METHOD1(OnBootstrapTokenUpdated
, void(const std::string
&)); // NOLINT
682 MOCK_METHOD0(OnStopSyncingPermanently
, void()); // NOLINT
683 MOCK_METHOD1(OnUpdatedToken
, void(const std::string
&)); // NOLINT
684 MOCK_METHOD2(OnEncryptedTypesChanged
,
685 void(ModelTypeSet
, bool)); // NOLINT
686 MOCK_METHOD0(OnEncryptionComplete
, void()); // NOLINT
687 MOCK_METHOD1(OnActionableError
,
688 void(const syncer::SyncProtocolError
&)); // NOLINT
691 class SyncNotifierMock
: public syncer::SyncNotifier
{
693 MOCK_METHOD1(AddObserver
, void(syncer::SyncNotifierObserver
*));
694 MOCK_METHOD1(RemoveObserver
, void(syncer::SyncNotifierObserver
*));
695 MOCK_METHOD1(SetUniqueId
, void(const std::string
&));
696 MOCK_METHOD1(SetStateDeprecated
, void(const std::string
&));
697 MOCK_METHOD2(UpdateCredentials
,
698 void(const std::string
&, const std::string
&));
699 MOCK_METHOD1(UpdateEnabledTypes
,
700 void(syncer::ModelTypeSet
));
701 MOCK_METHOD1(SendNotification
, void(syncer::ModelTypeSet
));
706 class SyncManagerTest
: public testing::Test
,
707 public SyncManager::ChangeDelegate
{
714 enum EncryptionStatus
{
721 : sync_notifier_mock_(NULL
),
722 sync_manager_("Test sync manager"),
723 sync_notifier_observer_(NULL
),
724 update_enabled_types_call_count_(0) {}
726 virtual ~SyncManagerTest() {
727 EXPECT_FALSE(sync_notifier_mock_
);
730 // Test implementation.
732 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
734 SyncCredentials credentials
;
735 credentials
.email
= "foo@bar.com";
736 credentials
.sync_token
= "sometoken";
738 sync_notifier_mock_
= new StrictMock
<SyncNotifierMock
>();
739 EXPECT_CALL(*sync_notifier_mock_
, AddObserver(_
)).
740 WillOnce(Invoke(this, &SyncManagerTest::SyncNotifierAddObserver
));
741 EXPECT_CALL(*sync_notifier_mock_
, SetUniqueId(_
));
742 EXPECT_CALL(*sync_notifier_mock_
, SetStateDeprecated(""));
743 EXPECT_CALL(*sync_notifier_mock_
,
744 UpdateCredentials(credentials
.email
, credentials
.sync_token
));
745 EXPECT_CALL(*sync_notifier_mock_
, UpdateEnabledTypes(_
)).
747 Invoke(this, &SyncManagerTest::SyncNotifierUpdateEnabledTypes
));
748 EXPECT_CALL(*sync_notifier_mock_
, RemoveObserver(_
)).
749 WillOnce(Invoke(this, &SyncManagerTest::SyncNotifierRemoveObserver
));
751 sync_manager_
.AddObserver(&observer_
);
752 EXPECT_CALL(observer_
, OnInitializationComplete(_
, _
)).
753 WillOnce(SaveArg
<0>(&js_backend_
));
755 EXPECT_FALSE(sync_notifier_observer_
);
756 EXPECT_FALSE(js_backend_
.IsInitialized());
758 std::vector
<ModelSafeWorker
*> workers
;
759 ModelSafeRoutingInfo routing_info
;
760 GetModelSafeRoutingInfo(&routing_info
);
762 // Takes ownership of |sync_notifier_mock_|.
763 sync_manager_
.Init(temp_dir_
.path(),
764 WeakHandle
<JsEventHandler
>(),
766 base::MessageLoopProxy::current(),
767 new TestHttpPostProviderFactory(), routing_info
, workers
,
768 &extensions_activity_monitor_
, this,
770 sync_notifier_mock_
, "",
771 syncer::SyncManager::TEST_IN_MEMORY
,
776 EXPECT_TRUE(sync_notifier_observer_
);
777 EXPECT_TRUE(js_backend_
.IsInitialized());
779 EXPECT_EQ(0, update_enabled_types_call_count_
);
781 for (ModelSafeRoutingInfo::iterator i
= routing_info
.begin();
782 i
!= routing_info
.end(); ++i
) {
783 type_roots_
[i
->first
] = MakeServerNodeForType(
784 sync_manager_
.GetUserShare(), i
->first
);
790 sync_manager_
.RemoveObserver(&observer_
);
791 sync_manager_
.ShutdownOnSyncThread();
792 sync_notifier_mock_
= NULL
;
793 EXPECT_FALSE(sync_notifier_observer_
);
797 void GetModelSafeRoutingInfo(ModelSafeRoutingInfo
* out
) {
798 (*out
)[syncer::NIGORI
] = syncer::GROUP_PASSIVE
;
799 (*out
)[syncer::BOOKMARKS
] = syncer::GROUP_PASSIVE
;
800 (*out
)[syncer::THEMES
] = syncer::GROUP_PASSIVE
;
801 (*out
)[syncer::SESSIONS
] = syncer::GROUP_PASSIVE
;
802 (*out
)[syncer::PASSWORDS
] = syncer::GROUP_PASSIVE
;
803 (*out
)[syncer::PREFERENCES
] = syncer::GROUP_PASSIVE
;
806 virtual void OnChangesApplied(
807 syncer::ModelType model_type
,
808 const BaseTransaction
* trans
,
809 const ImmutableChangeRecordList
& changes
) OVERRIDE
{}
811 virtual void OnChangesComplete(syncer::ModelType model_type
) OVERRIDE
{}
814 bool SetUpEncryption(NigoriStatus nigori_status
,
815 EncryptionStatus encryption_status
) {
816 UserShare
* share
= sync_manager_
.GetUserShare();
817 share
->directory
->set_initial_sync_ended_for_type(syncer::NIGORI
, true);
819 // We need to create the nigori node as if it were an applied server update.
820 int64 nigori_id
= GetIdForDataType(syncer::NIGORI
);
821 if (nigori_id
== kInvalidId
)
824 // Set the nigori cryptographer information.
825 WriteTransaction
trans(FROM_HERE
, share
);
826 Cryptographer
* cryptographer
= trans
.GetCryptographer();
829 if (encryption_status
!= UNINITIALIZED
) {
830 KeyParams params
= {"localhost", "dummy", "foobar"};
831 cryptographer
->AddKey(params
);
833 DCHECK_NE(nigori_status
, WRITE_TO_NIGORI
);
835 if (encryption_status
== FULL_ENCRYPTION
)
836 cryptographer
->set_encrypt_everything();
837 if (nigori_status
== WRITE_TO_NIGORI
) {
838 sync_pb::NigoriSpecifics nigori
;
839 cryptographer
->GetKeys(nigori
.mutable_encrypted());
840 cryptographer
->UpdateNigoriFromEncryptedTypes(&nigori
);
841 WriteNode
node(&trans
);
842 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(nigori_id
));
843 node
.SetNigoriSpecifics(nigori
);
845 return cryptographer
->is_ready();
848 int64
GetIdForDataType(ModelType type
) {
849 if (type_roots_
.count(type
) == 0)
851 return type_roots_
[type
];
854 void SyncNotifierAddObserver(
855 syncer::SyncNotifierObserver
* sync_notifier_observer
) {
856 EXPECT_EQ(NULL
, sync_notifier_observer_
);
857 sync_notifier_observer_
= sync_notifier_observer
;
860 void SyncNotifierRemoveObserver(
861 syncer::SyncNotifierObserver
* sync_notifier_observer
) {
862 EXPECT_EQ(sync_notifier_observer_
, sync_notifier_observer
);
863 sync_notifier_observer_
= NULL
;
866 void SyncNotifierUpdateEnabledTypes(syncer::ModelTypeSet types
) {
867 ModelSafeRoutingInfo routes
;
868 GetModelSafeRoutingInfo(&routes
);
869 const syncer::ModelTypeSet expected_types
= GetRoutingInfoTypes(routes
);
870 EXPECT_TRUE(types
.Equals(expected_types
));
871 ++update_enabled_types_call_count_
;
875 message_loop_
.RunAllPending();
878 void SendJsMessage(const std::string
& name
, const JsArgList
& args
,
879 const WeakHandle
<JsReplyHandler
>& reply_handler
) {
880 js_backend_
.Call(FROM_HERE
, &JsBackend::ProcessJsMessage
,
881 name
, args
, reply_handler
);
885 void SetJsEventHandler(const WeakHandle
<JsEventHandler
>& event_handler
) {
886 js_backend_
.Call(FROM_HERE
, &JsBackend::SetJsEventHandler
,
891 // Looks up an entry by client tag and resets IS_UNSYNCED value to false.
892 // Returns true if entry was previously unsynced, false if IS_UNSYNCED was
894 bool ResetUnsyncedEntry(syncer::ModelType type
,
895 const std::string
& client_tag
) {
896 UserShare
* share
= sync_manager_
.GetUserShare();
897 syncable::WriteTransaction
trans(
898 FROM_HERE
, syncable::UNITTEST
, share
->directory
.get());
899 const std::string hash
= BaseNode::GenerateSyncableHash(type
, client_tag
);
900 syncable::MutableEntry
entry(&trans
, syncable::GET_BY_CLIENT_TAG
,
902 EXPECT_TRUE(entry
.good());
903 if (!entry
.Get(IS_UNSYNCED
))
905 entry
.Put(IS_UNSYNCED
, false);
910 // Needed by |sync_manager_|.
911 MessageLoop message_loop_
;
912 // Needed by |sync_manager_|.
913 ScopedTempDir temp_dir_
;
914 // Sync Id's for the roots of the enabled datatypes.
915 std::map
<ModelType
, int64
> type_roots_
;
916 FakeExtensionsActivityMonitor extensions_activity_monitor_
;
917 StrictMock
<SyncNotifierMock
>* sync_notifier_mock_
;
920 FakeEncryptor encryptor_
;
921 TestUnrecoverableErrorHandler handler_
;
922 SyncManager sync_manager_
;
923 WeakHandle
<JsBackend
> js_backend_
;
924 StrictMock
<SyncManagerObserverMock
> observer_
;
925 syncer::SyncNotifierObserver
* sync_notifier_observer_
;
926 int update_enabled_types_call_count_
;
929 TEST_F(SyncManagerTest
, UpdateEnabledTypes
) {
930 EXPECT_EQ(0, update_enabled_types_call_count_
);
932 ModelSafeRoutingInfo routes
;
933 GetModelSafeRoutingInfo(&routes
);
934 const syncer::ModelTypeSet enabled_types
= GetRoutingInfoTypes(routes
);
936 sync_manager_
.UpdateEnabledTypes(enabled_types
);
937 EXPECT_EQ(1, update_enabled_types_call_count_
);
940 TEST_F(SyncManagerTest
, ProcessJsMessage
) {
941 const JsArgList kNoArgs
;
943 StrictMock
<MockJsReplyHandler
> reply_handler
;
945 ListValue false_args
;
946 false_args
.Append(Value::CreateBooleanValue(false));
948 EXPECT_CALL(reply_handler
,
949 HandleJsReply("getNotificationState",
950 HasArgsAsList(false_args
)));
952 // This message should be dropped.
953 SendJsMessage("unknownMessage", kNoArgs
, reply_handler
.AsWeakHandle());
955 SendJsMessage("getNotificationState", kNoArgs
, reply_handler
.AsWeakHandle());
958 TEST_F(SyncManagerTest
, ProcessJsMessageGetRootNodeDetails
) {
959 const JsArgList kNoArgs
;
961 StrictMock
<MockJsReplyHandler
> reply_handler
;
963 JsArgList return_args
;
965 EXPECT_CALL(reply_handler
,
966 HandleJsReply("getRootNodeDetails", _
))
967 .WillOnce(SaveArg
<1>(&return_args
));
969 SendJsMessage("getRootNodeDetails", kNoArgs
, reply_handler
.AsWeakHandle());
971 EXPECT_EQ(1u, return_args
.Get().GetSize());
972 DictionaryValue
* node_info
= NULL
;
973 EXPECT_TRUE(return_args
.Get().GetDictionary(0, &node_info
));
975 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
976 ReadNode
node(&trans
);
977 node
.InitByRootLookup();
978 CheckNodeValue(node
, *node_info
, true);
984 void CheckGetNodesByIdReturnArgs(const SyncManager
& sync_manager
,
985 const JsArgList
& return_args
,
988 EXPECT_EQ(1u, return_args
.Get().GetSize());
989 ListValue
* nodes
= NULL
;
990 ASSERT_TRUE(return_args
.Get().GetList(0, &nodes
));
992 EXPECT_EQ(1u, nodes
->GetSize());
993 DictionaryValue
* node_info
= NULL
;
994 EXPECT_TRUE(nodes
->GetDictionary(0, &node_info
));
995 ASSERT_TRUE(node_info
);
996 ReadTransaction
trans(FROM_HERE
, sync_manager
.GetUserShare());
997 ReadNode
node(&trans
);
998 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(id
));
999 CheckNodeValue(node
, *node_info
, is_detailed
);
1002 class SyncManagerGetNodesByIdTest
: public SyncManagerTest
{
1004 virtual ~SyncManagerGetNodesByIdTest() {}
1006 void RunGetNodesByIdTest(const char* message_name
, bool is_detailed
) {
1007 int64 root_id
= kInvalidId
;
1009 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1010 ReadNode
root_node(&trans
);
1011 root_node
.InitByRootLookup();
1012 root_id
= root_node
.GetId();
1016 MakeNode(sync_manager_
.GetUserShare(), syncer::BOOKMARKS
, "testtag");
1018 StrictMock
<MockJsReplyHandler
> reply_handler
;
1020 JsArgList return_args
;
1022 const int64 ids
[] = { root_id
, child_id
};
1024 EXPECT_CALL(reply_handler
,
1025 HandleJsReply(message_name
, _
))
1026 .Times(arraysize(ids
)).WillRepeatedly(SaveArg
<1>(&return_args
));
1028 for (size_t i
= 0; i
< arraysize(ids
); ++i
) {
1030 ListValue
* id_values
= new ListValue();
1031 args
.Append(id_values
);
1032 id_values
->Append(Value::CreateStringValue(base::Int64ToString(ids
[i
])));
1033 SendJsMessage(message_name
,
1034 JsArgList(&args
), reply_handler
.AsWeakHandle());
1036 CheckGetNodesByIdReturnArgs(sync_manager_
, return_args
,
1037 ids
[i
], is_detailed
);
1041 void RunGetNodesByIdFailureTest(const char* message_name
) {
1042 StrictMock
<MockJsReplyHandler
> reply_handler
;
1044 ListValue empty_list_args
;
1045 empty_list_args
.Append(new ListValue());
1047 EXPECT_CALL(reply_handler
,
1048 HandleJsReply(message_name
,
1049 HasArgsAsList(empty_list_args
)))
1054 SendJsMessage(message_name
,
1055 JsArgList(&args
), reply_handler
.AsWeakHandle());
1060 args
.Append(new ListValue());
1061 SendJsMessage(message_name
,
1062 JsArgList(&args
), reply_handler
.AsWeakHandle());
1067 ListValue
* ids
= new ListValue();
1069 ids
->Append(Value::CreateStringValue(""));
1070 SendJsMessage(message_name
,
1071 JsArgList(&args
), reply_handler
.AsWeakHandle());
1076 ListValue
* ids
= new ListValue();
1078 ids
->Append(Value::CreateStringValue("nonsense"));
1079 SendJsMessage(message_name
,
1080 JsArgList(&args
), reply_handler
.AsWeakHandle());
1085 ListValue
* ids
= new ListValue();
1087 ids
->Append(Value::CreateStringValue("0"));
1088 SendJsMessage(message_name
,
1089 JsArgList(&args
), reply_handler
.AsWeakHandle());
1094 ListValue
* ids
= new ListValue();
1096 ids
->Append(Value::CreateStringValue("9999"));
1097 SendJsMessage(message_name
,
1098 JsArgList(&args
), reply_handler
.AsWeakHandle());
1103 TEST_F(SyncManagerGetNodesByIdTest
, GetNodeSummariesById
) {
1104 RunGetNodesByIdTest("getNodeSummariesById", false);
1107 TEST_F(SyncManagerGetNodesByIdTest
, GetNodeDetailsById
) {
1108 RunGetNodesByIdTest("getNodeDetailsById", true);
1111 TEST_F(SyncManagerGetNodesByIdTest
, GetNodeSummariesByIdFailure
) {
1112 RunGetNodesByIdFailureTest("getNodeSummariesById");
1115 TEST_F(SyncManagerGetNodesByIdTest
, GetNodeDetailsByIdFailure
) {
1116 RunGetNodesByIdFailureTest("getNodeDetailsById");
1119 TEST_F(SyncManagerTest
, GetChildNodeIds
) {
1120 StrictMock
<MockJsReplyHandler
> reply_handler
;
1122 JsArgList return_args
;
1124 EXPECT_CALL(reply_handler
,
1125 HandleJsReply("getChildNodeIds", _
))
1126 .Times(1).WillRepeatedly(SaveArg
<1>(&return_args
));
1130 args
.Append(Value::CreateStringValue("1"));
1131 SendJsMessage("getChildNodeIds",
1132 JsArgList(&args
), reply_handler
.AsWeakHandle());
1135 EXPECT_EQ(1u, return_args
.Get().GetSize());
1136 ListValue
* nodes
= NULL
;
1137 ASSERT_TRUE(return_args
.Get().GetList(0, &nodes
));
1139 EXPECT_EQ(6u, nodes
->GetSize());
1142 TEST_F(SyncManagerTest
, GetChildNodeIdsFailure
) {
1143 StrictMock
<MockJsReplyHandler
> reply_handler
;
1145 ListValue empty_list_args
;
1146 empty_list_args
.Append(new ListValue());
1148 EXPECT_CALL(reply_handler
,
1149 HandleJsReply("getChildNodeIds",
1150 HasArgsAsList(empty_list_args
)))
1155 SendJsMessage("getChildNodeIds",
1156 JsArgList(&args
), reply_handler
.AsWeakHandle());
1161 args
.Append(Value::CreateStringValue(""));
1162 SendJsMessage("getChildNodeIds",
1163 JsArgList(&args
), reply_handler
.AsWeakHandle());
1168 args
.Append(Value::CreateStringValue("nonsense"));
1169 SendJsMessage("getChildNodeIds",
1170 JsArgList(&args
), reply_handler
.AsWeakHandle());
1175 args
.Append(Value::CreateStringValue("0"));
1176 SendJsMessage("getChildNodeIds",
1177 JsArgList(&args
), reply_handler
.AsWeakHandle());
1182 args
.Append(Value::CreateStringValue("9999"));
1183 SendJsMessage("getChildNodeIds",
1184 JsArgList(&args
), reply_handler
.AsWeakHandle());
1188 TEST_F(SyncManagerTest
, GetAllNodesTest
) {
1189 StrictMock
<MockJsReplyHandler
> reply_handler
;
1190 JsArgList return_args
;
1192 EXPECT_CALL(reply_handler
,
1193 HandleJsReply("getAllNodes", _
))
1194 .Times(1).WillRepeatedly(SaveArg
<1>(&return_args
));
1198 SendJsMessage("getAllNodes",
1199 JsArgList(&args
), reply_handler
.AsWeakHandle());
1202 // There's not much value in verifying every attribute on every node here.
1203 // Most of the value of this test has already been achieved: we've verified we
1204 // can call the above function without crashing or leaking memory.
1206 // Let's just check the list size and a few of its elements. Anything more
1207 // would make this test brittle without greatly increasing our chances of
1208 // catching real bugs.
1210 ListValue
* node_list
;
1211 DictionaryValue
* first_result
;
1213 // The resulting argument list should have one argument, a list of nodes.
1214 ASSERT_EQ(1U, return_args
.Get().GetSize());
1215 ASSERT_TRUE(return_args
.Get().GetList(0, &node_list
));
1217 // The database creation logic depends on the routing info.
1218 // Refer to setup methods for more information.
1219 ModelSafeRoutingInfo routes
;
1220 GetModelSafeRoutingInfo(&routes
);
1221 size_t directory_size
= routes
.size() + 1;
1223 ASSERT_EQ(directory_size
, node_list
->GetSize());
1224 ASSERT_TRUE(node_list
->GetDictionary(0, &first_result
));
1225 EXPECT_TRUE(first_result
->HasKey("ID"));
1226 EXPECT_TRUE(first_result
->HasKey("NON_UNIQUE_NAME"));
1229 TEST_F(SyncManagerTest
, OnNotificationStateChange
) {
1231 StrictMock
<MockJsEventHandler
> event_handler
;
1233 DictionaryValue true_details
;
1234 true_details
.SetBoolean("enabled", true);
1235 DictionaryValue false_details
;
1236 false_details
.SetBoolean("enabled", false);
1238 EXPECT_CALL(event_handler
,
1239 HandleJsEvent("onNotificationStateChange",
1240 HasDetailsAsDictionary(true_details
)));
1241 EXPECT_CALL(event_handler
,
1242 HandleJsEvent("onNotificationStateChange",
1243 HasDetailsAsDictionary(false_details
)));
1245 sync_manager_
.SimulateEnableNotificationsForTest();
1246 sync_manager_
.SimulateDisableNotificationsForTest(
1247 syncer::TRANSIENT_NOTIFICATION_ERROR
);
1249 SetJsEventHandler(event_handler
.AsWeakHandle());
1250 sync_manager_
.SimulateEnableNotificationsForTest();
1251 sync_manager_
.SimulateDisableNotificationsForTest(
1252 syncer::TRANSIENT_NOTIFICATION_ERROR
);
1253 SetJsEventHandler(WeakHandle
<JsEventHandler
>());
1255 sync_manager_
.SimulateEnableNotificationsForTest();
1256 sync_manager_
.SimulateDisableNotificationsForTest(
1257 syncer::TRANSIENT_NOTIFICATION_ERROR
);
1259 // Should trigger the replies.
1263 TEST_F(SyncManagerTest
, OnIncomingNotification
) {
1264 StrictMock
<MockJsEventHandler
> event_handler
;
1266 const syncer::ModelTypeSet empty_model_types
;
1267 const syncer::ModelTypeSet
model_types(
1268 syncer::BOOKMARKS
, syncer::THEMES
);
1270 // Build expected_args to have a single argument with the string
1271 // equivalents of model_types.
1272 DictionaryValue expected_details
;
1274 ListValue
* model_type_list
= new ListValue();
1275 expected_details
.SetString("source", "REMOTE_NOTIFICATION");
1276 expected_details
.Set("changedTypes", model_type_list
);
1277 for (syncer::ModelTypeSet::Iterator it
= model_types
.First();
1278 it
.Good(); it
.Inc()) {
1279 model_type_list
->Append(
1280 Value::CreateStringValue(syncer::ModelTypeToString(it
.Get())));
1284 EXPECT_CALL(event_handler
,
1285 HandleJsEvent("onIncomingNotification",
1286 HasDetailsAsDictionary(expected_details
)));
1288 sync_manager_
.TriggerOnIncomingNotificationForTest(empty_model_types
);
1289 sync_manager_
.TriggerOnIncomingNotificationForTest(model_types
);
1291 SetJsEventHandler(event_handler
.AsWeakHandle());
1292 sync_manager_
.TriggerOnIncomingNotificationForTest(model_types
);
1293 SetJsEventHandler(WeakHandle
<JsEventHandler
>());
1295 sync_manager_
.TriggerOnIncomingNotificationForTest(empty_model_types
);
1296 sync_manager_
.TriggerOnIncomingNotificationForTest(model_types
);
1298 // Should trigger the replies.
1302 TEST_F(SyncManagerTest
, RefreshEncryptionReady
) {
1303 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1304 EXPECT_CALL(observer_
, OnEncryptionComplete());
1306 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
1309 const syncer::ModelTypeSet encrypted_types
=
1310 sync_manager_
.GetEncryptedDataTypesForTest();
1311 EXPECT_TRUE(encrypted_types
.Has(syncer::PASSWORDS
));
1312 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1314 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1315 ReadNode
node(&trans
);
1316 EXPECT_EQ(BaseNode::INIT_OK
,
1317 node
.InitByIdLookup(GetIdForDataType(syncer::NIGORI
)));
1318 sync_pb::NigoriSpecifics nigori
= node
.GetNigoriSpecifics();
1319 EXPECT_TRUE(nigori
.has_encrypted());
1320 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1321 EXPECT_TRUE(cryptographer
->is_ready());
1322 EXPECT_TRUE(cryptographer
->CanDecrypt(nigori
.encrypted()));
1326 // Attempt to refresh encryption when nigori not downloaded.
1327 TEST_F(SyncManagerTest
, RefreshEncryptionNotReady
) {
1328 // Don't set up encryption (no nigori node created).
1331 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
1334 const syncer::ModelTypeSet encrypted_types
=
1335 sync_manager_
.GetEncryptedDataTypesForTest();
1336 EXPECT_TRUE(encrypted_types
.Has(syncer::PASSWORDS
)); // Hardcoded.
1337 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1340 // Attempt to refresh encryption when nigori is empty.
1341 TEST_F(SyncManagerTest
, RefreshEncryptionEmptyNigori
) {
1342 EXPECT_TRUE(SetUpEncryption(DONT_WRITE_NIGORI
, DEFAULT_ENCRYPTION
));
1343 EXPECT_CALL(observer_
, OnEncryptionComplete());
1345 // Should write to nigori.
1346 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
1349 const syncer::ModelTypeSet encrypted_types
=
1350 sync_manager_
.GetEncryptedDataTypesForTest();
1351 EXPECT_TRUE(encrypted_types
.Has(syncer::PASSWORDS
)); // Hardcoded.
1352 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1354 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1355 ReadNode
node(&trans
);
1356 EXPECT_EQ(BaseNode::INIT_OK
,
1357 node
.InitByIdLookup(GetIdForDataType(syncer::NIGORI
)));
1358 sync_pb::NigoriSpecifics nigori
= node
.GetNigoriSpecifics();
1359 EXPECT_TRUE(nigori
.has_encrypted());
1360 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1361 EXPECT_TRUE(cryptographer
->is_ready());
1362 EXPECT_TRUE(cryptographer
->CanDecrypt(nigori
.encrypted()));
1366 TEST_F(SyncManagerTest
, EncryptDataTypesWithNoData
) {
1367 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1368 EXPECT_CALL(observer_
,
1369 OnEncryptedTypesChanged(
1370 HasModelTypes(syncer::ModelTypeSet::All()), true));
1371 EXPECT_CALL(observer_
, OnEncryptionComplete());
1372 sync_manager_
.EnableEncryptEverything();
1373 EXPECT_TRUE(sync_manager_
.EncryptEverythingEnabledForTest());
1376 TEST_F(SyncManagerTest
, EncryptDataTypesWithData
) {
1377 size_t batch_size
= 5;
1378 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1380 // Create some unencrypted unsynced data.
1381 int64 folder
= MakeFolderWithParent(sync_manager_
.GetUserShare(),
1383 GetIdForDataType(syncer::BOOKMARKS
),
1385 // First batch_size nodes are children of folder.
1387 for (i
= 0; i
< batch_size
; ++i
) {
1388 MakeNodeWithParent(sync_manager_
.GetUserShare(), syncer::BOOKMARKS
,
1389 base::StringPrintf("%"PRIuS
"", i
), folder
);
1391 // Next batch_size nodes are a different type and on their own.
1392 for (; i
< 2*batch_size
; ++i
) {
1393 MakeNodeWithParent(sync_manager_
.GetUserShare(), syncer::SESSIONS
,
1394 base::StringPrintf("%"PRIuS
"", i
),
1395 GetIdForDataType(syncer::SESSIONS
));
1397 // Last batch_size nodes are a third type that will not need encryption.
1398 for (; i
< 3*batch_size
; ++i
) {
1399 MakeNodeWithParent(sync_manager_
.GetUserShare(), syncer::THEMES
,
1400 base::StringPrintf("%"PRIuS
"", i
),
1401 GetIdForDataType(syncer::THEMES
));
1405 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1406 EXPECT_TRUE(GetEncryptedTypes(&trans
).Equals(
1407 Cryptographer::SensitiveTypes()));
1408 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1409 trans
.GetWrappedTrans(),
1410 trans
.GetCryptographer(),
1412 false /* not encrypted */));
1413 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1414 trans
.GetWrappedTrans(),
1415 trans
.GetCryptographer(),
1417 false /* not encrypted */));
1418 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1419 trans
.GetWrappedTrans(),
1420 trans
.GetCryptographer(),
1422 false /* not encrypted */));
1425 EXPECT_CALL(observer_
,
1426 OnEncryptedTypesChanged(
1427 HasModelTypes(syncer::ModelTypeSet::All()), true));
1428 EXPECT_CALL(observer_
, OnEncryptionComplete());
1429 sync_manager_
.EnableEncryptEverything();
1430 EXPECT_TRUE(sync_manager_
.EncryptEverythingEnabledForTest());
1432 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1433 EXPECT_TRUE(GetEncryptedTypes(&trans
).Equals(
1434 syncer::ModelTypeSet::All()));
1435 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1436 trans
.GetWrappedTrans(),
1437 trans
.GetCryptographer(),
1439 true /* is encrypted */));
1440 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1441 trans
.GetWrappedTrans(),
1442 trans
.GetCryptographer(),
1444 true /* is encrypted */));
1445 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1446 trans
.GetWrappedTrans(),
1447 trans
.GetCryptographer(),
1449 true /* is encrypted */));
1452 // Trigger's a ReEncryptEverything with new passphrase.
1453 testing::Mock::VerifyAndClearExpectations(&observer_
);
1454 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1455 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1456 EXPECT_CALL(observer_
, OnEncryptionComplete());
1457 sync_manager_
.SetEncryptionPassphrase("new_passphrase", true);
1458 EXPECT_TRUE(sync_manager_
.EncryptEverythingEnabledForTest());
1460 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1461 EXPECT_TRUE(GetEncryptedTypes(&trans
).Equals(syncer::ModelTypeSet::All()));
1462 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1463 trans
.GetWrappedTrans(),
1464 trans
.GetCryptographer(),
1466 true /* is encrypted */));
1467 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1468 trans
.GetWrappedTrans(),
1469 trans
.GetCryptographer(),
1471 true /* is encrypted */));
1472 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1473 trans
.GetWrappedTrans(),
1474 trans
.GetCryptographer(),
1476 true /* is encrypted */));
1478 // Calling EncryptDataTypes with an empty encrypted types should not trigger
1479 // a reencryption and should just notify immediately.
1480 // TODO(zea): add logic to ensure nothing was written.
1481 testing::Mock::VerifyAndClearExpectations(&observer_
);
1482 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
)).Times(0);
1483 EXPECT_CALL(observer_
, OnPassphraseAccepted()).Times(0);
1484 EXPECT_CALL(observer_
, OnEncryptionComplete());
1485 sync_manager_
.EnableEncryptEverything();
1488 // Test that when there are no pending keys and the cryptographer is not
1489 // initialized, we add a key based on the current GAIA password.
1490 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1491 TEST_F(SyncManagerTest
, SetInitialGaiaPass
) {
1492 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI
, UNINITIALIZED
));
1493 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1494 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1495 EXPECT_CALL(observer_
, OnEncryptionComplete());
1496 sync_manager_
.SetEncryptionPassphrase("new_passphrase", false);
1497 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1499 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1500 ReadNode
node(&trans
);
1501 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByTagLookup(kNigoriTag
));
1502 sync_pb::NigoriSpecifics nigori
= node
.GetNigoriSpecifics();
1503 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1504 EXPECT_TRUE(cryptographer
->is_ready());
1505 EXPECT_TRUE(cryptographer
->CanDecrypt(nigori
.encrypted()));
1509 // Test that when there are no pending keys and we have on the old GAIA
1510 // password, we update and re-encrypt everything with the new GAIA password.
1511 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1512 TEST_F(SyncManagerTest
, UpdateGaiaPass
) {
1513 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1514 Cryptographer
verifier(&encryptor_
);
1516 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1517 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1518 std::string bootstrap_token
;
1519 cryptographer
->GetBootstrapToken(&bootstrap_token
);
1520 verifier
.Bootstrap(bootstrap_token
);
1522 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1523 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1524 EXPECT_CALL(observer_
, OnEncryptionComplete());
1525 sync_manager_
.SetEncryptionPassphrase("new_passphrase", false);
1526 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1528 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1529 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1530 EXPECT_TRUE(cryptographer
->is_ready());
1531 // Verify the default key has changed.
1532 sync_pb::EncryptedData encrypted
;
1533 cryptographer
->GetKeys(&encrypted
);
1534 EXPECT_FALSE(verifier
.CanDecrypt(encrypted
));
1538 // Sets a new explicit passphrase. This should update the bootstrap token
1539 // and re-encrypt everything.
1540 // (case 2 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1541 TEST_F(SyncManagerTest
, SetPassphraseWithPassword
) {
1542 Cryptographer
verifier(&encryptor_
);
1543 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1545 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1546 // Store the default (soon to be old) key.
1547 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1548 std::string bootstrap_token
;
1549 cryptographer
->GetBootstrapToken(&bootstrap_token
);
1550 verifier
.Bootstrap(bootstrap_token
);
1552 ReadNode
root_node(&trans
);
1553 root_node
.InitByRootLookup();
1555 WriteNode
password_node(&trans
);
1556 syncer::WriteNode::InitUniqueByCreationResult result
=
1557 password_node
.InitUniqueByCreation(syncer::PASSWORDS
,
1559 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
1560 sync_pb::PasswordSpecificsData data
;
1561 data
.set_password_value("secret");
1562 password_node
.SetPasswordSpecifics(data
);
1564 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1565 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1566 EXPECT_CALL(observer_
, OnEncryptionComplete());
1567 sync_manager_
.SetEncryptionPassphrase("new_passphrase", true);
1568 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1570 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1571 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1572 EXPECT_TRUE(cryptographer
->is_ready());
1573 // Verify the default key has changed.
1574 sync_pb::EncryptedData encrypted
;
1575 cryptographer
->GetKeys(&encrypted
);
1576 EXPECT_FALSE(verifier
.CanDecrypt(encrypted
));
1578 ReadNode
password_node(&trans
);
1579 EXPECT_EQ(BaseNode::INIT_OK
,
1580 password_node
.InitByClientTagLookup(syncer::PASSWORDS
,
1582 const sync_pb::PasswordSpecificsData
& data
=
1583 password_node
.GetPasswordSpecifics();
1584 EXPECT_EQ("secret", data
.password_value());
1588 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1589 // being encrypted with a new (unprovided) GAIA password, then supply the
1591 // (case 7 in SyncManager::SyncInternal::SetDecryptionPassphrase)
1592 TEST_F(SyncManagerTest
, SupplyPendingGAIAPass
) {
1593 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1594 Cryptographer
other_cryptographer(&encryptor_
);
1596 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1597 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1598 std::string bootstrap_token
;
1599 cryptographer
->GetBootstrapToken(&bootstrap_token
);
1600 other_cryptographer
.Bootstrap(bootstrap_token
);
1602 // Now update the nigori to reflect the new keys, and update the
1603 // cryptographer to have pending keys.
1604 KeyParams params
= {"localhost", "dummy", "passphrase2"};
1605 other_cryptographer
.AddKey(params
);
1606 WriteNode
node(&trans
);
1607 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByTagLookup(kNigoriTag
));
1608 sync_pb::NigoriSpecifics nigori
;
1609 other_cryptographer
.GetKeys(nigori
.mutable_encrypted());
1610 cryptographer
->Update(nigori
);
1611 EXPECT_TRUE(cryptographer
->has_pending_keys());
1612 node
.SetNigoriSpecifics(nigori
);
1614 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1615 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1616 EXPECT_CALL(observer_
, OnEncryptionComplete());
1617 sync_manager_
.SetDecryptionPassphrase("passphrase2");
1618 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1620 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1621 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1622 EXPECT_TRUE(cryptographer
->is_ready());
1623 // Verify we're encrypting with the new key.
1624 sync_pb::EncryptedData encrypted
;
1625 cryptographer
->GetKeys(&encrypted
);
1626 EXPECT_TRUE(other_cryptographer
.CanDecrypt(encrypted
));
1630 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1631 // being encrypted with an old (unprovided) GAIA password. Attempt to supply
1632 // the current GAIA password and verify the bootstrap token is updated. Then
1633 // supply the old GAIA password, and verify we re-encrypt all data with the
1634 // new GAIA password.
1635 // (cases 4 and 5 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1636 TEST_F(SyncManagerTest
, SupplyPendingOldGAIAPass
) {
1637 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1638 Cryptographer
other_cryptographer(&encryptor_
);
1640 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1641 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1642 std::string bootstrap_token
;
1643 cryptographer
->GetBootstrapToken(&bootstrap_token
);
1644 other_cryptographer
.Bootstrap(bootstrap_token
);
1646 // Now update the nigori to reflect the new keys, and update the
1647 // cryptographer to have pending keys.
1648 KeyParams params
= {"localhost", "dummy", "old_gaia"};
1649 other_cryptographer
.AddKey(params
);
1650 WriteNode
node(&trans
);
1651 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByTagLookup(kNigoriTag
));
1652 sync_pb::NigoriSpecifics nigori
;
1653 other_cryptographer
.GetKeys(nigori
.mutable_encrypted());
1654 node
.SetNigoriSpecifics(nigori
);
1655 cryptographer
->Update(nigori
);
1657 // other_cryptographer now contains all encryption keys, and is encrypting
1658 // with the newest gaia.
1659 KeyParams new_params
= {"localhost", "dummy", "new_gaia"};
1660 other_cryptographer
.AddKey(new_params
);
1662 // The bootstrap token should have been updated. Save it to ensure it's based
1663 // on the new GAIA password.
1664 std::string bootstrap_token
;
1665 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
))
1666 .WillOnce(SaveArg
<0>(&bootstrap_token
));
1667 EXPECT_CALL(observer_
, OnPassphraseRequired(_
,_
));
1668 sync_manager_
.SetEncryptionPassphrase("new_gaia", false);
1669 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1670 testing::Mock::VerifyAndClearExpectations(&observer_
);
1672 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1673 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1674 EXPECT_TRUE(cryptographer
->is_initialized());
1675 EXPECT_FALSE(cryptographer
->is_ready());
1676 // Verify we're encrypting with the new key, even though we have pending
1678 sync_pb::EncryptedData encrypted
;
1679 other_cryptographer
.GetKeys(&encrypted
);
1680 EXPECT_TRUE(cryptographer
->CanDecrypt(encrypted
));
1682 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1683 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1684 EXPECT_CALL(observer_
, OnEncryptionComplete());
1685 sync_manager_
.SetEncryptionPassphrase("old_gaia", false);
1687 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1688 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1689 EXPECT_TRUE(cryptographer
->is_ready());
1691 // Verify we're encrypting with the new key.
1692 sync_pb::EncryptedData encrypted
;
1693 other_cryptographer
.GetKeys(&encrypted
);
1694 EXPECT_TRUE(cryptographer
->CanDecrypt(encrypted
));
1696 // Verify the saved bootstrap token is based on the new gaia password.
1697 Cryptographer
temp_cryptographer(&encryptor_
);
1698 temp_cryptographer
.Bootstrap(bootstrap_token
);
1699 EXPECT_TRUE(temp_cryptographer
.CanDecrypt(encrypted
));
1703 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1704 // being encrypted with an explicit (unprovided) passphrase, then supply the
1706 // (case 9 in SyncManager::SyncInternal::SetDecryptionPassphrase)
1707 TEST_F(SyncManagerTest
, SupplyPendingExplicitPass
) {
1708 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1709 Cryptographer
other_cryptographer(&encryptor_
);
1711 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1712 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1713 std::string bootstrap_token
;
1714 cryptographer
->GetBootstrapToken(&bootstrap_token
);
1715 other_cryptographer
.Bootstrap(bootstrap_token
);
1717 // Now update the nigori to reflect the new keys, and update the
1718 // cryptographer to have pending keys.
1719 KeyParams params
= {"localhost", "dummy", "explicit"};
1720 other_cryptographer
.AddKey(params
);
1721 WriteNode
node(&trans
);
1722 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByTagLookup(kNigoriTag
));
1723 sync_pb::NigoriSpecifics nigori
;
1724 other_cryptographer
.GetKeys(nigori
.mutable_encrypted());
1725 cryptographer
->Update(nigori
);
1726 EXPECT_TRUE(cryptographer
->has_pending_keys());
1727 nigori
.set_using_explicit_passphrase(true);
1728 node
.SetNigoriSpecifics(nigori
);
1730 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1731 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1732 EXPECT_CALL(observer_
, OnEncryptionComplete());
1733 sync_manager_
.SetDecryptionPassphrase("explicit");
1734 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1736 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1737 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1738 EXPECT_TRUE(cryptographer
->is_ready());
1739 // Verify we're encrypting with the new key.
1740 sync_pb::EncryptedData encrypted
;
1741 cryptographer
->GetKeys(&encrypted
);
1742 EXPECT_TRUE(other_cryptographer
.CanDecrypt(encrypted
));
1746 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1747 // being encrypted with a new (unprovided) GAIA password, then supply the
1748 // password as a user-provided password.
1749 // This is the android case 7/8.
1750 TEST_F(SyncManagerTest
, SupplyPendingGAIAPassUserProvided
) {
1751 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI
, UNINITIALIZED
));
1752 Cryptographer
other_cryptographer(&encryptor_
);
1754 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1755 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1756 // Now update the nigori to reflect the new keys, and update the
1757 // cryptographer to have pending keys.
1758 KeyParams params
= {"localhost", "dummy", "passphrase"};
1759 other_cryptographer
.AddKey(params
);
1760 WriteNode
node(&trans
);
1761 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByTagLookup(kNigoriTag
));
1762 sync_pb::NigoriSpecifics nigori
;
1763 other_cryptographer
.GetKeys(nigori
.mutable_encrypted());
1764 node
.SetNigoriSpecifics(nigori
);
1765 cryptographer
->Update(nigori
);
1766 EXPECT_FALSE(cryptographer
->is_ready());
1768 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1769 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1770 EXPECT_CALL(observer_
, OnEncryptionComplete());
1771 sync_manager_
.SetEncryptionPassphrase("passphrase", false);
1772 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1774 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1775 Cryptographer
* cryptographer
= trans
.GetCryptographer();
1776 EXPECT_TRUE(cryptographer
->is_ready());
1780 TEST_F(SyncManagerTest
, SetPassphraseWithEmptyPasswordNode
) {
1781 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1783 std::string tag
= "foo";
1785 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1786 ReadNode
root_node(&trans
);
1787 root_node
.InitByRootLookup();
1789 WriteNode
password_node(&trans
);
1790 syncer::WriteNode::InitUniqueByCreationResult result
=
1791 password_node
.InitUniqueByCreation(syncer::PASSWORDS
, root_node
, tag
);
1792 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
1793 node_id
= password_node
.GetId();
1795 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
1796 EXPECT_CALL(observer_
, OnPassphraseAccepted());
1797 EXPECT_CALL(observer_
, OnEncryptionComplete());
1798 sync_manager_
.SetEncryptionPassphrase("new_passphrase", true);
1799 EXPECT_FALSE(sync_manager_
.EncryptEverythingEnabledForTest());
1801 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1802 ReadNode
password_node(&trans
);
1803 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
,
1804 password_node
.InitByClientTagLookup(syncer::PASSWORDS
,
1808 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1809 ReadNode
password_node(&trans
);
1810 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY
,
1811 password_node
.InitByIdLookup(node_id
));
1815 TEST_F(SyncManagerTest
, NudgeDelayTest
) {
1816 EXPECT_EQ(sync_manager_
.GetNudgeDelayTimeDelta(syncer::BOOKMARKS
),
1817 base::TimeDelta::FromMilliseconds(
1818 SyncManager::kDefaultNudgeDelayMilliseconds
));
1820 EXPECT_EQ(sync_manager_
.GetNudgeDelayTimeDelta(syncer::AUTOFILL
),
1821 base::TimeDelta::FromSeconds(
1822 syncer::kDefaultShortPollIntervalSeconds
));
1824 EXPECT_EQ(sync_manager_
.GetNudgeDelayTimeDelta(syncer::PREFERENCES
),
1825 base::TimeDelta::FromMilliseconds(
1826 SyncManager::kPreferencesNudgeDelayMilliseconds
));
1829 // Friended by WriteNode, so can't be in an anonymouse namespace.
1830 TEST_F(SyncManagerTest
, EncryptBookmarksWithLegacyData
) {
1831 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
1833 SyncAPINameToServerName("Google", &title
);
1834 std::string url
= "http://www.google.com";
1835 std::string raw_title2
= ".."; // An invalid cosmo title.
1837 SyncAPINameToServerName(raw_title2
, &title2
);
1838 std::string url2
= "http://www.bla.com";
1840 // Create a bookmark using the legacy format.
1841 int64 node_id1
= MakeNode(sync_manager_
.GetUserShare(),
1844 int64 node_id2
= MakeNode(sync_manager_
.GetUserShare(),
1848 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1849 WriteNode
node(&trans
);
1850 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(node_id1
));
1852 sync_pb::EntitySpecifics entity_specifics
;
1853 entity_specifics
.mutable_bookmark()->set_url(url
);
1854 node
.SetEntitySpecifics(entity_specifics
);
1856 // Set the old style title.
1857 syncable::MutableEntry
* node_entry
= node
.entry_
;
1858 node_entry
->Put(syncable::NON_UNIQUE_NAME
, title
);
1860 WriteNode
node2(&trans
);
1861 EXPECT_EQ(BaseNode::INIT_OK
, node2
.InitByIdLookup(node_id2
));
1863 sync_pb::EntitySpecifics entity_specifics2
;
1864 entity_specifics2
.mutable_bookmark()->set_url(url2
);
1865 node2
.SetEntitySpecifics(entity_specifics2
);
1867 // Set the old style title.
1868 syncable::MutableEntry
* node_entry2
= node2
.entry_
;
1869 node_entry2
->Put(syncable::NON_UNIQUE_NAME
, title2
);
1873 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1874 ReadNode
node(&trans
);
1875 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(node_id1
));
1876 EXPECT_EQ(syncer::BOOKMARKS
, node
.GetModelType());
1877 EXPECT_EQ(title
, node
.GetTitle());
1878 EXPECT_EQ(title
, node
.GetBookmarkSpecifics().title());
1879 EXPECT_EQ(url
, node
.GetBookmarkSpecifics().url());
1881 ReadNode
node2(&trans
);
1882 EXPECT_EQ(BaseNode::INIT_OK
, node2
.InitByIdLookup(node_id2
));
1883 EXPECT_EQ(syncer::BOOKMARKS
, node2
.GetModelType());
1884 // We should de-canonicalize the title in GetTitle(), but the title in the
1885 // specifics should be stored in the server legal form.
1886 EXPECT_EQ(raw_title2
, node2
.GetTitle());
1887 EXPECT_EQ(title2
, node2
.GetBookmarkSpecifics().title());
1888 EXPECT_EQ(url2
, node2
.GetBookmarkSpecifics().url());
1892 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1893 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1894 trans
.GetWrappedTrans(),
1895 trans
.GetCryptographer(),
1897 false /* not encrypted */));
1900 EXPECT_CALL(observer_
,
1901 OnEncryptedTypesChanged(
1902 HasModelTypes(syncer::ModelTypeSet::All()), true));
1903 EXPECT_CALL(observer_
, OnEncryptionComplete());
1904 sync_manager_
.EnableEncryptEverything();
1905 EXPECT_TRUE(sync_manager_
.EncryptEverythingEnabledForTest());
1908 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1909 EXPECT_TRUE(GetEncryptedTypes(&trans
).Equals(syncer::ModelTypeSet::All()));
1910 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1911 trans
.GetWrappedTrans(),
1912 trans
.GetCryptographer(),
1914 true /* is encrypted */));
1916 ReadNode
node(&trans
);
1917 EXPECT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(node_id1
));
1918 EXPECT_EQ(syncer::BOOKMARKS
, node
.GetModelType());
1919 EXPECT_EQ(title
, node
.GetTitle());
1920 EXPECT_EQ(title
, node
.GetBookmarkSpecifics().title());
1921 EXPECT_EQ(url
, node
.GetBookmarkSpecifics().url());
1923 ReadNode
node2(&trans
);
1924 EXPECT_EQ(BaseNode::INIT_OK
, node2
.InitByIdLookup(node_id2
));
1925 EXPECT_EQ(syncer::BOOKMARKS
, node2
.GetModelType());
1926 // We should de-canonicalize the title in GetTitle(), but the title in the
1927 // specifics should be stored in the server legal form.
1928 EXPECT_EQ(raw_title2
, node2
.GetTitle());
1929 EXPECT_EQ(title2
, node2
.GetBookmarkSpecifics().title());
1930 EXPECT_EQ(url2
, node2
.GetBookmarkSpecifics().url());
1934 // Create a bookmark and set the title/url, then verify the data was properly
1935 // set. This replicates the unique way bookmarks have of creating sync nodes.
1936 // See BookmarkChangeProcessor::PlaceSyncNode(..).
1937 TEST_F(SyncManagerTest
, CreateLocalBookmark
) {
1938 std::string title
= "title";
1941 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1942 ReadNode
root_node(&trans
);
1943 root_node
.InitByRootLookup();
1944 WriteNode
node(&trans
);
1945 ASSERT_TRUE(node
.InitByCreation(syncer::BOOKMARKS
, root_node
, NULL
));
1946 node
.SetIsFolder(false);
1947 node
.SetTitle(UTF8ToWide(title
));
1951 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1952 ReadNode
root_node(&trans
);
1953 root_node
.InitByRootLookup();
1954 int64 child_id
= root_node
.GetFirstChildId();
1956 ReadNode
node(&trans
);
1957 ASSERT_EQ(BaseNode::INIT_OK
, node
.InitByIdLookup(child_id
));
1958 EXPECT_FALSE(node
.GetIsFolder());
1959 EXPECT_EQ(title
, node
.GetTitle());
1960 EXPECT_EQ(url
, node
.GetURL());
1964 // Verifies WriteNode::UpdateEntryWithEncryption does not make unnecessary
1966 TEST_F(SyncManagerTest
, UpdateEntryWithEncryption
) {
1967 std::string client_tag
= "title";
1968 sync_pb::EntitySpecifics entity_specifics
;
1969 entity_specifics
.mutable_bookmark()->set_url("url");
1970 entity_specifics
.mutable_bookmark()->set_title("title");
1971 MakeServerNode(sync_manager_
.GetUserShare(), syncer::BOOKMARKS
, client_tag
,
1972 BaseNode::GenerateSyncableHash(syncer::BOOKMARKS
,
1975 // New node shouldn't start off unsynced.
1976 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
1977 // Manually change to the same data. Should not set is_unsynced.
1979 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1980 WriteNode
node(&trans
);
1981 EXPECT_EQ(BaseNode::INIT_OK
,
1982 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
1983 node
.SetEntitySpecifics(entity_specifics
);
1985 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
1987 // Encrypt the datatatype, should set is_unsynced.
1988 EXPECT_CALL(observer_
,
1989 OnEncryptedTypesChanged(
1990 HasModelTypes(syncer::ModelTypeSet::All()), true));
1991 EXPECT_CALL(observer_
, OnEncryptionComplete());
1992 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, FULL_ENCRYPTION
));
1994 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
1997 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
1998 ReadNode
node(&trans
);
1999 EXPECT_EQ(BaseNode::INIT_OK
,
2000 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2001 const syncable::Entry
* node_entry
= node
.GetEntry();
2002 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2003 EXPECT_TRUE(specifics
.has_encrypted());
2004 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2005 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2006 EXPECT_TRUE(cryptographer
->is_ready());
2007 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
2008 specifics
.encrypted()));
2010 EXPECT_TRUE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2012 // Set a new passphrase. Should set is_unsynced.
2013 testing::Mock::VerifyAndClearExpectations(&observer_
);
2014 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
2015 EXPECT_CALL(observer_
, OnPassphraseAccepted());
2016 EXPECT_CALL(observer_
, OnEncryptionComplete());
2017 sync_manager_
.SetEncryptionPassphrase("new_passphrase", true);
2019 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2020 ReadNode
node(&trans
);
2021 EXPECT_EQ(BaseNode::INIT_OK
,
2022 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2023 const syncable::Entry
* node_entry
= node
.GetEntry();
2024 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2025 EXPECT_TRUE(specifics
.has_encrypted());
2026 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2027 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2028 EXPECT_TRUE(cryptographer
->is_ready());
2029 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
2030 specifics
.encrypted()));
2032 EXPECT_TRUE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2034 // Force a re-encrypt everything. Should not set is_unsynced.
2035 testing::Mock::VerifyAndClearExpectations(&observer_
);
2036 EXPECT_CALL(observer_
, OnEncryptionComplete());
2038 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
2042 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2043 ReadNode
node(&trans
);
2044 EXPECT_EQ(BaseNode::INIT_OK
,
2045 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2046 const syncable::Entry
* node_entry
= node
.GetEntry();
2047 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2048 EXPECT_TRUE(specifics
.has_encrypted());
2049 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2050 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2051 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
2052 specifics
.encrypted()));
2054 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2056 // Manually change to the same data. Should not set is_unsynced.
2058 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2059 WriteNode
node(&trans
);
2060 EXPECT_EQ(BaseNode::INIT_OK
,
2061 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2062 node
.SetEntitySpecifics(entity_specifics
);
2063 const syncable::Entry
* node_entry
= node
.GetEntry();
2064 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2065 EXPECT_TRUE(specifics
.has_encrypted());
2066 EXPECT_FALSE(node_entry
->Get(IS_UNSYNCED
));
2067 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2068 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2069 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
2070 specifics
.encrypted()));
2072 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2074 // Manually change to different data. Should set is_unsynced.
2076 entity_specifics
.mutable_bookmark()->set_url("url2");
2077 entity_specifics
.mutable_bookmark()->set_title("title2");
2078 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2079 WriteNode
node(&trans
);
2080 EXPECT_EQ(BaseNode::INIT_OK
,
2081 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2082 node
.SetEntitySpecifics(entity_specifics
);
2083 const syncable::Entry
* node_entry
= node
.GetEntry();
2084 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2085 EXPECT_TRUE(specifics
.has_encrypted());
2086 EXPECT_TRUE(node_entry
->Get(IS_UNSYNCED
));
2087 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2088 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2089 EXPECT_TRUE(cryptographer
->CanDecryptUsingDefaultKey(
2090 specifics
.encrypted()));
2094 // Passwords have their own handling for encryption. Verify it does not result
2095 // in unnecessary writes via SetEntitySpecifics.
2096 TEST_F(SyncManagerTest
, UpdatePasswordSetEntitySpecificsNoChange
) {
2097 std::string client_tag
= "title";
2098 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
2099 sync_pb::EntitySpecifics entity_specifics
;
2101 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2102 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2103 sync_pb::PasswordSpecificsData data
;
2104 data
.set_password_value("secret");
2105 cryptographer
->Encrypt(
2107 entity_specifics
.mutable_password()->
2108 mutable_encrypted());
2110 MakeServerNode(sync_manager_
.GetUserShare(), syncer::PASSWORDS
, client_tag
,
2111 BaseNode::GenerateSyncableHash(syncer::PASSWORDS
,
2114 // New node shouldn't start off unsynced.
2115 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2117 // Manually change to the same data via SetEntitySpecifics. Should not set
2120 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2121 WriteNode
node(&trans
);
2122 EXPECT_EQ(BaseNode::INIT_OK
,
2123 node
.InitByClientTagLookup(syncer::PASSWORDS
, client_tag
));
2124 node
.SetEntitySpecifics(entity_specifics
);
2126 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2129 // Passwords have their own handling for encryption. Verify it does not result
2130 // in unnecessary writes via SetPasswordSpecifics.
2131 TEST_F(SyncManagerTest
, UpdatePasswordSetPasswordSpecifics
) {
2132 std::string client_tag
= "title";
2133 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
2134 sync_pb::EntitySpecifics entity_specifics
;
2136 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2137 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2138 sync_pb::PasswordSpecificsData data
;
2139 data
.set_password_value("secret");
2140 cryptographer
->Encrypt(
2142 entity_specifics
.mutable_password()->
2143 mutable_encrypted());
2145 MakeServerNode(sync_manager_
.GetUserShare(), syncer::PASSWORDS
, client_tag
,
2146 BaseNode::GenerateSyncableHash(syncer::PASSWORDS
,
2149 // New node shouldn't start off unsynced.
2150 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2152 // Manually change to the same data via SetPasswordSpecifics. Should not set
2155 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2156 WriteNode
node(&trans
);
2157 EXPECT_EQ(BaseNode::INIT_OK
,
2158 node
.InitByClientTagLookup(syncer::PASSWORDS
, client_tag
));
2159 node
.SetPasswordSpecifics(node
.GetPasswordSpecifics());
2161 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2163 // Manually change to different data. Should set is_unsynced.
2165 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2166 WriteNode
node(&trans
);
2167 EXPECT_EQ(BaseNode::INIT_OK
,
2168 node
.InitByClientTagLookup(syncer::PASSWORDS
, client_tag
));
2169 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2170 sync_pb::PasswordSpecificsData data
;
2171 data
.set_password_value("secret2");
2172 cryptographer
->Encrypt(
2174 entity_specifics
.mutable_password()->mutable_encrypted());
2175 node
.SetPasswordSpecifics(data
);
2176 const syncable::Entry
* node_entry
= node
.GetEntry();
2177 EXPECT_TRUE(node_entry
->Get(IS_UNSYNCED
));
2181 // Passwords have their own handling for encryption. Verify setting a new
2182 // passphrase updates the data.
2183 TEST_F(SyncManagerTest
, UpdatePasswordNewPassphrase
) {
2184 std::string client_tag
= "title";
2185 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
2186 sync_pb::EntitySpecifics entity_specifics
;
2188 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2189 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2190 sync_pb::PasswordSpecificsData data
;
2191 data
.set_password_value("secret");
2192 cryptographer
->Encrypt(
2194 entity_specifics
.mutable_password()->mutable_encrypted());
2196 MakeServerNode(sync_manager_
.GetUserShare(), syncer::PASSWORDS
, client_tag
,
2197 BaseNode::GenerateSyncableHash(syncer::PASSWORDS
,
2200 // New node shouldn't start off unsynced.
2201 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2203 // Set a new passphrase. Should set is_unsynced.
2204 testing::Mock::VerifyAndClearExpectations(&observer_
);
2205 EXPECT_CALL(observer_
, OnBootstrapTokenUpdated(_
));
2206 EXPECT_CALL(observer_
, OnPassphraseAccepted());
2207 EXPECT_CALL(observer_
, OnEncryptionComplete());
2208 sync_manager_
.SetEncryptionPassphrase("new_passphrase", true);
2209 EXPECT_TRUE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2212 // Passwords have their own handling for encryption. Verify it does not result
2213 // in unnecessary writes via ReencryptEverything.
2214 TEST_F(SyncManagerTest
, UpdatePasswordReencryptEverything
) {
2215 std::string client_tag
= "title";
2216 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
2217 sync_pb::EntitySpecifics entity_specifics
;
2219 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2220 Cryptographer
* cryptographer
= trans
.GetCryptographer();
2221 sync_pb::PasswordSpecificsData data
;
2222 data
.set_password_value("secret");
2223 cryptographer
->Encrypt(
2225 entity_specifics
.mutable_password()->mutable_encrypted());
2227 MakeServerNode(sync_manager_
.GetUserShare(), syncer::PASSWORDS
, client_tag
,
2228 BaseNode::GenerateSyncableHash(syncer::PASSWORDS
,
2231 // New node shouldn't start off unsynced.
2232 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2234 // Force a re-encrypt everything. Should not set is_unsynced.
2235 testing::Mock::VerifyAndClearExpectations(&observer_
);
2236 EXPECT_CALL(observer_
, OnEncryptionComplete());
2237 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
2239 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PASSWORDS
, client_tag
));
2242 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for bookmarks
2243 // when we write the same data, but does set it when we write new data.
2244 TEST_F(SyncManagerTest
, SetBookmarkTitle
) {
2245 std::string client_tag
= "title";
2246 sync_pb::EntitySpecifics entity_specifics
;
2247 entity_specifics
.mutable_bookmark()->set_url("url");
2248 entity_specifics
.mutable_bookmark()->set_title("title");
2249 MakeServerNode(sync_manager_
.GetUserShare(), syncer::BOOKMARKS
, client_tag
,
2250 BaseNode::GenerateSyncableHash(syncer::BOOKMARKS
,
2253 // New node shouldn't start off unsynced.
2254 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2256 // Manually change to the same title. Should not set is_unsynced.
2258 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2259 WriteNode
node(&trans
);
2260 EXPECT_EQ(BaseNode::INIT_OK
,
2261 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2262 node
.SetTitle(UTF8ToWide(client_tag
));
2264 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2266 // Manually change to new title. Should set is_unsynced.
2268 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2269 WriteNode
node(&trans
);
2270 EXPECT_EQ(BaseNode::INIT_OK
,
2271 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2272 node
.SetTitle(UTF8ToWide("title2"));
2274 EXPECT_TRUE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2277 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted
2278 // bookmarks when we write the same data, but does set it when we write new
2280 TEST_F(SyncManagerTest
, SetBookmarkTitleWithEncryption
) {
2281 std::string client_tag
= "title";
2282 sync_pb::EntitySpecifics entity_specifics
;
2283 entity_specifics
.mutable_bookmark()->set_url("url");
2284 entity_specifics
.mutable_bookmark()->set_title("title");
2285 MakeServerNode(sync_manager_
.GetUserShare(), syncer::BOOKMARKS
, client_tag
,
2286 BaseNode::GenerateSyncableHash(syncer::BOOKMARKS
,
2289 // New node shouldn't start off unsynced.
2290 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2292 // Encrypt the datatatype, should set is_unsynced.
2293 EXPECT_CALL(observer_
,
2294 OnEncryptedTypesChanged(
2295 HasModelTypes(syncer::ModelTypeSet::All()), true));
2296 EXPECT_CALL(observer_
, OnEncryptionComplete());
2297 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, FULL_ENCRYPTION
));
2298 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
2300 EXPECT_TRUE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2302 // Manually change to the same title. Should not set is_unsynced.
2303 // NON_UNIQUE_NAME should be kEncryptedString.
2305 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2306 WriteNode
node(&trans
);
2307 EXPECT_EQ(BaseNode::INIT_OK
,
2308 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2309 node
.SetTitle(UTF8ToWide(client_tag
));
2310 const syncable::Entry
* node_entry
= node
.GetEntry();
2311 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2312 EXPECT_TRUE(specifics
.has_encrypted());
2313 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2315 EXPECT_FALSE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2317 // Manually change to new title. Should set is_unsynced. NON_UNIQUE_NAME
2318 // should still be kEncryptedString.
2320 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2321 WriteNode
node(&trans
);
2322 EXPECT_EQ(BaseNode::INIT_OK
,
2323 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2324 node
.SetTitle(UTF8ToWide("title2"));
2325 const syncable::Entry
* node_entry
= node
.GetEntry();
2326 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2327 EXPECT_TRUE(specifics
.has_encrypted());
2328 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2330 EXPECT_TRUE(ResetUnsyncedEntry(syncer::BOOKMARKS
, client_tag
));
2333 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for non-bookmarks
2334 // when we write the same data, but does set it when we write new data.
2335 TEST_F(SyncManagerTest
, SetNonBookmarkTitle
) {
2336 std::string client_tag
= "title";
2337 sync_pb::EntitySpecifics entity_specifics
;
2338 entity_specifics
.mutable_preference()->set_name("name");
2339 entity_specifics
.mutable_preference()->set_value("value");
2340 MakeServerNode(sync_manager_
.GetUserShare(),
2341 syncer::PREFERENCES
,
2343 BaseNode::GenerateSyncableHash(syncer::PREFERENCES
,
2346 // New node shouldn't start off unsynced.
2347 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PREFERENCES
, client_tag
));
2349 // Manually change to the same title. Should not set is_unsynced.
2351 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2352 WriteNode
node(&trans
);
2353 EXPECT_EQ(BaseNode::INIT_OK
,
2354 node
.InitByClientTagLookup(syncer::PREFERENCES
, client_tag
));
2355 node
.SetTitle(UTF8ToWide(client_tag
));
2357 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PREFERENCES
, client_tag
));
2359 // Manually change to new title. Should set is_unsynced.
2361 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2362 WriteNode
node(&trans
);
2363 EXPECT_EQ(BaseNode::INIT_OK
,
2364 node
.InitByClientTagLookup(syncer::PREFERENCES
, client_tag
));
2365 node
.SetTitle(UTF8ToWide("title2"));
2367 EXPECT_TRUE(ResetUnsyncedEntry(syncer::PREFERENCES
, client_tag
));
2370 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted
2371 // non-bookmarks when we write the same data or when we write new data
2372 // data (should remained kEncryptedString).
2373 TEST_F(SyncManagerTest
, SetNonBookmarkTitleWithEncryption
) {
2374 std::string client_tag
= "title";
2375 sync_pb::EntitySpecifics entity_specifics
;
2376 entity_specifics
.mutable_preference()->set_name("name");
2377 entity_specifics
.mutable_preference()->set_value("value");
2378 MakeServerNode(sync_manager_
.GetUserShare(),
2379 syncer::PREFERENCES
,
2381 BaseNode::GenerateSyncableHash(syncer::PREFERENCES
,
2384 // New node shouldn't start off unsynced.
2385 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PREFERENCES
, client_tag
));
2387 // Encrypt the datatatype, should set is_unsynced.
2388 EXPECT_CALL(observer_
,
2389 OnEncryptedTypesChanged(
2390 HasModelTypes(syncer::ModelTypeSet::All()), true));
2391 EXPECT_CALL(observer_
, OnEncryptionComplete());
2392 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, FULL_ENCRYPTION
));
2393 sync_manager_
.RefreshNigori(kTestChromeVersion
, base::Bind(&DoNothing
));
2395 EXPECT_TRUE(ResetUnsyncedEntry(syncer::PREFERENCES
, client_tag
));
2397 // Manually change to the same title. Should not set is_unsynced.
2398 // NON_UNIQUE_NAME should be kEncryptedString.
2400 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2401 WriteNode
node(&trans
);
2402 EXPECT_EQ(BaseNode::INIT_OK
,
2403 node
.InitByClientTagLookup(syncer::PREFERENCES
, client_tag
));
2404 node
.SetTitle(UTF8ToWide(client_tag
));
2405 const syncable::Entry
* node_entry
= node
.GetEntry();
2406 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2407 EXPECT_TRUE(specifics
.has_encrypted());
2408 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2410 EXPECT_FALSE(ResetUnsyncedEntry(syncer::PREFERENCES
, client_tag
));
2412 // Manually change to new title. Should not set is_unsynced because the
2413 // NON_UNIQUE_NAME should still be kEncryptedString.
2415 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2416 WriteNode
node(&trans
);
2417 EXPECT_EQ(BaseNode::INIT_OK
,
2418 node
.InitByClientTagLookup(syncer::PREFERENCES
, client_tag
));
2419 node
.SetTitle(UTF8ToWide("title2"));
2420 const syncable::Entry
* node_entry
= node
.GetEntry();
2421 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2422 EXPECT_TRUE(specifics
.has_encrypted());
2423 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2424 EXPECT_FALSE(node_entry
->Get(IS_UNSYNCED
));
2428 // Create an encrypted entry when the cryptographer doesn't think the type is
2429 // marked for encryption. Ensure reads/writes don't break and don't unencrypt
2431 TEST_F(SyncManagerTest
, SetPreviouslyEncryptedSpecifics
) {
2432 std::string client_tag
= "tag";
2433 std::string url
= "url";
2434 std::string url2
= "new_url";
2435 std::string title
= "title";
2436 sync_pb::EntitySpecifics entity_specifics
;
2437 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI
, DEFAULT_ENCRYPTION
));
2439 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2440 syncer::Cryptographer
* crypto
= trans
.GetCryptographer();
2441 sync_pb::EntitySpecifics bm_specifics
;
2442 bm_specifics
.mutable_bookmark()->set_title("title");
2443 bm_specifics
.mutable_bookmark()->set_url("url");
2444 sync_pb::EncryptedData encrypted
;
2445 crypto
->Encrypt(bm_specifics
, &encrypted
);
2446 entity_specifics
.mutable_encrypted()->CopyFrom(encrypted
);
2447 syncer::AddDefaultFieldValue(syncer::BOOKMARKS
, &entity_specifics
);
2449 MakeServerNode(sync_manager_
.GetUserShare(), syncer::BOOKMARKS
, client_tag
,
2450 BaseNode::GenerateSyncableHash(syncer::BOOKMARKS
,
2456 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2457 ReadNode
node(&trans
);
2458 EXPECT_EQ(BaseNode::INIT_OK
,
2459 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2460 EXPECT_EQ(title
, node
.GetTitle());
2461 EXPECT_EQ(GURL(url
), node
.GetURL());
2465 // Overwrite the url (which overwrites the specifics).
2466 WriteTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2467 WriteNode
node(&trans
);
2468 EXPECT_EQ(BaseNode::INIT_OK
,
2469 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2470 node
.SetURL(GURL(url2
));
2474 // Verify it's still encrypted and it has the most recent url.
2475 ReadTransaction
trans(FROM_HERE
, sync_manager_
.GetUserShare());
2476 ReadNode
node(&trans
);
2477 EXPECT_EQ(BaseNode::INIT_OK
,
2478 node
.InitByClientTagLookup(syncer::BOOKMARKS
, client_tag
));
2479 EXPECT_EQ(title
, node
.GetTitle());
2480 EXPECT_EQ(GURL(url2
), node
.GetURL());
2481 const syncable::Entry
* node_entry
= node
.GetEntry();
2482 EXPECT_EQ(kEncryptedString
, node_entry
->Get(NON_UNIQUE_NAME
));
2483 const sync_pb::EntitySpecifics
& specifics
= node_entry
->Get(SPECIFICS
);
2484 EXPECT_TRUE(specifics
.has_encrypted());
2488 } // namespace syncer