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