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