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