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