Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(412)

Side by Side Diff: sync/internal_api/syncapi_unittest.cc

Issue 10805002: [Sync] Enable adding notifier observers from ProfileSyncService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 // Unit tests for the SyncApi. Note that a lot of the underlying
6 // functionality is provided by the Syncable layer, which has its own
7 // unit tests. We'll test SyncApi specific things in this harness.
8
9 #include <cstddef>
10 #include <map>
11
12 #include "base/basictypes.h"
13 #include "base/callback.h"
14 #include "base/compiler_specific.h"
15 #include "base/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/engine/sync_scheduler.h"
28 #include "sync/internal_api/public/change_record.h"
29 #include "sync/internal_api/public/engine/model_safe_worker.h"
30 #include "sync/internal_api/public/engine/polling_constants.h"
31 #include "sync/internal_api/public/http_post_provider_factory.h"
32 #include "sync/internal_api/public/http_post_provider_interface.h"
33 #include "sync/internal_api/public/read_node.h"
34 #include "sync/internal_api/public/read_transaction.h"
35 #include "sync/internal_api/public/test/test_internal_components_factory.h"
36 #include "sync/internal_api/public/test/test_user_share.h"
37 #include "sync/internal_api/public/write_node.h"
38 #include "sync/internal_api/public/write_transaction.h"
39 #include "sync/internal_api/syncapi_internal.h"
40 #include "sync/internal_api/sync_manager_impl.h"
41 #include "sync/js/js_arg_list.h"
42 #include "sync/js/js_backend.h"
43 #include "sync/js/js_event_handler.h"
44 #include "sync/js/js_reply_handler.h"
45 #include "sync/js/js_test_util.h"
46 #include "sync/notifier/sync_notifier.h"
47 #include "sync/notifier/sync_notifier_observer.h"
48 #include "sync/protocol/bookmark_specifics.pb.h"
49 #include "sync/protocol/encryption.pb.h"
50 #include "sync/protocol/extension_specifics.pb.h"
51 #include "sync/protocol/password_specifics.pb.h"
52 #include "sync/protocol/preference_specifics.pb.h"
53 #include "sync/protocol/proto_value_conversions.h"
54 #include "sync/protocol/sync.pb.h"
55 #include "sync/sessions/sync_session.h"
56 #include "sync/syncable/directory.h"
57 #include "sync/syncable/entry.h"
58 #include "sync/syncable/mutable_entry.h"
59 #include "sync/syncable/nigori_util.h"
60 #include "sync/syncable/syncable_id.h"
61 #include "sync/syncable/write_transaction.h"
62 #include "sync/test/callback_counter.h"
63 #include "sync/test/fake_encryptor.h"
64 #include "sync/test/fake_extensions_activity_monitor.h"
65 #include "sync/test/engine/fake_sync_scheduler.h"
66 #include "sync/util/cryptographer.h"
67 #include "sync/util/extensions_activity_monitor.h"
68 #include "sync/util/test_unrecoverable_error_handler.h"
69 #include "sync/util/time.h"
70 #include "testing/gmock/include/gmock/gmock.h"
71 #include "testing/gtest/include/gtest/gtest.h"
72
73 using base::ExpectDictStringValue;
74 using testing::_;
75 using testing::AnyNumber;
76 using testing::AtLeast;
77 using testing::DoAll;
78 using testing::InSequence;
79 using testing::Invoke;
80 using testing::Return;
81 using testing::SaveArg;
82 using testing::StrictMock;
83
84 namespace syncer {
85
86 using sessions::SyncSessionSnapshot;
87 using syncable::IS_DEL;
88 using syncable::IS_UNSYNCED;
89 using syncable::kEncryptedString;
90 using syncable::NON_UNIQUE_NAME;
91 using syncable::SPECIFICS;
92
93 namespace {
94
95 const char kTestChromeVersion[] = "test chrome version";
96
97 void DoNothing() {}
98
99 void ExpectInt64Value(int64 expected_value,
100 const DictionaryValue& value, const std::string& key) {
101 std::string int64_str;
102 EXPECT_TRUE(value.GetString(key, &int64_str));
103 int64 val = 0;
104 EXPECT_TRUE(base::StringToInt64(int64_str, &val));
105 EXPECT_EQ(expected_value, val);
106 }
107
108 void ExpectTimeValue(const base::Time& expected_value,
109 const DictionaryValue& value, const std::string& key) {
110 std::string time_str;
111 EXPECT_TRUE(value.GetString(key, &time_str));
112 EXPECT_EQ(GetTimeDebugString(expected_value), time_str);
113 }
114
115 // Makes a non-folder child of the root node. Returns the id of the
116 // newly-created node.
117 int64 MakeNode(UserShare* share,
118 ModelType model_type,
119 const std::string& client_tag) {
120 WriteTransaction trans(FROM_HERE, share);
121 ReadNode root_node(&trans);
122 root_node.InitByRootLookup();
123 WriteNode node(&trans);
124 WriteNode::InitUniqueByCreationResult result =
125 node.InitUniqueByCreation(model_type, root_node, client_tag);
126 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
127 node.SetIsFolder(false);
128 return node.GetId();
129 }
130
131 // Makes a non-folder child of a non-root node. Returns the id of the
132 // newly-created node.
133 int64 MakeNodeWithParent(UserShare* share,
134 ModelType model_type,
135 const std::string& client_tag,
136 int64 parent_id) {
137 WriteTransaction trans(FROM_HERE, share);
138 ReadNode parent_node(&trans);
139 EXPECT_EQ(BaseNode::INIT_OK, parent_node.InitByIdLookup(parent_id));
140 WriteNode node(&trans);
141 WriteNode::InitUniqueByCreationResult result =
142 node.InitUniqueByCreation(model_type, parent_node, client_tag);
143 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
144 node.SetIsFolder(false);
145 return node.GetId();
146 }
147
148 // Makes a folder child of a non-root node. Returns the id of the
149 // newly-created node.
150 int64 MakeFolderWithParent(UserShare* share,
151 ModelType model_type,
152 int64 parent_id,
153 BaseNode* predecessor) {
154 WriteTransaction trans(FROM_HERE, share);
155 ReadNode parent_node(&trans);
156 EXPECT_EQ(BaseNode::INIT_OK, parent_node.InitByIdLookup(parent_id));
157 WriteNode node(&trans);
158 EXPECT_TRUE(node.InitByCreation(model_type, parent_node, predecessor));
159 node.SetIsFolder(true);
160 return node.GetId();
161 }
162
163 // Creates the "synced" root node for a particular datatype. We use the syncable
164 // methods here so that the syncer treats these nodes as if they were already
165 // received from the server.
166 int64 MakeServerNodeForType(UserShare* share,
167 ModelType model_type) {
168 sync_pb::EntitySpecifics specifics;
169 AddDefaultFieldValue(model_type, &specifics);
170 syncable::WriteTransaction trans(
171 FROM_HERE, syncable::UNITTEST, share->directory.get());
172 // Attempt to lookup by nigori tag.
173 std::string type_tag = ModelTypeToRootTag(model_type);
174 syncable::Id node_id = syncable::Id::CreateFromServerId(type_tag);
175 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
176 node_id);
177 EXPECT_TRUE(entry.good());
178 entry.Put(syncable::BASE_VERSION, 1);
179 entry.Put(syncable::SERVER_VERSION, 1);
180 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
181 entry.Put(syncable::SERVER_PARENT_ID, syncable::GetNullId());
182 entry.Put(syncable::SERVER_IS_DIR, true);
183 entry.Put(syncable::IS_DIR, true);
184 entry.Put(syncable::SERVER_SPECIFICS, specifics);
185 entry.Put(syncable::UNIQUE_SERVER_TAG, type_tag);
186 entry.Put(syncable::NON_UNIQUE_NAME, type_tag);
187 entry.Put(syncable::IS_DEL, false);
188 entry.Put(syncable::SPECIFICS, specifics);
189 return entry.Get(syncable::META_HANDLE);
190 }
191
192 // Simulates creating a "synced" node as a child of the root datatype node.
193 int64 MakeServerNode(UserShare* share, ModelType model_type,
194 const std::string& client_tag,
195 const std::string& hashed_tag,
196 const sync_pb::EntitySpecifics& specifics) {
197 syncable::WriteTransaction trans(
198 FROM_HERE, syncable::UNITTEST, share->directory.get());
199 syncable::Entry root_entry(&trans, syncable::GET_BY_SERVER_TAG,
200 ModelTypeToRootTag(model_type));
201 EXPECT_TRUE(root_entry.good());
202 syncable::Id root_id = root_entry.Get(syncable::ID);
203 syncable::Id node_id = syncable::Id::CreateFromServerId(client_tag);
204 syncable::MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
205 node_id);
206 EXPECT_TRUE(entry.good());
207 entry.Put(syncable::BASE_VERSION, 1);
208 entry.Put(syncable::SERVER_VERSION, 1);
209 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
210 entry.Put(syncable::SERVER_PARENT_ID, root_id);
211 entry.Put(syncable::PARENT_ID, root_id);
212 entry.Put(syncable::SERVER_IS_DIR, false);
213 entry.Put(syncable::IS_DIR, false);
214 entry.Put(syncable::SERVER_SPECIFICS, specifics);
215 entry.Put(syncable::NON_UNIQUE_NAME, client_tag);
216 entry.Put(syncable::UNIQUE_CLIENT_TAG, hashed_tag);
217 entry.Put(syncable::IS_DEL, false);
218 entry.Put(syncable::SPECIFICS, specifics);
219 return entry.Get(syncable::META_HANDLE);
220 }
221
222 } // namespace
223
224 class SyncApiTest : public testing::Test {
225 public:
226 virtual void SetUp() {
227 test_user_share_.SetUp();
228 }
229
230 virtual void TearDown() {
231 test_user_share_.TearDown();
232 }
233
234 protected:
235 MessageLoop message_loop_;
236 TestUserShare test_user_share_;
237 };
238
239 TEST_F(SyncApiTest, SanityCheckTest) {
240 {
241 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
242 EXPECT_TRUE(trans.GetWrappedTrans() != NULL);
243 }
244 {
245 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
246 EXPECT_TRUE(trans.GetWrappedTrans() != NULL);
247 }
248 {
249 // No entries but root should exist
250 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
251 ReadNode node(&trans);
252 // Metahandle 1 can be root, sanity check 2
253 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD, node.InitByIdLookup(2));
254 }
255 }
256
257 TEST_F(SyncApiTest, BasicTagWrite) {
258 {
259 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
260 ReadNode root_node(&trans);
261 root_node.InitByRootLookup();
262 EXPECT_EQ(root_node.GetFirstChildId(), 0);
263 }
264
265 ignore_result(MakeNode(test_user_share_.user_share(),
266 BOOKMARKS, "testtag"));
267
268 {
269 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
270 ReadNode node(&trans);
271 EXPECT_EQ(BaseNode::INIT_OK,
272 node.InitByClientTagLookup(BOOKMARKS, "testtag"));
273
274 ReadNode root_node(&trans);
275 root_node.InitByRootLookup();
276 EXPECT_NE(node.GetId(), 0);
277 EXPECT_EQ(node.GetId(), root_node.GetFirstChildId());
278 }
279 }
280
281 TEST_F(SyncApiTest, GenerateSyncableHash) {
282 EXPECT_EQ("OyaXV5mEzrPS4wbogmtKvRfekAI=",
283 BaseNode::GenerateSyncableHash(BOOKMARKS, "tag1"));
284 EXPECT_EQ("iNFQtRFQb+IZcn1kKUJEZDDkLs4=",
285 BaseNode::GenerateSyncableHash(PREFERENCES, "tag1"));
286 EXPECT_EQ("gO1cPZQXaM73sHOvSA+tKCKFs58=",
287 BaseNode::GenerateSyncableHash(AUTOFILL, "tag1"));
288
289 EXPECT_EQ("A0eYIHXM1/jVwKDDp12Up20IkKY=",
290 BaseNode::GenerateSyncableHash(BOOKMARKS, "tag2"));
291 EXPECT_EQ("XYxkF7bhS4eItStFgiOIAU23swI=",
292 BaseNode::GenerateSyncableHash(PREFERENCES, "tag2"));
293 EXPECT_EQ("GFiWzo5NGhjLlN+OyCfhy28DJTQ=",
294 BaseNode::GenerateSyncableHash(AUTOFILL, "tag2"));
295 }
296
297 TEST_F(SyncApiTest, ModelTypesSiloed) {
298 {
299 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
300 ReadNode root_node(&trans);
301 root_node.InitByRootLookup();
302 EXPECT_EQ(root_node.GetFirstChildId(), 0);
303 }
304
305 ignore_result(MakeNode(test_user_share_.user_share(),
306 BOOKMARKS, "collideme"));
307 ignore_result(MakeNode(test_user_share_.user_share(),
308 PREFERENCES, "collideme"));
309 ignore_result(MakeNode(test_user_share_.user_share(),
310 AUTOFILL, "collideme"));
311
312 {
313 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
314
315 ReadNode bookmarknode(&trans);
316 EXPECT_EQ(BaseNode::INIT_OK,
317 bookmarknode.InitByClientTagLookup(BOOKMARKS,
318 "collideme"));
319
320 ReadNode prefnode(&trans);
321 EXPECT_EQ(BaseNode::INIT_OK,
322 prefnode.InitByClientTagLookup(PREFERENCES,
323 "collideme"));
324
325 ReadNode autofillnode(&trans);
326 EXPECT_EQ(BaseNode::INIT_OK,
327 autofillnode.InitByClientTagLookup(AUTOFILL,
328 "collideme"));
329
330 EXPECT_NE(bookmarknode.GetId(), prefnode.GetId());
331 EXPECT_NE(autofillnode.GetId(), prefnode.GetId());
332 EXPECT_NE(bookmarknode.GetId(), autofillnode.GetId());
333 }
334 }
335
336 TEST_F(SyncApiTest, ReadMissingTagsFails) {
337 {
338 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
339 ReadNode node(&trans);
340 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD,
341 node.InitByClientTagLookup(BOOKMARKS,
342 "testtag"));
343 }
344 {
345 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
346 WriteNode node(&trans);
347 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD,
348 node.InitByClientTagLookup(BOOKMARKS,
349 "testtag"));
350 }
351 }
352
353 // TODO(chron): Hook this all up to the server and write full integration tests
354 // for update->undelete behavior.
355 TEST_F(SyncApiTest, TestDeleteBehavior) {
356 int64 node_id;
357 int64 folder_id;
358 std::string test_title("test1");
359
360 {
361 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
362 ReadNode root_node(&trans);
363 root_node.InitByRootLookup();
364
365 // we'll use this spare folder later
366 WriteNode folder_node(&trans);
367 EXPECT_TRUE(folder_node.InitByCreation(BOOKMARKS,
368 root_node, NULL));
369 folder_id = folder_node.GetId();
370
371 WriteNode wnode(&trans);
372 WriteNode::InitUniqueByCreationResult result =
373 wnode.InitUniqueByCreation(BOOKMARKS, root_node, "testtag");
374 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
375 wnode.SetIsFolder(false);
376 wnode.SetTitle(UTF8ToWide(test_title));
377
378 node_id = wnode.GetId();
379 }
380
381 // Ensure we can delete something with a tag.
382 {
383 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
384 WriteNode wnode(&trans);
385 EXPECT_EQ(BaseNode::INIT_OK,
386 wnode.InitByClientTagLookup(BOOKMARKS,
387 "testtag"));
388 EXPECT_FALSE(wnode.GetIsFolder());
389 EXPECT_EQ(wnode.GetTitle(), test_title);
390
391 wnode.Remove();
392 }
393
394 // Lookup of a node which was deleted should return failure,
395 // but have found some data about the node.
396 {
397 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
398 ReadNode node(&trans);
399 EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_IS_DEL,
400 node.InitByClientTagLookup(BOOKMARKS,
401 "testtag"));
402 // Note that for proper function of this API this doesn't need to be
403 // filled, we're checking just to make sure the DB worked in this test.
404 EXPECT_EQ(node.GetTitle(), test_title);
405 }
406
407 {
408 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
409 ReadNode folder_node(&trans);
410 EXPECT_EQ(BaseNode::INIT_OK, folder_node.InitByIdLookup(folder_id));
411
412 WriteNode wnode(&trans);
413 // This will undelete the tag.
414 WriteNode::InitUniqueByCreationResult result =
415 wnode.InitUniqueByCreation(BOOKMARKS, folder_node, "testtag");
416 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
417 EXPECT_EQ(wnode.GetIsFolder(), false);
418 EXPECT_EQ(wnode.GetParentId(), folder_node.GetId());
419 EXPECT_EQ(wnode.GetId(), node_id);
420 EXPECT_NE(wnode.GetTitle(), test_title); // Title should be cleared
421 wnode.SetTitle(UTF8ToWide(test_title));
422 }
423
424 // Now look up should work.
425 {
426 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
427 ReadNode node(&trans);
428 EXPECT_EQ(BaseNode::INIT_OK,
429 node.InitByClientTagLookup(BOOKMARKS,
430 "testtag"));
431 EXPECT_EQ(node.GetTitle(), test_title);
432 EXPECT_EQ(node.GetModelType(), BOOKMARKS);
433 }
434 }
435
436 TEST_F(SyncApiTest, WriteAndReadPassword) {
437 KeyParams params = {"localhost", "username", "passphrase"};
438 {
439 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
440 trans.GetCryptographer()->AddKey(params);
441 }
442 {
443 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
444 ReadNode root_node(&trans);
445 root_node.InitByRootLookup();
446
447 WriteNode password_node(&trans);
448 WriteNode::InitUniqueByCreationResult result =
449 password_node.InitUniqueByCreation(PASSWORDS,
450 root_node, "foo");
451 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
452 sync_pb::PasswordSpecificsData data;
453 data.set_password_value("secret");
454 password_node.SetPasswordSpecifics(data);
455 }
456 {
457 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
458 ReadNode root_node(&trans);
459 root_node.InitByRootLookup();
460
461 ReadNode password_node(&trans);
462 EXPECT_EQ(BaseNode::INIT_OK,
463 password_node.InitByClientTagLookup(PASSWORDS, "foo"));
464 const sync_pb::PasswordSpecificsData& data =
465 password_node.GetPasswordSpecifics();
466 EXPECT_EQ("secret", data.password_value());
467 }
468 }
469
470 TEST_F(SyncApiTest, WriteEncryptedTitle) {
471 KeyParams params = {"localhost", "username", "passphrase"};
472 {
473 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
474 trans.GetCryptographer()->AddKey(params);
475 trans.GetCryptographer()->set_encrypt_everything();
476 }
477 {
478 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
479 ReadNode root_node(&trans);
480 root_node.InitByRootLookup();
481
482 WriteNode bookmark_node(&trans);
483 WriteNode::InitUniqueByCreationResult result =
484 bookmark_node.InitUniqueByCreation(BOOKMARKS,
485 root_node, "foo");
486 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
487 bookmark_node.SetTitle(UTF8ToWide("foo"));
488
489 WriteNode pref_node(&trans);
490 result =
491 pref_node.InitUniqueByCreation(PREFERENCES, root_node, "bar");
492 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
493 pref_node.SetTitle(UTF8ToWide("bar"));
494 }
495 {
496 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
497 ReadNode root_node(&trans);
498 root_node.InitByRootLookup();
499
500 ReadNode bookmark_node(&trans);
501 EXPECT_EQ(BaseNode::INIT_OK,
502 bookmark_node.InitByClientTagLookup(BOOKMARKS,
503 "foo"));
504 EXPECT_EQ("foo", bookmark_node.GetTitle());
505 EXPECT_EQ(kEncryptedString,
506 bookmark_node.GetEntry()->Get(syncable::NON_UNIQUE_NAME));
507
508 ReadNode pref_node(&trans);
509 EXPECT_EQ(BaseNode::INIT_OK,
510 pref_node.InitByClientTagLookup(PREFERENCES,
511 "bar"));
512 EXPECT_EQ(kEncryptedString, pref_node.GetTitle());
513 }
514 }
515
516 TEST_F(SyncApiTest, BaseNodeSetSpecifics) {
517 int64 child_id = MakeNode(test_user_share_.user_share(),
518 BOOKMARKS, "testtag");
519 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
520 WriteNode node(&trans);
521 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id));
522
523 sync_pb::EntitySpecifics entity_specifics;
524 entity_specifics.mutable_bookmark()->set_url("http://www.google.com");
525
526 EXPECT_NE(entity_specifics.SerializeAsString(),
527 node.GetEntitySpecifics().SerializeAsString());
528 node.SetEntitySpecifics(entity_specifics);
529 EXPECT_EQ(entity_specifics.SerializeAsString(),
530 node.GetEntitySpecifics().SerializeAsString());
531 }
532
533 TEST_F(SyncApiTest, BaseNodeSetSpecificsPreservesUnknownFields) {
534 int64 child_id = MakeNode(test_user_share_.user_share(),
535 BOOKMARKS, "testtag");
536 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
537 WriteNode node(&trans);
538 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id));
539 EXPECT_TRUE(node.GetEntitySpecifics().unknown_fields().empty());
540
541 sync_pb::EntitySpecifics entity_specifics;
542 entity_specifics.mutable_bookmark()->set_url("http://www.google.com");
543 entity_specifics.mutable_unknown_fields()->AddFixed32(5, 100);
544 node.SetEntitySpecifics(entity_specifics);
545 EXPECT_FALSE(node.GetEntitySpecifics().unknown_fields().empty());
546
547 entity_specifics.mutable_unknown_fields()->Clear();
548 node.SetEntitySpecifics(entity_specifics);
549 EXPECT_FALSE(node.GetEntitySpecifics().unknown_fields().empty());
550 }
551
552 namespace {
553
554 void CheckNodeValue(const BaseNode& node, const DictionaryValue& value,
555 bool is_detailed) {
556 ExpectInt64Value(node.GetId(), value, "id");
557 {
558 bool is_folder = false;
559 EXPECT_TRUE(value.GetBoolean("isFolder", &is_folder));
560 EXPECT_EQ(node.GetIsFolder(), is_folder);
561 }
562 ExpectDictStringValue(node.GetTitle(), value, "title");
563 {
564 ModelType expected_model_type = node.GetModelType();
565 std::string type_str;
566 EXPECT_TRUE(value.GetString("type", &type_str));
567 if (expected_model_type >= FIRST_REAL_MODEL_TYPE) {
568 ModelType model_type = ModelTypeFromString(type_str);
569 EXPECT_EQ(expected_model_type, model_type);
570 } else if (expected_model_type == TOP_LEVEL_FOLDER) {
571 EXPECT_EQ("Top-level folder", type_str);
572 } else if (expected_model_type == UNSPECIFIED) {
573 EXPECT_EQ("Unspecified", type_str);
574 } else {
575 ADD_FAILURE();
576 }
577 }
578 if (is_detailed) {
579 ExpectInt64Value(node.GetParentId(), value, "parentId");
580 ExpectTimeValue(node.GetModificationTime(), value, "modificationTime");
581 ExpectInt64Value(node.GetExternalId(), value, "externalId");
582 ExpectInt64Value(node.GetPredecessorId(), value, "predecessorId");
583 ExpectInt64Value(node.GetSuccessorId(), value, "successorId");
584 ExpectInt64Value(node.GetFirstChildId(), value, "firstChildId");
585 {
586 scoped_ptr<DictionaryValue> expected_entry(node.GetEntry()->ToValue());
587 const Value* entry = NULL;
588 EXPECT_TRUE(value.Get("entry", &entry));
589 EXPECT_TRUE(Value::Equals(entry, expected_entry.get()));
590 }
591 EXPECT_EQ(11u, value.size());
592 } else {
593 EXPECT_EQ(4u, value.size());
594 }
595 }
596
597 } // namespace
598
599 TEST_F(SyncApiTest, BaseNodeGetSummaryAsValue) {
600 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
601 ReadNode node(&trans);
602 node.InitByRootLookup();
603 scoped_ptr<DictionaryValue> details(node.GetSummaryAsValue());
604 if (details.get()) {
605 CheckNodeValue(node, *details, false);
606 } else {
607 ADD_FAILURE();
608 }
609 }
610
611 TEST_F(SyncApiTest, BaseNodeGetDetailsAsValue) {
612 ReadTransaction trans(FROM_HERE, test_user_share_.user_share());
613 ReadNode node(&trans);
614 node.InitByRootLookup();
615 scoped_ptr<DictionaryValue> details(node.GetDetailsAsValue());
616 if (details.get()) {
617 CheckNodeValue(node, *details, true);
618 } else {
619 ADD_FAILURE();
620 }
621 }
622
623 TEST_F(SyncApiTest, EmptyTags) {
624 WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
625 ReadNode root_node(&trans);
626 root_node.InitByRootLookup();
627 WriteNode node(&trans);
628 std::string empty_tag;
629 WriteNode::InitUniqueByCreationResult result =
630 node.InitUniqueByCreation(TYPED_URLS, root_node, empty_tag);
631 EXPECT_NE(WriteNode::INIT_SUCCESS, result);
632 EXPECT_EQ(BaseNode::INIT_FAILED_PRECONDITION,
633 node.InitByTagLookup(empty_tag));
634 }
635
636 namespace {
637
638 class TestHttpPostProviderInterface : public HttpPostProviderInterface {
639 public:
640 virtual ~TestHttpPostProviderInterface() {}
641
642 virtual void SetExtraRequestHeaders(const char* headers) OVERRIDE {}
643 virtual void SetURL(const char* url, int port) OVERRIDE {}
644 virtual void SetPostPayload(const char* content_type,
645 int content_length,
646 const char* content) OVERRIDE {}
647 virtual bool MakeSynchronousPost(int* error_code, int* response_code)
648 OVERRIDE {
649 return false;
650 }
651 virtual int GetResponseContentLength() const OVERRIDE {
652 return 0;
653 }
654 virtual const char* GetResponseContent() const OVERRIDE {
655 return "";
656 }
657 virtual const std::string GetResponseHeaderValue(
658 const std::string& name) const OVERRIDE {
659 return "";
660 }
661 virtual void Abort() OVERRIDE {}
662 };
663
664 class TestHttpPostProviderFactory : public HttpPostProviderFactory {
665 public:
666 virtual ~TestHttpPostProviderFactory() {}
667 virtual HttpPostProviderInterface* Create() OVERRIDE {
668 return new TestHttpPostProviderInterface();
669 }
670 virtual void Destroy(HttpPostProviderInterface* http) OVERRIDE {
671 delete static_cast<TestHttpPostProviderInterface*>(http);
672 }
673 };
674
675 class SyncManagerObserverMock : public SyncManager::Observer {
676 public:
677 MOCK_METHOD1(OnSyncCycleCompleted,
678 void(const SyncSessionSnapshot&)); // NOLINT
679 MOCK_METHOD3(OnInitializationComplete,
680 void(const WeakHandle<JsBackend>&, bool,
681 syncer::ModelTypeSet)); // NOLINT
682 MOCK_METHOD1(OnConnectionStatusChange, void(ConnectionStatus)); // NOLINT
683 MOCK_METHOD2(OnPassphraseRequired,
684 void(PassphraseRequiredReason,
685 const sync_pb::EncryptedData&)); // NOLINT
686 MOCK_METHOD0(OnPassphraseAccepted, void()); // NOLINT
687 MOCK_METHOD1(OnBootstrapTokenUpdated, void(const std::string&)); // NOLINT
688 MOCK_METHOD0(OnStopSyncingPermanently, void()); // NOLINT
689 MOCK_METHOD1(OnUpdatedToken, void(const std::string&)); // NOLINT
690 MOCK_METHOD2(OnEncryptedTypesChanged,
691 void(ModelTypeSet, bool)); // NOLINT
692 MOCK_METHOD0(OnEncryptionComplete, void()); // NOLINT
693 MOCK_METHOD1(OnActionableError,
694 void(const SyncProtocolError&)); // NOLINT
695 };
696
697 class SyncNotifierMock : public SyncNotifier {
698 public:
699 MOCK_METHOD2(UpdateRegisteredIds, void(SyncNotifierObserver*,
700 const ObjectIdSet&));
701 MOCK_METHOD1(SetUniqueId, void(const std::string&));
702 MOCK_METHOD1(SetStateDeprecated, void(const std::string&));
703 MOCK_METHOD2(UpdateCredentials,
704 void(const std::string&, const std::string&));
705 MOCK_METHOD1(SendNotification, void(ModelTypeSet));
706 };
707
708 } // namespace
709
710 class SyncManagerTest : public testing::Test,
711 public SyncManager::ChangeDelegate {
712 protected:
713 enum NigoriStatus {
714 DONT_WRITE_NIGORI,
715 WRITE_TO_NIGORI
716 };
717
718 enum EncryptionStatus {
719 UNINITIALIZED,
720 DEFAULT_ENCRYPTION,
721 FULL_ENCRYPTION
722 };
723
724 SyncManagerTest()
725 : sync_notifier_mock_(NULL),
726 sync_manager_("Test sync manager") {}
727
728 virtual ~SyncManagerTest() {
729 EXPECT_FALSE(sync_notifier_mock_);
730 }
731
732 // Test implementation.
733 void SetUp() {
734 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
735
736 SyncCredentials credentials;
737 credentials.email = "foo@bar.com";
738 credentials.sync_token = "sometoken";
739
740 sync_notifier_mock_ = new StrictMock<SyncNotifierMock>();
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
746 sync_manager_.AddObserver(&observer_);
747 EXPECT_CALL(observer_, OnInitializationComplete(_, _, _)).
748 WillOnce(SaveArg<0>(&js_backend_));
749
750 EXPECT_FALSE(js_backend_.IsInitialized());
751
752 std::vector<ModelSafeWorker*> workers;
753 ModelSafeRoutingInfo routing_info;
754 GetModelSafeRoutingInfo(&routing_info);
755
756 // Takes ownership of |sync_notifier_mock_|.
757 sync_manager_.Init(temp_dir_.path(),
758 WeakHandle<JsEventHandler>(),
759 "bogus", 0, false,
760 base::MessageLoopProxy::current(),
761 scoped_ptr<HttpPostProviderFactory>(
762 new TestHttpPostProviderFactory()),
763 workers, &extensions_activity_monitor_, this,
764 credentials,
765 scoped_ptr<SyncNotifier>(sync_notifier_mock_),
766 "", "", // bootstrap tokens
767 true, // enable keystore encryption
768 scoped_ptr<InternalComponentsFactory>(GetFactory()),
769 &encryptor_,
770 &handler_,
771 NULL);
772
773 EXPECT_TRUE(js_backend_.IsInitialized());
774
775 for (ModelSafeRoutingInfo::iterator i = routing_info.begin();
776 i != routing_info.end(); ++i) {
777 type_roots_[i->first] = MakeServerNodeForType(
778 sync_manager_.GetUserShare(), i->first);
779 }
780 PumpLoop();
781 }
782
783 void TearDown() {
784 sync_manager_.RemoveObserver(&observer_);
785 EXPECT_CALL(*sync_notifier_mock_,
786 UpdateRegisteredIds(_, ObjectIdSet()));
787 sync_manager_.ShutdownOnSyncThread();
788 sync_notifier_mock_ = NULL;
789 PumpLoop();
790 }
791
792 void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
793 (*out)[NIGORI] = GROUP_PASSIVE;
794 (*out)[BOOKMARKS] = GROUP_PASSIVE;
795 (*out)[THEMES] = GROUP_PASSIVE;
796 (*out)[SESSIONS] = GROUP_PASSIVE;
797 (*out)[PASSWORDS] = GROUP_PASSIVE;
798 (*out)[PREFERENCES] = GROUP_PASSIVE;
799 }
800
801 virtual void OnChangesApplied(
802 ModelType model_type,
803 const BaseTransaction* trans,
804 const ImmutableChangeRecordList& changes) OVERRIDE {}
805
806 virtual void OnChangesComplete(ModelType model_type) OVERRIDE {}
807
808 // Helper methods.
809 bool SetUpEncryption(NigoriStatus nigori_status,
810 EncryptionStatus encryption_status) {
811 UserShare* share = sync_manager_.GetUserShare();
812 share->directory->set_initial_sync_ended_for_type(NIGORI, true);
813
814 // We need to create the nigori node as if it were an applied server update.
815 int64 nigori_id = GetIdForDataType(NIGORI);
816 if (nigori_id == kInvalidId)
817 return false;
818
819 // Set the nigori cryptographer information.
820 WriteTransaction trans(FROM_HERE, share);
821 Cryptographer* cryptographer = trans.GetCryptographer();
822 if (!cryptographer)
823 return false;
824 if (encryption_status != UNINITIALIZED) {
825 KeyParams params = {"localhost", "dummy", "foobar"};
826 cryptographer->AddKey(params);
827 } else {
828 DCHECK_NE(nigori_status, WRITE_TO_NIGORI);
829 }
830 if (encryption_status == FULL_ENCRYPTION)
831 cryptographer->set_encrypt_everything();
832 if (nigori_status == WRITE_TO_NIGORI) {
833 sync_pb::NigoriSpecifics nigori;
834 cryptographer->GetKeys(nigori.mutable_encrypted());
835 cryptographer->UpdateNigoriFromEncryptedTypes(&nigori);
836 WriteNode node(&trans);
837 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(nigori_id));
838 node.SetNigoriSpecifics(nigori);
839 }
840 return cryptographer->is_ready();
841 }
842
843 int64 GetIdForDataType(ModelType type) {
844 if (type_roots_.count(type) == 0)
845 return 0;
846 return type_roots_[type];
847 }
848
849 void PumpLoop() {
850 message_loop_.RunAllPending();
851 }
852
853 void SendJsMessage(const std::string& name, const JsArgList& args,
854 const WeakHandle<JsReplyHandler>& reply_handler) {
855 js_backend_.Call(FROM_HERE, &JsBackend::ProcessJsMessage,
856 name, args, reply_handler);
857 PumpLoop();
858 }
859
860 void SetJsEventHandler(const WeakHandle<JsEventHandler>& event_handler) {
861 js_backend_.Call(FROM_HERE, &JsBackend::SetJsEventHandler,
862 event_handler);
863 PumpLoop();
864 }
865
866 // Looks up an entry by client tag and resets IS_UNSYNCED value to false.
867 // Returns true if entry was previously unsynced, false if IS_UNSYNCED was
868 // already false.
869 bool ResetUnsyncedEntry(ModelType type,
870 const std::string& client_tag) {
871 UserShare* share = sync_manager_.GetUserShare();
872 syncable::WriteTransaction trans(
873 FROM_HERE, syncable::UNITTEST, share->directory.get());
874 const std::string hash = BaseNode::GenerateSyncableHash(type, client_tag);
875 syncable::MutableEntry entry(&trans, syncable::GET_BY_CLIENT_TAG,
876 hash);
877 EXPECT_TRUE(entry.good());
878 if (!entry.Get(IS_UNSYNCED))
879 return false;
880 entry.Put(IS_UNSYNCED, false);
881 return true;
882 }
883
884 virtual InternalComponentsFactory* GetFactory() {
885 return new TestInternalComponentsFactory(STORAGE_IN_MEMORY);
886 }
887
888 // Returns true if we are currently encrypting all sync data. May
889 // be called on any thread.
890 bool EncryptEverythingEnabledForTest() {
891 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
892 return trans.GetCryptographer()->encrypt_everything();
893 }
894
895 // Gets the set of encrypted types from the cryptographer
896 // Note: opens a transaction. May be called from any thread.
897 syncer::ModelTypeSet GetEncryptedDataTypesForTest() {
898 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
899 return GetEncryptedTypes(&trans);
900 }
901
902 void SimulateEnableNotificationsForTest() {
903 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread());
904 sync_manager_.OnNotificationsEnabled();
905 }
906
907 void SimulateDisableNotificationsForTest(
908 NotificationsDisabledReason reason) {
909 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread());
910 sync_manager_.OnNotificationsDisabled(reason);
911 }
912
913 void TriggerOnIncomingNotificationForTest(ModelTypeSet model_types) {
914 DCHECK(sync_manager_.thread_checker_.CalledOnValidThread());
915 ModelTypePayloadMap model_types_with_payloads =
916 ModelTypePayloadMapFromEnumSet(model_types, std::string());
917 sync_manager_.OnIncomingNotification(
918 ModelTypePayloadMapToObjectIdPayloadMap(model_types_with_payloads),
919 REMOTE_NOTIFICATION);
920 }
921
922 void SetProgressMarkerForType(ModelType type, bool set) {
923 if (set) {
924 sync_pb::DataTypeProgressMarker marker;
925 marker.set_token("token");
926 marker.set_data_type_id(GetSpecificsFieldNumberFromModelType(type));
927 sync_manager_.directory()->SetDownloadProgress(type, marker);
928 } else {
929 sync_pb::DataTypeProgressMarker marker;
930 sync_manager_.directory()->SetDownloadProgress(type, marker);
931 }
932 }
933
934 void SetInitialSyncEndedForType(ModelType type, bool value) {
935 sync_manager_.directory()->set_initial_sync_ended_for_type(type, value);
936 }
937
938 private:
939 // Needed by |sync_manager_|.
940 MessageLoop message_loop_;
941 // Needed by |sync_manager_|.
942 ScopedTempDir temp_dir_;
943 // Sync Id's for the roots of the enabled datatypes.
944 std::map<ModelType, int64> type_roots_;
945 FakeExtensionsActivityMonitor extensions_activity_monitor_;
946
947 protected:
948 FakeEncryptor encryptor_;
949 TestUnrecoverableErrorHandler handler_;
950 StrictMock<SyncNotifierMock>* sync_notifier_mock_;
951 SyncManagerImpl sync_manager_;
952 WeakHandle<JsBackend> js_backend_;
953 StrictMock<SyncManagerObserverMock> observer_;
954 };
955
956 TEST_F(SyncManagerTest, UpdateEnabledTypes) {
957 ModelSafeRoutingInfo routes;
958 GetModelSafeRoutingInfo(&routes);
959 const ModelTypeSet enabled_types = GetRoutingInfoTypes(routes);
960
961 EXPECT_CALL(*sync_notifier_mock_,
962 UpdateRegisteredIds(_, ModelTypeSetToObjectIdSet(enabled_types)));
963 sync_manager_.UpdateEnabledTypes(enabled_types);
964 }
965
966 TEST_F(SyncManagerTest, ProcessJsMessage) {
967 const JsArgList kNoArgs;
968
969 StrictMock<MockJsReplyHandler> reply_handler;
970
971 ListValue false_args;
972 false_args.Append(Value::CreateBooleanValue(false));
973
974 EXPECT_CALL(reply_handler,
975 HandleJsReply("getNotificationState",
976 HasArgsAsList(false_args)));
977
978 // This message should be dropped.
979 SendJsMessage("unknownMessage", kNoArgs, reply_handler.AsWeakHandle());
980
981 SendJsMessage("getNotificationState", kNoArgs, reply_handler.AsWeakHandle());
982 }
983
984 TEST_F(SyncManagerTest, ProcessJsMessageGetRootNodeDetails) {
985 const JsArgList kNoArgs;
986
987 StrictMock<MockJsReplyHandler> reply_handler;
988
989 JsArgList return_args;
990
991 EXPECT_CALL(reply_handler,
992 HandleJsReply("getRootNodeDetails", _))
993 .WillOnce(SaveArg<1>(&return_args));
994
995 SendJsMessage("getRootNodeDetails", kNoArgs, reply_handler.AsWeakHandle());
996
997 EXPECT_EQ(1u, return_args.Get().GetSize());
998 DictionaryValue* node_info = NULL;
999 EXPECT_TRUE(return_args.Get().GetDictionary(0, &node_info));
1000 if (node_info) {
1001 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1002 ReadNode node(&trans);
1003 node.InitByRootLookup();
1004 CheckNodeValue(node, *node_info, true);
1005 } else {
1006 ADD_FAILURE();
1007 }
1008 }
1009
1010 void CheckGetNodesByIdReturnArgs(SyncManager* sync_manager,
1011 const JsArgList& return_args,
1012 int64 id,
1013 bool is_detailed) {
1014 EXPECT_EQ(1u, return_args.Get().GetSize());
1015 ListValue* nodes = NULL;
1016 ASSERT_TRUE(return_args.Get().GetList(0, &nodes));
1017 ASSERT_TRUE(nodes);
1018 EXPECT_EQ(1u, nodes->GetSize());
1019 DictionaryValue* node_info = NULL;
1020 EXPECT_TRUE(nodes->GetDictionary(0, &node_info));
1021 ASSERT_TRUE(node_info);
1022 ReadTransaction trans(FROM_HERE, sync_manager->GetUserShare());
1023 ReadNode node(&trans);
1024 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
1025 CheckNodeValue(node, *node_info, is_detailed);
1026 }
1027
1028 class SyncManagerGetNodesByIdTest : public SyncManagerTest {
1029 protected:
1030 virtual ~SyncManagerGetNodesByIdTest() {}
1031
1032 void RunGetNodesByIdTest(const char* message_name, bool is_detailed) {
1033 int64 root_id = kInvalidId;
1034 {
1035 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1036 ReadNode root_node(&trans);
1037 root_node.InitByRootLookup();
1038 root_id = root_node.GetId();
1039 }
1040
1041 int64 child_id =
1042 MakeNode(sync_manager_.GetUserShare(), BOOKMARKS, "testtag");
1043
1044 StrictMock<MockJsReplyHandler> reply_handler;
1045
1046 JsArgList return_args;
1047
1048 const int64 ids[] = { root_id, child_id };
1049
1050 EXPECT_CALL(reply_handler,
1051 HandleJsReply(message_name, _))
1052 .Times(arraysize(ids)).WillRepeatedly(SaveArg<1>(&return_args));
1053
1054 for (size_t i = 0; i < arraysize(ids); ++i) {
1055 ListValue args;
1056 ListValue* id_values = new ListValue();
1057 args.Append(id_values);
1058 id_values->Append(Value::CreateStringValue(base::Int64ToString(ids[i])));
1059 SendJsMessage(message_name,
1060 JsArgList(&args), reply_handler.AsWeakHandle());
1061
1062 CheckGetNodesByIdReturnArgs(&sync_manager_, return_args,
1063 ids[i], is_detailed);
1064 }
1065 }
1066
1067 void RunGetNodesByIdFailureTest(const char* message_name) {
1068 StrictMock<MockJsReplyHandler> reply_handler;
1069
1070 ListValue empty_list_args;
1071 empty_list_args.Append(new ListValue());
1072
1073 EXPECT_CALL(reply_handler,
1074 HandleJsReply(message_name,
1075 HasArgsAsList(empty_list_args)))
1076 .Times(6);
1077
1078 {
1079 ListValue args;
1080 SendJsMessage(message_name,
1081 JsArgList(&args), reply_handler.AsWeakHandle());
1082 }
1083
1084 {
1085 ListValue args;
1086 args.Append(new ListValue());
1087 SendJsMessage(message_name,
1088 JsArgList(&args), reply_handler.AsWeakHandle());
1089 }
1090
1091 {
1092 ListValue args;
1093 ListValue* ids = new ListValue();
1094 args.Append(ids);
1095 ids->Append(Value::CreateStringValue(""));
1096 SendJsMessage(message_name,
1097 JsArgList(&args), reply_handler.AsWeakHandle());
1098 }
1099
1100 {
1101 ListValue args;
1102 ListValue* ids = new ListValue();
1103 args.Append(ids);
1104 ids->Append(Value::CreateStringValue("nonsense"));
1105 SendJsMessage(message_name,
1106 JsArgList(&args), reply_handler.AsWeakHandle());
1107 }
1108
1109 {
1110 ListValue args;
1111 ListValue* ids = new ListValue();
1112 args.Append(ids);
1113 ids->Append(Value::CreateStringValue("0"));
1114 SendJsMessage(message_name,
1115 JsArgList(&args), reply_handler.AsWeakHandle());
1116 }
1117
1118 {
1119 ListValue args;
1120 ListValue* ids = new ListValue();
1121 args.Append(ids);
1122 ids->Append(Value::CreateStringValue("9999"));
1123 SendJsMessage(message_name,
1124 JsArgList(&args), reply_handler.AsWeakHandle());
1125 }
1126 }
1127 };
1128
1129 TEST_F(SyncManagerGetNodesByIdTest, GetNodeSummariesById) {
1130 RunGetNodesByIdTest("getNodeSummariesById", false);
1131 }
1132
1133 TEST_F(SyncManagerGetNodesByIdTest, GetNodeDetailsById) {
1134 RunGetNodesByIdTest("getNodeDetailsById", true);
1135 }
1136
1137 TEST_F(SyncManagerGetNodesByIdTest, GetNodeSummariesByIdFailure) {
1138 RunGetNodesByIdFailureTest("getNodeSummariesById");
1139 }
1140
1141 TEST_F(SyncManagerGetNodesByIdTest, GetNodeDetailsByIdFailure) {
1142 RunGetNodesByIdFailureTest("getNodeDetailsById");
1143 }
1144
1145 TEST_F(SyncManagerTest, GetChildNodeIds) {
1146 StrictMock<MockJsReplyHandler> reply_handler;
1147
1148 JsArgList return_args;
1149
1150 EXPECT_CALL(reply_handler,
1151 HandleJsReply("getChildNodeIds", _))
1152 .Times(1).WillRepeatedly(SaveArg<1>(&return_args));
1153
1154 {
1155 ListValue args;
1156 args.Append(Value::CreateStringValue("1"));
1157 SendJsMessage("getChildNodeIds",
1158 JsArgList(&args), reply_handler.AsWeakHandle());
1159 }
1160
1161 EXPECT_EQ(1u, return_args.Get().GetSize());
1162 ListValue* nodes = NULL;
1163 ASSERT_TRUE(return_args.Get().GetList(0, &nodes));
1164 ASSERT_TRUE(nodes);
1165 EXPECT_EQ(6u, nodes->GetSize());
1166 }
1167
1168 TEST_F(SyncManagerTest, GetChildNodeIdsFailure) {
1169 StrictMock<MockJsReplyHandler> reply_handler;
1170
1171 ListValue empty_list_args;
1172 empty_list_args.Append(new ListValue());
1173
1174 EXPECT_CALL(reply_handler,
1175 HandleJsReply("getChildNodeIds",
1176 HasArgsAsList(empty_list_args)))
1177 .Times(5);
1178
1179 {
1180 ListValue args;
1181 SendJsMessage("getChildNodeIds",
1182 JsArgList(&args), reply_handler.AsWeakHandle());
1183 }
1184
1185 {
1186 ListValue args;
1187 args.Append(Value::CreateStringValue(""));
1188 SendJsMessage("getChildNodeIds",
1189 JsArgList(&args), reply_handler.AsWeakHandle());
1190 }
1191
1192 {
1193 ListValue args;
1194 args.Append(Value::CreateStringValue("nonsense"));
1195 SendJsMessage("getChildNodeIds",
1196 JsArgList(&args), reply_handler.AsWeakHandle());
1197 }
1198
1199 {
1200 ListValue args;
1201 args.Append(Value::CreateStringValue("0"));
1202 SendJsMessage("getChildNodeIds",
1203 JsArgList(&args), reply_handler.AsWeakHandle());
1204 }
1205
1206 {
1207 ListValue args;
1208 args.Append(Value::CreateStringValue("9999"));
1209 SendJsMessage("getChildNodeIds",
1210 JsArgList(&args), reply_handler.AsWeakHandle());
1211 }
1212 }
1213
1214 TEST_F(SyncManagerTest, GetAllNodesTest) {
1215 StrictMock<MockJsReplyHandler> reply_handler;
1216 JsArgList return_args;
1217
1218 EXPECT_CALL(reply_handler,
1219 HandleJsReply("getAllNodes", _))
1220 .Times(1).WillRepeatedly(SaveArg<1>(&return_args));
1221
1222 {
1223 ListValue args;
1224 SendJsMessage("getAllNodes",
1225 JsArgList(&args), reply_handler.AsWeakHandle());
1226 }
1227
1228 // There's not much value in verifying every attribute on every node here.
1229 // Most of the value of this test has already been achieved: we've verified we
1230 // can call the above function without crashing or leaking memory.
1231 //
1232 // Let's just check the list size and a few of its elements. Anything more
1233 // would make this test brittle without greatly increasing our chances of
1234 // catching real bugs.
1235
1236 ListValue* node_list;
1237 DictionaryValue* first_result;
1238
1239 // The resulting argument list should have one argument, a list of nodes.
1240 ASSERT_EQ(1U, return_args.Get().GetSize());
1241 ASSERT_TRUE(return_args.Get().GetList(0, &node_list));
1242
1243 // The database creation logic depends on the routing info.
1244 // Refer to setup methods for more information.
1245 ModelSafeRoutingInfo routes;
1246 GetModelSafeRoutingInfo(&routes);
1247 size_t directory_size = routes.size() + 1;
1248
1249 ASSERT_EQ(directory_size, node_list->GetSize());
1250 ASSERT_TRUE(node_list->GetDictionary(0, &first_result));
1251 EXPECT_TRUE(first_result->HasKey("ID"));
1252 EXPECT_TRUE(first_result->HasKey("NON_UNIQUE_NAME"));
1253 }
1254
1255 TEST_F(SyncManagerTest, OnNotificationStateChange) {
1256 InSequence dummy;
1257 StrictMock<MockJsEventHandler> event_handler;
1258
1259 DictionaryValue true_details;
1260 true_details.SetBoolean("enabled", true);
1261 DictionaryValue false_details;
1262 false_details.SetBoolean("enabled", false);
1263
1264 EXPECT_CALL(event_handler,
1265 HandleJsEvent("onNotificationStateChange",
1266 HasDetailsAsDictionary(true_details)));
1267 EXPECT_CALL(event_handler,
1268 HandleJsEvent("onNotificationStateChange",
1269 HasDetailsAsDictionary(false_details)));
1270
1271 SimulateEnableNotificationsForTest();
1272 SimulateDisableNotificationsForTest(TRANSIENT_NOTIFICATION_ERROR);
1273
1274 SetJsEventHandler(event_handler.AsWeakHandle());
1275 SimulateEnableNotificationsForTest();
1276 SimulateDisableNotificationsForTest(TRANSIENT_NOTIFICATION_ERROR);
1277 SetJsEventHandler(WeakHandle<JsEventHandler>());
1278
1279 SimulateEnableNotificationsForTest();
1280 SimulateDisableNotificationsForTest(TRANSIENT_NOTIFICATION_ERROR);
1281
1282 // Should trigger the replies.
1283 PumpLoop();
1284 }
1285
1286 TEST_F(SyncManagerTest, OnIncomingNotification) {
1287 StrictMock<MockJsEventHandler> event_handler;
1288
1289 const ModelTypeSet empty_model_types;
1290 const ModelTypeSet model_types(
1291 BOOKMARKS, THEMES);
1292
1293 // Build expected_args to have a single argument with the string
1294 // equivalents of model_types.
1295 DictionaryValue expected_details;
1296 {
1297 ListValue* model_type_list = new ListValue();
1298 expected_details.SetString("source", "REMOTE_NOTIFICATION");
1299 expected_details.Set("changedTypes", model_type_list);
1300 for (ModelTypeSet::Iterator it = model_types.First();
1301 it.Good(); it.Inc()) {
1302 model_type_list->Append(
1303 Value::CreateStringValue(ModelTypeToString(it.Get())));
1304 }
1305 }
1306
1307 EXPECT_CALL(event_handler,
1308 HandleJsEvent("onIncomingNotification",
1309 HasDetailsAsDictionary(expected_details)));
1310
1311 TriggerOnIncomingNotificationForTest(empty_model_types);
1312 TriggerOnIncomingNotificationForTest(model_types);
1313
1314 SetJsEventHandler(event_handler.AsWeakHandle());
1315 TriggerOnIncomingNotificationForTest(model_types);
1316 SetJsEventHandler(WeakHandle<JsEventHandler>());
1317
1318 TriggerOnIncomingNotificationForTest(empty_model_types);
1319 TriggerOnIncomingNotificationForTest(model_types);
1320
1321 // Should trigger the replies.
1322 PumpLoop();
1323 }
1324
1325 TEST_F(SyncManagerTest, RefreshEncryptionReady) {
1326 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1327 EXPECT_CALL(observer_, OnEncryptionComplete());
1328
1329 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
1330 PumpLoop();
1331
1332 const ModelTypeSet encrypted_types = GetEncryptedDataTypesForTest();
1333 EXPECT_TRUE(encrypted_types.Has(PASSWORDS));
1334 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1335
1336 {
1337 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1338 ReadNode node(&trans);
1339 EXPECT_EQ(BaseNode::INIT_OK,
1340 node.InitByIdLookup(GetIdForDataType(NIGORI)));
1341 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
1342 EXPECT_TRUE(nigori.has_encrypted());
1343 Cryptographer* cryptographer = trans.GetCryptographer();
1344 EXPECT_TRUE(cryptographer->is_ready());
1345 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encrypted()));
1346 }
1347 }
1348
1349 // Attempt to refresh encryption when nigori not downloaded.
1350 TEST_F(SyncManagerTest, RefreshEncryptionNotReady) {
1351 // Don't set up encryption (no nigori node created).
1352
1353 // Should fail.
1354 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
1355 PumpLoop();
1356
1357 const ModelTypeSet encrypted_types = GetEncryptedDataTypesForTest();
1358 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded.
1359 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1360 }
1361
1362 // Attempt to refresh encryption when nigori is empty.
1363 TEST_F(SyncManagerTest, RefreshEncryptionEmptyNigori) {
1364 EXPECT_TRUE(SetUpEncryption(DONT_WRITE_NIGORI, DEFAULT_ENCRYPTION));
1365 EXPECT_CALL(observer_, OnEncryptionComplete());
1366
1367 // Should write to nigori.
1368 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
1369 PumpLoop();
1370
1371 const ModelTypeSet encrypted_types = GetEncryptedDataTypesForTest();
1372 EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); // Hardcoded.
1373 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1374
1375 {
1376 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1377 ReadNode node(&trans);
1378 EXPECT_EQ(BaseNode::INIT_OK,
1379 node.InitByIdLookup(GetIdForDataType(NIGORI)));
1380 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
1381 EXPECT_TRUE(nigori.has_encrypted());
1382 Cryptographer* cryptographer = trans.GetCryptographer();
1383 EXPECT_TRUE(cryptographer->is_ready());
1384 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encrypted()));
1385 }
1386 }
1387
1388 TEST_F(SyncManagerTest, EncryptDataTypesWithNoData) {
1389 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1390 EXPECT_CALL(observer_,
1391 OnEncryptedTypesChanged(
1392 HasModelTypes(ModelTypeSet::All()), true));
1393 EXPECT_CALL(observer_, OnEncryptionComplete());
1394 sync_manager_.EnableEncryptEverything();
1395 EXPECT_TRUE(EncryptEverythingEnabledForTest());
1396 }
1397
1398 TEST_F(SyncManagerTest, EncryptDataTypesWithData) {
1399 size_t batch_size = 5;
1400 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1401
1402 // Create some unencrypted unsynced data.
1403 int64 folder = MakeFolderWithParent(sync_manager_.GetUserShare(),
1404 BOOKMARKS,
1405 GetIdForDataType(BOOKMARKS),
1406 NULL);
1407 // First batch_size nodes are children of folder.
1408 size_t i;
1409 for (i = 0; i < batch_size; ++i) {
1410 MakeNodeWithParent(sync_manager_.GetUserShare(), BOOKMARKS,
1411 base::StringPrintf("%"PRIuS"", i), folder);
1412 }
1413 // Next batch_size nodes are a different type and on their own.
1414 for (; i < 2*batch_size; ++i) {
1415 MakeNodeWithParent(sync_manager_.GetUserShare(), SESSIONS,
1416 base::StringPrintf("%"PRIuS"", i),
1417 GetIdForDataType(SESSIONS));
1418 }
1419 // Last batch_size nodes are a third type that will not need encryption.
1420 for (; i < 3*batch_size; ++i) {
1421 MakeNodeWithParent(sync_manager_.GetUserShare(), THEMES,
1422 base::StringPrintf("%"PRIuS"", i),
1423 GetIdForDataType(THEMES));
1424 }
1425
1426 {
1427 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1428 EXPECT_TRUE(GetEncryptedTypes(&trans).Equals(
1429 Cryptographer::SensitiveTypes()));
1430 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1431 trans.GetWrappedTrans(),
1432 trans.GetCryptographer(),
1433 BOOKMARKS,
1434 false /* not encrypted */));
1435 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1436 trans.GetWrappedTrans(),
1437 trans.GetCryptographer(),
1438 SESSIONS,
1439 false /* not encrypted */));
1440 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1441 trans.GetWrappedTrans(),
1442 trans.GetCryptographer(),
1443 THEMES,
1444 false /* not encrypted */));
1445 }
1446
1447 EXPECT_CALL(observer_,
1448 OnEncryptedTypesChanged(
1449 HasModelTypes(ModelTypeSet::All()), true));
1450 EXPECT_CALL(observer_, OnEncryptionComplete());
1451 sync_manager_.EnableEncryptEverything();
1452 EXPECT_TRUE(EncryptEverythingEnabledForTest());
1453 {
1454 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1455 EXPECT_TRUE(GetEncryptedTypes(&trans).Equals(
1456 ModelTypeSet::All()));
1457 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1458 trans.GetWrappedTrans(),
1459 trans.GetCryptographer(),
1460 BOOKMARKS,
1461 true /* is encrypted */));
1462 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1463 trans.GetWrappedTrans(),
1464 trans.GetCryptographer(),
1465 SESSIONS,
1466 true /* is encrypted */));
1467 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1468 trans.GetWrappedTrans(),
1469 trans.GetCryptographer(),
1470 THEMES,
1471 true /* is encrypted */));
1472 }
1473
1474 // Trigger's a ReEncryptEverything with new passphrase.
1475 testing::Mock::VerifyAndClearExpectations(&observer_);
1476 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1477 EXPECT_CALL(observer_, OnPassphraseAccepted());
1478 EXPECT_CALL(observer_, OnEncryptionComplete());
1479 sync_manager_.SetEncryptionPassphrase("new_passphrase", true);
1480 EXPECT_TRUE(EncryptEverythingEnabledForTest());
1481 {
1482 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1483 EXPECT_TRUE(GetEncryptedTypes(&trans).Equals(ModelTypeSet::All()));
1484 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1485 trans.GetWrappedTrans(),
1486 trans.GetCryptographer(),
1487 BOOKMARKS,
1488 true /* is encrypted */));
1489 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1490 trans.GetWrappedTrans(),
1491 trans.GetCryptographer(),
1492 SESSIONS,
1493 true /* is encrypted */));
1494 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1495 trans.GetWrappedTrans(),
1496 trans.GetCryptographer(),
1497 THEMES,
1498 true /* is encrypted */));
1499 }
1500 // Calling EncryptDataTypes with an empty encrypted types should not trigger
1501 // a reencryption and should just notify immediately.
1502 // TODO(zea): add logic to ensure nothing was written.
1503 testing::Mock::VerifyAndClearExpectations(&observer_);
1504 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_)).Times(0);
1505 EXPECT_CALL(observer_, OnPassphraseAccepted()).Times(0);
1506 EXPECT_CALL(observer_, OnEncryptionComplete());
1507 sync_manager_.EnableEncryptEverything();
1508 }
1509
1510 // Test that when there are no pending keys and the cryptographer is not
1511 // initialized, we add a key based on the current GAIA password.
1512 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1513 TEST_F(SyncManagerTest, SetInitialGaiaPass) {
1514 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED));
1515 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1516 EXPECT_CALL(observer_, OnPassphraseAccepted());
1517 EXPECT_CALL(observer_, OnEncryptionComplete());
1518 sync_manager_.SetEncryptionPassphrase("new_passphrase", false);
1519 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1520 {
1521 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1522 ReadNode node(&trans);
1523 EXPECT_EQ(BaseNode::INIT_OK, node.InitByTagLookup(kNigoriTag));
1524 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics();
1525 Cryptographer* cryptographer = trans.GetCryptographer();
1526 EXPECT_TRUE(cryptographer->is_ready());
1527 EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encrypted()));
1528 }
1529 }
1530
1531 // Test that when there are no pending keys and we have on the old GAIA
1532 // password, we update and re-encrypt everything with the new GAIA password.
1533 // (case 1 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1534 TEST_F(SyncManagerTest, UpdateGaiaPass) {
1535 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1536 Cryptographer verifier(&encryptor_);
1537 {
1538 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1539 Cryptographer* cryptographer = trans.GetCryptographer();
1540 std::string bootstrap_token;
1541 cryptographer->GetBootstrapToken(&bootstrap_token);
1542 verifier.Bootstrap(bootstrap_token);
1543 }
1544 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1545 EXPECT_CALL(observer_, OnPassphraseAccepted());
1546 EXPECT_CALL(observer_, OnEncryptionComplete());
1547 sync_manager_.SetEncryptionPassphrase("new_passphrase", false);
1548 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1549 {
1550 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1551 Cryptographer* cryptographer = trans.GetCryptographer();
1552 EXPECT_TRUE(cryptographer->is_ready());
1553 // Verify the default key has changed.
1554 sync_pb::EncryptedData encrypted;
1555 cryptographer->GetKeys(&encrypted);
1556 EXPECT_FALSE(verifier.CanDecrypt(encrypted));
1557 }
1558 }
1559
1560 // Sets a new explicit passphrase. This should update the bootstrap token
1561 // and re-encrypt everything.
1562 // (case 2 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1563 TEST_F(SyncManagerTest, SetPassphraseWithPassword) {
1564 Cryptographer verifier(&encryptor_);
1565 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1566 {
1567 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1568 // Store the default (soon to be old) key.
1569 Cryptographer* cryptographer = trans.GetCryptographer();
1570 std::string bootstrap_token;
1571 cryptographer->GetBootstrapToken(&bootstrap_token);
1572 verifier.Bootstrap(bootstrap_token);
1573
1574 ReadNode root_node(&trans);
1575 root_node.InitByRootLookup();
1576
1577 WriteNode password_node(&trans);
1578 WriteNode::InitUniqueByCreationResult result =
1579 password_node.InitUniqueByCreation(PASSWORDS,
1580 root_node, "foo");
1581 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
1582 sync_pb::PasswordSpecificsData data;
1583 data.set_password_value("secret");
1584 password_node.SetPasswordSpecifics(data);
1585 }
1586 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1587 EXPECT_CALL(observer_, OnPassphraseAccepted());
1588 EXPECT_CALL(observer_, OnEncryptionComplete());
1589 sync_manager_.SetEncryptionPassphrase("new_passphrase", true);
1590 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1591 {
1592 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1593 Cryptographer* cryptographer = trans.GetCryptographer();
1594 EXPECT_TRUE(cryptographer->is_ready());
1595 // Verify the default key has changed.
1596 sync_pb::EncryptedData encrypted;
1597 cryptographer->GetKeys(&encrypted);
1598 EXPECT_FALSE(verifier.CanDecrypt(encrypted));
1599
1600 ReadNode password_node(&trans);
1601 EXPECT_EQ(BaseNode::INIT_OK,
1602 password_node.InitByClientTagLookup(PASSWORDS,
1603 "foo"));
1604 const sync_pb::PasswordSpecificsData& data =
1605 password_node.GetPasswordSpecifics();
1606 EXPECT_EQ("secret", data.password_value());
1607 }
1608 }
1609
1610 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1611 // being encrypted with a new (unprovided) GAIA password, then supply the
1612 // password.
1613 // (case 7 in SyncManager::SyncInternal::SetDecryptionPassphrase)
1614 TEST_F(SyncManagerTest, SupplyPendingGAIAPass) {
1615 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1616 Cryptographer other_cryptographer(&encryptor_);
1617 {
1618 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1619 Cryptographer* cryptographer = trans.GetCryptographer();
1620 std::string bootstrap_token;
1621 cryptographer->GetBootstrapToken(&bootstrap_token);
1622 other_cryptographer.Bootstrap(bootstrap_token);
1623
1624 // Now update the nigori to reflect the new keys, and update the
1625 // cryptographer to have pending keys.
1626 KeyParams params = {"localhost", "dummy", "passphrase2"};
1627 other_cryptographer.AddKey(params);
1628 WriteNode node(&trans);
1629 EXPECT_EQ(BaseNode::INIT_OK, node.InitByTagLookup(kNigoriTag));
1630 sync_pb::NigoriSpecifics nigori;
1631 other_cryptographer.GetKeys(nigori.mutable_encrypted());
1632 cryptographer->Update(nigori);
1633 EXPECT_TRUE(cryptographer->has_pending_keys());
1634 node.SetNigoriSpecifics(nigori);
1635 }
1636 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1637 EXPECT_CALL(observer_, OnPassphraseAccepted());
1638 EXPECT_CALL(observer_, OnEncryptionComplete());
1639 sync_manager_.SetDecryptionPassphrase("passphrase2");
1640 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1641 {
1642 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1643 Cryptographer* cryptographer = trans.GetCryptographer();
1644 EXPECT_TRUE(cryptographer->is_ready());
1645 // Verify we're encrypting with the new key.
1646 sync_pb::EncryptedData encrypted;
1647 cryptographer->GetKeys(&encrypted);
1648 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted));
1649 }
1650 }
1651
1652 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1653 // being encrypted with an old (unprovided) GAIA password. Attempt to supply
1654 // the current GAIA password and verify the bootstrap token is updated. Then
1655 // supply the old GAIA password, and verify we re-encrypt all data with the
1656 // new GAIA password.
1657 // (cases 4 and 5 in SyncManager::SyncInternal::SetEncryptionPassphrase)
1658 TEST_F(SyncManagerTest, SupplyPendingOldGAIAPass) {
1659 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1660 Cryptographer other_cryptographer(&encryptor_);
1661 {
1662 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1663 Cryptographer* cryptographer = trans.GetCryptographer();
1664 std::string bootstrap_token;
1665 cryptographer->GetBootstrapToken(&bootstrap_token);
1666 other_cryptographer.Bootstrap(bootstrap_token);
1667
1668 // Now update the nigori to reflect the new keys, and update the
1669 // cryptographer to have pending keys.
1670 KeyParams params = {"localhost", "dummy", "old_gaia"};
1671 other_cryptographer.AddKey(params);
1672 WriteNode node(&trans);
1673 EXPECT_EQ(BaseNode::INIT_OK, node.InitByTagLookup(kNigoriTag));
1674 sync_pb::NigoriSpecifics nigori;
1675 other_cryptographer.GetKeys(nigori.mutable_encrypted());
1676 node.SetNigoriSpecifics(nigori);
1677 cryptographer->Update(nigori);
1678
1679 // other_cryptographer now contains all encryption keys, and is encrypting
1680 // with the newest gaia.
1681 KeyParams new_params = {"localhost", "dummy", "new_gaia"};
1682 other_cryptographer.AddKey(new_params);
1683 }
1684 // The bootstrap token should have been updated. Save it to ensure it's based
1685 // on the new GAIA password.
1686 std::string bootstrap_token;
1687 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_))
1688 .WillOnce(SaveArg<0>(&bootstrap_token));
1689 EXPECT_CALL(observer_, OnPassphraseRequired(_,_));
1690 sync_manager_.SetEncryptionPassphrase("new_gaia", false);
1691 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1692 testing::Mock::VerifyAndClearExpectations(&observer_);
1693 {
1694 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1695 Cryptographer* cryptographer = trans.GetCryptographer();
1696 EXPECT_TRUE(cryptographer->is_initialized());
1697 EXPECT_FALSE(cryptographer->is_ready());
1698 // Verify we're encrypting with the new key, even though we have pending
1699 // keys.
1700 sync_pb::EncryptedData encrypted;
1701 other_cryptographer.GetKeys(&encrypted);
1702 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted));
1703 }
1704 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1705 EXPECT_CALL(observer_, OnPassphraseAccepted());
1706 EXPECT_CALL(observer_, OnEncryptionComplete());
1707 sync_manager_.SetEncryptionPassphrase("old_gaia", false);
1708 {
1709 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1710 Cryptographer* cryptographer = trans.GetCryptographer();
1711 EXPECT_TRUE(cryptographer->is_ready());
1712
1713 // Verify we're encrypting with the new key.
1714 sync_pb::EncryptedData encrypted;
1715 other_cryptographer.GetKeys(&encrypted);
1716 EXPECT_TRUE(cryptographer->CanDecrypt(encrypted));
1717
1718 // Verify the saved bootstrap token is based on the new gaia password.
1719 Cryptographer temp_cryptographer(&encryptor_);
1720 temp_cryptographer.Bootstrap(bootstrap_token);
1721 EXPECT_TRUE(temp_cryptographer.CanDecrypt(encrypted));
1722 }
1723 }
1724
1725 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1726 // being encrypted with an explicit (unprovided) passphrase, then supply the
1727 // passphrase.
1728 // (case 9 in SyncManager::SyncInternal::SetDecryptionPassphrase)
1729 TEST_F(SyncManagerTest, SupplyPendingExplicitPass) {
1730 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1731 Cryptographer other_cryptographer(&encryptor_);
1732 {
1733 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1734 Cryptographer* cryptographer = trans.GetCryptographer();
1735 std::string bootstrap_token;
1736 cryptographer->GetBootstrapToken(&bootstrap_token);
1737 other_cryptographer.Bootstrap(bootstrap_token);
1738
1739 // Now update the nigori to reflect the new keys, and update the
1740 // cryptographer to have pending keys.
1741 KeyParams params = {"localhost", "dummy", "explicit"};
1742 other_cryptographer.AddKey(params);
1743 WriteNode node(&trans);
1744 EXPECT_EQ(BaseNode::INIT_OK, node.InitByTagLookup(kNigoriTag));
1745 sync_pb::NigoriSpecifics nigori;
1746 other_cryptographer.GetKeys(nigori.mutable_encrypted());
1747 cryptographer->Update(nigori);
1748 EXPECT_TRUE(cryptographer->has_pending_keys());
1749 nigori.set_using_explicit_passphrase(true);
1750 node.SetNigoriSpecifics(nigori);
1751 }
1752 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1753 EXPECT_CALL(observer_, OnPassphraseAccepted());
1754 EXPECT_CALL(observer_, OnEncryptionComplete());
1755 sync_manager_.SetDecryptionPassphrase("explicit");
1756 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1757 {
1758 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1759 Cryptographer* cryptographer = trans.GetCryptographer();
1760 EXPECT_TRUE(cryptographer->is_ready());
1761 // Verify we're encrypting with the new key.
1762 sync_pb::EncryptedData encrypted;
1763 cryptographer->GetKeys(&encrypted);
1764 EXPECT_TRUE(other_cryptographer.CanDecrypt(encrypted));
1765 }
1766 }
1767
1768 // Manually set the pending keys in the cryptographer/nigori to reflect the data
1769 // being encrypted with a new (unprovided) GAIA password, then supply the
1770 // password as a user-provided password.
1771 // This is the android case 7/8.
1772 TEST_F(SyncManagerTest, SupplyPendingGAIAPassUserProvided) {
1773 EXPECT_FALSE(SetUpEncryption(DONT_WRITE_NIGORI, UNINITIALIZED));
1774 Cryptographer other_cryptographer(&encryptor_);
1775 {
1776 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1777 Cryptographer* cryptographer = trans.GetCryptographer();
1778 // Now update the nigori to reflect the new keys, and update the
1779 // cryptographer to have pending keys.
1780 KeyParams params = {"localhost", "dummy", "passphrase"};
1781 other_cryptographer.AddKey(params);
1782 WriteNode node(&trans);
1783 EXPECT_EQ(BaseNode::INIT_OK, node.InitByTagLookup(kNigoriTag));
1784 sync_pb::NigoriSpecifics nigori;
1785 other_cryptographer.GetKeys(nigori.mutable_encrypted());
1786 node.SetNigoriSpecifics(nigori);
1787 cryptographer->Update(nigori);
1788 EXPECT_FALSE(cryptographer->is_ready());
1789 }
1790 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1791 EXPECT_CALL(observer_, OnPassphraseAccepted());
1792 EXPECT_CALL(observer_, OnEncryptionComplete());
1793 sync_manager_.SetEncryptionPassphrase("passphrase", false);
1794 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1795 {
1796 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1797 Cryptographer* cryptographer = trans.GetCryptographer();
1798 EXPECT_TRUE(cryptographer->is_ready());
1799 }
1800 }
1801
1802 TEST_F(SyncManagerTest, SetPassphraseWithEmptyPasswordNode) {
1803 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1804 int64 node_id = 0;
1805 std::string tag = "foo";
1806 {
1807 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1808 ReadNode root_node(&trans);
1809 root_node.InitByRootLookup();
1810
1811 WriteNode password_node(&trans);
1812 WriteNode::InitUniqueByCreationResult result =
1813 password_node.InitUniqueByCreation(PASSWORDS, root_node, tag);
1814 EXPECT_EQ(WriteNode::INIT_SUCCESS, result);
1815 node_id = password_node.GetId();
1816 }
1817 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
1818 EXPECT_CALL(observer_, OnPassphraseAccepted());
1819 EXPECT_CALL(observer_, OnEncryptionComplete());
1820 sync_manager_.SetEncryptionPassphrase("new_passphrase", true);
1821 EXPECT_FALSE(EncryptEverythingEnabledForTest());
1822 {
1823 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1824 ReadNode password_node(&trans);
1825 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY,
1826 password_node.InitByClientTagLookup(PASSWORDS,
1827 tag));
1828 }
1829 {
1830 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1831 ReadNode password_node(&trans);
1832 EXPECT_EQ(BaseNode::INIT_FAILED_DECRYPT_IF_NECESSARY,
1833 password_node.InitByIdLookup(node_id));
1834 }
1835 }
1836
1837 TEST_F(SyncManagerTest, NudgeDelayTest) {
1838 EXPECT_EQ(sync_manager_.GetNudgeDelayTimeDelta(BOOKMARKS),
1839 base::TimeDelta::FromMilliseconds(
1840 SyncManagerImpl::GetDefaultNudgeDelay()));
1841
1842 EXPECT_EQ(sync_manager_.GetNudgeDelayTimeDelta(AUTOFILL),
1843 base::TimeDelta::FromSeconds(
1844 kDefaultShortPollIntervalSeconds));
1845
1846 EXPECT_EQ(sync_manager_.GetNudgeDelayTimeDelta(PREFERENCES),
1847 base::TimeDelta::FromMilliseconds(
1848 SyncManagerImpl::GetPreferencesNudgeDelay()));
1849 }
1850
1851 // Friended by WriteNode, so can't be in an anonymouse namespace.
1852 TEST_F(SyncManagerTest, EncryptBookmarksWithLegacyData) {
1853 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
1854 std::string title;
1855 SyncAPINameToServerName("Google", &title);
1856 std::string url = "http://www.google.com";
1857 std::string raw_title2 = ".."; // An invalid cosmo title.
1858 std::string title2;
1859 SyncAPINameToServerName(raw_title2, &title2);
1860 std::string url2 = "http://www.bla.com";
1861
1862 // Create a bookmark using the legacy format.
1863 int64 node_id1 = MakeNode(sync_manager_.GetUserShare(),
1864 BOOKMARKS,
1865 "testtag");
1866 int64 node_id2 = MakeNode(sync_manager_.GetUserShare(),
1867 BOOKMARKS,
1868 "testtag2");
1869 {
1870 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1871 WriteNode node(&trans);
1872 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1));
1873
1874 sync_pb::EntitySpecifics entity_specifics;
1875 entity_specifics.mutable_bookmark()->set_url(url);
1876 node.SetEntitySpecifics(entity_specifics);
1877
1878 // Set the old style title.
1879 syncable::MutableEntry* node_entry = node.entry_;
1880 node_entry->Put(syncable::NON_UNIQUE_NAME, title);
1881
1882 WriteNode node2(&trans);
1883 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2));
1884
1885 sync_pb::EntitySpecifics entity_specifics2;
1886 entity_specifics2.mutable_bookmark()->set_url(url2);
1887 node2.SetEntitySpecifics(entity_specifics2);
1888
1889 // Set the old style title.
1890 syncable::MutableEntry* node_entry2 = node2.entry_;
1891 node_entry2->Put(syncable::NON_UNIQUE_NAME, title2);
1892 }
1893
1894 {
1895 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1896 ReadNode node(&trans);
1897 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1));
1898 EXPECT_EQ(BOOKMARKS, node.GetModelType());
1899 EXPECT_EQ(title, node.GetTitle());
1900 EXPECT_EQ(title, node.GetBookmarkSpecifics().title());
1901 EXPECT_EQ(url, node.GetBookmarkSpecifics().url());
1902
1903 ReadNode node2(&trans);
1904 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2));
1905 EXPECT_EQ(BOOKMARKS, node2.GetModelType());
1906 // We should de-canonicalize the title in GetTitle(), but the title in the
1907 // specifics should be stored in the server legal form.
1908 EXPECT_EQ(raw_title2, node2.GetTitle());
1909 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title());
1910 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url());
1911 }
1912
1913 {
1914 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1915 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1916 trans.GetWrappedTrans(),
1917 trans.GetCryptographer(),
1918 BOOKMARKS,
1919 false /* not encrypted */));
1920 }
1921
1922 EXPECT_CALL(observer_,
1923 OnEncryptedTypesChanged(
1924 HasModelTypes(ModelTypeSet::All()), true));
1925 EXPECT_CALL(observer_, OnEncryptionComplete());
1926 sync_manager_.EnableEncryptEverything();
1927 EXPECT_TRUE(EncryptEverythingEnabledForTest());
1928
1929 {
1930 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1931 EXPECT_TRUE(GetEncryptedTypes(&trans).Equals(ModelTypeSet::All()));
1932 EXPECT_TRUE(syncable::VerifyDataTypeEncryptionForTest(
1933 trans.GetWrappedTrans(),
1934 trans.GetCryptographer(),
1935 BOOKMARKS,
1936 true /* is encrypted */));
1937
1938 ReadNode node(&trans);
1939 EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(node_id1));
1940 EXPECT_EQ(BOOKMARKS, node.GetModelType());
1941 EXPECT_EQ(title, node.GetTitle());
1942 EXPECT_EQ(title, node.GetBookmarkSpecifics().title());
1943 EXPECT_EQ(url, node.GetBookmarkSpecifics().url());
1944
1945 ReadNode node2(&trans);
1946 EXPECT_EQ(BaseNode::INIT_OK, node2.InitByIdLookup(node_id2));
1947 EXPECT_EQ(BOOKMARKS, node2.GetModelType());
1948 // We should de-canonicalize the title in GetTitle(), but the title in the
1949 // specifics should be stored in the server legal form.
1950 EXPECT_EQ(raw_title2, node2.GetTitle());
1951 EXPECT_EQ(title2, node2.GetBookmarkSpecifics().title());
1952 EXPECT_EQ(url2, node2.GetBookmarkSpecifics().url());
1953 }
1954 }
1955
1956 // Create a bookmark and set the title/url, then verify the data was properly
1957 // set. This replicates the unique way bookmarks have of creating sync nodes.
1958 // See BookmarkChangeProcessor::PlaceSyncNode(..).
1959 TEST_F(SyncManagerTest, CreateLocalBookmark) {
1960 std::string title = "title";
1961 GURL url("url");
1962 {
1963 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1964 ReadNode root_node(&trans);
1965 root_node.InitByRootLookup();
1966 WriteNode node(&trans);
1967 ASSERT_TRUE(node.InitByCreation(BOOKMARKS, root_node, NULL));
1968 node.SetIsFolder(false);
1969 node.SetTitle(UTF8ToWide(title));
1970 node.SetURL(url);
1971 }
1972 {
1973 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
1974 ReadNode root_node(&trans);
1975 root_node.InitByRootLookup();
1976 int64 child_id = root_node.GetFirstChildId();
1977
1978 ReadNode node(&trans);
1979 ASSERT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(child_id));
1980 EXPECT_FALSE(node.GetIsFolder());
1981 EXPECT_EQ(title, node.GetTitle());
1982 EXPECT_EQ(url, node.GetURL());
1983 }
1984 }
1985
1986 // Verifies WriteNode::UpdateEntryWithEncryption does not make unnecessary
1987 // changes.
1988 TEST_F(SyncManagerTest, UpdateEntryWithEncryption) {
1989 std::string client_tag = "title";
1990 sync_pb::EntitySpecifics entity_specifics;
1991 entity_specifics.mutable_bookmark()->set_url("url");
1992 entity_specifics.mutable_bookmark()->set_title("title");
1993 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
1994 BaseNode::GenerateSyncableHash(BOOKMARKS,
1995 client_tag),
1996 entity_specifics);
1997 // New node shouldn't start off unsynced.
1998 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
1999 // Manually change to the same data. Should not set is_unsynced.
2000 {
2001 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2002 WriteNode node(&trans);
2003 EXPECT_EQ(BaseNode::INIT_OK,
2004 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2005 node.SetEntitySpecifics(entity_specifics);
2006 }
2007 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2008
2009 // Encrypt the datatatype, should set is_unsynced.
2010 EXPECT_CALL(observer_,
2011 OnEncryptedTypesChanged(
2012 HasModelTypes(ModelTypeSet::All()), true));
2013 EXPECT_CALL(observer_, OnEncryptionComplete());
2014 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
2015
2016 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
2017 PumpLoop();
2018 {
2019 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2020 ReadNode node(&trans);
2021 EXPECT_EQ(BaseNode::INIT_OK,
2022 node.InitByClientTagLookup(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()));
2031 }
2032 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2033
2034 // Set a new passphrase. Should set is_unsynced.
2035 testing::Mock::VerifyAndClearExpectations(&observer_);
2036 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
2037 EXPECT_CALL(observer_, OnPassphraseAccepted());
2038 EXPECT_CALL(observer_, OnEncryptionComplete());
2039 sync_manager_.SetEncryptionPassphrase("new_passphrase", true);
2040 {
2041 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2042 ReadNode node(&trans);
2043 EXPECT_EQ(BaseNode::INIT_OK,
2044 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2045 const syncable::Entry* node_entry = node.GetEntry();
2046 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2047 EXPECT_TRUE(specifics.has_encrypted());
2048 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2049 Cryptographer* cryptographer = trans.GetCryptographer();
2050 EXPECT_TRUE(cryptographer->is_ready());
2051 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
2052 specifics.encrypted()));
2053 }
2054 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2055
2056 // Force a re-encrypt everything. Should not set is_unsynced.
2057 testing::Mock::VerifyAndClearExpectations(&observer_);
2058 EXPECT_CALL(observer_, OnEncryptionComplete());
2059
2060 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
2061 PumpLoop();
2062
2063 {
2064 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2065 ReadNode node(&trans);
2066 EXPECT_EQ(BaseNode::INIT_OK,
2067 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2068 const syncable::Entry* node_entry = node.GetEntry();
2069 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2070 EXPECT_TRUE(specifics.has_encrypted());
2071 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2072 Cryptographer* cryptographer = trans.GetCryptographer();
2073 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
2074 specifics.encrypted()));
2075 }
2076 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2077
2078 // Manually change to the same data. Should not set is_unsynced.
2079 {
2080 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2081 WriteNode node(&trans);
2082 EXPECT_EQ(BaseNode::INIT_OK,
2083 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2084 node.SetEntitySpecifics(entity_specifics);
2085 const syncable::Entry* node_entry = node.GetEntry();
2086 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2087 EXPECT_TRUE(specifics.has_encrypted());
2088 EXPECT_FALSE(node_entry->Get(IS_UNSYNCED));
2089 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2090 Cryptographer* cryptographer = trans.GetCryptographer();
2091 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
2092 specifics.encrypted()));
2093 }
2094 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2095
2096 // Manually change to different data. Should set is_unsynced.
2097 {
2098 entity_specifics.mutable_bookmark()->set_url("url2");
2099 entity_specifics.mutable_bookmark()->set_title("title2");
2100 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2101 WriteNode node(&trans);
2102 EXPECT_EQ(BaseNode::INIT_OK,
2103 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2104 node.SetEntitySpecifics(entity_specifics);
2105 const syncable::Entry* node_entry = node.GetEntry();
2106 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2107 EXPECT_TRUE(specifics.has_encrypted());
2108 EXPECT_TRUE(node_entry->Get(IS_UNSYNCED));
2109 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2110 Cryptographer* cryptographer = trans.GetCryptographer();
2111 EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
2112 specifics.encrypted()));
2113 }
2114 }
2115
2116 // Passwords have their own handling for encryption. Verify it does not result
2117 // in unnecessary writes via SetEntitySpecifics.
2118 TEST_F(SyncManagerTest, UpdatePasswordSetEntitySpecificsNoChange) {
2119 std::string client_tag = "title";
2120 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2121 sync_pb::EntitySpecifics entity_specifics;
2122 {
2123 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2124 Cryptographer* cryptographer = trans.GetCryptographer();
2125 sync_pb::PasswordSpecificsData data;
2126 data.set_password_value("secret");
2127 cryptographer->Encrypt(
2128 data,
2129 entity_specifics.mutable_password()->
2130 mutable_encrypted());
2131 }
2132 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
2133 BaseNode::GenerateSyncableHash(PASSWORDS,
2134 client_tag),
2135 entity_specifics);
2136 // New node shouldn't start off unsynced.
2137 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2138
2139 // Manually change to the same data via SetEntitySpecifics. Should not set
2140 // is_unsynced.
2141 {
2142 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2143 WriteNode node(&trans);
2144 EXPECT_EQ(BaseNode::INIT_OK,
2145 node.InitByClientTagLookup(PASSWORDS, client_tag));
2146 node.SetEntitySpecifics(entity_specifics);
2147 }
2148 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2149 }
2150
2151 // Passwords have their own handling for encryption. Verify it does not result
2152 // in unnecessary writes via SetPasswordSpecifics.
2153 TEST_F(SyncManagerTest, UpdatePasswordSetPasswordSpecifics) {
2154 std::string client_tag = "title";
2155 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2156 sync_pb::EntitySpecifics entity_specifics;
2157 {
2158 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2159 Cryptographer* cryptographer = trans.GetCryptographer();
2160 sync_pb::PasswordSpecificsData data;
2161 data.set_password_value("secret");
2162 cryptographer->Encrypt(
2163 data,
2164 entity_specifics.mutable_password()->
2165 mutable_encrypted());
2166 }
2167 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
2168 BaseNode::GenerateSyncableHash(PASSWORDS,
2169 client_tag),
2170 entity_specifics);
2171 // New node shouldn't start off unsynced.
2172 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2173
2174 // Manually change to the same data via SetPasswordSpecifics. Should not set
2175 // is_unsynced.
2176 {
2177 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2178 WriteNode node(&trans);
2179 EXPECT_EQ(BaseNode::INIT_OK,
2180 node.InitByClientTagLookup(PASSWORDS, client_tag));
2181 node.SetPasswordSpecifics(node.GetPasswordSpecifics());
2182 }
2183 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2184
2185 // Manually change to different data. Should set is_unsynced.
2186 {
2187 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2188 WriteNode node(&trans);
2189 EXPECT_EQ(BaseNode::INIT_OK,
2190 node.InitByClientTagLookup(PASSWORDS, client_tag));
2191 Cryptographer* cryptographer = trans.GetCryptographer();
2192 sync_pb::PasswordSpecificsData data;
2193 data.set_password_value("secret2");
2194 cryptographer->Encrypt(
2195 data,
2196 entity_specifics.mutable_password()->mutable_encrypted());
2197 node.SetPasswordSpecifics(data);
2198 const syncable::Entry* node_entry = node.GetEntry();
2199 EXPECT_TRUE(node_entry->Get(IS_UNSYNCED));
2200 }
2201 }
2202
2203 // Passwords have their own handling for encryption. Verify setting a new
2204 // passphrase updates the data.
2205 TEST_F(SyncManagerTest, UpdatePasswordNewPassphrase) {
2206 std::string client_tag = "title";
2207 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2208 sync_pb::EntitySpecifics entity_specifics;
2209 {
2210 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2211 Cryptographer* cryptographer = trans.GetCryptographer();
2212 sync_pb::PasswordSpecificsData data;
2213 data.set_password_value("secret");
2214 cryptographer->Encrypt(
2215 data,
2216 entity_specifics.mutable_password()->mutable_encrypted());
2217 }
2218 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
2219 BaseNode::GenerateSyncableHash(PASSWORDS,
2220 client_tag),
2221 entity_specifics);
2222 // New node shouldn't start off unsynced.
2223 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2224
2225 // Set a new passphrase. Should set is_unsynced.
2226 testing::Mock::VerifyAndClearExpectations(&observer_);
2227 EXPECT_CALL(observer_, OnBootstrapTokenUpdated(_));
2228 EXPECT_CALL(observer_, OnPassphraseAccepted());
2229 EXPECT_CALL(observer_, OnEncryptionComplete());
2230 sync_manager_.SetEncryptionPassphrase("new_passphrase", true);
2231 EXPECT_TRUE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2232 }
2233
2234 // Passwords have their own handling for encryption. Verify it does not result
2235 // in unnecessary writes via ReencryptEverything.
2236 TEST_F(SyncManagerTest, UpdatePasswordReencryptEverything) {
2237 std::string client_tag = "title";
2238 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2239 sync_pb::EntitySpecifics entity_specifics;
2240 {
2241 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2242 Cryptographer* cryptographer = trans.GetCryptographer();
2243 sync_pb::PasswordSpecificsData data;
2244 data.set_password_value("secret");
2245 cryptographer->Encrypt(
2246 data,
2247 entity_specifics.mutable_password()->mutable_encrypted());
2248 }
2249 MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, client_tag,
2250 BaseNode::GenerateSyncableHash(PASSWORDS,
2251 client_tag),
2252 entity_specifics);
2253 // New node shouldn't start off unsynced.
2254 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2255
2256 // Force a re-encrypt everything. Should not set is_unsynced.
2257 testing::Mock::VerifyAndClearExpectations(&observer_);
2258 EXPECT_CALL(observer_, OnEncryptionComplete());
2259 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
2260 PumpLoop();
2261 EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
2262 }
2263
2264 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for bookmarks
2265 // when we write the same data, but does set it when we write new data.
2266 TEST_F(SyncManagerTest, SetBookmarkTitle) {
2267 std::string client_tag = "title";
2268 sync_pb::EntitySpecifics entity_specifics;
2269 entity_specifics.mutable_bookmark()->set_url("url");
2270 entity_specifics.mutable_bookmark()->set_title("title");
2271 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2272 BaseNode::GenerateSyncableHash(BOOKMARKS,
2273 client_tag),
2274 entity_specifics);
2275 // New node shouldn't start off unsynced.
2276 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2277
2278 // Manually change to the same title. Should not set is_unsynced.
2279 {
2280 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2281 WriteNode node(&trans);
2282 EXPECT_EQ(BaseNode::INIT_OK,
2283 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2284 node.SetTitle(UTF8ToWide(client_tag));
2285 }
2286 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2287
2288 // Manually change to new title. Should set is_unsynced.
2289 {
2290 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2291 WriteNode node(&trans);
2292 EXPECT_EQ(BaseNode::INIT_OK,
2293 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2294 node.SetTitle(UTF8ToWide("title2"));
2295 }
2296 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2297 }
2298
2299 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted
2300 // bookmarks when we write the same data, but does set it when we write new
2301 // data.
2302 TEST_F(SyncManagerTest, SetBookmarkTitleWithEncryption) {
2303 std::string client_tag = "title";
2304 sync_pb::EntitySpecifics entity_specifics;
2305 entity_specifics.mutable_bookmark()->set_url("url");
2306 entity_specifics.mutable_bookmark()->set_title("title");
2307 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2308 BaseNode::GenerateSyncableHash(BOOKMARKS,
2309 client_tag),
2310 entity_specifics);
2311 // New node shouldn't start off unsynced.
2312 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2313
2314 // Encrypt the datatatype, should set is_unsynced.
2315 EXPECT_CALL(observer_,
2316 OnEncryptedTypesChanged(
2317 HasModelTypes(ModelTypeSet::All()), true));
2318 EXPECT_CALL(observer_, OnEncryptionComplete());
2319 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
2320 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
2321 PumpLoop();
2322 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2323
2324 // Manually change to the same title. Should not set is_unsynced.
2325 // NON_UNIQUE_NAME should be kEncryptedString.
2326 {
2327 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2328 WriteNode node(&trans);
2329 EXPECT_EQ(BaseNode::INIT_OK,
2330 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2331 node.SetTitle(UTF8ToWide(client_tag));
2332 const syncable::Entry* node_entry = node.GetEntry();
2333 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2334 EXPECT_TRUE(specifics.has_encrypted());
2335 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2336 }
2337 EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2338
2339 // Manually change to new title. Should set is_unsynced. NON_UNIQUE_NAME
2340 // should still be kEncryptedString.
2341 {
2342 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2343 WriteNode node(&trans);
2344 EXPECT_EQ(BaseNode::INIT_OK,
2345 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2346 node.SetTitle(UTF8ToWide("title2"));
2347 const syncable::Entry* node_entry = node.GetEntry();
2348 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2349 EXPECT_TRUE(specifics.has_encrypted());
2350 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2351 }
2352 EXPECT_TRUE(ResetUnsyncedEntry(BOOKMARKS, client_tag));
2353 }
2354
2355 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for non-bookmarks
2356 // when we write the same data, but does set it when we write new data.
2357 TEST_F(SyncManagerTest, SetNonBookmarkTitle) {
2358 std::string client_tag = "title";
2359 sync_pb::EntitySpecifics entity_specifics;
2360 entity_specifics.mutable_preference()->set_name("name");
2361 entity_specifics.mutable_preference()->set_value("value");
2362 MakeServerNode(sync_manager_.GetUserShare(),
2363 PREFERENCES,
2364 client_tag,
2365 BaseNode::GenerateSyncableHash(PREFERENCES,
2366 client_tag),
2367 entity_specifics);
2368 // New node shouldn't start off unsynced.
2369 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2370
2371 // Manually change to the same title. Should not set is_unsynced.
2372 {
2373 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2374 WriteNode node(&trans);
2375 EXPECT_EQ(BaseNode::INIT_OK,
2376 node.InitByClientTagLookup(PREFERENCES, client_tag));
2377 node.SetTitle(UTF8ToWide(client_tag));
2378 }
2379 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2380
2381 // Manually change to new title. Should set is_unsynced.
2382 {
2383 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2384 WriteNode node(&trans);
2385 EXPECT_EQ(BaseNode::INIT_OK,
2386 node.InitByClientTagLookup(PREFERENCES, client_tag));
2387 node.SetTitle(UTF8ToWide("title2"));
2388 }
2389 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2390 }
2391
2392 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for encrypted
2393 // non-bookmarks when we write the same data or when we write new data
2394 // data (should remained kEncryptedString).
2395 TEST_F(SyncManagerTest, SetNonBookmarkTitleWithEncryption) {
2396 std::string client_tag = "title";
2397 sync_pb::EntitySpecifics entity_specifics;
2398 entity_specifics.mutable_preference()->set_name("name");
2399 entity_specifics.mutable_preference()->set_value("value");
2400 MakeServerNode(sync_manager_.GetUserShare(),
2401 PREFERENCES,
2402 client_tag,
2403 BaseNode::GenerateSyncableHash(PREFERENCES,
2404 client_tag),
2405 entity_specifics);
2406 // New node shouldn't start off unsynced.
2407 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2408
2409 // Encrypt the datatatype, should set is_unsynced.
2410 EXPECT_CALL(observer_,
2411 OnEncryptedTypesChanged(
2412 HasModelTypes(ModelTypeSet::All()), true));
2413 EXPECT_CALL(observer_, OnEncryptionComplete());
2414 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
2415 sync_manager_.RefreshNigori(kTestChromeVersion, base::Bind(&DoNothing));
2416 PumpLoop();
2417 EXPECT_TRUE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2418
2419 // Manually change to the same title. Should not set is_unsynced.
2420 // NON_UNIQUE_NAME should be kEncryptedString.
2421 {
2422 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2423 WriteNode node(&trans);
2424 EXPECT_EQ(BaseNode::INIT_OK,
2425 node.InitByClientTagLookup(PREFERENCES, client_tag));
2426 node.SetTitle(UTF8ToWide(client_tag));
2427 const syncable::Entry* node_entry = node.GetEntry();
2428 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2429 EXPECT_TRUE(specifics.has_encrypted());
2430 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2431 }
2432 EXPECT_FALSE(ResetUnsyncedEntry(PREFERENCES, client_tag));
2433
2434 // Manually change to new title. Should not set is_unsynced because the
2435 // NON_UNIQUE_NAME should still be kEncryptedString.
2436 {
2437 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2438 WriteNode node(&trans);
2439 EXPECT_EQ(BaseNode::INIT_OK,
2440 node.InitByClientTagLookup(PREFERENCES, client_tag));
2441 node.SetTitle(UTF8ToWide("title2"));
2442 const syncable::Entry* node_entry = node.GetEntry();
2443 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2444 EXPECT_TRUE(specifics.has_encrypted());
2445 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2446 EXPECT_FALSE(node_entry->Get(IS_UNSYNCED));
2447 }
2448 }
2449
2450 // Create an encrypted entry when the cryptographer doesn't think the type is
2451 // marked for encryption. Ensure reads/writes don't break and don't unencrypt
2452 // the data.
2453 TEST_F(SyncManagerTest, SetPreviouslyEncryptedSpecifics) {
2454 std::string client_tag = "tag";
2455 std::string url = "url";
2456 std::string url2 = "new_url";
2457 std::string title = "title";
2458 sync_pb::EntitySpecifics entity_specifics;
2459 EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
2460 {
2461 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2462 Cryptographer* crypto = trans.GetCryptographer();
2463 sync_pb::EntitySpecifics bm_specifics;
2464 bm_specifics.mutable_bookmark()->set_title("title");
2465 bm_specifics.mutable_bookmark()->set_url("url");
2466 sync_pb::EncryptedData encrypted;
2467 crypto->Encrypt(bm_specifics, &encrypted);
2468 entity_specifics.mutable_encrypted()->CopyFrom(encrypted);
2469 AddDefaultFieldValue(BOOKMARKS, &entity_specifics);
2470 }
2471 MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, client_tag,
2472 BaseNode::GenerateSyncableHash(BOOKMARKS,
2473 client_tag),
2474 entity_specifics);
2475
2476 {
2477 // Verify the data.
2478 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2479 ReadNode node(&trans);
2480 EXPECT_EQ(BaseNode::INIT_OK,
2481 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2482 EXPECT_EQ(title, node.GetTitle());
2483 EXPECT_EQ(GURL(url), node.GetURL());
2484 }
2485
2486 {
2487 // Overwrite the url (which overwrites the specifics).
2488 WriteTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2489 WriteNode node(&trans);
2490 EXPECT_EQ(BaseNode::INIT_OK,
2491 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2492 node.SetURL(GURL(url2));
2493 }
2494
2495 {
2496 // Verify it's still encrypted and it has the most recent url.
2497 ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
2498 ReadNode node(&trans);
2499 EXPECT_EQ(BaseNode::INIT_OK,
2500 node.InitByClientTagLookup(BOOKMARKS, client_tag));
2501 EXPECT_EQ(title, node.GetTitle());
2502 EXPECT_EQ(GURL(url2), node.GetURL());
2503 const syncable::Entry* node_entry = node.GetEntry();
2504 EXPECT_EQ(kEncryptedString, node_entry->Get(NON_UNIQUE_NAME));
2505 const sync_pb::EntitySpecifics& specifics = node_entry->Get(SPECIFICS);
2506 EXPECT_TRUE(specifics.has_encrypted());
2507 }
2508 }
2509
2510 class MockSyncScheduler : public FakeSyncScheduler {
2511 public:
2512 MockSyncScheduler() : FakeSyncScheduler() {}
2513 virtual ~MockSyncScheduler() {}
2514
2515 MOCK_METHOD1(Start, void(SyncScheduler::Mode));
2516 MOCK_METHOD1(ScheduleConfiguration, bool(const ConfigurationParams&));
2517 };
2518
2519 class ComponentsFactory : public TestInternalComponentsFactory {
2520 public:
2521 ComponentsFactory(SyncScheduler* scheduler_to_use,
2522 sessions::SyncSessionContext** session_context)
2523 : TestInternalComponentsFactory(
2524 syncer::STORAGE_IN_MEMORY),
2525 scheduler_to_use_(scheduler_to_use),
2526 session_context_(session_context) {}
2527 virtual ~ComponentsFactory() {}
2528
2529 virtual scoped_ptr<SyncScheduler> BuildScheduler(
2530 const std::string& name,
2531 sessions::SyncSessionContext* context) OVERRIDE {
2532 *session_context_ = context;
2533 return scheduler_to_use_.Pass();
2534 }
2535
2536 private:
2537 scoped_ptr<SyncScheduler> scheduler_to_use_;
2538 sessions::SyncSessionContext** session_context_;
2539 };
2540
2541 class SyncManagerTestWithMockScheduler : public SyncManagerTest {
2542 public:
2543 SyncManagerTestWithMockScheduler() : scheduler_(NULL) {}
2544 virtual InternalComponentsFactory* GetFactory() OVERRIDE {
2545 scheduler_ = new MockSyncScheduler();
2546 return new ComponentsFactory(scheduler_, &session_context_);
2547 }
2548
2549 MockSyncScheduler* scheduler() { return scheduler_; }
2550 sessions::SyncSessionContext* session_context() {
2551 return session_context_;
2552 }
2553
2554 private:
2555 MockSyncScheduler* scheduler_;
2556 sessions::SyncSessionContext* session_context_;
2557 };
2558
2559 // Test that the configuration params are properly created and sent to
2560 // ScheduleConfigure. No callback should be invoked. Any disabled datatypes
2561 // should be purged.
2562 // Fails on Windows: crbug.com/139726
2563 #if defined(OS_WIN)
2564 #define MAYBE_BasicConfiguration DISABLED_BasicConfiguration
2565 #else
2566 #define MAYBE_BasicConfiguration BasicConfiguration
2567 #endif
2568 TEST_F(SyncManagerTestWithMockScheduler, MAYBE_BasicConfiguration) {
2569 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
2570 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
2571 ModelSafeRoutingInfo new_routing_info;
2572 GetModelSafeRoutingInfo(&new_routing_info);
2573 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info);
2574 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
2575
2576 ConfigurationParams params;
2577 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE));
2578 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)).
2579 WillOnce(DoAll(SaveArg<0>(&params), Return(true)));
2580
2581 // Set data for all types.
2582 for (ModelTypeSet::Iterator iter = ModelTypeSet::All().First(); iter.Good();
2583 iter.Inc()) {
2584 SetProgressMarkerForType(iter.Get(), true);
2585 SetInitialSyncEndedForType(iter.Get(), true);
2586 }
2587
2588 CallbackCounter ready_task_counter, retry_task_counter;
2589 sync_manager_.ConfigureSyncer(
2590 reason,
2591 types_to_download,
2592 new_routing_info,
2593 base::Bind(&CallbackCounter::Callback,
2594 base::Unretained(&ready_task_counter)),
2595 base::Bind(&CallbackCounter::Callback,
2596 base::Unretained(&retry_task_counter)));
2597 EXPECT_EQ(0, ready_task_counter.times_called());
2598 EXPECT_EQ(0, retry_task_counter.times_called());
2599 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
2600 params.source);
2601 EXPECT_TRUE(types_to_download.Equals(params.types_to_download));
2602 EXPECT_EQ(new_routing_info, params.routing_info);
2603
2604 // Verify all the disabled types were purged.
2605 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().Equals(
2606 enabled_types));
2607 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken(
2608 ModelTypeSet::All()).Equals(disabled_types));
2609 }
2610
2611 // Test that on a reconfiguration (configuration where the session context
2612 // already has routing info), only those recently disabled types are purged.
2613 TEST_F(SyncManagerTestWithMockScheduler, ReConfiguration) {
2614 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
2615 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
2616 ModelTypeSet disabled_types = ModelTypeSet(THEMES, SESSIONS);
2617 ModelSafeRoutingInfo old_routing_info;
2618 ModelSafeRoutingInfo new_routing_info;
2619 GetModelSafeRoutingInfo(&old_routing_info);
2620 new_routing_info = old_routing_info;
2621 new_routing_info.erase(THEMES);
2622 new_routing_info.erase(SESSIONS);
2623 ModelTypeSet enabled_types = GetRoutingInfoTypes(new_routing_info);
2624
2625 ConfigurationParams params;
2626 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE));
2627 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)).
2628 WillOnce(DoAll(SaveArg<0>(&params), Return(true)));
2629
2630 // Set data for all types except those recently disabled (so we can verify
2631 // only those recently disabled are purged) .
2632 for (ModelTypeSet::Iterator iter = ModelTypeSet::All().First(); iter.Good();
2633 iter.Inc()) {
2634 if (!disabled_types.Has(iter.Get())) {
2635 SetProgressMarkerForType(iter.Get(), true);
2636 SetInitialSyncEndedForType(iter.Get(), true);
2637 } else {
2638 SetProgressMarkerForType(iter.Get(), false);
2639 SetInitialSyncEndedForType(iter.Get(), false);
2640 }
2641 }
2642
2643 // Set the context to have the old routing info.
2644 session_context()->set_routing_info(old_routing_info);
2645
2646 CallbackCounter ready_task_counter, retry_task_counter;
2647 sync_manager_.ConfigureSyncer(
2648 reason,
2649 types_to_download,
2650 new_routing_info,
2651 base::Bind(&CallbackCounter::Callback,
2652 base::Unretained(&ready_task_counter)),
2653 base::Bind(&CallbackCounter::Callback,
2654 base::Unretained(&retry_task_counter)));
2655 EXPECT_EQ(0, ready_task_counter.times_called());
2656 EXPECT_EQ(0, retry_task_counter.times_called());
2657 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
2658 params.source);
2659 EXPECT_TRUE(types_to_download.Equals(params.types_to_download));
2660 EXPECT_EQ(new_routing_info, params.routing_info);
2661
2662 // Verify only the recently disabled types were purged.
2663 EXPECT_TRUE(sync_manager_.InitialSyncEndedTypes().Equals(
2664 Difference(ModelTypeSet::All(), disabled_types)));
2665 EXPECT_TRUE(sync_manager_.GetTypesWithEmptyProgressMarkerToken(
2666 ModelTypeSet::All()).Equals(disabled_types));
2667 }
2668
2669 // Test that the retry callback is invoked on configuration failure.
2670 TEST_F(SyncManagerTestWithMockScheduler, ConfigurationRetry) {
2671 ConfigureReason reason = CONFIGURE_REASON_RECONFIGURATION;
2672 ModelTypeSet types_to_download(BOOKMARKS, PREFERENCES);
2673 ModelSafeRoutingInfo new_routing_info;
2674 GetModelSafeRoutingInfo(&new_routing_info);
2675
2676 ConfigurationParams params;
2677 EXPECT_CALL(*scheduler(), Start(SyncScheduler::CONFIGURATION_MODE));
2678 EXPECT_CALL(*scheduler(), ScheduleConfiguration(_)).
2679 WillOnce(DoAll(SaveArg<0>(&params), Return(false)));
2680
2681 CallbackCounter ready_task_counter, retry_task_counter;
2682 sync_manager_.ConfigureSyncer(
2683 reason,
2684 types_to_download,
2685 new_routing_info,
2686 base::Bind(&CallbackCounter::Callback,
2687 base::Unretained(&ready_task_counter)),
2688 base::Bind(&CallbackCounter::Callback,
2689 base::Unretained(&retry_task_counter)));
2690 EXPECT_EQ(0, ready_task_counter.times_called());
2691 EXPECT_EQ(1, retry_task_counter.times_called());
2692 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
2693 params.source);
2694 EXPECT_TRUE(types_to_download.Equals(params.types_to_download));
2695 EXPECT_EQ(new_routing_info, params.routing_info);
2696 }
2697
2698 // Test that PurgePartiallySyncedTypes purges only those types that don't
2699 // have empty progress marker and don't have initial sync ended set.
2700 TEST_F(SyncManagerTest, PurgePartiallySyncedTypes) {
2701 UserShare* share = sync_manager_.GetUserShare();
2702
2703 // Set Nigori and Bookmarks to be partial types.
2704 sync_pb::DataTypeProgressMarker nigori_marker;
2705 nigori_marker.set_data_type_id(
2706 GetSpecificsFieldNumberFromModelType(NIGORI));
2707 nigori_marker.set_token("token");
2708 sync_pb::DataTypeProgressMarker bookmark_marker;
2709 bookmark_marker.set_data_type_id(
2710 GetSpecificsFieldNumberFromModelType(BOOKMARKS));
2711 bookmark_marker.set_token("token");
2712 share->directory->SetDownloadProgress(NIGORI, nigori_marker);
2713 share->directory->SetDownloadProgress(BOOKMARKS, bookmark_marker);
2714
2715 // Set Preferences to be a full type.
2716 sync_pb::DataTypeProgressMarker pref_marker;
2717 pref_marker.set_data_type_id(
2718 GetSpecificsFieldNumberFromModelType(PREFERENCES));
2719 pref_marker.set_token("token");
2720 share->directory->SetDownloadProgress(PREFERENCES, pref_marker);
2721 share->directory->set_initial_sync_ended_for_type(PREFERENCES, true);
2722
2723 ModelTypeSet partial_types =
2724 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All());
2725 EXPECT_FALSE(partial_types.Has(NIGORI));
2726 EXPECT_FALSE(partial_types.Has(BOOKMARKS));
2727 EXPECT_FALSE(partial_types.Has(PREFERENCES));
2728
2729 EXPECT_TRUE(sync_manager_.PurgePartiallySyncedTypes());
2730
2731 // Ensure only bookmarks and nigori lost their progress marker. Preferences
2732 // should still have it.
2733 partial_types =
2734 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All());
2735 EXPECT_TRUE(partial_types.Has(NIGORI));
2736 EXPECT_TRUE(partial_types.Has(BOOKMARKS));
2737 EXPECT_FALSE(partial_types.Has(PREFERENCES));
2738 }
2739
2740 // Test CleanipDisabledTypes properly purges all disabled types as specified
2741 // by the previous and current enabled params. Enabled partial types should not
2742 // be purged.
2743 // Fails on Windows: crbug.com/139726
2744 #if defined(OS_WIN)
2745 #define MAYBE_PurgeDisabledTypes DISABLED_PurgeDisabledTypes
2746 #else
2747 #define MAYBE_PurgeDisabledTypes PurgeDisabledTypes
2748 #endif
2749 TEST_F(SyncManagerTest, MAYBE_PurgeDisabledTypes) {
2750 ModelSafeRoutingInfo routing_info;
2751 GetModelSafeRoutingInfo(&routing_info);
2752 ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
2753 ModelTypeSet disabled_types = Difference(ModelTypeSet::All(), enabled_types);
2754 ModelTypeSet partial_enabled_types(PASSWORDS);
2755
2756 // Set data for all non-partial types.
2757 for (ModelTypeSet::Iterator iter = ModelTypeSet::All().First(); iter.Good();
2758 iter.Inc()) {
2759 SetProgressMarkerForType(iter.Get(), true);
2760 if (!partial_enabled_types.Has(iter.Get()))
2761 SetInitialSyncEndedForType(iter.Get(), true);
2762 }
2763
2764 // Verify all the enabled types remain after cleanup, and all the disabled
2765 // types were purged.
2766 sync_manager_.PurgeDisabledTypes(ModelTypeSet::All(), enabled_types);
2767 EXPECT_TRUE(enabled_types.Equals(
2768 Union(sync_manager_.InitialSyncEndedTypes(), partial_enabled_types)));
2769 EXPECT_TRUE(disabled_types.Equals(
2770 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All())));
2771
2772 // Disable some more types.
2773 disabled_types.Put(BOOKMARKS);
2774 disabled_types.Put(PREFERENCES);
2775 ModelTypeSet new_enabled_types =
2776 Difference(ModelTypeSet::All(), disabled_types);
2777
2778 // Verify only the non-disabled types remain after cleanup.
2779 sync_manager_.PurgeDisabledTypes(enabled_types, new_enabled_types);
2780 EXPECT_TRUE(new_enabled_types.Equals(
2781 Union(sync_manager_.InitialSyncEndedTypes(), partial_enabled_types)));
2782 EXPECT_TRUE(disabled_types.Equals(
2783 sync_manager_.GetTypesWithEmptyProgressMarkerToken(ModelTypeSet::All())));
2784 }
2785
2786 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698