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