chromeos: Fix StartupBrowserCreatorImpl::Launch crash.
[chromium-blink-merge.git] / sync / internal_api / syncapi_unittest.cc
blob6fff8c5e9ea779ed57dcb72d5fddc267904e8eea
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.
9 #include <cstddef>
10 #include <map>
12 #include "base/basictypes.h"
13 #include "base/callback.h"
14 #include "base/compiler_specific.h"
15 #include "base/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;
70 using testing::_;
71 using testing::AnyNumber;
72 using testing::AtLeast;
73 using testing::InSequence;
74 using testing::Invoke;
75 using testing::SaveArg;
76 using testing::StrictMock;
78 namespace syncer {
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;
87 namespace {
89 const char kTestChromeVersion[] = "test chrome version";
91 void DoNothing() {}
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));
97 int64 val = 0;
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);
122 return node.GetId();
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,
130 int64 parent_id) {
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);
139 return node.GetId();
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,
146 int64 parent_id,
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);
154 return node.GetId();
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,
170 node_id);
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,
199 node_id);
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);
216 } // namespace
218 class SyncApiTest : public testing::Test {
219 public:
220 virtual void SetUp() {
221 test_user_share_.SetUp();
224 virtual void TearDown() {
225 test_user_share_.TearDown();
228 protected:
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,
312 "collideme"));
314 ReadNode prefnode(&trans);
315 EXPECT_EQ(BaseNode::INIT_OK,
316 prefnode.InitByClientTagLookup(syncer::PREFERENCES,
317 "collideme"));
319 ReadNode autofillnode(&trans);
320 EXPECT_EQ(BaseNode::INIT_OK,
321 autofillnode.InitByClientTagLookup(syncer::AUTOFILL,
322 "collideme"));
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,
336 "testtag"));
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,
343 "testtag"));
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) {
350 int64 node_id;
351 int64 folder_id;
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,
362 root_node, NULL));
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,
381 "testtag"));
382 EXPECT_FALSE(wnode.GetIsFolder());
383 EXPECT_EQ(wnode.GetTitle(), test_title);
385 wnode.Remove();
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,
395 "testtag"));
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,
424 "testtag"));
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,
444 root_node, "foo");
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,
458 "foo"));
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,
480 root_node, "foo");
481 EXPECT_EQ(syncer::WriteNode::INIT_SUCCESS, result);
482 bookmark_node.SetTitle(UTF8ToWide("foo"));
484 WriteNode pref_node(&trans);
485 result =
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,
498 "foo"));
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,
506 "bar"));
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());
547 namespace {
549 void CheckNodeValue(const BaseNode& node, const DictionaryValue& value,
550 bool is_detailed) {
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);
569 } else {
570 ADD_FAILURE();
573 if (is_detailed) {
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());
582 Value* entry = NULL;
583 EXPECT_TRUE(value.Get("entry", &entry));
584 EXPECT_TRUE(Value::Equals(entry, expected_entry.get()));
586 EXPECT_EQ(11u, value.size());
587 } else {
588 EXPECT_EQ(4u, value.size());
592 } // namespace
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());
599 if (details.get()) {
600 CheckNodeValue(node, *details, false);
601 } else {
602 ADD_FAILURE();
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());
611 if (details.get()) {
612 CheckNodeValue(node, *details, true);
613 } else {
614 ADD_FAILURE();
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));
631 namespace {
633 class TestHttpPostProviderInterface : public HttpPostProviderInterface {
634 public:
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,
640 int content_length,
641 const char* content) OVERRIDE {}
642 virtual bool MakeSynchronousPost(int* error_code, int* response_code)
643 OVERRIDE {
644 return false;
646 virtual int GetResponseContentLength() const OVERRIDE {
647 return 0;
649 virtual const char* GetResponseContent() const OVERRIDE {
650 return "";
652 virtual const std::string GetResponseHeaderValue(
653 const std::string& name) const OVERRIDE {
654 return "";
656 virtual void Abort() OVERRIDE {}
659 class TestHttpPostProviderFactory : public HttpPostProviderFactory {
660 public:
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 {
671 public:
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 {
692 public:
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));
704 } // namespace
706 class SyncManagerTest : public testing::Test,
707 public SyncManager::ChangeDelegate {
708 protected:
709 enum NigoriStatus {
710 DONT_WRITE_NIGORI,
711 WRITE_TO_NIGORI
714 enum EncryptionStatus {
715 UNINITIALIZED,
716 DEFAULT_ENCRYPTION,
717 FULL_ENCRYPTION
720 SyncManagerTest()
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.
731 void SetUp() {
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(_)).
746 WillRepeatedly(
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>(),
765 "bogus", 0, false,
766 base::MessageLoopProxy::current(),
767 new TestHttpPostProviderFactory(), routing_info, workers,
768 &extensions_activity_monitor_, this,
769 credentials,
770 sync_notifier_mock_, "",
771 syncer::SyncManager::TEST_IN_MEMORY,
772 &encryptor_,
773 &handler_,
774 NULL);
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);
786 PumpLoop();
789 void TearDown() {
790 sync_manager_.RemoveObserver(&observer_);
791 sync_manager_.ShutdownOnSyncThread();
792 sync_notifier_mock_ = NULL;
793 EXPECT_FALSE(sync_notifier_observer_);
794 PumpLoop();
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 {}
813 // Helper methods.
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)
822 return false;
824 // Set the nigori cryptographer information.
825 WriteTransaction trans(FROM_HERE, share);
826 Cryptographer* cryptographer = trans.GetCryptographer();
827 if (!cryptographer)
828 return false;
829 if (encryption_status != UNINITIALIZED) {
830 KeyParams params = {"localhost", "dummy", "foobar"};
831 cryptographer->AddKey(params);
832 } else {
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)
850 return 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_;
874 void PumpLoop() {
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);
882 PumpLoop();
885 void SetJsEventHandler(const WeakHandle<JsEventHandler>& event_handler) {
886 js_backend_.Call(FROM_HERE, &JsBackend::SetJsEventHandler,
887 event_handler);
888 PumpLoop();
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
893 // already false.
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,
901 hash);
902 EXPECT_TRUE(entry.good());
903 if (!entry.Get(IS_UNSYNCED))
904 return false;
905 entry.Put(IS_UNSYNCED, false);
906 return true;
909 private:
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_;
919 protected:
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));
974 if (node_info) {
975 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
976 ReadNode node(&trans);
977 node.InitByRootLookup();
978 CheckNodeValue(node, *node_info, true);
979 } else {
980 ADD_FAILURE();
984 void CheckGetNodesByIdReturnArgs(const SyncManager& sync_manager,
985 const JsArgList& return_args,
986 int64 id,
987 bool is_detailed) {
988 EXPECT_EQ(1u, return_args.Get().GetSize());
989 ListValue* nodes = NULL;
990 ASSERT_TRUE(return_args.Get().GetList(0, &nodes));
991 ASSERT_TRUE(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 {
1003 protected:
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();
1015 int64 child_id =
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) {
1029 ListValue args;
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)))
1050 .Times(6);
1053 ListValue args;
1054 SendJsMessage(message_name,
1055 JsArgList(&args), reply_handler.AsWeakHandle());
1059 ListValue args;
1060 args.Append(new ListValue());
1061 SendJsMessage(message_name,
1062 JsArgList(&args), reply_handler.AsWeakHandle());
1066 ListValue args;
1067 ListValue* ids = new ListValue();
1068 args.Append(ids);
1069 ids->Append(Value::CreateStringValue(""));
1070 SendJsMessage(message_name,
1071 JsArgList(&args), reply_handler.AsWeakHandle());
1075 ListValue args;
1076 ListValue* ids = new ListValue();
1077 args.Append(ids);
1078 ids->Append(Value::CreateStringValue("nonsense"));
1079 SendJsMessage(message_name,
1080 JsArgList(&args), reply_handler.AsWeakHandle());
1084 ListValue args;
1085 ListValue* ids = new ListValue();
1086 args.Append(ids);
1087 ids->Append(Value::CreateStringValue("0"));
1088 SendJsMessage(message_name,
1089 JsArgList(&args), reply_handler.AsWeakHandle());
1093 ListValue args;
1094 ListValue* ids = new ListValue();
1095 args.Append(ids);
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));
1129 ListValue 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));
1138 ASSERT_TRUE(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)))
1151 .Times(5);
1154 ListValue args;
1155 SendJsMessage("getChildNodeIds",
1156 JsArgList(&args), reply_handler.AsWeakHandle());
1160 ListValue args;
1161 args.Append(Value::CreateStringValue(""));
1162 SendJsMessage("getChildNodeIds",
1163 JsArgList(&args), reply_handler.AsWeakHandle());
1167 ListValue args;
1168 args.Append(Value::CreateStringValue("nonsense"));
1169 SendJsMessage("getChildNodeIds",
1170 JsArgList(&args), reply_handler.AsWeakHandle());
1174 ListValue args;
1175 args.Append(Value::CreateStringValue("0"));
1176 SendJsMessage("getChildNodeIds",
1177 JsArgList(&args), reply_handler.AsWeakHandle());
1181 ListValue args;
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));
1197 ListValue 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) {
1230 InSequence dummy;
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.
1260 PumpLoop();
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.
1299 PumpLoop();
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));
1307 PumpLoop();
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).
1330 // Should fail.
1331 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
1332 PumpLoop();
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));
1347 PumpLoop();
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(),
1382 syncer::BOOKMARKS,
1383 GetIdForDataType(syncer::BOOKMARKS),
1384 NULL);
1385 // First batch_size nodes are children of folder.
1386 size_t i;
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(),
1411 syncer::BOOKMARKS,
1412 false /* not encrypted */));
1413 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1414 trans.GetWrappedTrans(),
1415 trans.GetCryptographer(),
1416 syncer::SESSIONS,
1417 false /* not encrypted */));
1418 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1419 trans.GetWrappedTrans(),
1420 trans.GetCryptographer(),
1421 syncer::THEMES,
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(),
1438 syncer::BOOKMARKS,
1439 true /* is encrypted */));
1440 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1441 trans.GetWrappedTrans(),
1442 trans.GetCryptographer(),
1443 syncer::SESSIONS,
1444 true /* is encrypted */));
1445 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1446 trans.GetWrappedTrans(),
1447 trans.GetCryptographer(),
1448 syncer::THEMES,
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(),
1465 syncer::BOOKMARKS,
1466 true /* is encrypted */));
1467 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1468 trans.GetWrappedTrans(),
1469 trans.GetCryptographer(),
1470 syncer::SESSIONS,
1471 true /* is encrypted */));
1472 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1473 trans.GetWrappedTrans(),
1474 trans.GetCryptographer(),
1475 syncer::THEMES,
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,
1558 root_node, "foo");
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,
1581 "foo"));
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
1590 // password.
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
1677 // keys.
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
1705 // passphrase.
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));
1782 int64 node_id = 0;
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,
1805 tag));
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));
1832 std::string title;
1833 SyncAPINameToServerName("Google", &title);
1834 std::string url = "http://www.google.com";
1835 std::string raw_title2 = ".."; // An invalid cosmo title.
1836 std::string title2;
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(),
1842 syncer::BOOKMARKS,
1843 "testtag");
1844 int64 node_id2 = MakeNode(sync_manager_.GetUserShare(),
1845 syncer::BOOKMARKS,
1846 "testtag2");
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(),
1896 syncer::BOOKMARKS,
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(),
1913 syncer::BOOKMARKS,
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";
1939 GURL url("url");
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));
1948 node.SetURL(url);
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
1965 // changes.
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,
1973 client_tag),
1974 entity_specifics);
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));
1995 PumpLoop();
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));
2039 PumpLoop();
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(
2106 data,
2107 entity_specifics.mutable_password()->
2108 mutable_encrypted());
2110 MakeServerNode(sync_manager_.GetUserShare(), syncer::PASSWORDS, client_tag,
2111 BaseNode::GenerateSyncableHash(syncer::PASSWORDS,
2112 client_tag),
2113 entity_specifics);
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
2118 // is_unsynced.
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(
2141 data,
2142 entity_specifics.mutable_password()->
2143 mutable_encrypted());
2145 MakeServerNode(sync_manager_.GetUserShare(), syncer::PASSWORDS, client_tag,
2146 BaseNode::GenerateSyncableHash(syncer::PASSWORDS,
2147 client_tag),
2148 entity_specifics);
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
2153 // is_unsynced.
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(
2173 data,
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(
2193 data,
2194 entity_specifics.mutable_password()->mutable_encrypted());
2196 MakeServerNode(sync_manager_.GetUserShare(), syncer::PASSWORDS, client_tag,
2197 BaseNode::GenerateSyncableHash(syncer::PASSWORDS,
2198 client_tag),
2199 entity_specifics);
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(
2224 data,
2225 entity_specifics.mutable_password()->mutable_encrypted());
2227 MakeServerNode(sync_manager_.GetUserShare(), syncer::PASSWORDS, client_tag,
2228 BaseNode::GenerateSyncableHash(syncer::PASSWORDS,
2229 client_tag),
2230 entity_specifics);
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));
2238 PumpLoop();
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,
2251 client_tag),
2252 entity_specifics);
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
2279 // data.
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,
2287 client_tag),
2288 entity_specifics);
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));
2299 PumpLoop();
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,
2342 client_tag,
2343 BaseNode::GenerateSyncableHash(syncer::PREFERENCES,
2344 client_tag),
2345 entity_specifics);
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,
2380 client_tag,
2381 BaseNode::GenerateSyncableHash(syncer::PREFERENCES,
2382 client_tag),
2383 entity_specifics);
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));
2394 PumpLoop();
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
2430 // the data.
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,
2451 client_tag),
2452 entity_specifics);
2455 // Verify the data.
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