Home | History | Annotate | Download | only in engine
      1 // Copyright (c) 2011 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 // Syncer unit tests. Unfortunately a lot of these tests
      6 // are outdated and need to be reworked and updated.
      7 
      8 #include <algorithm>
      9 #include <limits>
     10 #include <list>
     11 #include <map>
     12 #include <set>
     13 #include <string>
     14 
     15 #include "base/callback.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/string_number_conversions.h"
     18 #include "build/build_config.h"
     19 #include "chrome/browser/sync/engine/conflict_resolver.h"
     20 #include "chrome/browser/sync/engine/get_commit_ids_command.h"
     21 #include "chrome/browser/sync/engine/model_safe_worker.h"
     22 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
     23 #include "chrome/browser/sync/engine/process_updates_command.h"
     24 #include "chrome/browser/sync/engine/syncer.h"
     25 #include "chrome/browser/sync/engine/syncer_proto_util.h"
     26 #include "chrome/browser/sync/engine/syncer_util.h"
     27 #include "chrome/browser/sync/engine/syncproto.h"
     28 #include "chrome/browser/sync/protocol/sync.pb.h"
     29 #include "chrome/browser/sync/sessions/sync_session_context.h"
     30 #include "chrome/browser/sync/syncable/directory_manager.h"
     31 #include "chrome/browser/sync/syncable/model_type.h"
     32 #include "chrome/browser/sync/syncable/syncable.h"
     33 #include "chrome/common/deprecated/event_sys-inl.h"
     34 #include "chrome/test/sync/engine/mock_connection_manager.h"
     35 #include "chrome/test/sync/engine/test_directory_setter_upper.h"
     36 #include "chrome/test/sync/engine/test_id_factory.h"
     37 #include "chrome/test/sync/engine/test_syncable_utils.h"
     38 #include "testing/gtest/include/gtest/gtest.h"
     39 
     40 using base::TimeDelta;
     41 
     42 using std::map;
     43 using std::multimap;
     44 using std::set;
     45 using std::string;
     46 
     47 namespace browser_sync {
     48 
     49 using syncable::BaseTransaction;
     50 using syncable::Blob;
     51 using syncable::CountEntriesWithName;
     52 using syncable::Directory;
     53 using syncable::Entry;
     54 using syncable::GetFirstEntryWithName;
     55 using syncable::GetOnlyEntryWithName;
     56 using syncable::Id;
     57 using syncable::MutableEntry;
     58 using syncable::ReadTransaction;
     59 using syncable::ScopedDirLookup;
     60 using syncable::WriteTransaction;
     61 
     62 using syncable::BASE_VERSION;
     63 using syncable::CREATE;
     64 using syncable::CREATE_NEW_UPDATE_ITEM;
     65 using syncable::GET_BY_HANDLE;
     66 using syncable::GET_BY_ID;
     67 using syncable::GET_BY_CLIENT_TAG;
     68 using syncable::GET_BY_SERVER_TAG;
     69 using syncable::ID;
     70 using syncable::IS_DEL;
     71 using syncable::IS_DIR;
     72 using syncable::IS_UNAPPLIED_UPDATE;
     73 using syncable::IS_UNSYNCED;
     74 using syncable::META_HANDLE;
     75 using syncable::MTIME;
     76 using syncable::NEXT_ID;
     77 using syncable::NON_UNIQUE_NAME;
     78 using syncable::PARENT_ID;
     79 using syncable::PREV_ID;
     80 using syncable::SERVER_IS_DEL;
     81 using syncable::SERVER_NON_UNIQUE_NAME;
     82 using syncable::SERVER_PARENT_ID;
     83 using syncable::SERVER_POSITION_IN_PARENT;
     84 using syncable::SERVER_SPECIFICS;
     85 using syncable::SERVER_VERSION;
     86 using syncable::UNIQUE_CLIENT_TAG;
     87 using syncable::UNIQUE_SERVER_TAG;
     88 using syncable::SPECIFICS;
     89 using syncable::SYNCING;
     90 using syncable::UNITTEST;
     91 
     92 using sessions::ConflictProgress;
     93 using sessions::ScopedSetSessionWriteTransaction;
     94 using sessions::StatusController;
     95 using sessions::SyncSessionContext;
     96 using sessions::SyncSession;
     97 
     98 class SyncerTest : public testing::Test,
     99                    public SyncSession::Delegate,
    100                    public ModelSafeWorkerRegistrar,
    101                    public SyncEngineEventListener {
    102  protected:
    103   SyncerTest() : syncer_(NULL), saw_syncer_event_(false) {}
    104 
    105   // SyncSession::Delegate implementation.
    106   virtual void OnSilencedUntil(const base::TimeTicks& silenced_until) {
    107     FAIL() << "Should not get silenced.";
    108   }
    109   virtual bool IsSyncingCurrentlySilenced() {
    110     return false;
    111   }
    112   virtual void OnReceivedLongPollIntervalUpdate(
    113       const base::TimeDelta& new_interval) {
    114     last_long_poll_interval_received_ = new_interval;
    115   }
    116   virtual void OnReceivedShortPollIntervalUpdate(
    117       const base::TimeDelta& new_interval) {
    118     last_short_poll_interval_received_ = new_interval;
    119   }
    120   virtual void OnShouldStopSyncingPermanently() {
    121   }
    122 
    123   // ModelSafeWorkerRegistrar implementation.
    124   virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {
    125     out->push_back(worker_.get());
    126   }
    127 
    128   virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
    129     // We're just testing the sync engine here, so we shunt everything to
    130     // the SyncerThread.  Datatypes which aren't enabled aren't in the map.
    131     for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
    132       if (enabled_datatypes_[i]) {
    133         (*out)[syncable::ModelTypeFromInt(i)] = GROUP_PASSIVE;
    134       }
    135     }
    136   }
    137 
    138   virtual void OnSyncEngineEvent(const SyncEngineEvent& event) {
    139     VLOG(1) << "HandleSyncEngineEvent in unittest " << event.what_happened;
    140     // we only test for entry-specific events, not status changed ones.
    141     switch (event.what_happened) {
    142       case SyncEngineEvent::STATUS_CHANGED:
    143         // fall through
    144       case SyncEngineEvent::SYNC_CYCLE_ENDED:
    145         return;
    146       default:
    147         CHECK(false) << "Handling unknown error type in unit tests!!";
    148     }
    149     saw_syncer_event_ = true;
    150   }
    151 
    152   SyncSession* MakeSession() {
    153     ModelSafeRoutingInfo info;
    154     std::vector<ModelSafeWorker*> workers;
    155     GetModelSafeRoutingInfo(&info);
    156     GetWorkers(&workers);
    157     syncable::ModelTypePayloadMap types =
    158         syncable::ModelTypePayloadMapFromRoutingInfo(info, std::string());
    159     return new SyncSession(context_.get(), this,
    160         sessions::SyncSourceInfo(sync_pb::GetUpdatesCallerInfo::UNKNOWN, types),
    161         info, workers);
    162   }
    163 
    164   bool SyncShareAsDelegate() {
    165     scoped_ptr<SyncSession> session(MakeSession());
    166     syncer_->SyncShare(session.get());
    167     return session->HasMoreToSync();
    168   }
    169 
    170   void LoopSyncShare() {
    171     bool should_loop = false;
    172     int loop_iterations = 0;
    173     do {
    174       ASSERT_LT(++loop_iterations, 100) << "infinite loop detected. please fix";
    175       should_loop = SyncShareAsDelegate();
    176     } while (should_loop);
    177   }
    178 
    179   virtual void SetUp() {
    180     syncdb_.SetUp();
    181 
    182     mock_server_.reset(
    183         new MockConnectionManager(syncdb_.manager(), syncdb_.name()));
    184     EnableDatatype(syncable::BOOKMARKS);
    185     worker_ = new ModelSafeWorker();
    186     std::vector<SyncEngineEventListener*> listeners;
    187     listeners.push_back(this);
    188     context_.reset(new SyncSessionContext(mock_server_.get(),
    189         syncdb_.manager(), this, listeners));
    190     context_->set_account_name(syncdb_.name());
    191     ASSERT_FALSE(context_->resolver());
    192     syncer_ = new Syncer();
    193     session_.reset(MakeSession());
    194 
    195     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    196     CHECK(dir.good());
    197     ReadTransaction trans(dir, __FILE__, __LINE__);
    198     syncable::Directory::ChildHandles children;
    199     dir->GetChildHandles(&trans, trans.root_id(), &children);
    200     ASSERT_TRUE(0 == children.size());
    201     saw_syncer_event_ = false;
    202     root_id_ = TestIdFactory::root();
    203     parent_id_ = ids_.MakeServer("parent id");
    204     child_id_ = ids_.MakeServer("child id");
    205   }
    206 
    207   virtual void TearDown() {
    208     mock_server_.reset();
    209     delete syncer_;
    210     syncer_ = NULL;
    211     syncdb_.TearDown();
    212   }
    213   void WriteTestDataToEntry(WriteTransaction* trans, MutableEntry* entry) {
    214     EXPECT_FALSE(entry->Get(IS_DIR));
    215     EXPECT_FALSE(entry->Get(IS_DEL));
    216     sync_pb::EntitySpecifics specifics;
    217     specifics.MutableExtension(sync_pb::bookmark)->set_url("http://demo/");
    218     specifics.MutableExtension(sync_pb::bookmark)->set_favicon("PNG");
    219     entry->Put(syncable::SPECIFICS, specifics);
    220     entry->Put(syncable::IS_UNSYNCED, true);
    221   }
    222   void VerifyTestDataInEntry(BaseTransaction* trans, Entry* entry) {
    223     EXPECT_FALSE(entry->Get(IS_DIR));
    224     EXPECT_FALSE(entry->Get(IS_DEL));
    225     VerifyTestBookmarkDataInEntry(entry);
    226   }
    227   void VerifyTestBookmarkDataInEntry(Entry* entry) {
    228     const sync_pb::EntitySpecifics& specifics = entry->Get(syncable::SPECIFICS);
    229     EXPECT_TRUE(specifics.HasExtension(sync_pb::bookmark));
    230     EXPECT_EQ("PNG", specifics.GetExtension(sync_pb::bookmark).favicon());
    231     EXPECT_EQ("http://demo/", specifics.GetExtension(sync_pb::bookmark).url());
    232   }
    233 
    234   void SyncRepeatedlyToTriggerConflictResolution(SyncSession* session) {
    235     // We should trigger after less than 6 syncs, but extra does no harm.
    236     for (int i = 0 ; i < 6 ; ++i)
    237       syncer_->SyncShare(session);
    238   }
    239   void SyncRepeatedlyToTriggerStuckSignal(SyncSession* session) {
    240     // We should trigger after less than 10 syncs, but we want to avoid brittle
    241     // tests.
    242     for (int i = 0 ; i < 12 ; ++i)
    243       syncer_->SyncShare(session);
    244   }
    245   sync_pb::EntitySpecifics DefaultBookmarkSpecifics() {
    246     sync_pb::EntitySpecifics result;
    247     AddDefaultExtensionValue(syncable::BOOKMARKS, &result);
    248     return result;
    249   }
    250 
    251   sync_pb::EntitySpecifics DefaultPreferencesSpecifics() {
    252     sync_pb::EntitySpecifics result;
    253     AddDefaultExtensionValue(syncable::PREFERENCES, &result);
    254     return result;
    255   }
    256   // Enumeration of alterations to entries for commit ordering tests.
    257   enum EntryFeature {
    258     LIST_END = 0,  // Denotes the end of the list of features from below.
    259     SYNCED,  // Items are unsynced by default
    260     DELETED,
    261     OLD_MTIME,
    262     MOVED_FROM_ROOT,
    263   };
    264 
    265   struct CommitOrderingTest {
    266     // expected commit index.
    267     int commit_index;
    268     // Details about the item
    269     syncable::Id id;
    270     syncable::Id parent_id;
    271     EntryFeature features[10];
    272 
    273     static const CommitOrderingTest LAST_COMMIT_ITEM;
    274   };
    275 
    276   void RunCommitOrderingTest(CommitOrderingTest* test) {
    277     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    278     ASSERT_TRUE(dir.good());
    279 
    280     map<int, syncable::Id> expected_positions;
    281     {  // Transaction scope.
    282       WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
    283       while (!test->id.IsRoot()) {
    284         if (test->commit_index >= 0) {
    285           map<int, syncable::Id>::value_type entry(test->commit_index,
    286                                                    test->id);
    287           bool double_position = !expected_positions.insert(entry).second;
    288           ASSERT_FALSE(double_position) << "Two id's expected at one position";
    289         }
    290         string utf8_name = test->id.GetServerId();
    291         string name(utf8_name.begin(), utf8_name.end());
    292         MutableEntry entry(&trans, CREATE, test->parent_id, name);
    293 
    294         entry.Put(syncable::ID, test->id);
    295         if (test->id.ServerKnows()) {
    296           entry.Put(BASE_VERSION, 5);
    297           entry.Put(SERVER_VERSION, 5);
    298           entry.Put(SERVER_PARENT_ID, test->parent_id);
    299         }
    300         entry.Put(syncable::IS_DIR, true);
    301         entry.Put(syncable::IS_UNSYNCED, true);
    302         entry.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    303         // Set the time to 30 seconds in the future to reduce the chance of
    304         // flaky tests.
    305         int64 now_server_time = ClientTimeToServerTime(syncable::Now());
    306         int64 now_plus_30s = ServerTimeToClientTime(now_server_time + 30000);
    307         int64 now_minus_2h = ServerTimeToClientTime(now_server_time - 7200000);
    308         entry.Put(syncable::MTIME, now_plus_30s);
    309         for (size_t i = 0 ; i < arraysize(test->features) ; ++i) {
    310           switch (test->features[i]) {
    311             case LIST_END:
    312               break;
    313             case SYNCED:
    314               entry.Put(syncable::IS_UNSYNCED, false);
    315               break;
    316             case DELETED:
    317               entry.Put(syncable::IS_DEL, true);
    318               break;
    319             case OLD_MTIME:
    320               entry.Put(MTIME, now_minus_2h);
    321               break;
    322             case MOVED_FROM_ROOT:
    323               entry.Put(SERVER_PARENT_ID, trans.root_id());
    324               break;
    325             default:
    326               FAIL() << "Bad value in CommitOrderingTest list";
    327           }
    328         }
    329         test++;
    330       }
    331     }
    332     LoopSyncShare();
    333     ASSERT_TRUE(expected_positions.size() ==
    334                 mock_server_->committed_ids().size());
    335     // If this test starts failing, be aware other sort orders could be valid.
    336     for (size_t i = 0; i < expected_positions.size(); ++i) {
    337       EXPECT_TRUE(1 == expected_positions.count(i));
    338       EXPECT_TRUE(expected_positions[i] == mock_server_->committed_ids()[i]);
    339     }
    340   }
    341 
    342   void DoTruncationTest(const ScopedDirLookup& dir,
    343                         const vector<int64>& unsynced_handle_view,
    344                         const vector<syncable::Id>& expected_id_order) {
    345     // The expected order is "x", "b", "c", "e", truncated appropriately.
    346     for (size_t limit = expected_id_order.size() + 2; limit > 0; --limit) {
    347       StatusController* status = session_->status_controller();
    348       WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    349       ScopedSetSessionWriteTransaction set_trans(session_.get(), &wtrans);
    350       status->set_unsynced_handles(unsynced_handle_view);
    351 
    352       ModelSafeRoutingInfo routes;
    353       GetModelSafeRoutingInfo(&routes);
    354       GetCommitIdsCommand command(limit);
    355       command.BuildCommitIds(session_->status_controller()->unsynced_handles(),
    356           session_->write_transaction(), routes);
    357       vector<syncable::Id> output =
    358           command.ordered_commit_set_->GetAllCommitIds();
    359       size_t truncated_size = std::min(limit, expected_id_order.size());
    360       ASSERT_TRUE(truncated_size == output.size());
    361       for (size_t i = 0; i < truncated_size; ++i) {
    362         ASSERT_TRUE(expected_id_order[i] == output[i])
    363             << "At index " << i << " with batch size limited to " << limit;
    364       }
    365       sessions::OrderedCommitSet::Projection proj;
    366       proj = command.ordered_commit_set_->GetCommitIdProjection(GROUP_PASSIVE);
    367       ASSERT_EQ(truncated_size, proj.size());
    368       for (size_t i = 0; i < truncated_size; ++i) {
    369         SCOPED_TRACE(::testing::Message("Projection mismatch with i = ") << i);
    370         syncable::Id projected =
    371             command.ordered_commit_set_->GetCommitIdAt(proj[i]);
    372         ASSERT_TRUE(expected_id_order[proj[i]] == projected);
    373         // Since this projection is the identity, the following holds.
    374         ASSERT_TRUE(expected_id_order[i] == projected);
    375       }
    376     }
    377   }
    378 
    379   int64 CreateUnsyncedDirectory(const string& entry_name,
    380       const string& idstring) {
    381     return CreateUnsyncedDirectory(entry_name,
    382         syncable::Id::CreateFromServerId(idstring));
    383   }
    384 
    385   int64 CreateUnsyncedDirectory(const string& entry_name,
    386       const syncable::Id& id) {
    387     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    388     EXPECT_TRUE(dir.good());
    389     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    390     MutableEntry entry(&wtrans, syncable::CREATE, wtrans.root_id(),
    391                        entry_name);
    392     EXPECT_TRUE(entry.good());
    393     entry.Put(syncable::IS_UNSYNCED, true);
    394     entry.Put(syncable::IS_DIR, true);
    395     entry.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    396     entry.Put(syncable::BASE_VERSION, id.ServerKnows() ? 1 : 0);
    397     entry.Put(syncable::ID, id);
    398     return entry.Get(META_HANDLE);
    399   }
    400 
    401   void EnableDatatype(syncable::ModelType model_type) {
    402     enabled_datatypes_[model_type] = true;
    403     mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
    404   }
    405 
    406   void DisableDatatype(syncable::ModelType model_type) {
    407     enabled_datatypes_[model_type] = false;
    408     mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
    409   }
    410 
    411   template<typename FieldType, typename ValueType>
    412   ValueType GetField(int64 metahandle, FieldType field,
    413       ValueType default_value) const {
    414     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    415     EXPECT_TRUE(dir.good());
    416     ReadTransaction trans(dir, __FILE__, __LINE__);
    417     Entry entry(&trans, GET_BY_HANDLE, metahandle);
    418     EXPECT_TRUE(entry.good());
    419     if (!entry.good()) {
    420       return default_value;
    421     }
    422     EXPECT_EQ(metahandle, entry.Get(META_HANDLE));
    423     return entry.Get(field);
    424   }
    425 
    426   // Helper getters that work without a transaction, to reduce boilerplate.
    427   Id Get(int64 metahandle, syncable::IdField field) const {
    428     return GetField(metahandle, field, syncable::kNullId);
    429   }
    430 
    431   string Get(int64 metahandle, syncable::StringField field) const {
    432     return GetField(metahandle, field, string());
    433   }
    434 
    435   int64 Get(int64 metahandle, syncable::Int64Field field) const {
    436     return GetField(metahandle, field, syncable::kInvalidMetaHandle);
    437   }
    438 
    439   int64 Get(int64 metahandle, syncable::BaseVersion field) const {
    440     const int64 kDefaultValue = -100;
    441     return GetField(metahandle, field, kDefaultValue);
    442   }
    443 
    444   bool Get(int64 metahandle, syncable::IndexedBitField field) const {
    445     return GetField(metahandle, field, false);
    446   }
    447 
    448   bool Get(int64 metahandle, syncable::IsDelField field) const {
    449     return GetField(metahandle, field, false);
    450   }
    451 
    452   bool Get(int64 metahandle, syncable::BitField field) const {
    453     return GetField(metahandle, field, false);
    454   }
    455 
    456   // Some ids to aid tests. Only the root one's value is specific. The rest
    457   // are named for test clarity.
    458   // TODO(chron): Get rid of these inbuilt IDs. They only make it
    459   // more confusing.
    460   syncable::Id root_id_;
    461   syncable::Id parent_id_;
    462   syncable::Id child_id_;
    463 
    464   TestIdFactory ids_;
    465 
    466   TestDirectorySetterUpper syncdb_;
    467   scoped_ptr<MockConnectionManager> mock_server_;
    468 
    469   Syncer* syncer_;
    470 
    471   scoped_ptr<SyncSession> session_;
    472   scoped_ptr<SyncSessionContext> context_;
    473   bool saw_syncer_event_;
    474   base::TimeDelta last_short_poll_interval_received_;
    475   base::TimeDelta last_long_poll_interval_received_;
    476   scoped_refptr<ModelSafeWorker> worker_;
    477 
    478   syncable::ModelTypeBitSet enabled_datatypes_;
    479 
    480   DISALLOW_COPY_AND_ASSIGN(SyncerTest);
    481 };
    482 
    483 TEST_F(SyncerTest, TestCallGatherUnsyncedEntries) {
    484   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    485   ASSERT_TRUE(dir.good());
    486   {
    487     Syncer::UnsyncedMetaHandles handles;
    488     {
    489       ReadTransaction trans(dir, __FILE__, __LINE__);
    490       SyncerUtil::GetUnsyncedEntries(&trans, &handles);
    491     }
    492     ASSERT_TRUE(0 == handles.size());
    493   }
    494   // TODO(sync): When we can dynamically connect and disconnect the mock
    495   // ServerConnectionManager test disconnected GetUnsyncedEntries here. It's a
    496   // regression for a very old bug.
    497 }
    498 
    499 TEST_F(SyncerTest, GetCommitIdsCommandTruncates) {
    500   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    501   ASSERT_TRUE(dir.good());
    502   int64 handle_c = CreateUnsyncedDirectory("C", ids_.MakeLocal("c"));
    503   int64 handle_x = CreateUnsyncedDirectory("X", ids_.MakeLocal("x"));
    504   int64 handle_b = CreateUnsyncedDirectory("B", ids_.MakeLocal("b"));
    505   int64 handle_d = CreateUnsyncedDirectory("D", ids_.MakeLocal("d"));
    506   int64 handle_e = CreateUnsyncedDirectory("E", ids_.MakeLocal("e"));
    507   {
    508     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    509     MutableEntry entry_x(&wtrans, GET_BY_HANDLE, handle_x);
    510     MutableEntry entry_b(&wtrans, GET_BY_HANDLE, handle_b);
    511     MutableEntry entry_c(&wtrans, GET_BY_HANDLE, handle_c);
    512     MutableEntry entry_d(&wtrans, GET_BY_HANDLE, handle_d);
    513     MutableEntry entry_e(&wtrans, GET_BY_HANDLE, handle_e);
    514     entry_x.Put(SPECIFICS, DefaultBookmarkSpecifics());
    515     entry_b.Put(SPECIFICS, DefaultBookmarkSpecifics());
    516     entry_c.Put(SPECIFICS, DefaultBookmarkSpecifics());
    517     entry_d.Put(SPECIFICS, DefaultBookmarkSpecifics());
    518     entry_e.Put(SPECIFICS, DefaultBookmarkSpecifics());
    519     entry_b.Put(PARENT_ID, entry_x.Get(ID));
    520     entry_c.Put(PARENT_ID, entry_x.Get(ID));
    521     entry_c.PutPredecessor(entry_b.Get(ID));
    522     entry_d.Put(PARENT_ID, entry_b.Get(ID));
    523     entry_e.Put(PARENT_ID, entry_c.Get(ID));
    524   }
    525 
    526   // The arrangement is now: x (b (d) c (e)).
    527   vector<int64> unsynced_handle_view;
    528   vector<syncable::Id> expected_order;
    529   // The expected order is "x", "b", "c", "e", truncated appropriately.
    530   unsynced_handle_view.push_back(handle_e);
    531   expected_order.push_back(ids_.MakeLocal("x"));
    532   expected_order.push_back(ids_.MakeLocal("b"));
    533   expected_order.push_back(ids_.MakeLocal("c"));
    534   expected_order.push_back(ids_.MakeLocal("e"));
    535   DoTruncationTest(dir, unsynced_handle_view, expected_order);
    536 }
    537 
    538 // TODO(chron): More corner case unit tests around validation.
    539 TEST_F(SyncerTest, TestCommitMetahandleIterator) {
    540   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    541   ASSERT_TRUE(dir.good());
    542   StatusController* status = session_->status_controller();
    543   const vector<int64>& unsynced(status->unsynced_handles());
    544 
    545   {
    546     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    547     ScopedSetSessionWriteTransaction set_trans(session_.get(), &wtrans);
    548 
    549     sessions::OrderedCommitSet commit_set(session_->routing_info());
    550     GetCommitIdsCommand::CommitMetahandleIterator iterator(unsynced, &wtrans,
    551         &commit_set);
    552     EXPECT_FALSE(iterator.Valid());
    553     EXPECT_FALSE(iterator.Increment());
    554   }
    555 
    556   {
    557     vector<int64> session_metahandles;
    558     session_metahandles.push_back(CreateUnsyncedDirectory("test1", "testid1"));
    559     session_metahandles.push_back(CreateUnsyncedDirectory("test2", "testid2"));
    560     session_metahandles.push_back(CreateUnsyncedDirectory("test3", "testid3"));
    561     status->set_unsynced_handles(session_metahandles);
    562 
    563     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    564     ScopedSetSessionWriteTransaction set_trans(session_.get(), &wtrans);
    565     sessions::OrderedCommitSet commit_set(session_->routing_info());
    566     GetCommitIdsCommand::CommitMetahandleIterator iterator(unsynced, &wtrans,
    567         &commit_set);
    568 
    569     EXPECT_TRUE(iterator.Valid());
    570     EXPECT_TRUE(iterator.Current() == session_metahandles[0]);
    571     EXPECT_TRUE(iterator.Increment());
    572 
    573     EXPECT_TRUE(iterator.Valid());
    574     EXPECT_TRUE(iterator.Current() == session_metahandles[1]);
    575     EXPECT_TRUE(iterator.Increment());
    576 
    577     EXPECT_TRUE(iterator.Valid());
    578     EXPECT_TRUE(iterator.Current() == session_metahandles[2]);
    579     EXPECT_FALSE(iterator.Increment());
    580 
    581     EXPECT_FALSE(iterator.Valid());
    582   }
    583 }
    584 
    585 TEST_F(SyncerTest, TestGetUnsyncedAndSimpleCommit) {
    586   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    587   ASSERT_TRUE(dir.good());
    588   {
    589     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    590     MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(),
    591                         "Pete");
    592     ASSERT_TRUE(parent.good());
    593     parent.Put(syncable::IS_UNSYNCED, true);
    594     parent.Put(syncable::IS_DIR, true);
    595     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    596     parent.Put(syncable::BASE_VERSION, 1);
    597     parent.Put(syncable::ID, parent_id_);
    598     MutableEntry child(&wtrans, syncable::CREATE, parent_id_, "Pete");
    599     ASSERT_TRUE(child.good());
    600     child.Put(syncable::ID, child_id_);
    601     child.Put(syncable::BASE_VERSION, 1);
    602     WriteTestDataToEntry(&wtrans, &child);
    603   }
    604 
    605   StatusController* status = session_->status_controller();
    606   syncer_->SyncShare(session_.get());
    607   EXPECT_TRUE(2 == status->unsynced_handles().size());
    608   ASSERT_TRUE(2 == mock_server_->committed_ids().size());
    609   // If this test starts failing, be aware other sort orders could be valid.
    610   EXPECT_TRUE(parent_id_ == mock_server_->committed_ids()[0]);
    611   EXPECT_TRUE(child_id_ == mock_server_->committed_ids()[1]);
    612   {
    613     ReadTransaction rt(dir, __FILE__, __LINE__);
    614     Entry entry(&rt, syncable::GET_BY_ID, child_id_);
    615     ASSERT_TRUE(entry.good());
    616     VerifyTestDataInEntry(&rt, &entry);
    617   }
    618 }
    619 
    620 TEST_F(SyncerTest, TestPurgeWhileUnsynced) {
    621   // Similar to above, but throw a purge operation into the mix. Bug 49278.
    622   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    623   ASSERT_TRUE(dir.good());
    624   syncable::Id pref_node_id = TestIdFactory::MakeServer("Tim");
    625   {
    626     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    627     MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(), "Pete");
    628     ASSERT_TRUE(parent.good());
    629     parent.Put(syncable::IS_UNSYNCED, true);
    630     parent.Put(syncable::IS_DIR, true);
    631     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    632     parent.Put(syncable::BASE_VERSION, 1);
    633     parent.Put(syncable::ID, parent_id_);
    634     MutableEntry child(&wtrans, syncable::CREATE, parent_id_, "Pete");
    635     ASSERT_TRUE(child.good());
    636     child.Put(syncable::ID, child_id_);
    637     child.Put(syncable::BASE_VERSION, 1);
    638     WriteTestDataToEntry(&wtrans, &child);
    639 
    640     MutableEntry parent2(&wtrans, syncable::CREATE, wtrans.root_id(), "Tim");
    641     ASSERT_TRUE(parent2.good());
    642     parent2.Put(syncable::IS_UNSYNCED, true);
    643     parent2.Put(syncable::IS_DIR, true);
    644     parent2.Put(syncable::SPECIFICS, DefaultPreferencesSpecifics());
    645     parent2.Put(syncable::BASE_VERSION, 1);
    646     parent2.Put(syncable::ID, pref_node_id);
    647   }
    648 
    649   std::set<syncable::ModelType> types_to_purge;
    650   types_to_purge.insert(syncable::PREFERENCES);
    651   dir->PurgeEntriesWithTypeIn(types_to_purge);
    652 
    653   StatusController* status = session_->status_controller();
    654   syncer_->SyncShare(session_.get());
    655   EXPECT_EQ(2U, status->unsynced_handles().size());
    656   ASSERT_EQ(2U, mock_server_->committed_ids().size());
    657   // If this test starts failing, be aware other sort orders could be valid.
    658   EXPECT_TRUE(parent_id_ == mock_server_->committed_ids()[0]);
    659   EXPECT_TRUE(child_id_ == mock_server_->committed_ids()[1]);
    660   {
    661     ReadTransaction rt(dir, __FILE__, __LINE__);
    662     Entry entry(&rt, syncable::GET_BY_ID, child_id_);
    663     ASSERT_TRUE(entry.good());
    664     VerifyTestDataInEntry(&rt, &entry);
    665   }
    666   dir->SaveChanges();
    667   {
    668     ReadTransaction rt(dir, __FILE__, __LINE__);
    669     Entry entry(&rt, syncable::GET_BY_ID, pref_node_id);
    670     ASSERT_FALSE(entry.good());
    671   }
    672 }
    673 
    674 TEST_F(SyncerTest, TestPurgeWhileUnapplied) {
    675   // Similar to above, but for unapplied items. Bug 49278.
    676   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    677   ASSERT_TRUE(dir.good());
    678   {
    679     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    680     MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(), "Pete");
    681     ASSERT_TRUE(parent.good());
    682     parent.Put(syncable::IS_UNAPPLIED_UPDATE, true);
    683     parent.Put(syncable::IS_DIR, true);
    684     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    685     parent.Put(syncable::BASE_VERSION, 1);
    686     parent.Put(syncable::ID, parent_id_);
    687   }
    688 
    689   std::set<syncable::ModelType> types_to_purge;
    690   types_to_purge.insert(syncable::BOOKMARKS);
    691   dir->PurgeEntriesWithTypeIn(types_to_purge);
    692 
    693   syncer_->SyncShare(session_.get());
    694   dir->SaveChanges();
    695   {
    696     ReadTransaction rt(dir, __FILE__, __LINE__);
    697     Entry entry(&rt, syncable::GET_BY_ID, parent_id_);
    698     ASSERT_FALSE(entry.good());
    699   }
    700 }
    701 
    702 TEST_F(SyncerTest, TestCommitListOrderingTwoItemsTall) {
    703   CommitOrderingTest items[] = {
    704     {1, ids_.FromNumber(-1001), ids_.FromNumber(-1000)},
    705     {0, ids_.FromNumber(-1000), ids_.FromNumber(0)},
    706     CommitOrderingTest::LAST_COMMIT_ITEM,
    707   };
    708   RunCommitOrderingTest(items);
    709 }
    710 
    711 TEST_F(SyncerTest, TestCommitListOrderingThreeItemsTall) {
    712   CommitOrderingTest items[] = {
    713     {1, ids_.FromNumber(-2001), ids_.FromNumber(-2000)},
    714     {0, ids_.FromNumber(-2000), ids_.FromNumber(0)},
    715     {2, ids_.FromNumber(-2002), ids_.FromNumber(-2001)},
    716     CommitOrderingTest::LAST_COMMIT_ITEM,
    717   };
    718   RunCommitOrderingTest(items);
    719 }
    720 
    721 TEST_F(SyncerTest, TestCommitListOrderingThreeItemsTallLimitedSize) {
    722   context_->set_max_commit_batch_size(2);
    723   CommitOrderingTest items[] = {
    724     {1, ids_.FromNumber(-2001), ids_.FromNumber(-2000)},
    725     {0, ids_.FromNumber(-2000), ids_.FromNumber(0)},
    726     {2, ids_.FromNumber(-2002), ids_.FromNumber(-2001)},
    727     CommitOrderingTest::LAST_COMMIT_ITEM,
    728   };
    729   RunCommitOrderingTest(items);
    730 }
    731 
    732 TEST_F(SyncerTest, TestCommitListOrderingSingleDeletedItem) {
    733   CommitOrderingTest items[] = {
    734     {0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED}},
    735     CommitOrderingTest::LAST_COMMIT_ITEM,
    736   };
    737   RunCommitOrderingTest(items);
    738 }
    739 
    740 TEST_F(SyncerTest, TestCommitListOrderingSingleUncommittedDeletedItem) {
    741   CommitOrderingTest items[] = {
    742     {-1, ids_.FromNumber(-1000), ids_.FromNumber(0), {DELETED}},
    743     CommitOrderingTest::LAST_COMMIT_ITEM,
    744   };
    745   RunCommitOrderingTest(items);
    746 }
    747 
    748 TEST_F(SyncerTest, TestCommitListOrderingSingleDeletedItemWithUnroll) {
    749   CommitOrderingTest items[] = {
    750     {0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED}},
    751     CommitOrderingTest::LAST_COMMIT_ITEM,
    752   };
    753   RunCommitOrderingTest(items);
    754 }
    755 
    756 TEST_F(SyncerTest,
    757        TestCommitListOrderingSingleLongDeletedItemWithUnroll) {
    758   CommitOrderingTest items[] = {
    759     {0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    760     CommitOrderingTest::LAST_COMMIT_ITEM,
    761   };
    762   RunCommitOrderingTest(items);
    763 }
    764 
    765 TEST_F(SyncerTest, TestCommitListOrderingTwoLongDeletedItemWithUnroll) {
    766   CommitOrderingTest items[] = {
    767     {0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    768     {-1, ids_.FromNumber(1001), ids_.FromNumber(1000), {DELETED, OLD_MTIME}},
    769     CommitOrderingTest::LAST_COMMIT_ITEM,
    770   };
    771   RunCommitOrderingTest(items);
    772 }
    773 
    774 TEST_F(SyncerTest, TestCommitListOrdering3LongDeletedItemsWithSizeLimit) {
    775   context_->set_max_commit_batch_size(2);
    776   CommitOrderingTest items[] = {
    777     {0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    778     {1, ids_.FromNumber(1001), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    779     {2, ids_.FromNumber(1002), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    780     CommitOrderingTest::LAST_COMMIT_ITEM,
    781   };
    782   RunCommitOrderingTest(items);
    783 }
    784 
    785 TEST_F(SyncerTest, TestCommitListOrderingTwoDeletedItemsWithUnroll) {
    786   CommitOrderingTest items[] = {
    787     {0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED}},
    788     {-1, ids_.FromNumber(1001), ids_.FromNumber(1000), {DELETED}},
    789     CommitOrderingTest::LAST_COMMIT_ITEM,
    790   };
    791   RunCommitOrderingTest(items);
    792 }
    793 
    794 TEST_F(SyncerTest, TestCommitListOrderingComplexDeletionScenario) {
    795   CommitOrderingTest items[] = {
    796     { 0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    797     {-1, ids_.FromNumber(1001), ids_.FromNumber(0), {SYNCED}},
    798     {1, ids_.FromNumber(1002), ids_.FromNumber(1001), {DELETED, OLD_MTIME}},
    799     {-1, ids_.FromNumber(1003), ids_.FromNumber(1001), {SYNCED}},
    800     {2, ids_.FromNumber(1004), ids_.FromNumber(1003), {DELETED}},
    801     CommitOrderingTest::LAST_COMMIT_ITEM,
    802   };
    803   RunCommitOrderingTest(items);
    804 }
    805 
    806 TEST_F(SyncerTest,
    807        TestCommitListOrderingComplexDeletionScenarioWith2RecentDeletes) {
    808   CommitOrderingTest items[] = {
    809     { 0, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    810     {-1, ids_.FromNumber(1001), ids_.FromNumber(0), {SYNCED}},
    811     {1, ids_.FromNumber(1002), ids_.FromNumber(1001), {DELETED, OLD_MTIME}},
    812     {-1, ids_.FromNumber(1003), ids_.FromNumber(1001), {SYNCED}},
    813     {2, ids_.FromNumber(1004), ids_.FromNumber(1003), {DELETED}},
    814     {3, ids_.FromNumber(1005), ids_.FromNumber(1003), {DELETED}},
    815     CommitOrderingTest::LAST_COMMIT_ITEM,
    816   };
    817   RunCommitOrderingTest(items);
    818 }
    819 
    820 TEST_F(SyncerTest, TestCommitListOrderingDeleteMovedItems) {
    821   CommitOrderingTest items[] = {
    822     {1, ids_.FromNumber(1000), ids_.FromNumber(0), {DELETED, OLD_MTIME}},
    823     {0, ids_.FromNumber(1001), ids_.FromNumber(1000), {DELETED, OLD_MTIME,
    824                                               MOVED_FROM_ROOT}},
    825     CommitOrderingTest::LAST_COMMIT_ITEM,
    826   };
    827   RunCommitOrderingTest(items);
    828 }
    829 
    830 TEST_F(SyncerTest, TestCommitListOrderingWithNesting) {
    831   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    832   ASSERT_TRUE(dir.good());
    833   int64 now_server_time = ClientTimeToServerTime(syncable::Now());
    834   int64 now_minus_2h = ServerTimeToClientTime(now_server_time - 7200000);
    835 
    836   {
    837     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    838     {
    839       MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(),
    840                           "Bob");
    841       ASSERT_TRUE(parent.good());
    842       parent.Put(syncable::IS_UNSYNCED, true);
    843       parent.Put(syncable::IS_DIR, true);
    844       parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    845       parent.Put(syncable::ID, ids_.FromNumber(100));
    846       parent.Put(syncable::BASE_VERSION, 1);
    847       MutableEntry child(&wtrans, syncable::CREATE, ids_.FromNumber(100),
    848                          "Bob");
    849       ASSERT_TRUE(child.good());
    850       child.Put(syncable::IS_UNSYNCED, true);
    851       child.Put(syncable::IS_DIR, true);
    852       child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    853       child.Put(syncable::ID, ids_.FromNumber(101));
    854       child.Put(syncable::BASE_VERSION, 1);
    855       MutableEntry grandchild(&wtrans, syncable::CREATE, ids_.FromNumber(101),
    856                               "Bob");
    857       ASSERT_TRUE(grandchild.good());
    858       grandchild.Put(syncable::ID, ids_.FromNumber(102));
    859       grandchild.Put(syncable::IS_UNSYNCED, true);
    860       grandchild.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    861       grandchild.Put(syncable::BASE_VERSION, 1);
    862     }
    863     {
    864       // Create three deleted items which deletions we expect to be sent to the
    865       // server.
    866       MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(),
    867                           "Pete");
    868       ASSERT_TRUE(parent.good());
    869       parent.Put(syncable::IS_UNSYNCED, true);
    870       parent.Put(syncable::IS_DIR, true);
    871       parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    872       parent.Put(syncable::IS_DEL, true);
    873       parent.Put(syncable::ID, ids_.FromNumber(103));
    874       parent.Put(syncable::BASE_VERSION, 1);
    875       parent.Put(syncable::MTIME, now_minus_2h);
    876       MutableEntry child(&wtrans, syncable::CREATE, ids_.FromNumber(103),
    877                          "Pete");
    878       ASSERT_TRUE(child.good());
    879       child.Put(syncable::IS_UNSYNCED, true);
    880       child.Put(syncable::IS_DIR, true);
    881       child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    882       child.Put(syncable::IS_DEL, true);
    883       child.Put(syncable::ID, ids_.FromNumber(104));
    884       child.Put(syncable::BASE_VERSION, 1);
    885       child.Put(syncable::MTIME, now_minus_2h);
    886       MutableEntry grandchild(&wtrans, syncable::CREATE, ids_.FromNumber(104),
    887                               "Pete");
    888       ASSERT_TRUE(grandchild.good());
    889       grandchild.Put(syncable::IS_UNSYNCED, true);
    890       grandchild.Put(syncable::ID, ids_.FromNumber(105));
    891       grandchild.Put(syncable::IS_DEL, true);
    892       grandchild.Put(syncable::IS_DIR, false);
    893       grandchild.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    894       grandchild.Put(syncable::BASE_VERSION, 1);
    895       grandchild.Put(syncable::MTIME, now_minus_2h);
    896     }
    897   }
    898 
    899   syncer_->SyncShare(session_.get());
    900   EXPECT_TRUE(6 == session_->status_controller()->unsynced_handles().size());
    901   ASSERT_TRUE(6 == mock_server_->committed_ids().size());
    902   // This test will NOT unroll deletes because SERVER_PARENT_ID is not set.
    903   // It will treat these like moves.
    904   vector<syncable::Id> commit_ids(mock_server_->committed_ids());
    905   EXPECT_TRUE(ids_.FromNumber(100) == commit_ids[0]);
    906   EXPECT_TRUE(ids_.FromNumber(101) == commit_ids[1]);
    907   EXPECT_TRUE(ids_.FromNumber(102) == commit_ids[2]);
    908   // We don't guarantee the delete orders in this test, only that they occur
    909   // at the end.
    910   std::sort(commit_ids.begin() + 3, commit_ids.end());
    911   EXPECT_TRUE(ids_.FromNumber(103) == commit_ids[3]);
    912   EXPECT_TRUE(ids_.FromNumber(104) == commit_ids[4]);
    913   EXPECT_TRUE(ids_.FromNumber(105) == commit_ids[5]);
    914 }
    915 
    916 TEST_F(SyncerTest, TestCommitListOrderingWithNewItems) {
    917   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    918   ASSERT_TRUE(dir.good());
    919   {
    920     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    921     MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(), "1");
    922     ASSERT_TRUE(parent.good());
    923     parent.Put(syncable::IS_UNSYNCED, true);
    924     parent.Put(syncable::IS_DIR, true);
    925     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    926     parent.Put(syncable::ID, parent_id_);
    927     MutableEntry child(&wtrans, syncable::CREATE, wtrans.root_id(), "2");
    928     ASSERT_TRUE(child.good());
    929     child.Put(syncable::IS_UNSYNCED, true);
    930     child.Put(syncable::IS_DIR, true);
    931     child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    932     child.Put(syncable::ID, child_id_);
    933     parent.Put(syncable::BASE_VERSION, 1);
    934     child.Put(syncable::BASE_VERSION, 1);
    935   }
    936   {
    937     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    938     MutableEntry parent(&wtrans, syncable::CREATE, parent_id_, "A");
    939     ASSERT_TRUE(parent.good());
    940     parent.Put(syncable::IS_UNSYNCED, true);
    941     parent.Put(syncable::IS_DIR, true);
    942     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    943     parent.Put(syncable::ID, ids_.FromNumber(102));
    944     MutableEntry child(&wtrans, syncable::CREATE, parent_id_, "B");
    945     ASSERT_TRUE(child.good());
    946     child.Put(syncable::IS_UNSYNCED, true);
    947     child.Put(syncable::IS_DIR, true);
    948     child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    949     child.Put(syncable::ID, ids_.FromNumber(-103));
    950     parent.Put(syncable::BASE_VERSION, 1);
    951   }
    952   {
    953     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    954     MutableEntry parent(&wtrans, syncable::CREATE, child_id_, "A");
    955     ASSERT_TRUE(parent.good());
    956     parent.Put(syncable::IS_UNSYNCED, true);
    957     parent.Put(syncable::IS_DIR, true);
    958     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    959     parent.Put(syncable::ID, ids_.FromNumber(-104));
    960     MutableEntry child(&wtrans, syncable::CREATE, child_id_, "B");
    961     ASSERT_TRUE(child.good());
    962     child.Put(syncable::IS_UNSYNCED, true);
    963     child.Put(syncable::IS_DIR, true);
    964     child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    965     child.Put(syncable::ID, ids_.FromNumber(105));
    966     child.Put(syncable::BASE_VERSION, 1);
    967   }
    968 
    969   syncer_->SyncShare(session_.get());
    970   EXPECT_TRUE(6 == session_->status_controller()->unsynced_handles().size());
    971   ASSERT_TRUE(6 == mock_server_->committed_ids().size());
    972   // If this test starts failing, be aware other sort orders could be valid.
    973   EXPECT_TRUE(parent_id_ == mock_server_->committed_ids()[0]);
    974   EXPECT_TRUE(child_id_ == mock_server_->committed_ids()[1]);
    975   EXPECT_TRUE(ids_.FromNumber(102) == mock_server_->committed_ids()[2]);
    976   EXPECT_TRUE(ids_.FromNumber(-103) == mock_server_->committed_ids()[3]);
    977   EXPECT_TRUE(ids_.FromNumber(-104) == mock_server_->committed_ids()[4]);
    978   EXPECT_TRUE(ids_.FromNumber(105) == mock_server_->committed_ids()[5]);
    979 }
    980 
    981 TEST_F(SyncerTest, TestCommitListOrderingCounterexample) {
    982   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
    983   ASSERT_TRUE(dir.good());
    984 
    985   syncable::Id child2_id = ids_.NewServerId();
    986 
    987   {
    988     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
    989     MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(), "P");
    990     ASSERT_TRUE(parent.good());
    991     parent.Put(syncable::IS_UNSYNCED, true);
    992     parent.Put(syncable::IS_DIR, true);
    993     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
    994     parent.Put(syncable::ID, parent_id_);
    995     MutableEntry child1(&wtrans, syncable::CREATE, parent_id_, "1");
    996     ASSERT_TRUE(child1.good());
    997     child1.Put(syncable::IS_UNSYNCED, true);
    998     child1.Put(syncable::ID, child_id_);
    999     child1.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1000     MutableEntry child2(&wtrans, syncable::CREATE, parent_id_, "2");
   1001     ASSERT_TRUE(child2.good());
   1002     child2.Put(syncable::IS_UNSYNCED, true);
   1003     child2.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1004     child2.Put(syncable::ID, child2_id);
   1005 
   1006     parent.Put(syncable::BASE_VERSION, 1);
   1007     child1.Put(syncable::BASE_VERSION, 1);
   1008     child2.Put(syncable::BASE_VERSION, 1);
   1009   }
   1010 
   1011   syncer_->SyncShare(session_.get());
   1012   EXPECT_TRUE(3 == session_->status_controller()->unsynced_handles().size());
   1013   ASSERT_TRUE(3 == mock_server_->committed_ids().size());
   1014   // If this test starts failing, be aware other sort orders could be valid.
   1015   EXPECT_TRUE(parent_id_ == mock_server_->committed_ids()[0]);
   1016   EXPECT_TRUE(child_id_ == mock_server_->committed_ids()[1]);
   1017   EXPECT_TRUE(child2_id == mock_server_->committed_ids()[2]);
   1018 }
   1019 
   1020 TEST_F(SyncerTest, TestCommitListOrderingAndNewParent) {
   1021   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1022   ASSERT_TRUE(dir.good());
   1023 
   1024   string parent1_name = "1";
   1025   string parent2_name = "A";
   1026   string child_name = "B";
   1027 
   1028   {
   1029     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1030     MutableEntry parent(&wtrans, syncable::CREATE, wtrans.root_id(),
   1031                         parent1_name);
   1032     ASSERT_TRUE(parent.good());
   1033     parent.Put(syncable::IS_UNSYNCED, true);
   1034     parent.Put(syncable::IS_DIR, true);
   1035     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1036     parent.Put(syncable::ID, parent_id_);
   1037     parent.Put(syncable::BASE_VERSION, 1);
   1038   }
   1039 
   1040   syncable::Id parent2_id = ids_.NewLocalId();
   1041   syncable::Id child_id = ids_.NewServerId();
   1042   {
   1043     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1044     MutableEntry parent2(&wtrans, syncable::CREATE, parent_id_, parent2_name);
   1045     ASSERT_TRUE(parent2.good());
   1046     parent2.Put(syncable::IS_UNSYNCED, true);
   1047     parent2.Put(syncable::IS_DIR, true);
   1048     parent2.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1049     parent2.Put(syncable::ID, parent2_id);
   1050 
   1051     MutableEntry child(&wtrans, syncable::CREATE, parent2_id, child_name);
   1052     ASSERT_TRUE(child.good());
   1053     child.Put(syncable::IS_UNSYNCED, true);
   1054     child.Put(syncable::IS_DIR, true);
   1055     child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1056     child.Put(syncable::ID, child_id);
   1057     child.Put(syncable::BASE_VERSION, 1);
   1058   }
   1059 
   1060   syncer_->SyncShare(session_.get());
   1061   EXPECT_TRUE(3 == session_->status_controller()->unsynced_handles().size());
   1062   ASSERT_TRUE(3 == mock_server_->committed_ids().size());
   1063   // If this test starts failing, be aware other sort orders could be valid.
   1064   EXPECT_TRUE(parent_id_ == mock_server_->committed_ids()[0]);
   1065   EXPECT_TRUE(parent2_id == mock_server_->committed_ids()[1]);
   1066   EXPECT_TRUE(child_id == mock_server_->committed_ids()[2]);
   1067   {
   1068     ReadTransaction rtrans(dir, __FILE__, __LINE__);
   1069     // Check that things committed correctly.
   1070     Entry entry_1(&rtrans, syncable::GET_BY_ID, parent_id_);
   1071     EXPECT_EQ(entry_1.Get(NON_UNIQUE_NAME), parent1_name);
   1072     // Check that parent2 is a subfolder of parent1.
   1073     EXPECT_EQ(1, CountEntriesWithName(&rtrans,
   1074                                       parent_id_,
   1075                                       parent2_name));
   1076 
   1077     // Parent2 was a local ID and thus should have changed on commit!
   1078     Entry pre_commit_entry_parent2(&rtrans, syncable::GET_BY_ID, parent2_id);
   1079     ASSERT_FALSE(pre_commit_entry_parent2.good());
   1080 
   1081     // Look up the new ID.
   1082     Id parent2_committed_id =
   1083         GetOnlyEntryWithName(&rtrans, parent_id_, parent2_name);
   1084     EXPECT_TRUE(parent2_committed_id.ServerKnows());
   1085 
   1086     Entry child(&rtrans, syncable::GET_BY_ID, child_id);
   1087     EXPECT_EQ(parent2_committed_id, child.Get(syncable::PARENT_ID));
   1088   }
   1089 }
   1090 
   1091 TEST_F(SyncerTest, TestCommitListOrderingAndNewParentAndChild) {
   1092   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1093   ASSERT_TRUE(dir.good());
   1094 
   1095   string parent_name = "1";
   1096   string parent2_name = "A";
   1097   string child_name = "B";
   1098 
   1099   {
   1100     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1101     MutableEntry parent(&wtrans,
   1102                         syncable::CREATE,
   1103                         wtrans.root_id(),
   1104                         parent_name);
   1105     ASSERT_TRUE(parent.good());
   1106     parent.Put(syncable::IS_UNSYNCED, true);
   1107     parent.Put(syncable::IS_DIR, true);
   1108     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1109     parent.Put(syncable::ID, parent_id_);
   1110     parent.Put(syncable::BASE_VERSION, 1);
   1111   }
   1112 
   1113   int64 meta_handle_a, meta_handle_b;
   1114   const Id parent2_local_id = ids_.NewLocalId();
   1115   const Id child_local_id = ids_.NewLocalId();
   1116   {
   1117     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1118     MutableEntry parent2(&wtrans, syncable::CREATE, parent_id_, parent2_name);
   1119     ASSERT_TRUE(parent2.good());
   1120     parent2.Put(syncable::IS_UNSYNCED, true);
   1121     parent2.Put(syncable::IS_DIR, true);
   1122     parent2.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1123 
   1124     parent2.Put(syncable::ID, parent2_local_id);
   1125     meta_handle_a = parent2.Get(syncable::META_HANDLE);
   1126     MutableEntry child(&wtrans, syncable::CREATE, parent2_local_id, child_name);
   1127     ASSERT_TRUE(child.good());
   1128     child.Put(syncable::IS_UNSYNCED, true);
   1129     child.Put(syncable::IS_DIR, true);
   1130     child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1131     child.Put(syncable::ID, child_local_id);
   1132     meta_handle_b = child.Get(syncable::META_HANDLE);
   1133   }
   1134 
   1135   syncer_->SyncShare(session_.get());
   1136   EXPECT_TRUE(3 == session_->status_controller()->unsynced_handles().size());
   1137   ASSERT_TRUE(3 == mock_server_->committed_ids().size());
   1138   // If this test starts failing, be aware other sort orders could be valid.
   1139   EXPECT_TRUE(parent_id_ == mock_server_->committed_ids()[0]);
   1140   EXPECT_TRUE(parent2_local_id == mock_server_->committed_ids()[1]);
   1141   EXPECT_TRUE(child_local_id == mock_server_->committed_ids()[2]);
   1142   {
   1143     ReadTransaction rtrans(dir, __FILE__, __LINE__);
   1144 
   1145     Entry parent(&rtrans, syncable::GET_BY_ID,
   1146                  GetOnlyEntryWithName(&rtrans, rtrans.root_id(), parent_name));
   1147     ASSERT_TRUE(parent.good());
   1148     EXPECT_TRUE(parent.Get(syncable::ID).ServerKnows());
   1149 
   1150     Entry parent2(&rtrans, syncable::GET_BY_ID,
   1151                   GetOnlyEntryWithName(&rtrans, parent.Get(ID), parent2_name));
   1152     ASSERT_TRUE(parent2.good());
   1153     EXPECT_TRUE(parent2.Get(syncable::ID).ServerKnows());
   1154 
   1155     // Id changed on commit, so this should fail.
   1156     Entry local_parent2_id_entry(&rtrans,
   1157                                  syncable::GET_BY_ID,
   1158                                  parent2_local_id);
   1159     ASSERT_FALSE(local_parent2_id_entry.good());
   1160 
   1161     Entry entry_b(&rtrans, syncable::GET_BY_HANDLE, meta_handle_b);
   1162     EXPECT_TRUE(entry_b.Get(syncable::ID).ServerKnows());
   1163     EXPECT_TRUE(parent2.Get(syncable::ID) == entry_b.Get(syncable::PARENT_ID));
   1164   }
   1165 }
   1166 
   1167 TEST_F(SyncerTest, UpdateWithZeroLengthName) {
   1168   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1169   ASSERT_TRUE(dir.good());
   1170   // One illegal update
   1171   mock_server_->AddUpdateDirectory(1, 0, "", 1, 10);
   1172   // And one legal one that we're going to delete.
   1173   mock_server_->AddUpdateDirectory(2, 0, "FOO", 1, 10);
   1174   SyncShareAsDelegate();
   1175   // Delete the legal one. The new update has a null name.
   1176   mock_server_->AddUpdateDirectory(2, 0, "", 2, 20);
   1177   mock_server_->SetLastUpdateDeleted();
   1178   SyncShareAsDelegate();
   1179 }
   1180 
   1181 TEST_F(SyncerTest, DontGetStuckWithTwoSameNames) {
   1182   // We should not get stuck here because we get
   1183   // two server updates with exactly the same name.
   1184   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1185   ASSERT_TRUE(dir.good());
   1186   mock_server_->AddUpdateDirectory(1, 0, "foo:", 1, 10);
   1187   SyncShareAsDelegate();
   1188   mock_server_->AddUpdateDirectory(2, 0, "foo:", 1, 20);
   1189   SyncRepeatedlyToTriggerStuckSignal(session_.get());
   1190   EXPECT_FALSE(session_->status_controller()->syncer_status().syncer_stuck);
   1191   saw_syncer_event_ = false;
   1192 }
   1193 
   1194 TEST_F(SyncerTest, TestBasicUpdate) {
   1195   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1196   ASSERT_TRUE(dir.good());
   1197   string id = "some_id";
   1198   string parent_id = "0";
   1199   string name = "in_root";
   1200   int64 version = 10;
   1201   int64 timestamp = 10;
   1202   mock_server_->AddUpdateDirectory(id, parent_id, name, version, timestamp);
   1203 
   1204   SyncShareAsDelegate();
   1205   {
   1206     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1207     Entry entry(&trans, GET_BY_ID,
   1208                syncable::Id::CreateFromServerId("some_id"));
   1209     ASSERT_TRUE(entry.good());
   1210     EXPECT_TRUE(entry.Get(IS_DIR));
   1211     EXPECT_TRUE(entry.Get(SERVER_VERSION) == version);
   1212     EXPECT_TRUE(entry.Get(BASE_VERSION) == version);
   1213     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   1214     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   1215     EXPECT_FALSE(entry.Get(SERVER_IS_DEL));
   1216     EXPECT_FALSE(entry.Get(IS_DEL));
   1217   }
   1218 }
   1219 
   1220 TEST_F(SyncerTest, IllegalAndLegalUpdates) {
   1221   Id root = TestIdFactory::root();
   1222   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1223   ASSERT_TRUE(dir.good());
   1224   // Should apply just fine.
   1225   mock_server_->AddUpdateDirectory(1, 0, "in_root", 10, 10);
   1226 
   1227   // Same name. But this SHOULD work.
   1228   mock_server_->AddUpdateDirectory(2, 0, "in_root", 10, 10);
   1229 
   1230   // Unknown parent: should never be applied. "-80" is a legal server ID,
   1231   // because any string sent by the server is a legal server ID in the sync
   1232   // protocol, but it's not the ID of any item known to the client.  This
   1233   // update should succeed validation, but be stuck in the unapplied state
   1234   // until an item with the server ID "-80" arrives.
   1235   mock_server_->AddUpdateDirectory(3, -80, "bad_parent", 10, 10);
   1236 
   1237   syncer_->SyncShare(session_.get());
   1238   StatusController* status = session_->status_controller();
   1239 
   1240   // Id 3 should be in conflict now.
   1241   EXPECT_EQ(1, status->TotalNumConflictingItems());
   1242   {
   1243     sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
   1244     EXPECT_EQ(1, status->conflict_progress().ConflictingItemsSize());
   1245   }
   1246 
   1247   // These entries will be used in the second set of updates.
   1248   mock_server_->AddUpdateDirectory(4, 0, "newer_version", 20, 10);
   1249   mock_server_->AddUpdateDirectory(5, 0, "circular1", 10, 10);
   1250   mock_server_->AddUpdateDirectory(6, 5, "circular2", 10, 10);
   1251   mock_server_->AddUpdateDirectory(9, 3, "bad_parent_child", 10, 10);
   1252   mock_server_->AddUpdateDirectory(100, 9, "bad_parent_child2", 10, 10);
   1253   mock_server_->AddUpdateDirectory(10, 0, "dir_to_bookmark", 10, 10);
   1254 
   1255   syncer_->SyncShare(session_.get());
   1256   // The three items with an unresolved parent should be unapplied (3, 9, 100).
   1257   // The name clash should also still be in conflict.
   1258   EXPECT_EQ(3, status->TotalNumConflictingItems());
   1259   {
   1260     sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
   1261     EXPECT_EQ(3, status->conflict_progress().ConflictingItemsSize());
   1262   }
   1263 
   1264   {
   1265     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1266     // Even though it has the same name, it should work.
   1267     Entry name_clash(&trans, GET_BY_ID, ids_.FromNumber(2));
   1268     ASSERT_TRUE(name_clash.good());
   1269     EXPECT_FALSE(name_clash.Get(IS_UNAPPLIED_UPDATE))
   1270         << "Duplicate name SHOULD be OK.";
   1271 
   1272     Entry bad_parent(&trans, GET_BY_ID, ids_.FromNumber(3));
   1273     ASSERT_TRUE(bad_parent.good());
   1274     EXPECT_TRUE(bad_parent.Get(IS_UNAPPLIED_UPDATE))
   1275         << "child of unknown parent should be in conflict";
   1276 
   1277     Entry bad_parent_child(&trans, GET_BY_ID, ids_.FromNumber(9));
   1278     ASSERT_TRUE(bad_parent_child.good());
   1279     EXPECT_TRUE(bad_parent_child.Get(IS_UNAPPLIED_UPDATE))
   1280         << "grandchild of unknown parent should be in conflict";
   1281 
   1282     Entry bad_parent_child2(&trans, GET_BY_ID, ids_.FromNumber(100));
   1283     ASSERT_TRUE(bad_parent_child2.good());
   1284     EXPECT_TRUE(bad_parent_child2.Get(IS_UNAPPLIED_UPDATE))
   1285         << "great-grandchild of unknown parent should be in conflict";
   1286   }
   1287 
   1288   // Updating 1 should not affect item 2 of the same name.
   1289   mock_server_->AddUpdateDirectory(1, 0, "new_name", 20, 20);
   1290 
   1291   // Moving 5 under 6 will create a cycle: a conflict.
   1292   mock_server_->AddUpdateDirectory(5, 6, "circular3", 20, 20);
   1293 
   1294   // Flip the is_dir bit: should fail verify & be dropped.
   1295   mock_server_->AddUpdateBookmark(10, 0, "dir_to_bookmark", 20, 20);
   1296   syncer_->SyncShare(session_.get());
   1297 
   1298   // Version number older than last known: should fail verify & be dropped.
   1299   mock_server_->AddUpdateDirectory(4, 0, "old_version", 10, 10);
   1300   syncer_->SyncShare(session_.get());
   1301   {
   1302     ReadTransaction trans(dir, __FILE__, __LINE__);
   1303 
   1304     Entry still_a_dir(&trans, GET_BY_ID, ids_.FromNumber(10));
   1305     ASSERT_TRUE(still_a_dir.good());
   1306     EXPECT_FALSE(still_a_dir.Get(IS_UNAPPLIED_UPDATE));
   1307     EXPECT_TRUE(10 == still_a_dir.Get(BASE_VERSION));
   1308     EXPECT_TRUE(10 == still_a_dir.Get(SERVER_VERSION));
   1309     EXPECT_TRUE(still_a_dir.Get(IS_DIR));
   1310 
   1311     Entry rename(&trans, GET_BY_ID, ids_.FromNumber(1));
   1312     ASSERT_TRUE(rename.good());
   1313     EXPECT_EQ(root, rename.Get(PARENT_ID));
   1314     EXPECT_EQ("new_name", rename.Get(NON_UNIQUE_NAME));
   1315     EXPECT_FALSE(rename.Get(IS_UNAPPLIED_UPDATE));
   1316     EXPECT_TRUE(ids_.FromNumber(1) == rename.Get(ID));
   1317     EXPECT_TRUE(20 == rename.Get(BASE_VERSION));
   1318 
   1319     Entry name_clash(&trans, GET_BY_ID, ids_.FromNumber(2));
   1320     ASSERT_TRUE(name_clash.good());
   1321     EXPECT_EQ(root, name_clash.Get(PARENT_ID));
   1322     EXPECT_TRUE(ids_.FromNumber(2) == name_clash.Get(ID));
   1323     EXPECT_TRUE(10 == name_clash.Get(BASE_VERSION));
   1324     EXPECT_EQ("in_root", name_clash.Get(NON_UNIQUE_NAME));
   1325 
   1326     Entry ignored_old_version(&trans, GET_BY_ID, ids_.FromNumber(4));
   1327     ASSERT_TRUE(ignored_old_version.good());
   1328     EXPECT_TRUE(
   1329         ignored_old_version.Get(NON_UNIQUE_NAME) == "newer_version");
   1330     EXPECT_FALSE(ignored_old_version.Get(IS_UNAPPLIED_UPDATE));
   1331     EXPECT_TRUE(20 == ignored_old_version.Get(BASE_VERSION));
   1332 
   1333     Entry circular_parent_issue(&trans, GET_BY_ID, ids_.FromNumber(5));
   1334     ASSERT_TRUE(circular_parent_issue.good());
   1335     EXPECT_TRUE(circular_parent_issue.Get(IS_UNAPPLIED_UPDATE))
   1336         << "circular move should be in conflict";
   1337     EXPECT_TRUE(circular_parent_issue.Get(PARENT_ID) == root_id_);
   1338     EXPECT_TRUE(circular_parent_issue.Get(SERVER_PARENT_ID) ==
   1339                 ids_.FromNumber(6));
   1340     EXPECT_TRUE(10 == circular_parent_issue.Get(BASE_VERSION));
   1341 
   1342     Entry circular_parent_target(&trans, GET_BY_ID, ids_.FromNumber(6));
   1343     ASSERT_TRUE(circular_parent_target.good());
   1344     EXPECT_FALSE(circular_parent_target.Get(IS_UNAPPLIED_UPDATE));
   1345     EXPECT_TRUE(circular_parent_issue.Get(ID) ==
   1346         circular_parent_target.Get(PARENT_ID));
   1347     EXPECT_TRUE(10 == circular_parent_target.Get(BASE_VERSION));
   1348   }
   1349 
   1350   EXPECT_FALSE(saw_syncer_event_);
   1351   EXPECT_EQ(4, status->TotalNumConflictingItems());
   1352   {
   1353     sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
   1354     EXPECT_EQ(4, status->conflict_progress().ConflictingItemsSize());
   1355   }
   1356 }
   1357 
   1358 TEST_F(SyncerTest, CommitTimeRename) {
   1359   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1360   ASSERT_TRUE(dir.good());
   1361   int64 metahandle_folder;
   1362   int64 metahandle_new_entry;
   1363 
   1364   // Create a folder and an entry.
   1365   {
   1366     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1367     MutableEntry parent(&trans, CREATE, root_id_, "Folder");
   1368     ASSERT_TRUE(parent.good());
   1369     parent.Put(IS_DIR, true);
   1370     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1371     parent.Put(IS_UNSYNCED, true);
   1372     metahandle_folder = parent.Get(META_HANDLE);
   1373 
   1374     MutableEntry entry(&trans, CREATE, parent.Get(ID), "new_entry");
   1375     ASSERT_TRUE(entry.good());
   1376     metahandle_new_entry = entry.Get(META_HANDLE);
   1377     WriteTestDataToEntry(&trans, &entry);
   1378   }
   1379 
   1380   // Mix in a directory creation too for later.
   1381   mock_server_->AddUpdateDirectory(2, 0, "dir_in_root", 10, 10);
   1382   mock_server_->SetCommitTimeRename("renamed_");
   1383   SyncShareAsDelegate();
   1384 
   1385   // Verify it was correctly renamed.
   1386   {
   1387     ReadTransaction trans(dir, __FILE__, __LINE__);
   1388     Entry entry_folder(&trans, GET_BY_HANDLE, metahandle_folder);
   1389     ASSERT_TRUE(entry_folder.good());
   1390     EXPECT_EQ("renamed_Folder", entry_folder.Get(NON_UNIQUE_NAME));
   1391 
   1392     Entry entry_new(&trans, GET_BY_HANDLE, metahandle_new_entry);
   1393     ASSERT_TRUE(entry_new.good());
   1394     EXPECT_EQ(entry_folder.Get(ID), entry_new.Get(PARENT_ID));
   1395     EXPECT_EQ("renamed_new_entry", entry_new.Get(NON_UNIQUE_NAME));
   1396 
   1397     // And that the unrelated directory creation worked without a rename.
   1398     Entry new_dir(&trans, GET_BY_ID, ids_.FromNumber(2));
   1399     EXPECT_TRUE(new_dir.good());
   1400     EXPECT_EQ("dir_in_root", new_dir.Get(NON_UNIQUE_NAME));
   1401   }
   1402 }
   1403 
   1404 
   1405 TEST_F(SyncerTest, CommitTimeRenameI18N) {
   1406   // This is utf-8 for the diacritized Internationalization.
   1407   const char* i18nString = "\xc3\x8e\xc3\xb1\x74\xc3\xa9\x72\xc3\xb1"
   1408       "\xc3\xa5\x74\xc3\xae\xc3\xb6\xc3\xb1\xc3\xa5\x6c\xc3\xae"
   1409       "\xc2\x9e\xc3\xa5\x74\xc3\xae\xc3\xb6\xc3\xb1";
   1410 
   1411   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1412   ASSERT_TRUE(dir.good());
   1413   int64 metahandle;
   1414   // Create a folder, expect a commit time rename.
   1415   {
   1416     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1417     MutableEntry parent(&trans, CREATE, root_id_, "Folder");
   1418     ASSERT_TRUE(parent.good());
   1419     parent.Put(IS_DIR, true);
   1420     parent.Put(SPECIFICS, DefaultBookmarkSpecifics());
   1421     parent.Put(IS_UNSYNCED, true);
   1422     metahandle = parent.Get(META_HANDLE);
   1423   }
   1424 
   1425   mock_server_->SetCommitTimeRename(i18nString);
   1426   SyncShareAsDelegate();
   1427 
   1428   // Verify it was correctly renamed.
   1429   {
   1430     ReadTransaction trans(dir, __FILE__, __LINE__);
   1431     string expected_folder_name(i18nString);
   1432     expected_folder_name.append("Folder");
   1433 
   1434 
   1435     Entry entry_folder(&trans, GET_BY_HANDLE, metahandle);
   1436     ASSERT_TRUE(entry_folder.good());
   1437     EXPECT_EQ(expected_folder_name, entry_folder.Get(NON_UNIQUE_NAME));
   1438   }
   1439 }
   1440 
   1441 // A commit with a lost response produces an update that has to be reunited with
   1442 // its parent.
   1443 TEST_F(SyncerTest, CommitReuniteUpdateAdjustsChildren) {
   1444   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1445   ASSERT_TRUE(dir.good());
   1446 
   1447   // Create a folder in the root.
   1448   int64 metahandle_folder;
   1449   {
   1450     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1451     MutableEntry entry(&trans, CREATE, trans.root_id(), "new_folder");
   1452     ASSERT_TRUE(entry.good());
   1453     entry.Put(IS_DIR, true);
   1454     entry.Put(SPECIFICS, DefaultBookmarkSpecifics());
   1455     entry.Put(IS_UNSYNCED, true);
   1456     metahandle_folder = entry.Get(META_HANDLE);
   1457   }
   1458 
   1459   // Verify it and pull the ID out of the folder.
   1460   syncable::Id folder_id;
   1461   int64 metahandle_entry;
   1462   {
   1463     ReadTransaction trans(dir, __FILE__, __LINE__);
   1464     Entry entry(&trans, GET_BY_HANDLE, metahandle_folder);
   1465     ASSERT_TRUE(entry.good());
   1466     folder_id = entry.Get(ID);
   1467     ASSERT_TRUE(!folder_id.ServerKnows());
   1468   }
   1469 
   1470   // Create an entry in the newly created folder.
   1471   {
   1472     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1473     MutableEntry entry(&trans, CREATE, folder_id, "new_entry");
   1474     ASSERT_TRUE(entry.good());
   1475     metahandle_entry = entry.Get(META_HANDLE);
   1476     WriteTestDataToEntry(&trans, &entry);
   1477   }
   1478 
   1479   // Verify it and pull the ID out of the entry.
   1480   syncable::Id entry_id;
   1481   {
   1482     ReadTransaction trans(dir, __FILE__, __LINE__);
   1483     Entry entry(&trans, syncable::GET_BY_HANDLE, metahandle_entry);
   1484     ASSERT_TRUE(entry.good());
   1485     EXPECT_EQ(folder_id, entry.Get(PARENT_ID));
   1486     EXPECT_EQ("new_entry", entry.Get(NON_UNIQUE_NAME));
   1487     entry_id = entry.Get(ID);
   1488     EXPECT_TRUE(!entry_id.ServerKnows());
   1489     VerifyTestDataInEntry(&trans, &entry);
   1490   }
   1491 
   1492   // Now, to emulate a commit response failure, we just don't commit it.
   1493   int64 new_version = 150;  // any larger value.
   1494   int64 timestamp = 20;  // arbitrary value.
   1495   syncable::Id new_folder_id =
   1496       syncable::Id::CreateFromServerId("folder_server_id");
   1497 
   1498   // The following update should cause the folder to both apply the update, as
   1499   // well as reassociate the id.
   1500   mock_server_->AddUpdateDirectory(new_folder_id, root_id_,
   1501       "new_folder", new_version, timestamp);
   1502   mock_server_->SetLastUpdateOriginatorFields(
   1503       dir->cache_guid(), folder_id.GetServerId());
   1504 
   1505   // We don't want it accidentally committed, just the update applied.
   1506   mock_server_->set_conflict_all_commits(true);
   1507 
   1508   // Alright! Apply that update!
   1509   SyncShareAsDelegate();
   1510   {
   1511     // The folder's ID should have been updated.
   1512     ReadTransaction trans(dir, __FILE__, __LINE__);
   1513     Entry folder(&trans, GET_BY_HANDLE, metahandle_folder);
   1514     ASSERT_TRUE(folder.good());
   1515     EXPECT_EQ("new_folder", folder.Get(NON_UNIQUE_NAME));
   1516     EXPECT_TRUE(new_version == folder.Get(BASE_VERSION));
   1517     EXPECT_TRUE(new_folder_id == folder.Get(ID));
   1518     EXPECT_TRUE(folder.Get(ID).ServerKnows());
   1519     EXPECT_EQ(trans.root_id(), folder.Get(PARENT_ID));
   1520 
   1521     // Since it was updated, the old folder should not exist.
   1522     Entry old_dead_folder(&trans, GET_BY_ID, folder_id);
   1523     EXPECT_FALSE(old_dead_folder.good());
   1524 
   1525     // The child's parent should have changed.
   1526     Entry entry(&trans, syncable::GET_BY_HANDLE, metahandle_entry);
   1527     ASSERT_TRUE(entry.good());
   1528     EXPECT_EQ("new_entry", entry.Get(NON_UNIQUE_NAME));
   1529     EXPECT_EQ(new_folder_id, entry.Get(PARENT_ID));
   1530     EXPECT_TRUE(!entry.Get(ID).ServerKnows());
   1531     VerifyTestDataInEntry(&trans, &entry);
   1532   }
   1533 }
   1534 
   1535 // A commit with a lost response produces an update that has to be reunited with
   1536 // its parent.
   1537 TEST_F(SyncerTest, CommitReuniteUpdate) {
   1538   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1539   ASSERT_TRUE(dir.good());
   1540 
   1541   // Create an entry in the root.
   1542   int64 entry_metahandle;
   1543   {
   1544     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1545     MutableEntry entry(&trans, CREATE, trans.root_id(), "new_entry");
   1546     ASSERT_TRUE(entry.good());
   1547     entry_metahandle = entry.Get(META_HANDLE);
   1548     WriteTestDataToEntry(&trans, &entry);
   1549   }
   1550 
   1551   // Verify it and pull the ID out.
   1552   syncable::Id entry_id;
   1553   {
   1554     ReadTransaction trans(dir, __FILE__, __LINE__);
   1555 
   1556     Entry entry(&trans, GET_BY_HANDLE, entry_metahandle);
   1557     ASSERT_TRUE(entry.good());
   1558     entry_id = entry.Get(ID);
   1559     EXPECT_TRUE(!entry_id.ServerKnows());
   1560     VerifyTestDataInEntry(&trans, &entry);
   1561   }
   1562 
   1563   // Now, to emulate a commit response failure, we just don't commit it.
   1564   int64 new_version = 150;  // any larger value.
   1565   int64 timestamp = 20;  // arbitrary value.
   1566   syncable::Id new_entry_id = syncable::Id::CreateFromServerId("server_id");
   1567 
   1568   // Generate an update from the server with a relevant ID reassignment.
   1569   mock_server_->AddUpdateBookmark(new_entry_id, root_id_,
   1570       "new_entry", new_version, timestamp);
   1571   mock_server_->SetLastUpdateOriginatorFields(
   1572       dir->cache_guid(), entry_id.GetServerId());
   1573 
   1574   // We don't want it accidentally committed, just the update applied.
   1575   mock_server_->set_conflict_all_commits(true);
   1576 
   1577   // Alright! Apply that update!
   1578   SyncShareAsDelegate();
   1579   {
   1580     ReadTransaction trans(dir, __FILE__, __LINE__);
   1581     Entry entry(&trans, GET_BY_HANDLE, entry_metahandle);
   1582     ASSERT_TRUE(entry.good());
   1583     EXPECT_TRUE(new_version == entry.Get(BASE_VERSION));
   1584     EXPECT_TRUE(new_entry_id == entry.Get(ID));
   1585     EXPECT_EQ("new_entry", entry.Get(NON_UNIQUE_NAME));
   1586   }
   1587 }
   1588 
   1589 // A commit with a lost response must work even if the local entry was deleted
   1590 // before the update is applied. We should not duplicate the local entry in
   1591 // this case, but just create another one alongside. We may wish to examine
   1592 // this behavior in the future as it can create hanging uploads that never
   1593 // finish, that must be cleaned up on the server side after some time.
   1594 TEST_F(SyncerTest, CommitReuniteUpdateDoesNotChokeOnDeletedLocalEntry) {
   1595   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1596   ASSERT_TRUE(dir.good());
   1597 
   1598   // Create a entry in the root.
   1599   int64 entry_metahandle;
   1600   {
   1601     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1602     MutableEntry entry(&trans, CREATE, trans.root_id(), "new_entry");
   1603     ASSERT_TRUE(entry.good());
   1604     entry_metahandle = entry.Get(META_HANDLE);
   1605     WriteTestDataToEntry(&trans, &entry);
   1606   }
   1607   // Verify it and pull the ID out.
   1608   syncable::Id entry_id;
   1609   {
   1610     ReadTransaction trans(dir, __FILE__, __LINE__);
   1611     Entry entry(&trans, GET_BY_HANDLE, entry_metahandle);
   1612     ASSERT_TRUE(entry.good());
   1613     entry_id = entry.Get(ID);
   1614     EXPECT_TRUE(!entry_id.ServerKnows());
   1615     VerifyTestDataInEntry(&trans, &entry);
   1616   }
   1617 
   1618   // Now, to emulate a commit response failure, we just don't commit it.
   1619   int64 new_version = 150;  // any larger value.
   1620   int64 timestamp = 20;  // arbitrary value.
   1621   syncable::Id new_entry_id = syncable::Id::CreateFromServerId("server_id");
   1622 
   1623   // Generate an update from the server with a relevant ID reassignment.
   1624   mock_server_->AddUpdateBookmark(new_entry_id, root_id_,
   1625       "new_entry", new_version, timestamp);
   1626   mock_server_->SetLastUpdateOriginatorFields(
   1627       dir->cache_guid(),
   1628       entry_id.GetServerId());
   1629 
   1630   // We don't want it accidentally committed, just the update applied.
   1631   mock_server_->set_conflict_all_commits(true);
   1632 
   1633   // Purposefully delete the entry now before the update application finishes.
   1634   {
   1635     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1636     Id new_entry_id = GetOnlyEntryWithName(
   1637         &trans, trans.root_id(), "new_entry");
   1638     MutableEntry entry(&trans, GET_BY_ID, new_entry_id);
   1639     ASSERT_TRUE(entry.good());
   1640     entry.Put(syncable::IS_DEL, true);
   1641   }
   1642 
   1643   // Just don't CHECK fail in sync, have the update split.
   1644   SyncShareAsDelegate();
   1645   {
   1646     ReadTransaction trans(dir, __FILE__, __LINE__);
   1647     Id new_entry_id = GetOnlyEntryWithName(
   1648         &trans, trans.root_id(), "new_entry");
   1649     Entry entry(&trans, GET_BY_ID, new_entry_id);
   1650     ASSERT_TRUE(entry.good());
   1651     EXPECT_FALSE(entry.Get(IS_DEL));
   1652 
   1653     Entry old_entry(&trans, GET_BY_ID, entry_id);
   1654     ASSERT_TRUE(old_entry.good());
   1655     EXPECT_TRUE(old_entry.Get(IS_DEL));
   1656   }
   1657 }
   1658 
   1659 // TODO(chron): Add more unsanitized name tests.
   1660 TEST_F(SyncerTest, ConflictMatchingEntryHandlesUnsanitizedNames) {
   1661   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1662   CHECK(dir.good());
   1663   mock_server_->AddUpdateDirectory(1, 0, "A/A", 10, 10);
   1664   mock_server_->AddUpdateDirectory(2, 0, "B/B", 10, 10);
   1665   mock_server_->set_conflict_all_commits(true);
   1666   SyncShareAsDelegate();
   1667   {
   1668     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1669 
   1670     MutableEntry A(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   1671     ASSERT_TRUE(A.good());
   1672     A.Put(IS_UNSYNCED, true);
   1673     A.Put(IS_UNAPPLIED_UPDATE, true);
   1674     A.Put(SERVER_VERSION, 20);
   1675 
   1676     MutableEntry B(&wtrans, GET_BY_ID, ids_.FromNumber(2));
   1677     ASSERT_TRUE(B.good());
   1678     B.Put(IS_UNAPPLIED_UPDATE, true);
   1679     B.Put(SERVER_VERSION, 20);
   1680   }
   1681   LoopSyncShare();
   1682   saw_syncer_event_ = false;
   1683   mock_server_->set_conflict_all_commits(false);
   1684 
   1685   {
   1686     ReadTransaction trans(dir, __FILE__, __LINE__);
   1687 
   1688     Entry A(&trans, GET_BY_ID, ids_.FromNumber(1));
   1689     ASSERT_TRUE(A.good());
   1690     EXPECT_TRUE(A.Get(IS_UNSYNCED) == false);
   1691     EXPECT_TRUE(A.Get(IS_UNAPPLIED_UPDATE) == false);
   1692     EXPECT_TRUE(A.Get(SERVER_VERSION) == 20);
   1693 
   1694     Entry B(&trans, GET_BY_ID, ids_.FromNumber(2));
   1695     ASSERT_TRUE(B.good());
   1696     EXPECT_TRUE(B.Get(IS_UNSYNCED) == false);
   1697     EXPECT_TRUE(B.Get(IS_UNAPPLIED_UPDATE) == false);
   1698     EXPECT_TRUE(B.Get(SERVER_VERSION) == 20);
   1699   }
   1700 }
   1701 
   1702 TEST_F(SyncerTest, ConflictMatchingEntryHandlesNormalNames) {
   1703   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1704   CHECK(dir.good());
   1705   mock_server_->AddUpdateDirectory(1, 0, "A", 10, 10);
   1706   mock_server_->AddUpdateDirectory(2, 0, "B", 10, 10);
   1707   mock_server_->set_conflict_all_commits(true);
   1708   SyncShareAsDelegate();
   1709   {
   1710     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1711 
   1712     MutableEntry A(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   1713     ASSERT_TRUE(A.good());
   1714     A.Put(IS_UNSYNCED, true);
   1715     A.Put(IS_UNAPPLIED_UPDATE, true);
   1716     A.Put(SERVER_VERSION, 20);
   1717 
   1718     MutableEntry B(&wtrans, GET_BY_ID, ids_.FromNumber(2));
   1719     ASSERT_TRUE(B.good());
   1720     B.Put(IS_UNAPPLIED_UPDATE, true);
   1721     B.Put(SERVER_VERSION, 20);
   1722   }
   1723   LoopSyncShare();
   1724   saw_syncer_event_ = false;
   1725   mock_server_->set_conflict_all_commits(false);
   1726 
   1727   {
   1728     ReadTransaction trans(dir, __FILE__, __LINE__);
   1729 
   1730     Entry A(&trans, GET_BY_ID, ids_.FromNumber(1));
   1731     ASSERT_TRUE(A.good());
   1732     EXPECT_TRUE(A.Get(IS_UNSYNCED) == false);
   1733     EXPECT_TRUE(A.Get(IS_UNAPPLIED_UPDATE) == false);
   1734     EXPECT_TRUE(A.Get(SERVER_VERSION) == 20);
   1735 
   1736     Entry B(&trans, GET_BY_ID, ids_.FromNumber(2));
   1737     ASSERT_TRUE(B.good());
   1738     EXPECT_TRUE(B.Get(IS_UNSYNCED) == false);
   1739     EXPECT_TRUE(B.Get(IS_UNAPPLIED_UPDATE) == false);
   1740     EXPECT_TRUE(B.Get(SERVER_VERSION) == 20);
   1741   }
   1742 }
   1743 
   1744 TEST_F(SyncerTest, ReverseFolderOrderingTest) {
   1745   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1746   ASSERT_TRUE(dir.good());
   1747   mock_server_->AddUpdateDirectory(4, 3, "ggchild", 10, 10);
   1748   mock_server_->AddUpdateDirectory(3, 2, "gchild", 10, 10);
   1749   mock_server_->AddUpdateDirectory(5, 4, "gggchild", 10, 10);
   1750   mock_server_->AddUpdateDirectory(2, 1, "child", 10, 10);
   1751   mock_server_->AddUpdateDirectory(1, 0, "parent", 10, 10);
   1752   LoopSyncShare();
   1753   ReadTransaction trans(dir, __FILE__, __LINE__);
   1754 
   1755   Id child_id = GetOnlyEntryWithName(
   1756         &trans, ids_.FromNumber(4), "gggchild");
   1757   Entry child(&trans, GET_BY_ID, child_id);
   1758   ASSERT_TRUE(child.good());
   1759 }
   1760 
   1761 class EntryCreatedInNewFolderTest : public SyncerTest {
   1762  public:
   1763   void CreateFolderInBob() {
   1764     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1765     CHECK(dir.good());
   1766 
   1767     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1768     MutableEntry bob(&trans,
   1769                      syncable::GET_BY_ID,
   1770                      GetOnlyEntryWithName(&trans,
   1771                                           TestIdFactory::root(),
   1772                                           "bob"));
   1773     CHECK(bob.good());
   1774 
   1775     MutableEntry entry2(&trans, syncable::CREATE, bob.Get(syncable::ID),
   1776                         "bob");
   1777     CHECK(entry2.good());
   1778     entry2.Put(syncable::IS_DIR, true);
   1779     entry2.Put(syncable::IS_UNSYNCED, true);
   1780     entry2.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1781   }
   1782 };
   1783 
   1784 TEST_F(EntryCreatedInNewFolderTest, EntryCreatedInNewFolderMidSync) {
   1785   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1786   ASSERT_TRUE(dir.good());
   1787   dir->set_store_birthday(mock_server_->store_birthday());
   1788   {
   1789     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1790     MutableEntry entry(&trans, syncable::CREATE, trans.root_id(),
   1791                        "bob");
   1792     ASSERT_TRUE(entry.good());
   1793     entry.Put(syncable::IS_DIR, true);
   1794     entry.Put(syncable::IS_UNSYNCED, true);
   1795     entry.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1796   }
   1797 
   1798   mock_server_->SetMidCommitCallback(
   1799       NewCallback<EntryCreatedInNewFolderTest>(this,
   1800           &EntryCreatedInNewFolderTest::CreateFolderInBob));
   1801   syncer_->SyncShare(session_.get(), BUILD_COMMIT_REQUEST, SYNCER_END);
   1802   EXPECT_TRUE(1 == mock_server_->committed_ids().size());
   1803   {
   1804     ReadTransaction trans(dir, __FILE__, __LINE__);
   1805     Entry parent_entry(&trans, syncable::GET_BY_ID,
   1806         GetOnlyEntryWithName(&trans, TestIdFactory::root(), "bob"));
   1807     ASSERT_TRUE(parent_entry.good());
   1808 
   1809     Id child_id =
   1810         GetOnlyEntryWithName(&trans, parent_entry.Get(ID), "bob");
   1811     Entry child(&trans, syncable::GET_BY_ID, child_id);
   1812     ASSERT_TRUE(child.good());
   1813     EXPECT_EQ(parent_entry.Get(ID), child.Get(PARENT_ID));
   1814 }
   1815 }
   1816 
   1817 TEST_F(SyncerTest, NegativeIDInUpdate) {
   1818   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1819   CHECK(dir.good());
   1820   mock_server_->AddUpdateBookmark(-10, 0, "bad", 40, 40);
   1821   SyncShareAsDelegate();
   1822   // The negative id would make us CHECK!
   1823 }
   1824 
   1825 TEST_F(SyncerTest, UnappliedUpdateOnCreatedItemItemDoesNotCrash) {
   1826   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1827   CHECK(dir.good());
   1828 
   1829   int64 metahandle_fred;
   1830   {
   1831     // Create an item.
   1832     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1833     MutableEntry fred_match(&trans, CREATE, trans.root_id(),
   1834                             "fred_match");
   1835     ASSERT_TRUE(fred_match.good());
   1836     metahandle_fred = fred_match.Get(META_HANDLE);
   1837     WriteTestDataToEntry(&trans, &fred_match);
   1838   }
   1839   // Commit it.
   1840   SyncShareAsDelegate();
   1841   EXPECT_TRUE(1 == mock_server_->committed_ids().size());
   1842   mock_server_->set_conflict_all_commits(true);
   1843   syncable::Id fred_match_id;
   1844   {
   1845     // Now receive a change from outside.
   1846     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   1847     MutableEntry fred_match(&trans, GET_BY_HANDLE, metahandle_fred);
   1848     ASSERT_TRUE(fred_match.good());
   1849     EXPECT_TRUE(fred_match.Get(ID).ServerKnows());
   1850     fred_match_id = fred_match.Get(ID);
   1851     mock_server_->AddUpdateBookmark(fred_match_id, trans.root_id(),
   1852         "fred_match", 40, 40);
   1853   }
   1854   // Run the syncer.
   1855   for (int i = 0 ; i < 30 ; ++i) {
   1856     SyncShareAsDelegate();
   1857   }
   1858 }
   1859 
   1860 /**
   1861  * In the event that we have a double changed entry, that is changed on both
   1862  * the client and the server, the conflict resolver should just drop one of
   1863  * them and accept the other.
   1864  */
   1865 
   1866 TEST_F(SyncerTest, DoublyChangedWithResolver) {
   1867   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1868   CHECK(dir.good());
   1869   {
   1870     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1871     MutableEntry parent(&wtrans, syncable::CREATE, root_id_, "Folder");
   1872     ASSERT_TRUE(parent.good());
   1873     parent.Put(syncable::IS_DIR, true);
   1874     parent.Put(syncable::ID, parent_id_);
   1875     parent.Put(syncable::BASE_VERSION, 5);
   1876     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1877     MutableEntry child(&wtrans, syncable::CREATE, parent_id_, "Pete.htm");
   1878     ASSERT_TRUE(child.good());
   1879     child.Put(syncable::ID, child_id_);
   1880     child.Put(syncable::BASE_VERSION, 10);
   1881     WriteTestDataToEntry(&wtrans, &child);
   1882   }
   1883   mock_server_->AddUpdateBookmark(child_id_, parent_id_, "Pete2.htm", 11, 10);
   1884   mock_server_->set_conflict_all_commits(true);
   1885   LoopSyncShare();
   1886   syncable::Directory::ChildHandles children;
   1887   {
   1888     ReadTransaction trans(dir, __FILE__, __LINE__);
   1889     dir->GetChildHandles(&trans, parent_id_, &children);
   1890     // We expect the conflict resolver to preserve the local entry.
   1891     Entry child(&trans, syncable::GET_BY_ID, child_id_);
   1892     ASSERT_TRUE(child.good());
   1893     EXPECT_TRUE(child.Get(syncable::IS_UNSYNCED));
   1894     EXPECT_FALSE(child.Get(syncable::IS_UNAPPLIED_UPDATE));
   1895     EXPECT_TRUE(child.Get(SPECIFICS).HasExtension(sync_pb::bookmark));
   1896     EXPECT_EQ("Pete.htm", child.Get(NON_UNIQUE_NAME));
   1897     VerifyTestBookmarkDataInEntry(&child);
   1898   }
   1899 
   1900   // Only one entry, since we just overwrite one.
   1901   EXPECT_TRUE(1 == children.size());
   1902   saw_syncer_event_ = false;
   1903 }
   1904 
   1905 // We got this repro case when someone was editing bookmarks while sync was
   1906 // occuring. The entry had changed out underneath the user.
   1907 TEST_F(SyncerTest, CommitsUpdateDoesntAlterEntry) {
   1908   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1909   CHECK(dir.good());
   1910   int64 test_time = 123456;
   1911   int64 entry_metahandle;
   1912   {
   1913     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1914     MutableEntry entry(&wtrans, syncable::CREATE, root_id_, "Pete");
   1915     ASSERT_TRUE(entry.good());
   1916     EXPECT_FALSE(entry.Get(ID).ServerKnows());
   1917     entry.Put(syncable::IS_DIR, true);
   1918     entry.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   1919     entry.Put(syncable::IS_UNSYNCED, true);
   1920     entry.Put(syncable::MTIME, test_time);
   1921     entry_metahandle = entry.Get(META_HANDLE);
   1922   }
   1923   SyncShareAsDelegate();
   1924   syncable::Id id;
   1925   int64 version;
   1926   int64 server_position_in_parent;
   1927   {
   1928     ReadTransaction trans(dir, __FILE__, __LINE__);
   1929     Entry entry(&trans, syncable::GET_BY_HANDLE, entry_metahandle);
   1930     ASSERT_TRUE(entry.good());
   1931     id = entry.Get(ID);
   1932     EXPECT_TRUE(id.ServerKnows());
   1933     version = entry.Get(BASE_VERSION);
   1934     server_position_in_parent = entry.Get(SERVER_POSITION_IN_PARENT);
   1935   }
   1936   sync_pb::SyncEntity* update = mock_server_->AddUpdateFromLastCommit();
   1937   EXPECT_EQ("Pete", update->name());
   1938   EXPECT_EQ(id.GetServerId(), update->id_string());
   1939   EXPECT_EQ(root_id_.GetServerId(), update->parent_id_string());
   1940   EXPECT_EQ(version, update->version());
   1941   EXPECT_EQ(server_position_in_parent, update->position_in_parent());
   1942   SyncShareAsDelegate();
   1943   {
   1944     ReadTransaction trans(dir, __FILE__, __LINE__);
   1945     Entry entry(&trans, syncable::GET_BY_ID, id);
   1946     ASSERT_TRUE(entry.good());
   1947     EXPECT_TRUE(entry.Get(MTIME) == test_time);
   1948   }
   1949 }
   1950 
   1951 TEST_F(SyncerTest, ParentAndChildBothMatch) {
   1952   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1953   CHECK(dir.good());
   1954   syncable::Id parent_id = ids_.NewServerId();
   1955   syncable::Id child_id = ids_.NewServerId();
   1956 
   1957   {
   1958     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   1959     MutableEntry parent(&wtrans, CREATE, root_id_, "Folder");
   1960     ASSERT_TRUE(parent.good());
   1961     parent.Put(IS_DIR, true);
   1962     parent.Put(IS_UNSYNCED, true);
   1963     parent.Put(ID, parent_id);
   1964     parent.Put(BASE_VERSION, 1);
   1965     parent.Put(SPECIFICS, DefaultBookmarkSpecifics());
   1966 
   1967     MutableEntry child(&wtrans, CREATE, parent.Get(ID), "test.htm");
   1968     ASSERT_TRUE(child.good());
   1969     child.Put(ID, child_id);
   1970     child.Put(BASE_VERSION, 1);
   1971     child.Put(SPECIFICS, DefaultBookmarkSpecifics());
   1972     WriteTestDataToEntry(&wtrans, &child);
   1973   }
   1974   mock_server_->AddUpdateDirectory(parent_id, root_id_, "Folder", 10, 10);
   1975   mock_server_->AddUpdateBookmark(child_id, parent_id, "test.htm", 10, 10);
   1976   mock_server_->set_conflict_all_commits(true);
   1977   SyncShareAsDelegate();
   1978   SyncShareAsDelegate();
   1979   SyncShareAsDelegate();
   1980   {
   1981     ReadTransaction trans(dir, __FILE__, __LINE__);
   1982     Directory::ChildHandles children;
   1983     dir->GetChildHandles(&trans, root_id_, &children);
   1984     EXPECT_TRUE(1 == children.size());
   1985     dir->GetChildHandles(&trans, parent_id, &children);
   1986     EXPECT_TRUE(1 == children.size());
   1987     Directory::UnappliedUpdateMetaHandles unapplied;
   1988     dir->GetUnappliedUpdateMetaHandles(&trans, &unapplied);
   1989     EXPECT_TRUE(0 == unapplied.size());
   1990     syncable::Directory::UnsyncedMetaHandles unsynced;
   1991     dir->GetUnsyncedMetaHandles(&trans, &unsynced);
   1992     EXPECT_TRUE(0 == unsynced.size());
   1993     saw_syncer_event_ = false;
   1994   }
   1995 }
   1996 
   1997 TEST_F(SyncerTest, CommittingNewDeleted) {
   1998   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   1999   CHECK(dir.good());
   2000   {
   2001     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2002     MutableEntry entry(&trans, CREATE, trans.root_id(), "bob");
   2003     entry.Put(IS_UNSYNCED, true);
   2004     entry.Put(IS_DEL, true);
   2005   }
   2006   SyncShareAsDelegate();
   2007   EXPECT_TRUE(0 == mock_server_->committed_ids().size());
   2008 }
   2009 
   2010 // Original problem synopsis:
   2011 // Check failed: entry->Get(BASE_VERSION) <= entry->Get(SERVER_VERSION)
   2012 // Client creates entry, client finishes committing entry. Between
   2013 // commit and getting update back, we delete the entry.
   2014 // We get the update for the entry, but the local one was modified
   2015 // so we store the entry but don't apply it. IS_UNAPPLIED_UPDATE is set.
   2016 // We commit deletion and get a new version number.
   2017 // We apply unapplied updates again before we get the update about the deletion.
   2018 // This means we have an unapplied update where server_version < base_version.
   2019 TEST_F(SyncerTest, UnappliedUpdateDuringCommit) {
   2020   // This test is a little fake.
   2021   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2022   CHECK(dir.good());
   2023   {
   2024     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2025     MutableEntry entry(&trans, CREATE, trans.root_id(), "bob");
   2026     entry.Put(ID, ids_.FromNumber(20));
   2027     entry.Put(BASE_VERSION, 1);
   2028     entry.Put(SERVER_VERSION, 1);
   2029     entry.Put(SERVER_PARENT_ID, ids_.FromNumber(9999));  // Bad parent.
   2030     entry.Put(IS_UNSYNCED, true);
   2031     entry.Put(IS_UNAPPLIED_UPDATE, true);
   2032     entry.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2033     entry.Put(SERVER_SPECIFICS, DefaultBookmarkSpecifics());
   2034     entry.Put(IS_DEL, false);
   2035   }
   2036   syncer_->SyncShare(session_.get());
   2037   syncer_->SyncShare(session_.get());
   2038   EXPECT_TRUE(0 == session_->status_controller()->TotalNumConflictingItems());
   2039   saw_syncer_event_ = false;
   2040 }
   2041 
   2042 // Original problem synopsis:
   2043 //   Illegal parent
   2044 // Unexpected error during sync if we:
   2045 //   make a new folder bob
   2046 //   wait for sync
   2047 //   make a new folder fred
   2048 //   move bob into fred
   2049 //   remove bob
   2050 //   remove fred
   2051 // if no syncing occured midway, bob will have an illegal parent
   2052 TEST_F(SyncerTest, DeletingEntryInFolder) {
   2053   // This test is a little fake.
   2054   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2055   CHECK(dir.good());
   2056 
   2057   int64 existing_metahandle;
   2058   {
   2059     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2060     MutableEntry entry(&trans, CREATE, trans.root_id(), "existing");
   2061     ASSERT_TRUE(entry.good());
   2062     entry.Put(IS_DIR, true);
   2063     entry.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2064     entry.Put(IS_UNSYNCED, true);
   2065     existing_metahandle = entry.Get(META_HANDLE);
   2066   }
   2067   syncer_->SyncShare(session_.get());
   2068   {
   2069     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2070     MutableEntry newfolder(&trans, CREATE, trans.root_id(), "new");
   2071     ASSERT_TRUE(newfolder.good());
   2072     newfolder.Put(IS_DIR, true);
   2073     newfolder.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2074     newfolder.Put(IS_UNSYNCED, true);
   2075 
   2076     MutableEntry existing(&trans, GET_BY_HANDLE, existing_metahandle);
   2077     ASSERT_TRUE(existing.good());
   2078     existing.Put(PARENT_ID, newfolder.Get(ID));
   2079     existing.Put(IS_UNSYNCED, true);
   2080     EXPECT_TRUE(existing.Get(ID).ServerKnows());
   2081 
   2082     newfolder.Put(IS_DEL, true);
   2083     existing.Put(IS_DEL, true);
   2084   }
   2085   syncer_->SyncShare(session_.get());
   2086   StatusController* status(session_->status_controller());
   2087   EXPECT_TRUE(0 == status->error_counters().num_conflicting_commits);
   2088 }
   2089 
   2090 TEST_F(SyncerTest, DeletingEntryWithLocalEdits) {
   2091   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2092   CHECK(dir.good());
   2093   int64 newfolder_metahandle;
   2094 
   2095   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2096   SyncShareAsDelegate();
   2097   {
   2098     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2099     MutableEntry newfolder(&trans, CREATE, ids_.FromNumber(1), "local");
   2100     ASSERT_TRUE(newfolder.good());
   2101     newfolder.Put(IS_UNSYNCED, true);
   2102     newfolder.Put(IS_DIR, true);
   2103     newfolder.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2104     newfolder_metahandle = newfolder.Get(META_HANDLE);
   2105   }
   2106   mock_server_->AddUpdateDirectory(1, 0, "bob", 2, 20);
   2107   mock_server_->SetLastUpdateDeleted();
   2108   syncer_->SyncShare(session_.get(), SYNCER_BEGIN, APPLY_UPDATES);
   2109   {
   2110     ReadTransaction trans(dir, __FILE__, __LINE__);
   2111     Entry entry(&trans, syncable::GET_BY_HANDLE, newfolder_metahandle);
   2112     ASSERT_TRUE(entry.good());
   2113   }
   2114 }
   2115 
   2116 TEST_F(SyncerTest, FolderSwapUpdate) {
   2117   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2118   CHECK(dir.good());
   2119   mock_server_->AddUpdateDirectory(7801, 0, "bob", 1, 10);
   2120   mock_server_->AddUpdateDirectory(1024, 0, "fred", 1, 10);
   2121   SyncShareAsDelegate();
   2122   mock_server_->AddUpdateDirectory(1024, 0, "bob", 2, 20);
   2123   mock_server_->AddUpdateDirectory(7801, 0, "fred", 2, 20);
   2124   SyncShareAsDelegate();
   2125   {
   2126     ReadTransaction trans(dir, __FILE__, __LINE__);
   2127     Entry id1(&trans, GET_BY_ID, ids_.FromNumber(7801));
   2128     ASSERT_TRUE(id1.good());
   2129     EXPECT_TRUE("fred" == id1.Get(NON_UNIQUE_NAME));
   2130     EXPECT_TRUE(root_id_ == id1.Get(PARENT_ID));
   2131     Entry id2(&trans, GET_BY_ID, ids_.FromNumber(1024));
   2132     ASSERT_TRUE(id2.good());
   2133     EXPECT_TRUE("bob" == id2.Get(NON_UNIQUE_NAME));
   2134     EXPECT_TRUE(root_id_ == id2.Get(PARENT_ID));
   2135   }
   2136   saw_syncer_event_ = false;
   2137 }
   2138 
   2139 TEST_F(SyncerTest, NameCollidingFolderSwapWorksFine) {
   2140   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2141   CHECK(dir.good());
   2142   mock_server_->AddUpdateDirectory(7801, 0, "bob", 1, 10);
   2143   mock_server_->AddUpdateDirectory(1024, 0, "fred", 1, 10);
   2144   mock_server_->AddUpdateDirectory(4096, 0, "alice", 1, 10);
   2145   SyncShareAsDelegate();
   2146   {
   2147     ReadTransaction trans(dir, __FILE__, __LINE__);
   2148     Entry id1(&trans, GET_BY_ID, ids_.FromNumber(7801));
   2149     ASSERT_TRUE(id1.good());
   2150     EXPECT_TRUE("bob" == id1.Get(NON_UNIQUE_NAME));
   2151     EXPECT_TRUE(root_id_ == id1.Get(PARENT_ID));
   2152     Entry id2(&trans, GET_BY_ID, ids_.FromNumber(1024));
   2153     ASSERT_TRUE(id2.good());
   2154     EXPECT_TRUE("fred" == id2.Get(NON_UNIQUE_NAME));
   2155     EXPECT_TRUE(root_id_ == id2.Get(PARENT_ID));
   2156     Entry id3(&trans, GET_BY_ID, ids_.FromNumber(4096));
   2157     ASSERT_TRUE(id3.good());
   2158     EXPECT_TRUE("alice" == id3.Get(NON_UNIQUE_NAME));
   2159     EXPECT_TRUE(root_id_ == id3.Get(PARENT_ID));
   2160   }
   2161   mock_server_->AddUpdateDirectory(1024, 0, "bob", 2, 20);
   2162   mock_server_->AddUpdateDirectory(7801, 0, "fred", 2, 20);
   2163   mock_server_->AddUpdateDirectory(4096, 0, "bob", 2, 20);
   2164   SyncShareAsDelegate();
   2165   {
   2166     ReadTransaction trans(dir, __FILE__, __LINE__);
   2167     Entry id1(&trans, GET_BY_ID, ids_.FromNumber(7801));
   2168     ASSERT_TRUE(id1.good());
   2169     EXPECT_TRUE("fred" == id1.Get(NON_UNIQUE_NAME));
   2170     EXPECT_TRUE(root_id_ == id1.Get(PARENT_ID));
   2171     Entry id2(&trans, GET_BY_ID, ids_.FromNumber(1024));
   2172     ASSERT_TRUE(id2.good());
   2173     EXPECT_TRUE("bob" == id2.Get(NON_UNIQUE_NAME));
   2174     EXPECT_TRUE(root_id_ == id2.Get(PARENT_ID));
   2175     Entry id3(&trans, GET_BY_ID, ids_.FromNumber(4096));
   2176     ASSERT_TRUE(id3.good());
   2177     EXPECT_TRUE("bob" == id3.Get(NON_UNIQUE_NAME));
   2178     EXPECT_TRUE(root_id_ == id3.Get(PARENT_ID));
   2179   }
   2180   saw_syncer_event_ = false;
   2181 }
   2182 
   2183 TEST_F(SyncerTest, CommitManyItemsInOneGo) {
   2184   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2185   uint32 max_batches = 3;
   2186   uint32 items_to_commit = kDefaultMaxCommitBatchSize * max_batches;
   2187   CHECK(dir.good());
   2188   {
   2189     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2190     for (uint32 i = 0; i < items_to_commit; i++) {
   2191       string nameutf8 = StringPrintf("%d", i);
   2192       string name(nameutf8.begin(), nameutf8.end());
   2193       MutableEntry e(&trans, CREATE, trans.root_id(), name);
   2194       e.Put(IS_UNSYNCED, true);
   2195       e.Put(IS_DIR, true);
   2196       e.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2197     }
   2198   }
   2199   uint32 num_loops = 0;
   2200   while (SyncShareAsDelegate()) {
   2201     num_loops++;
   2202     ASSERT_LT(num_loops, max_batches * 2);
   2203   }
   2204   EXPECT_GE(mock_server_->commit_messages().size(), max_batches);
   2205 }
   2206 
   2207 TEST_F(SyncerTest, HugeConflict) {
   2208   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2209   int item_count = 300;  // We should be able to do 300 or 3000 w/o issue.
   2210   CHECK(dir.good());
   2211 
   2212   syncable::Id parent_id = ids_.NewServerId();
   2213   syncable::Id last_id = parent_id;
   2214   vector<syncable::Id> tree_ids;
   2215 
   2216   // Create a lot of updates for which the parent does not exist yet.
   2217   // Generate a huge deep tree which should all fail to apply at first.
   2218   {
   2219     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2220     for (int i = 0; i < item_count ; i++) {
   2221       syncable::Id next_id = ids_.NewServerId();
   2222       tree_ids.push_back(next_id);
   2223       mock_server_->AddUpdateDirectory(next_id, last_id, "BOB", 2, 20);
   2224       last_id = next_id;
   2225     }
   2226   }
   2227   SyncShareAsDelegate();
   2228 
   2229   // Check they're in the expected conflict state.
   2230   {
   2231     ReadTransaction trans(dir, __FILE__, __LINE__);
   2232     for (int i = 0; i < item_count; i++) {
   2233       Entry e(&trans, GET_BY_ID, tree_ids[i]);
   2234       // They should all exist but none should be applied.
   2235       ASSERT_TRUE(e.good());
   2236       EXPECT_TRUE(e.Get(IS_DEL));
   2237       EXPECT_TRUE(e.Get(IS_UNAPPLIED_UPDATE));
   2238     }
   2239   }
   2240 
   2241   // Add the missing parent directory.
   2242   mock_server_->AddUpdateDirectory(parent_id, TestIdFactory::root(),
   2243       "BOB", 2, 20);
   2244   SyncShareAsDelegate();
   2245 
   2246   // Now they should all be OK.
   2247   {
   2248     ReadTransaction trans(dir, __FILE__, __LINE__);
   2249     for (int i = 0; i < item_count; i++) {
   2250       Entry e(&trans, GET_BY_ID, tree_ids[i]);
   2251       ASSERT_TRUE(e.good());
   2252       EXPECT_FALSE(e.Get(IS_DEL));
   2253       EXPECT_FALSE(e.Get(IS_UNAPPLIED_UPDATE));
   2254     }
   2255   }
   2256 }
   2257 
   2258 TEST_F(SyncerTest, DontCrashOnCaseChange) {
   2259   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2260   CHECK(dir.good());
   2261   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2262   SyncShareAsDelegate();
   2263   {
   2264     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2265     MutableEntry e(&trans, GET_BY_ID, ids_.FromNumber(1));
   2266     ASSERT_TRUE(e.good());
   2267     e.Put(IS_UNSYNCED, true);
   2268   }
   2269   mock_server_->set_conflict_all_commits(true);
   2270   mock_server_->AddUpdateDirectory(1, 0, "BOB", 2, 20);
   2271   SyncShareAsDelegate();  // USED TO CAUSE AN ASSERT
   2272   saw_syncer_event_ = false;
   2273 }
   2274 
   2275 TEST_F(SyncerTest, UnsyncedItemAndUpdate) {
   2276   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2277   CHECK(dir.good());
   2278   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2279   SyncShareAsDelegate();
   2280   mock_server_->set_conflict_all_commits(true);
   2281   mock_server_->AddUpdateDirectory(2, 0, "bob", 2, 20);
   2282   SyncShareAsDelegate();  // USED TO CAUSE AN ASSERT
   2283   saw_syncer_event_ = false;
   2284 }
   2285 
   2286 TEST_F(SyncerTest, NewEntryAndAlteredServerEntrySharePath) {
   2287   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2288   CHECK(dir.good());
   2289   mock_server_->AddUpdateBookmark(1, 0, "Foo.htm", 10, 10);
   2290   SyncShareAsDelegate();
   2291   int64 local_folder_handle;
   2292   syncable::Id local_folder_id;
   2293   {
   2294     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2295     MutableEntry new_entry(&wtrans, CREATE, wtrans.root_id(), "Bar.htm");
   2296     ASSERT_TRUE(new_entry.good());
   2297     local_folder_id = new_entry.Get(ID);
   2298     local_folder_handle = new_entry.Get(META_HANDLE);
   2299     new_entry.Put(IS_UNSYNCED, true);
   2300     new_entry.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2301     MutableEntry old(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2302     ASSERT_TRUE(old.good());
   2303     WriteTestDataToEntry(&wtrans, &old);
   2304   }
   2305   mock_server_->AddUpdateBookmark(1, 0, "Bar.htm", 20, 20);
   2306   mock_server_->set_conflict_all_commits(true);
   2307   SyncShareAsDelegate();
   2308   saw_syncer_event_ = false;
   2309   {
   2310     // Update #20 should have been dropped in favor of the local version.
   2311     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2312     MutableEntry server(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2313     MutableEntry local(&wtrans, GET_BY_HANDLE, local_folder_handle);
   2314     ASSERT_TRUE(server.good());
   2315     ASSERT_TRUE(local.good());
   2316     EXPECT_TRUE(local.Get(META_HANDLE) != server.Get(META_HANDLE));
   2317     EXPECT_FALSE(server.Get(IS_UNAPPLIED_UPDATE));
   2318     EXPECT_FALSE(local.Get(IS_UNAPPLIED_UPDATE));
   2319     EXPECT_TRUE(server.Get(IS_UNSYNCED));
   2320     EXPECT_TRUE(local.Get(IS_UNSYNCED));
   2321     EXPECT_EQ("Foo.htm", server.Get(NON_UNIQUE_NAME));
   2322     EXPECT_EQ("Bar.htm", local.Get(NON_UNIQUE_NAME));
   2323   }
   2324   // Allow local changes to commit.
   2325   mock_server_->set_conflict_all_commits(false);
   2326   SyncShareAsDelegate();
   2327   saw_syncer_event_ = false;
   2328 
   2329   // Now add a server change to make the two names equal.  There should
   2330   // be no conflict with that, since names are not unique.
   2331   mock_server_->AddUpdateBookmark(1, 0, "Bar.htm", 30, 30);
   2332   SyncShareAsDelegate();
   2333   saw_syncer_event_ = false;
   2334   {
   2335     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2336     MutableEntry server(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2337     MutableEntry local(&wtrans, GET_BY_HANDLE, local_folder_handle);
   2338     ASSERT_TRUE(server.good());
   2339     ASSERT_TRUE(local.good());
   2340     EXPECT_TRUE(local.Get(META_HANDLE) != server.Get(META_HANDLE));
   2341     EXPECT_FALSE(server.Get(IS_UNAPPLIED_UPDATE));
   2342     EXPECT_FALSE(local.Get(IS_UNAPPLIED_UPDATE));
   2343     EXPECT_FALSE(server.Get(IS_UNSYNCED));
   2344     EXPECT_FALSE(local.Get(IS_UNSYNCED));
   2345     EXPECT_EQ("Bar.htm", server.Get(NON_UNIQUE_NAME));
   2346     EXPECT_EQ("Bar.htm", local.Get(NON_UNIQUE_NAME));
   2347     EXPECT_EQ("http://google.com",  // Default from AddUpdateBookmark.
   2348         server.Get(SPECIFICS).GetExtension(sync_pb::bookmark).url());
   2349   }
   2350 }
   2351 
   2352 // Same as NewEntryAnddServerEntrySharePath, but using the old-style protocol.
   2353 TEST_F(SyncerTest, NewEntryAndAlteredServerEntrySharePath_OldBookmarksProto) {
   2354   mock_server_->set_use_legacy_bookmarks_protocol(true);
   2355   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2356   CHECK(dir.good());
   2357   mock_server_->AddUpdateBookmark(1, 0, "Foo.htm", 10, 10);
   2358   SyncShareAsDelegate();
   2359   int64 local_folder_handle;
   2360   syncable::Id local_folder_id;
   2361   {
   2362     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2363     MutableEntry new_entry(&wtrans, CREATE, wtrans.root_id(), "Bar.htm");
   2364     ASSERT_TRUE(new_entry.good());
   2365     local_folder_id = new_entry.Get(ID);
   2366     local_folder_handle = new_entry.Get(META_HANDLE);
   2367     new_entry.Put(IS_UNSYNCED, true);
   2368     new_entry.Put(SPECIFICS, DefaultBookmarkSpecifics());
   2369     MutableEntry old(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2370     ASSERT_TRUE(old.good());
   2371     WriteTestDataToEntry(&wtrans, &old);
   2372   }
   2373   mock_server_->AddUpdateBookmark(1, 0, "Bar.htm", 20, 20);
   2374   mock_server_->set_conflict_all_commits(true);
   2375   SyncShareAsDelegate();
   2376   saw_syncer_event_ = false;
   2377   {
   2378     // Update #20 should have been dropped in favor of the local version.
   2379     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2380     MutableEntry server(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2381     MutableEntry local(&wtrans, GET_BY_HANDLE, local_folder_handle);
   2382     ASSERT_TRUE(server.good());
   2383     ASSERT_TRUE(local.good());
   2384     EXPECT_TRUE(local.Get(META_HANDLE) != server.Get(META_HANDLE));
   2385     EXPECT_FALSE(server.Get(IS_UNAPPLIED_UPDATE));
   2386     EXPECT_FALSE(local.Get(IS_UNAPPLIED_UPDATE));
   2387     EXPECT_TRUE(server.Get(IS_UNSYNCED));
   2388     EXPECT_TRUE(local.Get(IS_UNSYNCED));
   2389     EXPECT_EQ("Foo.htm", server.Get(NON_UNIQUE_NAME));
   2390     EXPECT_EQ("Bar.htm", local.Get(NON_UNIQUE_NAME));
   2391   }
   2392   // Allow local changes to commit.
   2393   mock_server_->set_conflict_all_commits(false);
   2394   SyncShareAsDelegate();
   2395   saw_syncer_event_ = false;
   2396 
   2397   // Now add a server change to make the two names equal.  There should
   2398   // be no conflict with that, since names are not unique.
   2399   mock_server_->AddUpdateBookmark(1, 0, "Bar.htm", 30, 30);
   2400   SyncShareAsDelegate();
   2401   saw_syncer_event_ = false;
   2402   {
   2403     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2404     MutableEntry server(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2405     MutableEntry local(&wtrans, GET_BY_HANDLE, local_folder_handle);
   2406     ASSERT_TRUE(server.good());
   2407     ASSERT_TRUE(local.good());
   2408     EXPECT_TRUE(local.Get(META_HANDLE) != server.Get(META_HANDLE));
   2409     EXPECT_FALSE(server.Get(IS_UNAPPLIED_UPDATE));
   2410     EXPECT_FALSE(local.Get(IS_UNAPPLIED_UPDATE));
   2411     EXPECT_FALSE(server.Get(IS_UNSYNCED));
   2412     EXPECT_FALSE(local.Get(IS_UNSYNCED));
   2413     EXPECT_EQ("Bar.htm", server.Get(NON_UNIQUE_NAME));
   2414     EXPECT_EQ("Bar.htm", local.Get(NON_UNIQUE_NAME));
   2415     EXPECT_EQ("http://google.com",  // Default from AddUpdateBookmark.
   2416         server.Get(SPECIFICS).GetExtension(sync_pb::bookmark).url());
   2417   }
   2418 }
   2419 
   2420 
   2421 // Circular links should be resolved by the server.
   2422 TEST_F(SyncerTest, SiblingDirectoriesBecomeCircular) {
   2423   // we don't currently resolve this. This test ensures we don't.
   2424   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2425   CHECK(dir.good());
   2426   mock_server_->AddUpdateDirectory(1, 0, "A", 10, 10);
   2427   mock_server_->AddUpdateDirectory(2, 0, "B", 10, 10);
   2428   SyncShareAsDelegate();
   2429   {
   2430     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2431     MutableEntry A(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2432     ASSERT_TRUE(A.good());
   2433     A.Put(IS_UNSYNCED, true);
   2434     ASSERT_TRUE(A.Put(PARENT_ID, ids_.FromNumber(2)));
   2435     ASSERT_TRUE(A.Put(NON_UNIQUE_NAME, "B"));
   2436   }
   2437   mock_server_->AddUpdateDirectory(2, 1, "A", 20, 20);
   2438   mock_server_->set_conflict_all_commits(true);
   2439   SyncShareAsDelegate();
   2440   saw_syncer_event_ = false;
   2441   {
   2442     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2443     MutableEntry A(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2444     ASSERT_TRUE(A.good());
   2445     MutableEntry B(&wtrans, GET_BY_ID, ids_.FromNumber(2));
   2446     ASSERT_TRUE(B.good());
   2447     EXPECT_TRUE(A.Get(NON_UNIQUE_NAME) == "B");
   2448     EXPECT_TRUE(B.Get(NON_UNIQUE_NAME) == "B");
   2449   }
   2450 }
   2451 
   2452 TEST_F(SyncerTest, ConflictSetClassificationError) {
   2453   // This code used to cause a CHECK failure because we incorrectly thought
   2454   // a set was only unapplied updates.
   2455   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2456   CHECK(dir.good());
   2457   mock_server_->AddUpdateDirectory(1, 0, "A", 10, 10);
   2458   mock_server_->AddUpdateDirectory(2, 0, "B", 10, 10);
   2459   mock_server_->set_conflict_all_commits(true);
   2460   SyncShareAsDelegate();
   2461   {
   2462     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2463     MutableEntry A(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2464     ASSERT_TRUE(A.good());
   2465     A.Put(IS_UNSYNCED, true);
   2466     A.Put(IS_UNAPPLIED_UPDATE, true);
   2467     A.Put(SERVER_NON_UNIQUE_NAME, "B");
   2468     MutableEntry B(&wtrans, GET_BY_ID, ids_.FromNumber(2));
   2469     ASSERT_TRUE(B.good());
   2470     B.Put(IS_UNAPPLIED_UPDATE, true);
   2471     B.Put(SERVER_NON_UNIQUE_NAME, "A");
   2472   }
   2473   SyncShareAsDelegate();
   2474   saw_syncer_event_ = false;
   2475 }
   2476 
   2477 TEST_F(SyncerTest, SwapEntryNames) {
   2478   // Simple transaction test.
   2479   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2480   CHECK(dir.good());
   2481   mock_server_->AddUpdateDirectory(1, 0, "A", 10, 10);
   2482   mock_server_->AddUpdateDirectory(2, 0, "B", 10, 10);
   2483   mock_server_->set_conflict_all_commits(true);
   2484   SyncShareAsDelegate();
   2485   {
   2486     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   2487     MutableEntry A(&wtrans, GET_BY_ID, ids_.FromNumber(1));
   2488     ASSERT_TRUE(A.good());
   2489     A.Put(IS_UNSYNCED, true);
   2490     MutableEntry B(&wtrans, GET_BY_ID, ids_.FromNumber(2));
   2491     ASSERT_TRUE(B.good());
   2492     B.Put(IS_UNSYNCED, true);
   2493     ASSERT_TRUE(A.Put(NON_UNIQUE_NAME, "C"));
   2494     ASSERT_TRUE(B.Put(NON_UNIQUE_NAME, "A"));
   2495     ASSERT_TRUE(A.Put(NON_UNIQUE_NAME, "B"));
   2496   }
   2497   SyncShareAsDelegate();
   2498   saw_syncer_event_ = false;
   2499 }
   2500 
   2501 TEST_F(SyncerTest, DualDeletionWithNewItemNameClash) {
   2502   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2503   CHECK(dir.good());
   2504   mock_server_->AddUpdateDirectory(1, 0, "A", 10, 10);
   2505   mock_server_->AddUpdateBookmark(2, 0, "B", 10, 10);
   2506   mock_server_->set_conflict_all_commits(true);
   2507   SyncShareAsDelegate();
   2508   {
   2509     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2510     MutableEntry B(&trans, GET_BY_ID, ids_.FromNumber(2));
   2511     ASSERT_TRUE(B.good());
   2512     WriteTestDataToEntry(&trans, &B);
   2513     B.Put(IS_DEL, true);
   2514   }
   2515   mock_server_->AddUpdateBookmark(2, 0, "A", 11, 11);
   2516   mock_server_->SetLastUpdateDeleted();
   2517   SyncShareAsDelegate();
   2518   {
   2519     ReadTransaction trans(dir, __FILE__, __LINE__);
   2520     Entry B(&trans, GET_BY_ID, ids_.FromNumber(2));
   2521     ASSERT_TRUE(B.good());
   2522     EXPECT_FALSE(B.Get(IS_UNSYNCED));
   2523     EXPECT_FALSE(B.Get(IS_UNAPPLIED_UPDATE));
   2524   }
   2525   saw_syncer_event_ = false;
   2526 }
   2527 
   2528 TEST_F(SyncerTest, FixDirectoryLoopConflict) {
   2529   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2530   CHECK(dir.good());
   2531   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2532   mock_server_->AddUpdateDirectory(2, 0, "fred", 1, 10);
   2533   SyncShareAsDelegate();
   2534   {
   2535     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2536     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2537     ASSERT_TRUE(bob.good());
   2538     bob.Put(IS_UNSYNCED, true);
   2539     bob.Put(PARENT_ID, ids_.FromNumber(2));
   2540   }
   2541   mock_server_->AddUpdateDirectory(2, 1, "fred", 2, 20);
   2542   mock_server_->set_conflict_all_commits(true);
   2543   SyncShareAsDelegate();
   2544   SyncShareAsDelegate();
   2545   {
   2546     ReadTransaction trans(dir, __FILE__, __LINE__);
   2547     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2548     ASSERT_TRUE(bob.good());
   2549     Entry fred(&trans, GET_BY_ID, ids_.FromNumber(2));
   2550     ASSERT_TRUE(fred.good());
   2551     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   2552     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2553     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   2554     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2555   }
   2556   saw_syncer_event_ = false;
   2557 }
   2558 
   2559 TEST_F(SyncerTest, ResolveWeWroteTheyDeleted) {
   2560   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2561   CHECK(dir.good());
   2562 
   2563   int64 bob_metahandle;
   2564 
   2565   mock_server_->AddUpdateBookmark(1, 0, "bob", 1, 10);
   2566   SyncShareAsDelegate();
   2567   {
   2568     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2569     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2570     ASSERT_TRUE(bob.good());
   2571     bob_metahandle = bob.Get(META_HANDLE);
   2572     WriteTestDataToEntry(&trans, &bob);
   2573   }
   2574   mock_server_->AddUpdateBookmark(1, 0, "bob", 2, 10);
   2575   mock_server_->SetLastUpdateDeleted();
   2576   mock_server_->set_conflict_all_commits(true);
   2577   SyncShareAsDelegate();
   2578   SyncShareAsDelegate();
   2579   {
   2580     ReadTransaction trans(dir, __FILE__, __LINE__);
   2581     Entry bob(&trans, GET_BY_HANDLE, bob_metahandle);
   2582     ASSERT_TRUE(bob.good());
   2583     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2584     EXPECT_FALSE(bob.Get(ID).ServerKnows());
   2585     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2586     EXPECT_FALSE(bob.Get(IS_DEL));
   2587   }
   2588   saw_syncer_event_ = false;
   2589 }
   2590 
   2591 TEST_F(SyncerTest, ServerDeletingFolderWeHaveMovedSomethingInto) {
   2592   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2593   CHECK(dir.good());
   2594 
   2595   syncable::Id bob_id = ids_.NewServerId();
   2596   syncable::Id fred_id = ids_.NewServerId();
   2597 
   2598   mock_server_->AddUpdateDirectory(bob_id, TestIdFactory::root(),
   2599       "bob", 1, 10);
   2600   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2601       "fred", 1, 10);
   2602   SyncShareAsDelegate();
   2603   {
   2604     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2605     MutableEntry bob(&trans, GET_BY_ID, bob_id);
   2606     ASSERT_TRUE(bob.good());
   2607     bob.Put(IS_UNSYNCED, true);
   2608     bob.Put(PARENT_ID, fred_id);
   2609   }
   2610   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2611       "fred", 2, 20);
   2612   mock_server_->SetLastUpdateDeleted();
   2613   mock_server_->set_conflict_all_commits(true);
   2614   SyncShareAsDelegate();
   2615   SyncShareAsDelegate();
   2616   {
   2617     ReadTransaction trans(dir, __FILE__, __LINE__);
   2618 
   2619     Entry bob(&trans, GET_BY_ID, bob_id);
   2620     ASSERT_TRUE(bob.good());
   2621     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2622     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2623     EXPECT_TRUE(bob.Get(NON_UNIQUE_NAME) == "bob");
   2624     EXPECT_NE(bob.Get(PARENT_ID), fred_id);
   2625 
   2626     // Entry was deleted and reborn.
   2627     Entry dead_fred(&trans, GET_BY_ID, fred_id);
   2628     EXPECT_FALSE(dead_fred.good());
   2629 
   2630     // Reborn fred
   2631     Entry fred(&trans, GET_BY_ID, bob.Get(PARENT_ID));
   2632     ASSERT_TRUE(fred.good());
   2633     EXPECT_TRUE(fred.Get(PARENT_ID) == trans.root_id());
   2634     EXPECT_EQ("fred", fred.Get(NON_UNIQUE_NAME));
   2635     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   2636     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   2637   }
   2638   saw_syncer_event_ = false;
   2639 }
   2640 
   2641 // TODO(ncarter): This test is bogus, but it actually seems to hit an
   2642 // interesting case the 4th time SyncShare is called.
   2643 // TODO(chron): The fourth time that SyncShare is called it crashes.
   2644 // This seems to be due to a bug in the conflict set building logic.
   2645 // http://crbug.com/46621
   2646 TEST_F(SyncerTest, DISABLED_ServerDeletingFolderWeHaveAnOpenEntryIn) {
   2647   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2648   CHECK(dir.good());
   2649   mock_server_->AddUpdateBookmark(1, 0, "bob", 1, 10);
   2650   mock_server_->AddUpdateDirectory(2, 0, "fred", 1, 10);
   2651   SyncShareAsDelegate();
   2652   {
   2653     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2654     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2655     ASSERT_TRUE(bob.good());
   2656     bob.Put(IS_UNSYNCED, true);
   2657     WriteTestDataToEntry(&trans, &bob);
   2658   }
   2659   SyncShareAsDelegate();
   2660   {
   2661     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2662     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2663     ASSERT_TRUE(bob.good());
   2664     EXPECT_FALSE(bob.Get(IS_UNSYNCED));
   2665     bob.Put(IS_UNSYNCED, true);
   2666     bob.Put(PARENT_ID, ids_.FromNumber(2));
   2667   }
   2668   mock_server_->AddUpdateDirectory(2, 0, "fred", 2, 20);
   2669   mock_server_->SetLastUpdateDeleted();
   2670   mock_server_->set_conflict_all_commits(true);
   2671   saw_syncer_event_ = false;
   2672   // These SyncShares would cause a CHECK because we'd think we were stuck.
   2673   SyncShareAsDelegate();
   2674   SyncShareAsDelegate();
   2675   SyncShareAsDelegate();
   2676   SyncShareAsDelegate();
   2677   SyncShareAsDelegate();
   2678   SyncShareAsDelegate();
   2679   SyncShareAsDelegate();
   2680   SyncShareAsDelegate();
   2681   EXPECT_FALSE(saw_syncer_event_);
   2682   {
   2683     ReadTransaction trans(dir, __FILE__, __LINE__);
   2684     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2685     ASSERT_TRUE(bob.good());
   2686     Id fred_id =
   2687         GetOnlyEntryWithName(&trans, TestIdFactory::root(), "fred");
   2688     Entry fred(&trans, GET_BY_ID, fred_id);
   2689     ASSERT_TRUE(fred.good());
   2690     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   2691     EXPECT_TRUE(fred.Get(IS_UNAPPLIED_UPDATE));
   2692     EXPECT_TRUE(bob.Get(PARENT_ID) == fred.Get(ID));
   2693     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2694   }
   2695   saw_syncer_event_ = false;
   2696 }
   2697 
   2698 TEST_F(SyncerTest, WeMovedSomethingIntoAFolderServerHasDeleted) {
   2699   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2700   CHECK(dir.good());
   2701 
   2702   syncable::Id bob_id = ids_.NewServerId();
   2703   syncable::Id fred_id = ids_.NewServerId();
   2704 
   2705   mock_server_->AddUpdateDirectory(bob_id, TestIdFactory::root(),
   2706       "bob", 1, 10);
   2707   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2708       "fred", 1, 10);
   2709   SyncShareAsDelegate();
   2710   {
   2711     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2712     Entry fred(&trans, GET_BY_ID, fred_id);
   2713     ASSERT_TRUE(fred.good());
   2714 
   2715     MutableEntry bob(&trans, GET_BY_ID, bob_id);
   2716     ASSERT_TRUE(bob.good());
   2717     bob.Put(IS_UNSYNCED, true);
   2718     bob.Put(PARENT_ID, fred_id);
   2719   }
   2720   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2721       "fred", 2, 20);
   2722   mock_server_->SetLastUpdateDeleted();
   2723   mock_server_->set_conflict_all_commits(true);
   2724   SyncShareAsDelegate();
   2725   SyncShareAsDelegate();
   2726   {
   2727     ReadTransaction trans(dir, __FILE__, __LINE__);
   2728     Entry bob(&trans, GET_BY_ID, bob_id);
   2729     ASSERT_TRUE(bob.good());
   2730 
   2731     // Entry was deleted by server. We'll make a new one though with a new ID.
   2732     Entry dead_fred(&trans, GET_BY_ID, fred_id);
   2733     EXPECT_FALSE(dead_fred.good());
   2734 
   2735     // Fred is reborn with a local ID.
   2736     Entry fred(&trans, GET_BY_ID, bob.Get(PARENT_ID));
   2737     EXPECT_EQ("fred", fred.Get(NON_UNIQUE_NAME));
   2738     EXPECT_EQ(TestIdFactory::root(), fred.Get(PARENT_ID));
   2739     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   2740     EXPECT_FALSE(fred.Get(ID).ServerKnows());
   2741 
   2742     // Bob needs to update his parent.
   2743     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2744     EXPECT_TRUE(bob.Get(PARENT_ID) == fred.Get(ID));
   2745     EXPECT_TRUE(fred.Get(PARENT_ID) == root_id_);
   2746     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   2747     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2748   }
   2749   saw_syncer_event_ = false;
   2750 }
   2751 
   2752 class FolderMoveDeleteRenameTest : public SyncerTest {
   2753  public:
   2754   FolderMoveDeleteRenameTest() : done_(false) {}
   2755 
   2756   static const int64 bob_id_number = 1;
   2757   static const int64 fred_id_number = 2;
   2758 
   2759   void MoveBobIntoID2Runner() {
   2760     if (!done_) {
   2761       MoveBobIntoID2();
   2762       done_ = true;
   2763     }
   2764   }
   2765 
   2766  protected:
   2767   void MoveBobIntoID2() {
   2768     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2769     CHECK(dir.good());
   2770 
   2771     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2772     Entry alice(&trans, GET_BY_ID,
   2773                 TestIdFactory::FromNumber(fred_id_number));
   2774     CHECK(alice.good());
   2775     EXPECT_TRUE(!alice.Get(IS_DEL));
   2776     EXPECT_TRUE(alice.Get(SYNCING)) << "Expected to be called mid-commit.";
   2777     MutableEntry bob(&trans, GET_BY_ID,
   2778                      TestIdFactory::FromNumber(bob_id_number));
   2779     CHECK(bob.good());
   2780     bob.Put(IS_UNSYNCED, true);
   2781 
   2782     bob.Put(SYNCING, false);
   2783     bob.Put(PARENT_ID, alice.Get(ID));
   2784   }
   2785 
   2786   bool done_;
   2787 };
   2788 
   2789 TEST_F(FolderMoveDeleteRenameTest,
   2790        WeMovedSomethingIntoAFolderServerHasDeletedAndWeRenamed) {
   2791   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2792   CHECK(dir.good());
   2793 
   2794   const syncable::Id bob_id = TestIdFactory::FromNumber(
   2795       FolderMoveDeleteRenameTest::bob_id_number);
   2796   const syncable::Id fred_id = TestIdFactory::FromNumber(
   2797       FolderMoveDeleteRenameTest::fred_id_number);
   2798 
   2799   mock_server_->AddUpdateDirectory(bob_id, TestIdFactory::root(),
   2800       "bob", 1, 10);
   2801   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2802       "fred", 1, 10);
   2803   SyncShareAsDelegate();
   2804   {
   2805     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2806     MutableEntry fred(&trans, GET_BY_ID, fred_id);
   2807     ASSERT_TRUE(fred.good());
   2808     fred.Put(IS_UNSYNCED, true);
   2809     fred.Put(SYNCING, false);
   2810     fred.Put(NON_UNIQUE_NAME, "Alice");
   2811   }
   2812   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2813       "fred", 2, 20);
   2814   mock_server_->SetLastUpdateDeleted();
   2815   mock_server_->set_conflict_all_commits(true);
   2816   // This test is a little brittle. We want to move the item into the folder
   2817   // such that we think we're dealing with a simple conflict, but in reality
   2818   // it's actually a conflict set.
   2819   mock_server_->SetMidCommitCallback(
   2820       NewCallback<FolderMoveDeleteRenameTest>(this,
   2821           &FolderMoveDeleteRenameTest::MoveBobIntoID2Runner));
   2822   SyncShareAsDelegate();
   2823   SyncShareAsDelegate();
   2824   SyncShareAsDelegate();
   2825   {
   2826     ReadTransaction trans(dir, __FILE__, __LINE__);
   2827     Entry bob(&trans, GET_BY_ID, bob_id);
   2828     ASSERT_TRUE(bob.good());
   2829 
   2830     // Old entry is dead
   2831     Entry dead_fred(&trans, GET_BY_ID, fred_id);
   2832     EXPECT_FALSE(dead_fred.good());
   2833 
   2834     // New ID is created to fill parent folder, named correctly
   2835     Entry alice(&trans, GET_BY_ID, bob.Get(PARENT_ID));
   2836     ASSERT_TRUE(alice.good());
   2837     EXPECT_EQ("Alice", alice.Get(NON_UNIQUE_NAME));
   2838     EXPECT_TRUE(alice.Get(IS_UNSYNCED));
   2839     EXPECT_FALSE(alice.Get(ID).ServerKnows());
   2840     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2841     EXPECT_TRUE(bob.Get(PARENT_ID) == alice.Get(ID));
   2842     EXPECT_TRUE(alice.Get(PARENT_ID) == root_id_);
   2843     EXPECT_FALSE(alice.Get(IS_UNAPPLIED_UPDATE));
   2844     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2845   }
   2846   saw_syncer_event_ = false;
   2847 }
   2848 
   2849 
   2850 TEST_F(SyncerTest,
   2851        WeMovedADirIntoAndCreatedAnEntryInAFolderServerHasDeleted) {
   2852   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2853   CHECK(dir.good());
   2854 
   2855   syncable::Id bob_id = ids_.NewServerId();
   2856   syncable::Id fred_id = ids_.NewServerId();
   2857 
   2858   mock_server_->AddUpdateDirectory(bob_id, TestIdFactory::root(),
   2859       "bob", 1, 10);
   2860   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2861       "fred", 1, 10);
   2862   SyncShareAsDelegate();
   2863   syncable::Id new_item_id;
   2864   {
   2865     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2866     MutableEntry bob(&trans, GET_BY_ID, bob_id);
   2867     ASSERT_TRUE(bob.good());
   2868     bob.Put(IS_UNSYNCED, true);
   2869     bob.Put(PARENT_ID, fred_id);
   2870     MutableEntry new_item(&trans, CREATE, fred_id, "new_item");
   2871     WriteTestDataToEntry(&trans, &new_item);
   2872     new_item_id = new_item.Get(ID);
   2873   }
   2874   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   2875       "fred", 2, 20);
   2876   mock_server_->SetLastUpdateDeleted();
   2877   mock_server_->set_conflict_all_commits(true);
   2878   SyncShareAsDelegate();
   2879   SyncShareAsDelegate();
   2880   {
   2881     ReadTransaction trans(dir, __FILE__, __LINE__);
   2882 
   2883     Entry bob(&trans, GET_BY_ID, bob_id);
   2884     ASSERT_TRUE(bob.good());
   2885     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2886     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2887     EXPECT_NE(bob.Get(PARENT_ID), fred_id);
   2888 
   2889     // Was recreated. Old one shouldn't exist.
   2890     Entry dead_fred(&trans, GET_BY_ID, fred_id);
   2891     EXPECT_FALSE(dead_fred.good());
   2892 
   2893     Entry fred(&trans, GET_BY_ID, bob.Get(PARENT_ID));
   2894     ASSERT_TRUE(fred.good());
   2895     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   2896     EXPECT_FALSE(fred.Get(ID).ServerKnows());
   2897     EXPECT_EQ("fred", fred.Get(NON_UNIQUE_NAME));
   2898     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   2899     EXPECT_TRUE(fred.Get(PARENT_ID) == root_id_);
   2900 
   2901     Entry new_item(&trans, GET_BY_ID, new_item_id);
   2902     ASSERT_TRUE(new_item.good());
   2903     EXPECT_EQ(new_item.Get(PARENT_ID), fred.Get(ID));
   2904   }
   2905   saw_syncer_event_ = false;
   2906 }
   2907 
   2908 TEST_F(SyncerTest, ServerMovedSomethingIntoAFolderWeHaveDeleted) {
   2909   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2910   CHECK(dir.good());
   2911   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2912   mock_server_->AddUpdateDirectory(2, 0, "fred", 1, 10);
   2913   LoopSyncShare();
   2914   {
   2915     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2916     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2917     ASSERT_TRUE(bob.good());
   2918     bob.Put(IS_UNSYNCED, true);
   2919     bob.Put(IS_DEL, true);
   2920   }
   2921   mock_server_->AddUpdateDirectory(2, 1, "fred", 2, 20);
   2922   mock_server_->set_conflict_all_commits(true);
   2923   LoopSyncShare();
   2924   LoopSyncShare();
   2925   {
   2926     ReadTransaction trans(dir, __FILE__, __LINE__);
   2927     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2928     ASSERT_TRUE(bob.good());
   2929     Entry fred(&trans, GET_BY_ID, ids_.FromNumber(2));
   2930     ASSERT_TRUE(fred.good());
   2931     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   2932     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2933     EXPECT_TRUE(fred.Get(PARENT_ID) == bob.Get(ID));
   2934     EXPECT_TRUE(bob.Get(PARENT_ID) == root_id_);
   2935     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   2936     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2937   }
   2938   saw_syncer_event_ = false;
   2939 }
   2940 
   2941 TEST_F(SyncerTest, ServerMovedAFolderIntoAFolderWeHaveDeletedAndMovedIntoIt) {
   2942   // This test combines circular folders and deleted parents.
   2943   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2944   CHECK(dir.good());
   2945   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2946   mock_server_->AddUpdateDirectory(2, 0, "fred", 1, 10);
   2947   SyncShareAsDelegate();
   2948   {
   2949     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2950     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2951     ASSERT_TRUE(bob.good());
   2952     bob.Put(IS_UNSYNCED, true);
   2953     bob.Put(IS_DEL, true);
   2954     bob.Put(PARENT_ID, ids_.FromNumber(2));
   2955   }
   2956   mock_server_->AddUpdateDirectory(2, 1, "fred", 2, 20);
   2957   mock_server_->set_conflict_all_commits(true);
   2958   SyncShareAsDelegate();
   2959   SyncShareAsDelegate();
   2960   {
   2961     ReadTransaction trans(dir, __FILE__, __LINE__);
   2962     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2963     ASSERT_TRUE(bob.good());
   2964     Entry fred(&trans, GET_BY_ID, ids_.FromNumber(2));
   2965     ASSERT_TRUE(fred.good());
   2966     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   2967     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   2968     EXPECT_TRUE(bob.Get(IS_DEL));
   2969     EXPECT_TRUE(fred.Get(PARENT_ID) == root_id_);
   2970     EXPECT_TRUE(bob.Get(PARENT_ID) == fred.Get(ID));
   2971     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   2972     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   2973   }
   2974   saw_syncer_event_ = false;
   2975 }
   2976 
   2977 TEST_F(SyncerTest, NewServerItemInAFolderWeHaveDeleted) {
   2978   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   2979   CHECK(dir.good());
   2980   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   2981   LoopSyncShare();
   2982   {
   2983     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   2984     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2985     ASSERT_TRUE(bob.good());
   2986     bob.Put(IS_UNSYNCED, true);
   2987     bob.Put(IS_DEL, true);
   2988   }
   2989   mock_server_->AddUpdateDirectory(2, 1, "fred", 2, 20);
   2990   mock_server_->set_conflict_all_commits(true);
   2991   LoopSyncShare();
   2992   LoopSyncShare();
   2993   {
   2994     ReadTransaction trans(dir, __FILE__, __LINE__);
   2995     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   2996     ASSERT_TRUE(bob.good());
   2997     Entry fred(&trans, GET_BY_ID, ids_.FromNumber(2));
   2998     ASSERT_TRUE(fred.good());
   2999     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   3000     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   3001     EXPECT_TRUE(fred.Get(PARENT_ID) == bob.Get(ID));
   3002     EXPECT_TRUE(bob.Get(PARENT_ID) == root_id_);
   3003     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   3004     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3005   }
   3006   saw_syncer_event_ = false;
   3007 }
   3008 
   3009 TEST_F(SyncerTest, NewServerItemInAFolderHierarchyWeHaveDeleted) {
   3010   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3011   CHECK(dir.good());
   3012   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   3013   mock_server_->AddUpdateDirectory(2, 1, "joe", 1, 10);
   3014   LoopSyncShare();
   3015   {
   3016     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3017     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   3018     ASSERT_TRUE(bob.good());
   3019     bob.Put(IS_UNSYNCED, true);
   3020     bob.Put(IS_DEL, true);
   3021     MutableEntry joe(&trans, GET_BY_ID, ids_.FromNumber(2));
   3022     ASSERT_TRUE(joe.good());
   3023     joe.Put(IS_UNSYNCED, true);
   3024     joe.Put(IS_DEL, true);
   3025   }
   3026   mock_server_->AddUpdateDirectory(3, 2, "fred", 2, 20);
   3027   mock_server_->set_conflict_all_commits(true);
   3028   LoopSyncShare();
   3029   LoopSyncShare();
   3030   {
   3031     ReadTransaction trans(dir, __FILE__, __LINE__);
   3032     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   3033     ASSERT_TRUE(bob.good());
   3034     Entry joe(&trans, GET_BY_ID, ids_.FromNumber(2));
   3035     ASSERT_TRUE(joe.good());
   3036     Entry fred(&trans, GET_BY_ID, ids_.FromNumber(3));
   3037     ASSERT_TRUE(fred.good());
   3038     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   3039     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   3040     EXPECT_TRUE(joe.Get(IS_UNSYNCED));
   3041     EXPECT_TRUE(fred.Get(PARENT_ID) == joe.Get(ID));
   3042     EXPECT_TRUE(joe.Get(PARENT_ID) == bob.Get(ID));
   3043     EXPECT_TRUE(bob.Get(PARENT_ID) == root_id_);
   3044     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   3045     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3046     EXPECT_FALSE(joe.Get(IS_UNAPPLIED_UPDATE));
   3047   }
   3048   saw_syncer_event_ = false;
   3049 }
   3050 
   3051 TEST_F(SyncerTest, NewServerItemInAFolderHierarchyWeHaveDeleted2) {
   3052   // The difference here is that the hierarchy's not in the root. We have
   3053   // another entry that shouldn't be touched.
   3054   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3055   CHECK(dir.good());
   3056   mock_server_->AddUpdateDirectory(4, 0, "susan", 1, 10);
   3057   mock_server_->AddUpdateDirectory(1, 4, "bob", 1, 10);
   3058   mock_server_->AddUpdateDirectory(2, 1, "joe", 1, 10);
   3059   LoopSyncShare();
   3060   {
   3061     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3062     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   3063     ASSERT_TRUE(bob.good());
   3064     bob.Put(IS_UNSYNCED, true);
   3065     bob.Put(IS_DEL, true);
   3066     MutableEntry joe(&trans, GET_BY_ID, ids_.FromNumber(2));
   3067     ASSERT_TRUE(joe.good());
   3068     joe.Put(IS_UNSYNCED, true);
   3069     joe.Put(IS_DEL, true);
   3070   }
   3071   mock_server_->AddUpdateDirectory(3, 2, "fred", 2, 20);
   3072   mock_server_->set_conflict_all_commits(true);
   3073   LoopSyncShare();
   3074   LoopSyncShare();
   3075   {
   3076     ReadTransaction trans(dir, __FILE__, __LINE__);
   3077     Entry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   3078     ASSERT_TRUE(bob.good());
   3079     Entry joe(&trans, GET_BY_ID, ids_.FromNumber(2));
   3080     ASSERT_TRUE(joe.good());
   3081     Entry fred(&trans, GET_BY_ID, ids_.FromNumber(3));
   3082     ASSERT_TRUE(fred.good());
   3083     Entry susan(&trans, GET_BY_ID, ids_.FromNumber(4));
   3084     ASSERT_TRUE(susan.good());
   3085     EXPECT_FALSE(susan.Get(IS_UNSYNCED));
   3086     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   3087     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   3088     EXPECT_TRUE(joe.Get(IS_UNSYNCED));
   3089     EXPECT_EQ(fred.Get(PARENT_ID), joe.Get(ID));
   3090     EXPECT_EQ(joe.Get(PARENT_ID), bob.Get(ID));
   3091     EXPECT_EQ(bob.Get(PARENT_ID), susan.Get(ID));
   3092     EXPECT_EQ(susan.Get(PARENT_ID), root_id_);
   3093     EXPECT_FALSE(susan.Get(IS_UNAPPLIED_UPDATE));
   3094     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   3095     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3096     EXPECT_FALSE(joe.Get(IS_UNAPPLIED_UPDATE));
   3097   }
   3098   saw_syncer_event_ = false;
   3099 }
   3100 
   3101 
   3102 class SusanDeletingTest : public SyncerTest {
   3103  public:
   3104   SusanDeletingTest() : countdown_till_delete_(0) {}
   3105 
   3106   static const int64 susan_int_id_ = 4;
   3107 
   3108   void DeleteSusanInRoot() {
   3109     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3110     ASSERT_TRUE(dir.good());
   3111 
   3112     const syncable::Id susan_id = TestIdFactory::FromNumber(susan_int_id_);
   3113     ASSERT_GT(countdown_till_delete_, 0);
   3114     if (0 != --countdown_till_delete_)
   3115     return;
   3116   WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3117     MutableEntry susan(&trans, GET_BY_ID, susan_id);
   3118   Directory::ChildHandles children;
   3119   dir->GetChildHandles(&trans, susan.Get(ID), &children);
   3120   ASSERT_TRUE(0 == children.size());
   3121   susan.Put(IS_DEL, true);
   3122   susan.Put(IS_UNSYNCED, true);
   3123 }
   3124 
   3125  protected:
   3126   int countdown_till_delete_;
   3127 };
   3128 
   3129 TEST_F(SusanDeletingTest,
   3130        NewServerItemInAFolderHierarchyWeHaveDeleted3) {
   3131   // Same as 2, except we deleted the folder the set is in between set building
   3132   // and conflict resolution.
   3133   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3134   CHECK(dir.good());
   3135 
   3136   const syncable::Id bob_id = TestIdFactory::FromNumber(1);
   3137   const syncable::Id joe_id = TestIdFactory::FromNumber(2);
   3138   const syncable::Id fred_id = TestIdFactory::FromNumber(3);
   3139   const syncable::Id susan_id = TestIdFactory::FromNumber(susan_int_id_);
   3140 
   3141   mock_server_->AddUpdateDirectory(susan_id, TestIdFactory::root(),
   3142       "susan", 1, 10);
   3143   mock_server_->AddUpdateDirectory(bob_id, susan_id, "bob", 1, 10);
   3144   mock_server_->AddUpdateDirectory(joe_id, bob_id, "joe", 1, 10);
   3145   LoopSyncShare();
   3146   {
   3147     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3148     MutableEntry bob(&trans, GET_BY_ID, bob_id);
   3149     ASSERT_TRUE(bob.good());
   3150     bob.Put(IS_UNSYNCED, true);
   3151     bob.Put(IS_DEL, true);
   3152 
   3153     MutableEntry joe(&trans, GET_BY_ID, joe_id);
   3154     ASSERT_TRUE(joe.good());
   3155     joe.Put(IS_UNSYNCED, true);
   3156     joe.Put(IS_DEL, true);
   3157   }
   3158   mock_server_->AddUpdateDirectory(fred_id, joe_id, "fred", 2, 20);
   3159   mock_server_->set_conflict_all_commits(true);
   3160   countdown_till_delete_ = 2;
   3161   syncer_->pre_conflict_resolution_closure_ =
   3162       NewCallback<SusanDeletingTest>(this,
   3163           &SusanDeletingTest::DeleteSusanInRoot);
   3164   SyncShareAsDelegate();
   3165   SyncShareAsDelegate();
   3166   {
   3167     ReadTransaction trans(dir, __FILE__, __LINE__);
   3168     Entry bob(&trans, GET_BY_ID, bob_id);
   3169     ASSERT_TRUE(bob.good());
   3170     Entry joe(&trans, GET_BY_ID, joe_id);
   3171     ASSERT_TRUE(joe.good());
   3172     Entry fred(&trans, GET_BY_ID, fred_id);
   3173     ASSERT_TRUE(fred.good());
   3174     Entry susan(&trans, GET_BY_ID, susan_id);
   3175     ASSERT_TRUE(susan.good());
   3176     EXPECT_FALSE(susan.Get(IS_UNAPPLIED_UPDATE));
   3177     EXPECT_TRUE(fred.Get(IS_UNAPPLIED_UPDATE));
   3178     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3179     EXPECT_FALSE(joe.Get(IS_UNAPPLIED_UPDATE));
   3180     EXPECT_TRUE(susan.Get(IS_UNSYNCED));
   3181     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   3182     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   3183     EXPECT_TRUE(joe.Get(IS_UNSYNCED));
   3184   }
   3185   EXPECT_TRUE(0 == countdown_till_delete_);
   3186   delete syncer_->pre_conflict_resolution_closure_;
   3187   syncer_->pre_conflict_resolution_closure_ = NULL;
   3188   LoopSyncShare();
   3189   LoopSyncShare();
   3190   {
   3191     ReadTransaction trans(dir, __FILE__, __LINE__);
   3192     Entry bob(&trans, GET_BY_ID, bob_id);
   3193     ASSERT_TRUE(bob.good());
   3194     Entry joe(&trans, GET_BY_ID, joe_id);
   3195     ASSERT_TRUE(joe.good());
   3196     Entry fred(&trans, GET_BY_ID, fred_id);
   3197     ASSERT_TRUE(fred.good());
   3198     Entry susan(&trans, GET_BY_ID, susan_id);
   3199     ASSERT_TRUE(susan.good());
   3200     EXPECT_TRUE(susan.Get(IS_UNSYNCED));
   3201     EXPECT_FALSE(fred.Get(IS_UNSYNCED));
   3202     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   3203     EXPECT_TRUE(joe.Get(IS_UNSYNCED));
   3204     EXPECT_TRUE(fred.Get(PARENT_ID) == joe.Get(ID));
   3205     EXPECT_TRUE(joe.Get(PARENT_ID) == bob.Get(ID));
   3206     EXPECT_TRUE(bob.Get(PARENT_ID) == susan.Get(ID));
   3207     EXPECT_TRUE(susan.Get(PARENT_ID) == root_id_);
   3208     EXPECT_FALSE(susan.Get(IS_UNAPPLIED_UPDATE));
   3209     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   3210     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3211     EXPECT_FALSE(joe.Get(IS_UNAPPLIED_UPDATE));
   3212   }
   3213   saw_syncer_event_ = false;
   3214 }
   3215 
   3216 TEST_F(SyncerTest, WeMovedSomethingIntoAFolderHierarchyServerHasDeleted) {
   3217   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3218   CHECK(dir.good());
   3219 
   3220   const syncable::Id bob_id = ids_.NewServerId();
   3221   const syncable::Id fred_id = ids_.NewServerId();
   3222   const syncable::Id alice_id = ids_.NewServerId();
   3223 
   3224   mock_server_->AddUpdateDirectory(bob_id, TestIdFactory::root(),
   3225       "bob", 1, 10);
   3226   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   3227       "fred", 1, 10);
   3228   mock_server_->AddUpdateDirectory(alice_id, fred_id, "alice", 1, 10);
   3229   SyncShareAsDelegate();
   3230   {
   3231     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3232     MutableEntry bob(&trans, GET_BY_ID, bob_id);
   3233     ASSERT_TRUE(bob.good());
   3234     bob.Put(IS_UNSYNCED, true);
   3235     bob.Put(PARENT_ID, alice_id);  // Move into alice.
   3236   }
   3237   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   3238       "fred", 2, 20);
   3239   mock_server_->SetLastUpdateDeleted();
   3240   mock_server_->AddUpdateDirectory(alice_id, TestIdFactory::root(),
   3241       "alice", 2, 20);
   3242   mock_server_->SetLastUpdateDeleted();
   3243   mock_server_->set_conflict_all_commits(true);
   3244   SyncShareAsDelegate();
   3245   SyncShareAsDelegate();
   3246   {
   3247     // Bob is the entry at the bottom of the tree.
   3248     // The tree should be regenerated and old IDs removed.
   3249     ReadTransaction trans(dir, __FILE__, __LINE__);
   3250     Entry bob(&trans, GET_BY_ID, bob_id);
   3251     ASSERT_TRUE(bob.good());
   3252     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3253     EXPECT_TRUE(bob.Get(IS_UNSYNCED));
   3254 
   3255     // Old one should be deleted, but new one should have been made.
   3256     Entry dead_alice(&trans, GET_BY_ID, alice_id);
   3257     EXPECT_FALSE(dead_alice.good());
   3258     EXPECT_NE(bob.Get(PARENT_ID), alice_id);
   3259 
   3260     // Newly born alice
   3261     Entry alice(&trans, GET_BY_ID, bob.Get(PARENT_ID));
   3262     ASSERT_TRUE(alice.good());
   3263     EXPECT_FALSE(alice.Get(IS_UNAPPLIED_UPDATE));
   3264     EXPECT_TRUE(alice.Get(IS_UNSYNCED));
   3265     EXPECT_FALSE(alice.Get(ID).ServerKnows());
   3266     EXPECT_TRUE(alice.Get(NON_UNIQUE_NAME) == "alice");
   3267 
   3268     // Alice needs a parent as well. Old parent should have been erased.
   3269     Entry dead_fred(&trans, GET_BY_ID, fred_id);
   3270     EXPECT_FALSE(dead_fred.good());
   3271     EXPECT_NE(alice.Get(PARENT_ID), fred_id);
   3272 
   3273     Entry fred(&trans, GET_BY_ID, alice.Get(PARENT_ID));
   3274     ASSERT_TRUE(fred.good());
   3275     EXPECT_EQ(fred.Get(PARENT_ID), TestIdFactory::root());
   3276     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   3277     EXPECT_FALSE(fred.Get(ID).ServerKnows());
   3278     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   3279     EXPECT_TRUE(fred.Get(NON_UNIQUE_NAME) == "fred");
   3280   }
   3281   saw_syncer_event_ = false;
   3282 }
   3283 
   3284 TEST_F(SyncerTest, WeMovedSomethingIntoAFolderHierarchyServerHasDeleted2) {
   3285   // The difference here is that the hierarchy is not in the root. We have
   3286   // another entry that shouldn't be touched.
   3287   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3288   CHECK(dir.good());
   3289 
   3290   const syncable::Id bob_id = ids_.NewServerId();
   3291   const syncable::Id fred_id = ids_.NewServerId();
   3292   const syncable::Id alice_id = ids_.NewServerId();
   3293   const syncable::Id susan_id = ids_.NewServerId();
   3294 
   3295   mock_server_->AddUpdateDirectory(bob_id, TestIdFactory::root(),
   3296       "bob", 1, 10);
   3297   mock_server_->AddUpdateDirectory(susan_id, TestIdFactory::root(),
   3298       "susan", 1, 10);
   3299   mock_server_->AddUpdateDirectory(fred_id, susan_id, "fred", 1, 10);
   3300   mock_server_->AddUpdateDirectory(alice_id, fred_id, "alice", 1, 10);
   3301   SyncShareAsDelegate();
   3302   {
   3303     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3304     MutableEntry bob(&trans, GET_BY_ID, bob_id);
   3305     ASSERT_TRUE(bob.good());
   3306     bob.Put(IS_UNSYNCED, true);
   3307     bob.Put(PARENT_ID, alice_id);  // Move into alice.
   3308   }
   3309   mock_server_->AddUpdateDirectory(fred_id, TestIdFactory::root(),
   3310       "fred", 2, 20);
   3311   mock_server_->SetLastUpdateDeleted();
   3312   mock_server_->AddUpdateDirectory(alice_id, TestIdFactory::root(),
   3313       "alice", 2, 20);
   3314   mock_server_->SetLastUpdateDeleted();
   3315   mock_server_->set_conflict_all_commits(true);
   3316   SyncShareAsDelegate();
   3317   SyncShareAsDelegate();
   3318   {
   3319     // Root
   3320     //   |- Susan
   3321     //        |- Fred
   3322     //            |- Alice
   3323     //                 |- Bob
   3324 
   3325     ReadTransaction trans(dir, __FILE__, __LINE__);
   3326     Entry bob(&trans, GET_BY_ID, bob_id);
   3327     ASSERT_TRUE(bob.good());
   3328     EXPECT_FALSE(bob.Get(IS_UNAPPLIED_UPDATE));
   3329     EXPECT_TRUE(bob.Get(IS_UNSYNCED));  // Parent changed
   3330     EXPECT_NE(bob.Get(PARENT_ID), alice_id);
   3331 
   3332     // New one was born, this is the old one
   3333     Entry dead_alice(&trans, GET_BY_ID, alice_id);
   3334     EXPECT_FALSE(dead_alice.good());
   3335 
   3336     // Newly born
   3337     Entry alice(&trans, GET_BY_ID, bob.Get(PARENT_ID));
   3338     EXPECT_TRUE(alice.Get(IS_UNSYNCED));
   3339     EXPECT_FALSE(alice.Get(IS_UNAPPLIED_UPDATE));
   3340     EXPECT_FALSE(alice.Get(ID).ServerKnows());
   3341     EXPECT_NE(alice.Get(PARENT_ID), fred_id);  // This fred was deleted
   3342 
   3343     // New one was born, this is the old one
   3344     Entry dead_fred(&trans, GET_BY_ID, fred_id);
   3345     EXPECT_FALSE(dead_fred.good());
   3346 
   3347     // Newly born
   3348     Entry fred(&trans, GET_BY_ID, alice.Get(PARENT_ID));
   3349     EXPECT_TRUE(fred.Get(IS_UNSYNCED));
   3350     EXPECT_FALSE(fred.Get(IS_UNAPPLIED_UPDATE));
   3351     EXPECT_FALSE(fred.Get(ID).ServerKnows());
   3352     EXPECT_TRUE(fred.Get(PARENT_ID) == susan_id);
   3353 
   3354     // Unchanged
   3355     Entry susan(&trans, GET_BY_ID, susan_id);
   3356     ASSERT_TRUE(susan.good());
   3357     EXPECT_FALSE(susan.Get(IS_UNSYNCED));
   3358     EXPECT_TRUE(susan.Get(PARENT_ID) == root_id_);
   3359     EXPECT_FALSE(susan.Get(IS_UNAPPLIED_UPDATE));
   3360   }
   3361   saw_syncer_event_ = false;
   3362 }
   3363 
   3364 // This test is to reproduce a check failure. Sometimes we would get a bad ID
   3365 // back when creating an entry.
   3366 TEST_F(SyncerTest, DuplicateIDReturn) {
   3367   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3368   ASSERT_TRUE(dir.good());
   3369   {
   3370     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3371     MutableEntry folder(&trans, CREATE, trans.root_id(), "bob");
   3372     ASSERT_TRUE(folder.good());
   3373     folder.Put(IS_UNSYNCED, true);
   3374     folder.Put(IS_DIR, true);
   3375     folder.Put(SPECIFICS, DefaultBookmarkSpecifics());
   3376     MutableEntry folder2(&trans, CREATE, trans.root_id(), "fred");
   3377     ASSERT_TRUE(folder2.good());
   3378     folder2.Put(IS_UNSYNCED, false);
   3379     folder2.Put(IS_DIR, true);
   3380     folder2.Put(SPECIFICS, DefaultBookmarkSpecifics());
   3381     folder2.Put(BASE_VERSION, 3);
   3382     folder2.Put(ID, syncable::Id::CreateFromServerId("mock_server:10000"));
   3383   }
   3384   mock_server_->set_next_new_id(10000);
   3385   EXPECT_TRUE(1 == dir->unsynced_entity_count());
   3386   // we get back a bad id in here (should never happen).
   3387   SyncShareAsDelegate();
   3388   EXPECT_TRUE(1 == dir->unsynced_entity_count());
   3389   SyncShareAsDelegate();  // another bad id in here.
   3390   EXPECT_TRUE(0 == dir->unsynced_entity_count());
   3391   saw_syncer_event_ = false;
   3392 }
   3393 
   3394 TEST_F(SyncerTest, DeletedEntryWithBadParentInLoopCalculation) {
   3395   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3396   ASSERT_TRUE(dir.good());
   3397   mock_server_->AddUpdateDirectory(1, 0, "bob", 1, 10);
   3398   SyncShareAsDelegate();
   3399   {
   3400     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3401     MutableEntry bob(&trans, GET_BY_ID, ids_.FromNumber(1));
   3402     ASSERT_TRUE(bob.good());
   3403     // This is valid, because the parent could have gone away a long time ago.
   3404     bob.Put(PARENT_ID, ids_.FromNumber(54));
   3405     bob.Put(IS_DEL, true);
   3406     bob.Put(IS_UNSYNCED, true);
   3407   }
   3408   mock_server_->AddUpdateDirectory(2, 1, "fred", 1, 10);
   3409   SyncShareAsDelegate();
   3410   SyncShareAsDelegate();
   3411 }
   3412 
   3413 TEST_F(SyncerTest, ConflictResolverMergeOverwritesLocalEntry) {
   3414   // This test would die because it would rename a entry to a name that was
   3415   // taken in the namespace
   3416   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3417   CHECK(dir.good());
   3418 
   3419   ConflictSet conflict_set;
   3420   {
   3421     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3422 
   3423     MutableEntry local_deleted(&trans, CREATE, trans.root_id(), "name");
   3424     local_deleted.Put(ID, ids_.FromNumber(1));
   3425     local_deleted.Put(BASE_VERSION, 1);
   3426     local_deleted.Put(IS_DEL, true);
   3427     local_deleted.Put(IS_UNSYNCED, true);
   3428 
   3429     MutableEntry in_the_way(&trans, CREATE, trans.root_id(), "name");
   3430     in_the_way.Put(ID, ids_.FromNumber(2));
   3431     in_the_way.Put(BASE_VERSION, 1);
   3432 
   3433     MutableEntry update(&trans, CREATE_NEW_UPDATE_ITEM, ids_.FromNumber(3));
   3434     update.Put(BASE_VERSION, 1);
   3435     update.Put(SERVER_NON_UNIQUE_NAME, "name");
   3436     update.Put(PARENT_ID, ids_.FromNumber(0));
   3437     update.Put(IS_UNAPPLIED_UPDATE, true);
   3438 
   3439     conflict_set.push_back(ids_.FromNumber(1));
   3440     conflict_set.push_back(ids_.FromNumber(3));
   3441   }
   3442   {
   3443     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3444     context_->resolver()->ProcessConflictSet(&trans, &conflict_set, 50);
   3445   }
   3446 }
   3447 
   3448 TEST_F(SyncerTest, ConflictResolverMergesLocalDeleteAndServerUpdate) {
   3449   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3450   CHECK(dir.good());
   3451 
   3452   {
   3453     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3454 
   3455     MutableEntry local_deleted(&trans, CREATE, trans.root_id(), "name");
   3456     local_deleted.Put(ID, ids_.FromNumber(1));
   3457     local_deleted.Put(BASE_VERSION, 1);
   3458     local_deleted.Put(IS_DEL, true);
   3459     local_deleted.Put(IS_DIR, false);
   3460     local_deleted.Put(IS_UNSYNCED, true);
   3461     local_deleted.Put(SPECIFICS, DefaultBookmarkSpecifics());
   3462   }
   3463 
   3464   mock_server_->AddUpdateBookmark(ids_.FromNumber(1), root_id_, "name", 10, 10);
   3465 
   3466   // We don't care about actually committing, just the resolution.
   3467   mock_server_->set_conflict_all_commits(true);
   3468   SyncShareAsDelegate();
   3469 
   3470   {
   3471     ReadTransaction trans(dir, __FILE__, __LINE__);
   3472     Entry local_deleted(&trans, GET_BY_ID, ids_.FromNumber(1));
   3473     EXPECT_TRUE(local_deleted.Get(BASE_VERSION) == 10);
   3474     EXPECT_TRUE(local_deleted.Get(IS_UNAPPLIED_UPDATE) == false);
   3475     EXPECT_TRUE(local_deleted.Get(IS_UNSYNCED) == true);
   3476     EXPECT_TRUE(local_deleted.Get(IS_DEL) == true);
   3477     EXPECT_TRUE(local_deleted.Get(IS_DIR) == false);
   3478   }
   3479 }
   3480 
   3481 // See what happens if the IS_DIR bit gets flipped.  This can cause us
   3482 // all kinds of disasters.
   3483 TEST_F(SyncerTest, UpdateFlipsTheFolderBit) {
   3484   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3485   CHECK(dir.good());
   3486 
   3487   // Local object: a deleted directory (container), revision 1, unsynced.
   3488   {
   3489     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3490 
   3491     MutableEntry local_deleted(&trans, CREATE, trans.root_id(), "name");
   3492     local_deleted.Put(ID, ids_.FromNumber(1));
   3493     local_deleted.Put(BASE_VERSION, 1);
   3494     local_deleted.Put(IS_DEL, true);
   3495     local_deleted.Put(IS_DIR, true);
   3496     local_deleted.Put(IS_UNSYNCED, true);
   3497     local_deleted.Put(SPECIFICS, DefaultBookmarkSpecifics());
   3498   }
   3499 
   3500   // Server update: entry-type object (not a container), revision 10.
   3501   mock_server_->AddUpdateBookmark(ids_.FromNumber(1), root_id_, "name", 10, 10);
   3502 
   3503   // Don't attempt to commit.
   3504   mock_server_->set_conflict_all_commits(true);
   3505 
   3506   // The syncer should not attempt to apply the invalid update.
   3507   SyncShareAsDelegate();
   3508 
   3509   {
   3510     ReadTransaction trans(dir, __FILE__, __LINE__);
   3511     Entry local_deleted(&trans, GET_BY_ID, ids_.FromNumber(1));
   3512     EXPECT_TRUE(local_deleted.Get(BASE_VERSION) == 1);
   3513     EXPECT_TRUE(local_deleted.Get(IS_UNAPPLIED_UPDATE) == false);
   3514     EXPECT_TRUE(local_deleted.Get(IS_UNSYNCED) == true);
   3515     EXPECT_TRUE(local_deleted.Get(IS_DEL) == true);
   3516     EXPECT_TRUE(local_deleted.Get(IS_DIR) == true);
   3517   }
   3518 }
   3519 
   3520 TEST(SyncerSyncProcessState, MergeSetsTest) {
   3521   TestIdFactory id_factory;
   3522   syncable::Id id[7];
   3523   for (int i = 1; i < 7; i++) {
   3524     id[i] = id_factory.NewServerId();
   3525   }
   3526   bool is_dirty = false;
   3527   ConflictProgress c(&is_dirty);
   3528   c.MergeSets(id[1], id[2]);
   3529   c.MergeSets(id[2], id[3]);
   3530   c.MergeSets(id[4], id[5]);
   3531   c.MergeSets(id[5], id[6]);
   3532   EXPECT_TRUE(6 == c.IdToConflictSetSize());
   3533   EXPECT_FALSE(is_dirty);
   3534   for (int i = 1; i < 7; i++) {
   3535     EXPECT_TRUE(NULL != c.IdToConflictSetGet(id[i]));
   3536     EXPECT_TRUE(c.IdToConflictSetGet(id[(i & ~3) + 1]) ==
   3537                 c.IdToConflictSetGet(id[i]));
   3538   }
   3539   c.MergeSets(id[1], id[6]);
   3540   for (int i = 1; i < 7; i++) {
   3541     EXPECT_TRUE(NULL != c.IdToConflictSetGet(id[i]));
   3542     EXPECT_TRUE(c.IdToConflictSetGet(id[1]) == c.IdToConflictSetGet(id[i]));
   3543   }
   3544 
   3545   // Check dupes don't cause double sets.
   3546   ConflictProgress identical_set(&is_dirty);
   3547   identical_set.MergeSets(id[1], id[1]);
   3548   EXPECT_TRUE(identical_set.IdToConflictSetSize() == 1);
   3549   EXPECT_TRUE(identical_set.IdToConflictSetGet(id[1])->size() == 1);
   3550   EXPECT_FALSE(is_dirty);
   3551 }
   3552 
   3553 // Bug Synopsis:
   3554 // Merge conflict resolution will merge a new local entry with another entry
   3555 // that needs updates, resulting in CHECK.
   3556 TEST_F(SyncerTest, MergingExistingItems) {
   3557   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3558   CHECK(dir.good());
   3559   mock_server_->set_conflict_all_commits(true);
   3560   mock_server_->AddUpdateBookmark(1, 0, "base", 10, 10);
   3561   SyncShareAsDelegate();
   3562   {
   3563     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3564     MutableEntry entry(&trans, CREATE, trans.root_id(), "Copy of base");
   3565     WriteTestDataToEntry(&trans, &entry);
   3566   }
   3567   mock_server_->AddUpdateBookmark(1, 0, "Copy of base", 50, 50);
   3568   SyncRepeatedlyToTriggerConflictResolution(session_.get());
   3569 }
   3570 
   3571 TEST_F(SyncerTest, OneBajillionUpdates) {
   3572   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3573   CHECK(dir.good());
   3574   int one_bajillion = 4000;
   3575 
   3576   syncable::Id parent_id = ids_.MakeServer("Parent");
   3577   mock_server_->AddUpdateDirectory(parent_id, ids_.root(), "foo", 1, 1);
   3578 
   3579   for (int i = 1; i <= one_bajillion; ++i) {
   3580     syncable::Id item_id = ids_.FromNumber(i);
   3581     mock_server_->AddUpdateDirectory(item_id, parent_id, "dude", 1, 1);
   3582   }
   3583 
   3584   syncer_->SyncShare(session_.get());
   3585   EXPECT_FALSE(session_->status_controller()->syncer_status().syncer_stuck);
   3586 }
   3587 
   3588 // In this test a long changelog contains a child at the start of the changelog
   3589 // and a parent at the end. While these updates are in progress the client would
   3590 // appear stuck.
   3591 TEST_F(SyncerTest, LongChangelistWithApplicationConflict) {
   3592   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3593   CHECK(dir.good());
   3594   const int depth = 400;
   3595   syncable::Id folder_id = ids_.FromNumber(1);
   3596 
   3597   // First we an item in a folder in the root. However the folder won't come
   3598   // till much later.
   3599   syncable::Id stuck_entry_id = TestIdFactory::FromNumber(99999);
   3600   mock_server_->AddUpdateDirectory(stuck_entry_id,
   3601       folder_id, "stuck", 1, 1);
   3602   mock_server_->SetChangesRemaining(depth - 1);
   3603   syncer_->SyncShare(session_.get());
   3604 
   3605   // Buffer up a very long series of downloads.
   3606   // We should never be stuck (conflict resolution shouldn't
   3607   // kick in so long as we're making forward progress).
   3608   for (int i = 0; i < depth; i++) {
   3609     mock_server_->NextUpdateBatch();
   3610     mock_server_->SetNewTimestamp(i + 1);
   3611     mock_server_->SetChangesRemaining(depth - i);
   3612   }
   3613 
   3614   syncer_->SyncShare(session_.get());
   3615   EXPECT_FALSE(session_->status_controller()->syncer_status().syncer_stuck);
   3616 
   3617   // Ensure our folder hasn't somehow applied.
   3618   {
   3619     ReadTransaction trans(dir, __FILE__, __LINE__);
   3620     Entry child(&trans, GET_BY_ID, stuck_entry_id);
   3621     EXPECT_TRUE(child.good());
   3622     EXPECT_TRUE(child.Get(IS_UNAPPLIED_UPDATE));
   3623     EXPECT_TRUE(child.Get(IS_DEL));
   3624     EXPECT_FALSE(child.Get(IS_UNSYNCED));
   3625   }
   3626 
   3627   // And finally the folder.
   3628   mock_server_->AddUpdateDirectory(folder_id,
   3629       TestIdFactory::root(), "folder", 1, 1);
   3630   mock_server_->SetChangesRemaining(0);
   3631   LoopSyncShare();
   3632   LoopSyncShare();
   3633   // Check that everything is as expected after the commit.
   3634   {
   3635     ReadTransaction trans(dir, __FILE__, __LINE__);
   3636     Entry entry(&trans, GET_BY_ID, folder_id);
   3637     ASSERT_TRUE(entry.good());
   3638     Entry child(&trans, GET_BY_ID, stuck_entry_id);
   3639     EXPECT_EQ(entry.Get(ID), child.Get(PARENT_ID));
   3640     EXPECT_EQ("stuck", child.Get(NON_UNIQUE_NAME));
   3641     EXPECT_TRUE(child.good());
   3642   }
   3643 }
   3644 
   3645 TEST_F(SyncerTest, DontMergeTwoExistingItems) {
   3646   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3647   EXPECT_TRUE(dir.good());
   3648   mock_server_->set_conflict_all_commits(true);
   3649   mock_server_->AddUpdateBookmark(1, 0, "base", 10, 10);
   3650   mock_server_->AddUpdateBookmark(2, 0, "base2", 10, 10);
   3651   SyncShareAsDelegate();
   3652   {
   3653     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3654     MutableEntry entry(&trans, GET_BY_ID, ids_.FromNumber(2));
   3655     ASSERT_TRUE(entry.good());
   3656     EXPECT_TRUE(entry.Put(NON_UNIQUE_NAME, "Copy of base"));
   3657     entry.Put(IS_UNSYNCED, true);
   3658   }
   3659   mock_server_->AddUpdateBookmark(1, 0, "Copy of base", 50, 50);
   3660   SyncRepeatedlyToTriggerConflictResolution(session_.get());
   3661   {
   3662     ReadTransaction trans(dir, __FILE__, __LINE__);
   3663     Entry entry1(&trans, GET_BY_ID, ids_.FromNumber(1));
   3664     EXPECT_FALSE(entry1.Get(IS_UNAPPLIED_UPDATE));
   3665     EXPECT_FALSE(entry1.Get(IS_UNSYNCED));
   3666     EXPECT_FALSE(entry1.Get(IS_DEL));
   3667     Entry entry2(&trans, GET_BY_ID, ids_.FromNumber(2));
   3668     EXPECT_FALSE(entry2.Get(IS_UNAPPLIED_UPDATE));
   3669     EXPECT_TRUE(entry2.Get(IS_UNSYNCED));
   3670     EXPECT_FALSE(entry2.Get(IS_DEL));
   3671     EXPECT_EQ(entry1.Get(NON_UNIQUE_NAME), entry2.Get(NON_UNIQUE_NAME));
   3672   }
   3673 }
   3674 
   3675 TEST_F(SyncerTest, TestUndeleteUpdate) {
   3676   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3677   EXPECT_TRUE(dir.good());
   3678   mock_server_->set_conflict_all_commits(true);
   3679   mock_server_->AddUpdateDirectory(1, 0, "foo", 1, 1);
   3680   mock_server_->AddUpdateDirectory(2, 1, "bar", 1, 2);
   3681   SyncShareAsDelegate();
   3682   mock_server_->AddUpdateDirectory(2, 1, "bar", 2, 3);
   3683   mock_server_->SetLastUpdateDeleted();
   3684   SyncShareAsDelegate();
   3685 
   3686   int64 metahandle;
   3687   {
   3688     ReadTransaction trans(dir, __FILE__, __LINE__);
   3689     Entry entry(&trans, GET_BY_ID, ids_.FromNumber(2));
   3690     ASSERT_TRUE(entry.good());
   3691     EXPECT_TRUE(entry.Get(IS_DEL));
   3692     metahandle = entry.Get(META_HANDLE);
   3693   }
   3694   mock_server_->AddUpdateDirectory(1, 0, "foo", 2, 4);
   3695   mock_server_->SetLastUpdateDeleted();
   3696   SyncShareAsDelegate();
   3697   // This used to be rejected as it's an undeletion. Now, it results in moving
   3698   // the delete path aside.
   3699   mock_server_->AddUpdateDirectory(2, 1, "bar", 3, 5);
   3700   SyncShareAsDelegate();
   3701   {
   3702     ReadTransaction trans(dir, __FILE__, __LINE__);
   3703     Entry entry(&trans, GET_BY_ID, ids_.FromNumber(2));
   3704     ASSERT_TRUE(entry.good());
   3705     EXPECT_TRUE(entry.Get(IS_DEL));
   3706     EXPECT_FALSE(entry.Get(SERVER_IS_DEL));
   3707     EXPECT_TRUE(entry.Get(IS_UNAPPLIED_UPDATE));
   3708     EXPECT_NE(entry.Get(META_HANDLE), metahandle);
   3709   }
   3710 }
   3711 
   3712 TEST_F(SyncerTest, TestMoveSanitizedNamedFolder) {
   3713   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3714   EXPECT_TRUE(dir.good());
   3715   mock_server_->AddUpdateDirectory(1, 0, "foo", 1, 1);
   3716   mock_server_->AddUpdateDirectory(2, 0, ":::", 1, 2);
   3717   SyncShareAsDelegate();
   3718   {
   3719     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3720     MutableEntry entry(&trans, GET_BY_ID, ids_.FromNumber(2));
   3721     ASSERT_TRUE(entry.good());
   3722     EXPECT_TRUE(entry.Put(PARENT_ID, ids_.FromNumber(1)));
   3723     EXPECT_TRUE(entry.Put(IS_UNSYNCED, true));
   3724   }
   3725   SyncShareAsDelegate();
   3726   // We use the same sync ts as before so our times match up.
   3727   mock_server_->AddUpdateDirectory(2, 1, ":::", 2, 2);
   3728   SyncShareAsDelegate();
   3729 }
   3730 
   3731 TEST(SortedCollectionsIntersect, SortedCollectionsIntersectTest) {
   3732   int negative[] = {-3, -2, -1};
   3733   int straddle[] = {-1, 0, 1};
   3734   int positive[] = {1, 2, 3};
   3735   EXPECT_TRUE(SortedCollectionsIntersect(negative, negative + 3,
   3736                                          straddle, straddle + 3));
   3737   EXPECT_FALSE(SortedCollectionsIntersect(negative, negative + 3,
   3738                                           positive, positive + 3));
   3739   EXPECT_TRUE(SortedCollectionsIntersect(straddle, straddle + 3,
   3740                                          positive, positive + 3));
   3741   EXPECT_FALSE(SortedCollectionsIntersect(straddle + 2, straddle + 3,
   3742                                           positive, positive));
   3743   EXPECT_FALSE(SortedCollectionsIntersect(straddle, straddle + 3,
   3744                                           positive + 1, positive + 1));
   3745   EXPECT_TRUE(SortedCollectionsIntersect(straddle, straddle + 3,
   3746                                          positive, positive + 1));
   3747 }
   3748 
   3749 // Don't crash when this occurs.
   3750 TEST_F(SyncerTest, UpdateWhereParentIsNotAFolder) {
   3751   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3752   CHECK(dir.good());
   3753   mock_server_->AddUpdateBookmark(1, 0, "B", 10, 10);
   3754   mock_server_->AddUpdateDirectory(2, 1, "BookmarkParent", 10, 10);
   3755   // Used to cause a CHECK
   3756   SyncShareAsDelegate();
   3757   {
   3758     ReadTransaction rtrans(dir, __FILE__, __LINE__);
   3759     Entry good_entry(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(1));
   3760     ASSERT_TRUE(good_entry.good());
   3761     EXPECT_FALSE(good_entry.Get(IS_UNAPPLIED_UPDATE));
   3762     Entry bad_parent(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(2));
   3763     ASSERT_TRUE(bad_parent.good());
   3764     EXPECT_TRUE(bad_parent.Get(IS_UNAPPLIED_UPDATE));
   3765   }
   3766 }
   3767 
   3768 const char kRootId[] = "0";
   3769 
   3770 TEST_F(SyncerTest, DirectoryUpdateTest) {
   3771   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3772   CHECK(dir.good());
   3773 
   3774   Id in_root_id = ids_.NewServerId();
   3775   Id in_in_root_id = ids_.NewServerId();
   3776 
   3777   mock_server_->AddUpdateDirectory(in_root_id, TestIdFactory::root(),
   3778                                    "in_root_name", 2, 2);
   3779   mock_server_->AddUpdateDirectory(in_in_root_id, in_root_id,
   3780                                    "in_in_root_name", 3, 3);
   3781   SyncShareAsDelegate();
   3782   {
   3783     ReadTransaction trans(dir, __FILE__, __LINE__);
   3784     Entry in_root(&trans, GET_BY_ID, in_root_id);
   3785     ASSERT_TRUE(in_root.good());
   3786     EXPECT_EQ("in_root_name", in_root.Get(NON_UNIQUE_NAME));
   3787     EXPECT_EQ(TestIdFactory::root(), in_root.Get(PARENT_ID));
   3788 
   3789     Entry in_in_root(&trans, GET_BY_ID, in_in_root_id);
   3790     ASSERT_TRUE(in_in_root.good());
   3791     EXPECT_EQ("in_in_root_name", in_in_root.Get(NON_UNIQUE_NAME));
   3792     EXPECT_EQ(in_root_id, in_in_root.Get(PARENT_ID));
   3793   }
   3794 }
   3795 
   3796 TEST_F(SyncerTest, DirectoryCommitTest) {
   3797   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3798   CHECK(dir.good());
   3799 
   3800   syncable::Id in_root_id, in_dir_id;
   3801   int64 foo_metahandle;
   3802   int64 bar_metahandle;
   3803 
   3804   {
   3805     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   3806     MutableEntry parent(&wtrans, syncable::CREATE, root_id_, "foo");
   3807     ASSERT_TRUE(parent.good());
   3808     parent.Put(syncable::IS_UNSYNCED, true);
   3809     parent.Put(syncable::IS_DIR, true);
   3810     parent.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   3811     in_root_id = parent.Get(syncable::ID);
   3812     foo_metahandle = parent.Get(META_HANDLE);
   3813 
   3814     MutableEntry child(&wtrans, syncable::CREATE, parent.Get(ID), "bar");
   3815     ASSERT_TRUE(child.good());
   3816     child.Put(syncable::IS_UNSYNCED, true);
   3817     child.Put(syncable::IS_DIR, true);
   3818     child.Put(syncable::SPECIFICS, DefaultBookmarkSpecifics());
   3819     bar_metahandle = child.Get(META_HANDLE);
   3820     in_dir_id = parent.Get(syncable::ID);
   3821   }
   3822   SyncShareAsDelegate();
   3823   {
   3824     ReadTransaction trans(dir, __FILE__, __LINE__);
   3825     Entry fail_by_old_id_entry(&trans, GET_BY_ID, in_root_id);
   3826     ASSERT_FALSE(fail_by_old_id_entry.good());
   3827 
   3828     Entry foo_entry(&trans, GET_BY_HANDLE, foo_metahandle);
   3829     ASSERT_TRUE(foo_entry.good());
   3830     EXPECT_EQ("foo", foo_entry.Get(NON_UNIQUE_NAME));
   3831     EXPECT_NE(foo_entry.Get(syncable::ID), in_root_id);
   3832 
   3833     Entry bar_entry(&trans, GET_BY_HANDLE, bar_metahandle);
   3834     ASSERT_TRUE(bar_entry.good());
   3835     EXPECT_EQ("bar", bar_entry.Get(NON_UNIQUE_NAME));
   3836     EXPECT_NE(bar_entry.Get(syncable::ID), in_dir_id);
   3837     EXPECT_EQ(foo_entry.Get(syncable::ID), bar_entry.Get(PARENT_ID));
   3838   }
   3839 }
   3840 
   3841 TEST_F(SyncerTest, ConflictSetSizeReducedToOne) {
   3842   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3843   CHECK(dir.good());
   3844 
   3845   syncable::Id in_root_id = ids_.NewServerId();
   3846 
   3847   mock_server_->AddUpdateBookmark(in_root_id, TestIdFactory::root(),
   3848       "in_root", 1, 1);
   3849   SyncShareAsDelegate();
   3850   {
   3851     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3852     MutableEntry oentry(&trans, GET_BY_ID, in_root_id);
   3853     ASSERT_TRUE(oentry.good());
   3854     oentry.Put(NON_UNIQUE_NAME, "old_in_root");
   3855     WriteTestDataToEntry(&trans, &oentry);
   3856     MutableEntry entry(&trans, CREATE, trans.root_id(), "in_root");
   3857     ASSERT_TRUE(entry.good());
   3858     WriteTestDataToEntry(&trans, &entry);
   3859   }
   3860   mock_server_->set_conflict_all_commits(true);
   3861   // This SyncShare call used to result in a CHECK failure.
   3862   SyncShareAsDelegate();
   3863   saw_syncer_event_ = false;
   3864 }
   3865 
   3866 TEST_F(SyncerTest, TestClientCommand) {
   3867   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3868   CHECK(dir.good());
   3869   using sync_pb::ClientCommand;
   3870 
   3871   ClientCommand* command = mock_server_->GetNextClientCommand();
   3872   command->set_set_sync_poll_interval(8);
   3873   command->set_set_sync_long_poll_interval(800);
   3874   mock_server_->AddUpdateDirectory(1, 0, "in_root", 1, 1);
   3875   SyncShareAsDelegate();
   3876 
   3877   EXPECT_TRUE(TimeDelta::FromSeconds(8) ==
   3878               last_short_poll_interval_received_);
   3879   EXPECT_TRUE(TimeDelta::FromSeconds(800) ==
   3880               last_long_poll_interval_received_);
   3881 
   3882   command = mock_server_->GetNextClientCommand();
   3883   command->set_set_sync_poll_interval(180);
   3884   command->set_set_sync_long_poll_interval(190);
   3885   mock_server_->AddUpdateDirectory(1, 0, "in_root", 1, 1);
   3886   SyncShareAsDelegate();
   3887 
   3888   EXPECT_TRUE(TimeDelta::FromSeconds(180) ==
   3889               last_short_poll_interval_received_);
   3890   EXPECT_TRUE(TimeDelta::FromSeconds(190) ==
   3891               last_long_poll_interval_received_);
   3892 }
   3893 
   3894 TEST_F(SyncerTest, EnsureWeSendUpOldParent) {
   3895   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3896   CHECK(dir.good());
   3897 
   3898   syncable::Id folder_one_id = ids_.FromNumber(1);
   3899   syncable::Id folder_two_id = ids_.FromNumber(2);
   3900 
   3901   mock_server_->AddUpdateDirectory(folder_one_id, TestIdFactory::root(),
   3902       "folder_one", 1, 1);
   3903   mock_server_->AddUpdateDirectory(folder_two_id, TestIdFactory::root(),
   3904       "folder_two", 1, 1);
   3905   SyncShareAsDelegate();
   3906   {
   3907     // A moved entry should send an "old parent."
   3908     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   3909     MutableEntry entry(&trans, GET_BY_ID, folder_one_id);
   3910     ASSERT_TRUE(entry.good());
   3911     entry.Put(PARENT_ID, folder_two_id);
   3912     entry.Put(IS_UNSYNCED, true);
   3913     // A new entry should send no "old parent."
   3914     MutableEntry create(&trans, CREATE, trans.root_id(), "new_folder");
   3915     create.Put(IS_UNSYNCED, true);
   3916     create.Put(SPECIFICS, DefaultBookmarkSpecifics());
   3917   }
   3918   SyncShareAsDelegate();
   3919   const sync_pb::CommitMessage& commit = mock_server_->last_sent_commit();
   3920   ASSERT_TRUE(2 == commit.entries_size());
   3921   EXPECT_TRUE(commit.entries(0).parent_id_string() == "2");
   3922   EXPECT_TRUE(commit.entries(0).old_parent_id() == "0");
   3923   EXPECT_FALSE(commit.entries(1).has_old_parent_id());
   3924 }
   3925 
   3926 TEST_F(SyncerTest, Test64BitVersionSupport) {
   3927   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3928   CHECK(dir.good());
   3929   int64 really_big_int = std::numeric_limits<int64>::max() - 12;
   3930   const string name("ringo's dang orang ran rings around my o-ring");
   3931   int64 item_metahandle;
   3932 
   3933   // Try writing max int64 to the version fields of a meta entry.
   3934   {
   3935     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   3936     MutableEntry entry(&wtrans, syncable::CREATE, wtrans.root_id(), name);
   3937     ASSERT_TRUE(entry.good());
   3938     entry.Put(syncable::BASE_VERSION, really_big_int);
   3939     entry.Put(syncable::SERVER_VERSION, really_big_int);
   3940     entry.Put(syncable::ID, ids_.NewServerId());
   3941     item_metahandle = entry.Get(META_HANDLE);
   3942   }
   3943   // Now read it back out and make sure the value is max int64.
   3944   ReadTransaction rtrans(dir, __FILE__, __LINE__);
   3945   Entry entry(&rtrans, syncable::GET_BY_HANDLE, item_metahandle);
   3946   ASSERT_TRUE(entry.good());
   3947   EXPECT_TRUE(really_big_int == entry.Get(syncable::BASE_VERSION));
   3948 }
   3949 
   3950 TEST_F(SyncerTest, TestSimpleUndelete) {
   3951   Id id = ids_.MakeServer("undeletion item"), root = TestIdFactory::root();
   3952   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   3953   EXPECT_TRUE(dir.good());
   3954   mock_server_->set_conflict_all_commits(true);
   3955   // Let there be an entry from the server.
   3956   mock_server_->AddUpdateBookmark(id, root, "foo", 1, 10);
   3957   SyncShareAsDelegate();
   3958   // Check it out and delete it.
   3959   {
   3960     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   3961     MutableEntry entry(&wtrans, GET_BY_ID, id);
   3962     ASSERT_TRUE(entry.good());
   3963     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   3964     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   3965     EXPECT_FALSE(entry.Get(IS_DEL));
   3966     // Delete it locally.
   3967     entry.Put(IS_DEL, true);
   3968   }
   3969   SyncShareAsDelegate();
   3970   // Confirm we see IS_DEL and not SERVER_IS_DEL.
   3971   {
   3972     ReadTransaction trans(dir, __FILE__, __LINE__);
   3973     Entry entry(&trans, GET_BY_ID, id);
   3974     ASSERT_TRUE(entry.good());
   3975     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   3976     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   3977     EXPECT_TRUE(entry.Get(IS_DEL));
   3978     EXPECT_FALSE(entry.Get(SERVER_IS_DEL));
   3979   }
   3980   SyncShareAsDelegate();
   3981   // Update from server confirming deletion.
   3982   mock_server_->AddUpdateBookmark(id, root, "foo", 2, 11);
   3983   mock_server_->SetLastUpdateDeleted();
   3984   SyncShareAsDelegate();
   3985   // IS_DEL AND SERVER_IS_DEL now both true.
   3986   {
   3987     ReadTransaction trans(dir, __FILE__, __LINE__);
   3988     Entry entry(&trans, GET_BY_ID, id);
   3989     ASSERT_TRUE(entry.good());
   3990     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   3991     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   3992     EXPECT_TRUE(entry.Get(IS_DEL));
   3993     EXPECT_TRUE(entry.Get(SERVER_IS_DEL));
   3994   }
   3995   // Undelete from server.
   3996   mock_server_->AddUpdateBookmark(id, root, "foo", 2, 12);
   3997   SyncShareAsDelegate();
   3998   // IS_DEL and SERVER_IS_DEL now both false.
   3999   {
   4000     ReadTransaction trans(dir, __FILE__, __LINE__);
   4001     Entry entry(&trans, GET_BY_ID, id);
   4002     ASSERT_TRUE(entry.good());
   4003     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   4004     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   4005     EXPECT_FALSE(entry.Get(IS_DEL));
   4006     EXPECT_FALSE(entry.Get(SERVER_IS_DEL));
   4007   }
   4008 }
   4009 
   4010 TEST_F(SyncerTest, TestUndeleteWithMissingDeleteUpdate) {
   4011   Id id = ids_.MakeServer("undeletion item"), root = TestIdFactory::root();
   4012   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4013   EXPECT_TRUE(dir.good());
   4014   // Let there be a entry, from the server.
   4015   mock_server_->set_conflict_all_commits(true);
   4016   mock_server_->AddUpdateBookmark(id, root, "foo", 1, 10);
   4017   SyncShareAsDelegate();
   4018   // Check it out and delete it.
   4019   {
   4020     WriteTransaction wtrans(dir, UNITTEST, __FILE__, __LINE__);
   4021     MutableEntry entry(&wtrans, GET_BY_ID, id);
   4022     ASSERT_TRUE(entry.good());
   4023     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   4024     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   4025     EXPECT_FALSE(entry.Get(IS_DEL));
   4026     // Delete it locally.
   4027     entry.Put(IS_DEL, true);
   4028   }
   4029   SyncShareAsDelegate();
   4030   // Confirm we see IS_DEL and not SERVER_IS_DEL.
   4031   {
   4032     ReadTransaction trans(dir, __FILE__, __LINE__);
   4033     Entry entry(&trans, GET_BY_ID, id);
   4034     ASSERT_TRUE(entry.good());
   4035     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   4036     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   4037     EXPECT_TRUE(entry.Get(IS_DEL));
   4038     EXPECT_FALSE(entry.Get(SERVER_IS_DEL));
   4039   }
   4040   SyncShareAsDelegate();
   4041   // Say we do not get an update from server confirming deletion. Undelete
   4042   // from server
   4043   mock_server_->AddUpdateBookmark(id, root, "foo", 2, 12);
   4044   SyncShareAsDelegate();
   4045   // IS_DEL and SERVER_IS_DEL now both false.
   4046   {
   4047     ReadTransaction trans(dir, __FILE__, __LINE__);
   4048     Entry entry(&trans, GET_BY_ID, id);
   4049     ASSERT_TRUE(entry.good());
   4050     EXPECT_FALSE(entry.Get(IS_UNAPPLIED_UPDATE));
   4051     EXPECT_FALSE(entry.Get(IS_UNSYNCED));
   4052     EXPECT_FALSE(entry.Get(IS_DEL));
   4053     EXPECT_FALSE(entry.Get(SERVER_IS_DEL));
   4054   }
   4055 }
   4056 
   4057 TEST_F(SyncerTest, TestUndeleteIgnoreCorrectlyUnappliedUpdate) {
   4058   Id id1 = ids_.MakeServer("first"), id2 = ids_.MakeServer("second");
   4059   Id root = TestIdFactory::root();
   4060   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4061   EXPECT_TRUE(dir.good());
   4062   // Duplicate! expect path clashing!
   4063   mock_server_->set_conflict_all_commits(true);
   4064   mock_server_->AddUpdateBookmark(id1, root, "foo", 1, 10);
   4065   mock_server_->AddUpdateBookmark(id2, root, "foo", 1, 10);
   4066   SyncShareAsDelegate();
   4067   mock_server_->AddUpdateBookmark(id2, root, "foo2", 2, 20);
   4068   SyncShareAsDelegate();  // Now just don't explode.
   4069 }
   4070 
   4071 TEST_F(SyncerTest, ClientTagServerCreatedUpdatesWork) {
   4072   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4073   EXPECT_TRUE(dir.good());
   4074 
   4075   mock_server_->AddUpdateDirectory(1, 0, "permitem1", 1, 10);
   4076   mock_server_->SetLastUpdateClientTag("permfolder");
   4077 
   4078   SyncShareAsDelegate();
   4079 
   4080   {
   4081     ReadTransaction trans(dir, __FILE__, __LINE__);
   4082     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "permfolder");
   4083     ASSERT_TRUE(perm_folder.good());
   4084     EXPECT_FALSE(perm_folder.Get(IS_DEL));
   4085     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4086     EXPECT_FALSE(perm_folder.Get(IS_UNSYNCED));
   4087     EXPECT_EQ(perm_folder.Get(UNIQUE_CLIENT_TAG), "permfolder");
   4088     EXPECT_EQ(perm_folder.Get(NON_UNIQUE_NAME), "permitem1");
   4089   }
   4090 
   4091   mock_server_->AddUpdateDirectory(1, 0, "permitem_renamed", 10, 100);
   4092   mock_server_->SetLastUpdateClientTag("permfolder");
   4093   SyncShareAsDelegate();
   4094 
   4095   {
   4096     ReadTransaction trans(dir, __FILE__, __LINE__);
   4097 
   4098     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "permfolder");
   4099     ASSERT_TRUE(perm_folder.good());
   4100     EXPECT_FALSE(perm_folder.Get(IS_DEL));
   4101     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4102     EXPECT_FALSE(perm_folder.Get(IS_UNSYNCED));
   4103     EXPECT_EQ(perm_folder.Get(UNIQUE_CLIENT_TAG), "permfolder");
   4104     EXPECT_EQ(perm_folder.Get(NON_UNIQUE_NAME), "permitem_renamed");
   4105   }
   4106 }
   4107 
   4108 TEST_F(SyncerTest, ClientTagIllegalUpdateIgnored) {
   4109   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4110   EXPECT_TRUE(dir.good());
   4111 
   4112   mock_server_->AddUpdateDirectory(1, 0, "permitem1", 1, 10);
   4113   mock_server_->SetLastUpdateClientTag("permfolder");
   4114 
   4115   SyncShareAsDelegate();
   4116 
   4117   {
   4118     ReadTransaction trans(dir, __FILE__, __LINE__);
   4119     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "permfolder");
   4120     ASSERT_TRUE(perm_folder.good());
   4121     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4122     EXPECT_FALSE(perm_folder.Get(IS_UNSYNCED));
   4123     EXPECT_EQ(perm_folder.Get(UNIQUE_CLIENT_TAG), "permfolder");
   4124     EXPECT_TRUE(perm_folder.Get(NON_UNIQUE_NAME) == "permitem1");
   4125     EXPECT_TRUE(perm_folder.Get(ID).ServerKnows());
   4126   }
   4127 
   4128   mock_server_->AddUpdateDirectory(1, 0, "permitem_renamed", 10, 100);
   4129   mock_server_->SetLastUpdateClientTag("wrongtag");
   4130   SyncShareAsDelegate();
   4131 
   4132   {
   4133     ReadTransaction trans(dir, __FILE__, __LINE__);
   4134 
   4135     // This update is rejected because it has the same ID, but a
   4136     // different tag than one that is already on the client.
   4137     // The client has a ServerKnows ID, which cannot be overwritten.
   4138     Entry rejected_update(&trans, GET_BY_CLIENT_TAG, "wrongtag");
   4139     EXPECT_FALSE(rejected_update.good());
   4140 
   4141     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "permfolder");
   4142     ASSERT_TRUE(perm_folder.good());
   4143     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4144     EXPECT_FALSE(perm_folder.Get(IS_UNSYNCED));
   4145     EXPECT_EQ(perm_folder.Get(NON_UNIQUE_NAME), "permitem1");
   4146   }
   4147 }
   4148 
   4149 TEST_F(SyncerTest, ClientTagUncommittedTagMatchesUpdate) {
   4150   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4151   EXPECT_TRUE(dir.good());
   4152   int64 original_metahandle = 0;
   4153 
   4154   sync_pb::EntitySpecifics local_bookmark(DefaultBookmarkSpecifics());
   4155   local_bookmark.MutableExtension(sync_pb::bookmark)->
   4156       set_url("http://foo/localsite");
   4157   sync_pb::EntitySpecifics server_bookmark(DefaultBookmarkSpecifics());
   4158   server_bookmark.MutableExtension(sync_pb::bookmark)->
   4159       set_url("http://bar/serversite");
   4160 
   4161   {
   4162     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   4163     MutableEntry perm_folder(&trans, CREATE, ids_.root(), "clientname");
   4164     ASSERT_TRUE(perm_folder.good());
   4165     perm_folder.Put(UNIQUE_CLIENT_TAG, "clientperm");
   4166     perm_folder.Put(SPECIFICS, local_bookmark);
   4167     perm_folder.Put(IS_UNSYNCED, true);
   4168     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4169     EXPECT_FALSE(perm_folder.Get(ID).ServerKnows());
   4170     original_metahandle = perm_folder.Get(META_HANDLE);
   4171   }
   4172 
   4173   mock_server_->AddUpdateBookmark(1, 0, "permitem_renamed", 10, 100);
   4174   mock_server_->SetLastUpdateClientTag("clientperm");
   4175   mock_server_->GetMutableLastUpdate()->mutable_specifics()->
   4176       CopyFrom(server_bookmark);
   4177   mock_server_->set_conflict_all_commits(true);
   4178 
   4179   SyncShareAsDelegate();
   4180   // This should cause client tag reunion, preserving the metahandle.
   4181   {
   4182     ReadTransaction trans(dir, __FILE__, __LINE__);
   4183 
   4184     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "clientperm");
   4185     ASSERT_TRUE(perm_folder.good());
   4186     EXPECT_FALSE(perm_folder.Get(IS_DEL));
   4187     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4188     EXPECT_TRUE(perm_folder.Get(IS_UNSYNCED));
   4189     EXPECT_EQ(10, perm_folder.Get(BASE_VERSION));
   4190     // Entry should have been given the new ID while preserving the
   4191     // metahandle; client should have won the conflict resolution.
   4192     EXPECT_EQ(original_metahandle, perm_folder.Get(META_HANDLE));
   4193     EXPECT_EQ("clientperm", perm_folder.Get(UNIQUE_CLIENT_TAG));
   4194     EXPECT_EQ("clientname", perm_folder.Get(NON_UNIQUE_NAME));
   4195     EXPECT_EQ(local_bookmark.SerializeAsString(),
   4196               perm_folder.Get(SPECIFICS).SerializeAsString());
   4197     EXPECT_TRUE(perm_folder.Get(ID).ServerKnows());
   4198   }
   4199 
   4200   mock_server_->set_conflict_all_commits(false);
   4201   SyncShareAsDelegate();
   4202 
   4203   // The resolved entry ought to commit cleanly.
   4204   {
   4205     ReadTransaction trans(dir, __FILE__, __LINE__);
   4206 
   4207     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "clientperm");
   4208     ASSERT_TRUE(perm_folder.good());
   4209     EXPECT_FALSE(perm_folder.Get(IS_DEL));
   4210     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4211     EXPECT_FALSE(perm_folder.Get(IS_UNSYNCED));
   4212     EXPECT_TRUE(10 < perm_folder.Get(BASE_VERSION));
   4213     // Entry should have been given the new ID while preserving the
   4214     // metahandle; client should have won the conflict resolution.
   4215     EXPECT_EQ(original_metahandle, perm_folder.Get(META_HANDLE));
   4216     EXPECT_EQ("clientperm", perm_folder.Get(UNIQUE_CLIENT_TAG));
   4217     EXPECT_EQ("clientname", perm_folder.Get(NON_UNIQUE_NAME));
   4218     EXPECT_EQ(local_bookmark.SerializeAsString(),
   4219               perm_folder.Get(SPECIFICS).SerializeAsString());
   4220     EXPECT_TRUE(perm_folder.Get(ID).ServerKnows());
   4221   }
   4222 }
   4223 
   4224 TEST_F(SyncerTest, ClientTagConflictWithDeletedLocalEntry) {
   4225   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4226   EXPECT_TRUE(dir.good());
   4227 
   4228   {
   4229     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   4230     MutableEntry perm_folder(&trans, CREATE, ids_.root(), "clientname");
   4231     ASSERT_TRUE(perm_folder.good());
   4232     ASSERT_FALSE(perm_folder.Get(ID).ServerKnows());
   4233     perm_folder.Put(UNIQUE_CLIENT_TAG, "clientperm");
   4234     perm_folder.Put(SPECIFICS, DefaultBookmarkSpecifics());
   4235     perm_folder.Put(IS_UNSYNCED, true);
   4236     perm_folder.Put(IS_DEL, true);
   4237   }
   4238 
   4239   mock_server_->AddUpdateDirectory(1, 0, "permitem_renamed", 10, 100);
   4240   mock_server_->SetLastUpdateClientTag("clientperm");
   4241   mock_server_->set_conflict_all_commits(true);
   4242 
   4243   SyncShareAsDelegate();
   4244   // This should cause client tag overwrite.
   4245   {
   4246     ReadTransaction trans(dir, __FILE__, __LINE__);
   4247 
   4248     Entry perm_folder(&trans, GET_BY_CLIENT_TAG, "clientperm");
   4249     ASSERT_TRUE(perm_folder.good());
   4250     ASSERT_TRUE(perm_folder.Get(ID).ServerKnows());
   4251     EXPECT_TRUE(perm_folder.Get(IS_DEL));
   4252     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4253     EXPECT_TRUE(perm_folder.Get(IS_UNSYNCED));
   4254     EXPECT_EQ(perm_folder.Get(BASE_VERSION), 10);
   4255     EXPECT_EQ(perm_folder.Get(UNIQUE_CLIENT_TAG), "clientperm");
   4256   }
   4257 }
   4258 
   4259 TEST_F(SyncerTest, ClientTagUpdateClashesWithLocalEntry) {
   4260   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4261   EXPECT_TRUE(dir.good());
   4262 
   4263   // This test is written assuming that ID comparison
   4264   // will work out in a particular way.
   4265   EXPECT_TRUE(ids_.FromNumber(1) < ids_.FromNumber(2));
   4266   EXPECT_TRUE(ids_.FromNumber(3) < ids_.FromNumber(4));
   4267 
   4268   mock_server_->AddUpdateBookmark(1, 0, "One", 10, 100);
   4269   mock_server_->SetLastUpdateClientTag("tag1");
   4270   mock_server_->AddUpdateBookmark(4, 0, "Four", 11, 110);
   4271   mock_server_->SetLastUpdateClientTag("tag2");
   4272 
   4273   mock_server_->set_conflict_all_commits(true);
   4274 
   4275   SyncShareAsDelegate();
   4276   int64 tag1_metahandle = syncable::kInvalidMetaHandle;
   4277   int64 tag2_metahandle = syncable::kInvalidMetaHandle;
   4278   // This should cause client tag overwrite.
   4279   {
   4280     ReadTransaction trans(dir, __FILE__, __LINE__);
   4281 
   4282     Entry tag1(&trans, GET_BY_CLIENT_TAG, "tag1");
   4283     ASSERT_TRUE(tag1.good());
   4284     ASSERT_TRUE(tag1.Get(ID).ServerKnows());
   4285     ASSERT_TRUE(ids_.FromNumber(1) == tag1.Get(ID));
   4286     EXPECT_FALSE(tag1.Get(IS_DEL));
   4287     EXPECT_FALSE(tag1.Get(IS_UNAPPLIED_UPDATE));
   4288     EXPECT_FALSE(tag1.Get(IS_UNSYNCED));
   4289     EXPECT_EQ("One", tag1.Get(NON_UNIQUE_NAME));
   4290     EXPECT_EQ(10, tag1.Get(BASE_VERSION));
   4291     EXPECT_EQ("tag1", tag1.Get(UNIQUE_CLIENT_TAG));
   4292     tag1_metahandle = tag1.Get(META_HANDLE);
   4293 
   4294     Entry tag2(&trans, GET_BY_CLIENT_TAG, "tag2");
   4295     ASSERT_TRUE(tag2.good());
   4296     ASSERT_TRUE(tag2.Get(ID).ServerKnows());
   4297     ASSERT_TRUE(ids_.FromNumber(4) == tag2.Get(ID));
   4298     EXPECT_FALSE(tag2.Get(IS_DEL));
   4299     EXPECT_FALSE(tag2.Get(IS_UNAPPLIED_UPDATE));
   4300     EXPECT_FALSE(tag2.Get(IS_UNSYNCED));
   4301     EXPECT_EQ("Four", tag2.Get(NON_UNIQUE_NAME));
   4302     EXPECT_EQ(11, tag2.Get(BASE_VERSION));
   4303     EXPECT_EQ("tag2", tag2.Get(UNIQUE_CLIENT_TAG));
   4304     tag2_metahandle = tag2.Get(META_HANDLE);
   4305 
   4306     syncable::Directory::ChildHandles children;
   4307     dir->GetChildHandles(&trans, trans.root_id(), &children);
   4308     ASSERT_EQ(2U, children.size());
   4309   }
   4310 
   4311   mock_server_->AddUpdateBookmark(2, 0, "Two", 12, 120);
   4312   mock_server_->SetLastUpdateClientTag("tag1");
   4313   mock_server_->AddUpdateBookmark(3, 0, "Three", 13, 130);
   4314   mock_server_->SetLastUpdateClientTag("tag2");
   4315   SyncShareAsDelegate();
   4316 
   4317   {
   4318     ReadTransaction trans(dir, __FILE__, __LINE__);
   4319 
   4320     Entry tag1(&trans, GET_BY_CLIENT_TAG, "tag1");
   4321     ASSERT_TRUE(tag1.good());
   4322     ASSERT_TRUE(tag1.Get(ID).ServerKnows());
   4323     ASSERT_TRUE(ids_.FromNumber(1) == tag1.Get(ID))
   4324         << "ID 1 should be kept, since it was less than ID 2.";
   4325     EXPECT_FALSE(tag1.Get(IS_DEL));
   4326     EXPECT_FALSE(tag1.Get(IS_UNAPPLIED_UPDATE));
   4327     EXPECT_FALSE(tag1.Get(IS_UNSYNCED));
   4328     EXPECT_EQ(10, tag1.Get(BASE_VERSION));
   4329     EXPECT_EQ("tag1", tag1.Get(UNIQUE_CLIENT_TAG));
   4330     EXPECT_EQ("One", tag1.Get(NON_UNIQUE_NAME));
   4331     EXPECT_EQ(tag1_metahandle, tag1.Get(META_HANDLE));
   4332 
   4333     Entry tag2(&trans, GET_BY_CLIENT_TAG, "tag2");
   4334     ASSERT_TRUE(tag2.good());
   4335     ASSERT_TRUE(tag2.Get(ID).ServerKnows());
   4336     ASSERT_TRUE(ids_.FromNumber(3) == tag2.Get(ID))
   4337         << "ID 3 should be kept, since it was less than ID 4.";
   4338     EXPECT_FALSE(tag2.Get(IS_DEL));
   4339     EXPECT_FALSE(tag2.Get(IS_UNAPPLIED_UPDATE));
   4340     EXPECT_FALSE(tag2.Get(IS_UNSYNCED));
   4341     EXPECT_EQ("Three", tag2.Get(NON_UNIQUE_NAME));
   4342     EXPECT_EQ(13, tag2.Get(BASE_VERSION));
   4343     EXPECT_EQ("tag2", tag2.Get(UNIQUE_CLIENT_TAG));
   4344     EXPECT_EQ(tag2_metahandle, tag2.Get(META_HANDLE));
   4345 
   4346     syncable::Directory::ChildHandles children;
   4347     dir->GetChildHandles(&trans, trans.root_id(), &children);
   4348     ASSERT_EQ(2U, children.size());
   4349   }
   4350 }
   4351 
   4352 TEST_F(SyncerTest, ClientTagClashWithinBatchOfUpdates) {
   4353   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4354   EXPECT_TRUE(dir.good());
   4355 
   4356   // This test is written assuming that ID comparison
   4357   // will work out in a particular way.
   4358   EXPECT_TRUE(ids_.FromNumber(1) < ids_.FromNumber(4));
   4359   EXPECT_TRUE(ids_.FromNumber(201) < ids_.FromNumber(205));
   4360 
   4361   mock_server_->AddUpdateBookmark(1, 0, "One A", 1, 10);
   4362   mock_server_->SetLastUpdateClientTag("tag a");  // Least ID: winner.
   4363   mock_server_->AddUpdateBookmark(2, 0, "Two A", 11, 110);
   4364   mock_server_->SetLastUpdateClientTag("tag a");
   4365   mock_server_->AddUpdateBookmark(3, 0, "Three A", 12, 120);
   4366   mock_server_->SetLastUpdateClientTag("tag a");
   4367   mock_server_->AddUpdateBookmark(4, 0, "Four A", 13, 130);
   4368   mock_server_->SetLastUpdateClientTag("tag a");
   4369 
   4370   mock_server_->AddUpdateBookmark(105, 0, "One B", 14, 140);
   4371   mock_server_->SetLastUpdateClientTag("tag b");
   4372   mock_server_->AddUpdateBookmark(102, 0, "Two B", 15, 150);
   4373   mock_server_->SetLastUpdateClientTag("tag b");
   4374   mock_server_->AddUpdateBookmark(101, 0, "Three B", 16, 160);
   4375   mock_server_->SetLastUpdateClientTag("tag b");  // Least ID: winner.
   4376   mock_server_->AddUpdateBookmark(104, 0, "Four B", 17, 170);
   4377   mock_server_->SetLastUpdateClientTag("tag b");
   4378 
   4379   mock_server_->AddUpdateBookmark(205, 0, "One C", 18, 180);
   4380   mock_server_->SetLastUpdateClientTag("tag c");
   4381   mock_server_->AddUpdateBookmark(202, 0, "Two C", 19, 190);
   4382   mock_server_->SetLastUpdateClientTag("tag c");
   4383   mock_server_->AddUpdateBookmark(204, 0, "Three C", 20, 200);
   4384   mock_server_->SetLastUpdateClientTag("tag c");
   4385   mock_server_->AddUpdateBookmark(201, 0, "Four C", 21, 210);
   4386   mock_server_->SetLastUpdateClientTag("tag c");  // Least ID: winner.
   4387 
   4388   mock_server_->set_conflict_all_commits(true);
   4389 
   4390   SyncShareAsDelegate();
   4391   // This should cause client tag overwrite.
   4392   {
   4393     ReadTransaction trans(dir, __FILE__, __LINE__);
   4394 
   4395     Entry tag_a(&trans, GET_BY_CLIENT_TAG, "tag a");
   4396     ASSERT_TRUE(tag_a.good());
   4397     EXPECT_TRUE(tag_a.Get(ID).ServerKnows());
   4398     EXPECT_EQ(ids_.FromNumber(1), tag_a.Get(ID));
   4399     EXPECT_FALSE(tag_a.Get(IS_DEL));
   4400     EXPECT_FALSE(tag_a.Get(IS_UNAPPLIED_UPDATE));
   4401     EXPECT_FALSE(tag_a.Get(IS_UNSYNCED));
   4402     EXPECT_EQ("One A", tag_a.Get(NON_UNIQUE_NAME));
   4403     EXPECT_EQ(1, tag_a.Get(BASE_VERSION));
   4404     EXPECT_EQ("tag a", tag_a.Get(UNIQUE_CLIENT_TAG));
   4405 
   4406     Entry tag_b(&trans, GET_BY_CLIENT_TAG, "tag b");
   4407     ASSERT_TRUE(tag_b.good());
   4408     EXPECT_TRUE(tag_b.Get(ID).ServerKnows());
   4409     EXPECT_EQ(ids_.FromNumber(101), tag_b.Get(ID));
   4410     EXPECT_FALSE(tag_b.Get(IS_DEL));
   4411     EXPECT_FALSE(tag_b.Get(IS_UNAPPLIED_UPDATE));
   4412     EXPECT_FALSE(tag_b.Get(IS_UNSYNCED));
   4413     EXPECT_EQ("Three B", tag_b.Get(NON_UNIQUE_NAME));
   4414     EXPECT_EQ(16, tag_b.Get(BASE_VERSION));
   4415     EXPECT_EQ("tag b", tag_b.Get(UNIQUE_CLIENT_TAG));
   4416 
   4417     Entry tag_c(&trans, GET_BY_CLIENT_TAG, "tag c");
   4418     ASSERT_TRUE(tag_c.good());
   4419     EXPECT_TRUE(tag_c.Get(ID).ServerKnows());
   4420     EXPECT_EQ(ids_.FromNumber(201), tag_c.Get(ID));
   4421     EXPECT_FALSE(tag_c.Get(IS_DEL));
   4422     EXPECT_FALSE(tag_c.Get(IS_UNAPPLIED_UPDATE));
   4423     EXPECT_FALSE(tag_c.Get(IS_UNSYNCED));
   4424     EXPECT_EQ("Four C", tag_c.Get(NON_UNIQUE_NAME));
   4425     EXPECT_EQ(21, tag_c.Get(BASE_VERSION));
   4426     EXPECT_EQ("tag c", tag_c.Get(UNIQUE_CLIENT_TAG));
   4427 
   4428     syncable::Directory::ChildHandles children;
   4429     dir->GetChildHandles(&trans, trans.root_id(), &children);
   4430     ASSERT_EQ(3U, children.size());
   4431   }
   4432 }
   4433 
   4434 TEST_F(SyncerTest, UniqueServerTagUpdates) {
   4435   ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4436   EXPECT_TRUE(dir.good());
   4437   // As a hurdle, introduce an item whose name is the same as the tag value
   4438   // we'll use later.
   4439   int64 hurdle_handle = CreateUnsyncedDirectory("bob", "id_bob");
   4440   {
   4441     ReadTransaction trans(dir, __FILE__, __LINE__);
   4442     Entry hurdle(&trans, GET_BY_HANDLE, hurdle_handle);
   4443     ASSERT_TRUE(hurdle.good());
   4444     ASSERT_TRUE(!hurdle.Get(IS_DEL));
   4445     ASSERT_TRUE(hurdle.Get(UNIQUE_SERVER_TAG).empty());
   4446     ASSERT_TRUE(hurdle.Get(NON_UNIQUE_NAME) == "bob");
   4447 
   4448     // Try to lookup by the tagname.  These should fail.
   4449     Entry tag_alpha(&trans, GET_BY_SERVER_TAG, "alpha");
   4450     EXPECT_FALSE(tag_alpha.good());
   4451     Entry tag_bob(&trans, GET_BY_SERVER_TAG, "bob");
   4452     EXPECT_FALSE(tag_bob.good());
   4453   }
   4454 
   4455   // Now download some tagged items as updates.
   4456   mock_server_->AddUpdateDirectory(1, 0, "update1", 1, 10);
   4457   mock_server_->SetLastUpdateServerTag("alpha");
   4458   mock_server_->AddUpdateDirectory(2, 0, "update2", 2, 20);
   4459   mock_server_->SetLastUpdateServerTag("bob");
   4460   SyncShareAsDelegate();
   4461 
   4462   {
   4463     ReadTransaction trans(dir, __FILE__, __LINE__);
   4464 
   4465     // The new items should be applied as new entries, and we should be able
   4466     // to look them up by their tag values.
   4467     Entry tag_alpha(&trans, GET_BY_SERVER_TAG, "alpha");
   4468     ASSERT_TRUE(tag_alpha.good());
   4469     ASSERT_TRUE(!tag_alpha.Get(IS_DEL));
   4470     ASSERT_TRUE(tag_alpha.Get(UNIQUE_SERVER_TAG) == "alpha");
   4471     ASSERT_TRUE(tag_alpha.Get(NON_UNIQUE_NAME) == "update1");
   4472     Entry tag_bob(&trans, GET_BY_SERVER_TAG, "bob");
   4473     ASSERT_TRUE(tag_bob.good());
   4474     ASSERT_TRUE(!tag_bob.Get(IS_DEL));
   4475     ASSERT_TRUE(tag_bob.Get(UNIQUE_SERVER_TAG) == "bob");
   4476     ASSERT_TRUE(tag_bob.Get(NON_UNIQUE_NAME) == "update2");
   4477     // The old item should be unchanged.
   4478     Entry hurdle(&trans, GET_BY_HANDLE, hurdle_handle);
   4479     ASSERT_TRUE(hurdle.good());
   4480     ASSERT_TRUE(!hurdle.Get(IS_DEL));
   4481     ASSERT_TRUE(hurdle.Get(UNIQUE_SERVER_TAG).empty());
   4482     ASSERT_TRUE(hurdle.Get(NON_UNIQUE_NAME) == "bob");
   4483   }
   4484 }
   4485 
   4486 TEST_F(SyncerTest, GetUpdatesSetsRequestedTypes) {
   4487   // The expectations of this test happen in the MockConnectionManager's
   4488   // GetUpdates handler.  EnableDatatype sets the expectation value from our
   4489   // set of enabled/disabled datatypes.
   4490   EnableDatatype(syncable::BOOKMARKS);
   4491   SyncShareAsDelegate();
   4492   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4493 
   4494   EnableDatatype(syncable::AUTOFILL);
   4495   SyncShareAsDelegate();
   4496   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4497 
   4498   EnableDatatype(syncable::PREFERENCES);
   4499   SyncShareAsDelegate();
   4500   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4501 
   4502   DisableDatatype(syncable::BOOKMARKS);
   4503   SyncShareAsDelegate();
   4504   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4505 
   4506   DisableDatatype(syncable::AUTOFILL);
   4507   SyncShareAsDelegate();
   4508   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4509 
   4510   DisableDatatype(syncable::PREFERENCES);
   4511   EnableDatatype(syncable::AUTOFILL);
   4512   SyncShareAsDelegate();
   4513   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4514 }
   4515 
   4516 // Test what happens if a client deletes, then recreates, an object very
   4517 // quickly.  It is possible that the deletion gets sent as a commit, and
   4518 // the undelete happens during the commit request.  The principle here
   4519 // is that with a single committing client, conflicts should never
   4520 // be encountered, and a client encountering its past actions during
   4521 // getupdates should never feed back to override later actions.
   4522 //
   4523 // In cases of ordering A-F below, the outcome should be the same.
   4524 //   Exercised by UndeleteDuringCommit:
   4525 //     A. Delete - commit - undelete - commitresponse.
   4526 //     B. Delete - commit - undelete - commitresponse - getupdates.
   4527 //   Exercised by UndeleteBeforeCommit:
   4528 //     C. Delete - undelete - commit - commitresponse.
   4529 //     D. Delete - undelete - commit - commitresponse - getupdates.
   4530 //   Exercised by UndeleteAfterCommit:
   4531 //     E. Delete - commit - commitresponse - undelete - commit
   4532 //        - commitresponse.
   4533 //     F. Delete - commit - commitresponse - undelete - commit -
   4534 //        - commitresponse - getupdates.
   4535 class SyncerUndeletionTest : public SyncerTest {
   4536  public:
   4537   SyncerUndeletionTest()
   4538       : client_tag_("foobar"),
   4539         metahandle_(syncable::kInvalidMetaHandle) {
   4540   }
   4541 
   4542   void Create() {
   4543     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4544     EXPECT_TRUE(dir.good());
   4545     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   4546     MutableEntry perm_folder(&trans, CREATE, ids_.root(), "clientname");
   4547     ASSERT_TRUE(perm_folder.good());
   4548     perm_folder.Put(UNIQUE_CLIENT_TAG, client_tag_);
   4549     perm_folder.Put(IS_UNSYNCED, true);
   4550     perm_folder.Put(SYNCING, false);
   4551     perm_folder.Put(SPECIFICS, DefaultBookmarkSpecifics());
   4552     EXPECT_FALSE(perm_folder.Get(IS_UNAPPLIED_UPDATE));
   4553     EXPECT_FALSE(perm_folder.Get(ID).ServerKnows());
   4554     metahandle_ = perm_folder.Get(META_HANDLE);
   4555   }
   4556 
   4557   void Delete() {
   4558     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4559     EXPECT_TRUE(dir.good());
   4560     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   4561     MutableEntry entry(&trans, GET_BY_CLIENT_TAG, client_tag_);
   4562     ASSERT_TRUE(entry.good());
   4563     EXPECT_EQ(metahandle_, entry.Get(META_HANDLE));
   4564     entry.Put(IS_DEL, true);
   4565     entry.Put(IS_UNSYNCED, true);
   4566     entry.Put(SYNCING, false);
   4567   }
   4568 
   4569   void Undelete() {
   4570     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4571     EXPECT_TRUE(dir.good());
   4572     WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
   4573     MutableEntry entry(&trans, GET_BY_CLIENT_TAG, client_tag_);
   4574     ASSERT_TRUE(entry.good());
   4575     EXPECT_EQ(metahandle_, entry.Get(META_HANDLE));
   4576     EXPECT_TRUE(entry.Get(IS_DEL));
   4577     entry.Put(IS_DEL, false);
   4578     entry.Put(IS_UNSYNCED, true);
   4579     entry.Put(SYNCING, false);
   4580   }
   4581 
   4582   int64 GetMetahandleOfTag() {
   4583     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4584     EXPECT_TRUE(dir.good());
   4585     ReadTransaction trans(dir, __FILE__, __LINE__);
   4586     Entry entry(&trans, GET_BY_CLIENT_TAG, client_tag_);
   4587     EXPECT_TRUE(entry.good());
   4588     if (!entry.good()) {
   4589       return syncable::kInvalidMetaHandle;
   4590     }
   4591     return entry.Get(META_HANDLE);
   4592   }
   4593 
   4594   void ExpectUnsyncedCreation() {
   4595     EXPECT_EQ(metahandle_, GetMetahandleOfTag());
   4596     EXPECT_FALSE(Get(metahandle_, IS_DEL));
   4597     EXPECT_FALSE(Get(metahandle_, SERVER_IS_DEL));  // Never been committed.
   4598     EXPECT_GE(0, Get(metahandle_, BASE_VERSION));
   4599     EXPECT_TRUE(Get(metahandle_, IS_UNSYNCED));
   4600     EXPECT_FALSE(Get(metahandle_, IS_UNAPPLIED_UPDATE));
   4601   }
   4602 
   4603   void ExpectUnsyncedUndeletion() {
   4604     EXPECT_EQ(metahandle_, GetMetahandleOfTag());
   4605     EXPECT_FALSE(Get(metahandle_, IS_DEL));
   4606     EXPECT_TRUE(Get(metahandle_, SERVER_IS_DEL));
   4607     EXPECT_EQ(0, Get(metahandle_, BASE_VERSION));
   4608     EXPECT_TRUE(Get(metahandle_, IS_UNSYNCED));
   4609     EXPECT_FALSE(Get(metahandle_, IS_UNAPPLIED_UPDATE));
   4610     EXPECT_TRUE(Get(metahandle_, ID).ServerKnows());
   4611   }
   4612 
   4613   void ExpectUnsyncedEdit() {
   4614     EXPECT_EQ(metahandle_, GetMetahandleOfTag());
   4615     EXPECT_FALSE(Get(metahandle_, IS_DEL));
   4616     EXPECT_FALSE(Get(metahandle_, SERVER_IS_DEL));
   4617     EXPECT_LT(0, Get(metahandle_, BASE_VERSION));
   4618     EXPECT_TRUE(Get(metahandle_, IS_UNSYNCED));
   4619     EXPECT_FALSE(Get(metahandle_, IS_UNAPPLIED_UPDATE));
   4620     EXPECT_TRUE(Get(metahandle_, ID).ServerKnows());
   4621   }
   4622 
   4623   void ExpectUnsyncedDeletion() {
   4624     EXPECT_EQ(metahandle_, GetMetahandleOfTag());
   4625     EXPECT_TRUE(Get(metahandle_, IS_DEL));
   4626     EXPECT_FALSE(Get(metahandle_, SERVER_IS_DEL));
   4627     EXPECT_TRUE(Get(metahandle_, IS_UNSYNCED));
   4628     EXPECT_FALSE(Get(metahandle_, IS_UNAPPLIED_UPDATE));
   4629     EXPECT_LT(0, Get(metahandle_, BASE_VERSION));
   4630     EXPECT_LT(0, Get(metahandle_, SERVER_VERSION));
   4631   }
   4632 
   4633   void ExpectSyncedAndCreated() {
   4634     EXPECT_EQ(metahandle_, GetMetahandleOfTag());
   4635     EXPECT_FALSE(Get(metahandle_, IS_DEL));
   4636     EXPECT_FALSE(Get(metahandle_, SERVER_IS_DEL));
   4637     EXPECT_LT(0, Get(metahandle_, BASE_VERSION));
   4638     EXPECT_EQ(Get(metahandle_, BASE_VERSION), Get(metahandle_, SERVER_VERSION));
   4639     EXPECT_FALSE(Get(metahandle_, IS_UNSYNCED));
   4640     EXPECT_FALSE(Get(metahandle_, IS_UNAPPLIED_UPDATE));
   4641   }
   4642 
   4643   void ExpectSyncedAndDeleted() {
   4644     EXPECT_EQ(metahandle_, GetMetahandleOfTag());
   4645     EXPECT_TRUE(Get(metahandle_, IS_DEL));
   4646     EXPECT_TRUE(Get(metahandle_, SERVER_IS_DEL));
   4647     EXPECT_FALSE(Get(metahandle_, IS_UNSYNCED));
   4648     EXPECT_FALSE(Get(metahandle_, IS_UNAPPLIED_UPDATE));
   4649     EXPECT_GE(0, Get(metahandle_, BASE_VERSION));
   4650     EXPECT_GE(0, Get(metahandle_, SERVER_VERSION));
   4651   }
   4652 
   4653  protected:
   4654   const std::string client_tag_;
   4655   int64 metahandle_;
   4656 };
   4657 
   4658 TEST_F(SyncerUndeletionTest, UndeleteDuringCommit) {
   4659   StatusController* status = session_->status_controller();
   4660 
   4661   Create();
   4662   ExpectUnsyncedCreation();
   4663   SyncShareAsDelegate();
   4664 
   4665   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4666   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4667   ExpectSyncedAndCreated();
   4668 
   4669   // Delete, begin committing the delete, then undelete while committing.
   4670   Delete();
   4671   ExpectUnsyncedDeletion();
   4672   mock_server_->SetMidCommitCallback(
   4673       NewCallback<SyncerUndeletionTest>(this,
   4674           &SyncerUndeletionTest::Undelete));
   4675   SyncShareAsDelegate();
   4676 
   4677   // The item ought to exist as an unsynced undeletion (meaning,
   4678   // we think that the next commit ought to be a recreation commit).
   4679   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4680   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4681   ExpectUnsyncedUndeletion();
   4682 
   4683   // Now, encounter a GetUpdates corresponding to the deletion from
   4684   // the server.  The undeletion should prevail again and be committed.
   4685   // None of this should trigger any conflict detection -- it is perfectly
   4686   // normal to recieve updates from our own commits.
   4687   mock_server_->SetMidCommitCallback(NULL);
   4688   mock_server_->AddUpdateTombstone(Get(metahandle_, ID));
   4689   SyncShareAsDelegate();
   4690   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4691   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4692   ExpectSyncedAndCreated();
   4693 }
   4694 
   4695 TEST_F(SyncerUndeletionTest, UndeleteBeforeCommit) {
   4696   StatusController* status = session_->status_controller();
   4697 
   4698   Create();
   4699   ExpectUnsyncedCreation();
   4700   SyncShareAsDelegate();
   4701 
   4702   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4703   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4704   ExpectSyncedAndCreated();
   4705 
   4706   // Delete and undelete, then sync to pick up the result.
   4707   Delete();
   4708   ExpectUnsyncedDeletion();
   4709   Undelete();
   4710   ExpectUnsyncedEdit();  // Edit, not undelete: server thinks it exists.
   4711   SyncShareAsDelegate();
   4712 
   4713   // The item ought to have committed successfully.
   4714   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4715   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4716   ExpectSyncedAndCreated();
   4717   EXPECT_EQ(2, Get(metahandle_, BASE_VERSION));
   4718 
   4719   // Now, encounter a GetUpdates corresponding to the just-committed
   4720   // update.
   4721   mock_server_->AddUpdateFromLastCommit();
   4722   SyncShareAsDelegate();
   4723   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4724   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4725   ExpectSyncedAndCreated();
   4726 }
   4727 
   4728 TEST_F(SyncerUndeletionTest, UndeleteAfterCommitButBeforeGetUpdates) {
   4729   StatusController* status = session_->status_controller();
   4730 
   4731   Create();
   4732   ExpectUnsyncedCreation();
   4733   SyncShareAsDelegate();
   4734 
   4735   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4736   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4737   ExpectSyncedAndCreated();
   4738 
   4739   // Delete and commit.
   4740   Delete();
   4741   ExpectUnsyncedDeletion();
   4742   SyncShareAsDelegate();
   4743 
   4744   // The item ought to have committed successfully.
   4745   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4746   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4747   ExpectSyncedAndDeleted();
   4748 
   4749   // Before the GetUpdates, the item is locally undeleted.
   4750   Undelete();
   4751   ExpectUnsyncedUndeletion();
   4752 
   4753   // Now, encounter a GetUpdates corresponding to the just-committed
   4754   // deletion update.  The undeletion should prevail.
   4755   mock_server_->AddUpdateFromLastCommit();
   4756   SyncShareAsDelegate();
   4757   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4758   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4759   ExpectSyncedAndCreated();
   4760 }
   4761 
   4762 TEST_F(SyncerUndeletionTest, UndeleteAfterDeleteAndGetUpdates) {
   4763   StatusController* status = session_->status_controller();
   4764 
   4765   Create();
   4766   ExpectUnsyncedCreation();
   4767   SyncShareAsDelegate();
   4768 
   4769   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4770   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4771   ExpectSyncedAndCreated();
   4772 
   4773   mock_server_->AddUpdateFromLastCommit();
   4774   SyncShareAsDelegate();
   4775   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4776   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4777   ExpectSyncedAndCreated();
   4778 
   4779   // Delete and commit.
   4780   Delete();
   4781   ExpectUnsyncedDeletion();
   4782   SyncShareAsDelegate();
   4783 
   4784   // The item ought to have committed successfully.
   4785   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4786   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4787   ExpectSyncedAndDeleted();
   4788 
   4789   // Now, encounter a GetUpdates corresponding to the just-committed
   4790   // deletion update.  Should be consistent.
   4791   mock_server_->AddUpdateFromLastCommit();
   4792   SyncShareAsDelegate();
   4793   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4794   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4795   ExpectSyncedAndDeleted();
   4796 
   4797   // After the GetUpdates, the item is locally undeleted.
   4798   Undelete();
   4799   ExpectUnsyncedUndeletion();
   4800 
   4801   // Now, encounter a GetUpdates corresponding to the just-committed
   4802   // deletion update.  The undeletion should prevail.
   4803   SyncShareAsDelegate();
   4804   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4805   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4806   ExpectSyncedAndCreated();
   4807 }
   4808 
   4809 // Test processing of undeletion GetUpdateses.
   4810 TEST_F(SyncerUndeletionTest, UndeleteAfterOtherClientDeletes) {
   4811   StatusController* status = session_->status_controller();
   4812 
   4813   Create();
   4814   ExpectUnsyncedCreation();
   4815   SyncShareAsDelegate();
   4816 
   4817   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4818   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4819   ExpectSyncedAndCreated();
   4820 
   4821   // Add a delete from the server.
   4822   mock_server_->AddUpdateFromLastCommit();
   4823   SyncShareAsDelegate();
   4824   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4825   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4826   ExpectSyncedAndCreated();
   4827 
   4828   // Some other client deletes the item.
   4829   mock_server_->AddUpdateTombstone(Get(metahandle_, ID));
   4830   SyncShareAsDelegate();
   4831 
   4832   // The update ought to have applied successfully.
   4833   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4834   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4835   ExpectSyncedAndDeleted();
   4836 
   4837   // Undelete it locally.
   4838   Undelete();
   4839   ExpectUnsyncedUndeletion();
   4840   SyncShareAsDelegate();
   4841   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4842   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4843   ExpectSyncedAndCreated();
   4844 
   4845   // Now, encounter a GetUpdates corresponding to the just-committed
   4846   // deletion update.  The undeletion should prevail.
   4847   mock_server_->AddUpdateFromLastCommit();
   4848   SyncShareAsDelegate();
   4849   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4850   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4851   ExpectSyncedAndCreated();
   4852 }
   4853 
   4854 TEST_F(SyncerUndeletionTest, UndeleteAfterOtherClientDeletesImmediately) {
   4855   StatusController* status = session_->status_controller();
   4856 
   4857   Create();
   4858   ExpectUnsyncedCreation();
   4859   SyncShareAsDelegate();
   4860 
   4861   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4862   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4863   ExpectSyncedAndCreated();
   4864 
   4865   // Some other client deletes the item before we get a chance
   4866   // to GetUpdates our original request.
   4867   mock_server_->AddUpdateTombstone(Get(metahandle_, ID));
   4868   SyncShareAsDelegate();
   4869 
   4870   // The update ought to have applied successfully.
   4871   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4872   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4873   ExpectSyncedAndDeleted();
   4874 
   4875   // Undelete it locally.
   4876   Undelete();
   4877   ExpectUnsyncedUndeletion();
   4878   SyncShareAsDelegate();
   4879   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4880   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4881   ExpectSyncedAndCreated();
   4882 
   4883   // Now, encounter a GetUpdates corresponding to the just-committed
   4884   // deletion update.  The undeletion should prevail.
   4885   mock_server_->AddUpdateFromLastCommit();
   4886   SyncShareAsDelegate();
   4887   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4888   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4889   ExpectSyncedAndCreated();
   4890 }
   4891 
   4892 TEST_F(SyncerUndeletionTest, OtherClientUndeletes) {
   4893   StatusController* status = session_->status_controller();
   4894 
   4895   Create();
   4896   ExpectUnsyncedCreation();
   4897   SyncShareAsDelegate();
   4898 
   4899   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4900   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4901   ExpectSyncedAndCreated();
   4902 
   4903   // Get the updates of our just-committed entry.
   4904   mock_server_->AddUpdateFromLastCommit();
   4905   SyncShareAsDelegate();
   4906   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4907   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4908   ExpectSyncedAndCreated();
   4909 
   4910   // We delete the item.
   4911   Delete();
   4912   ExpectUnsyncedDeletion();
   4913   SyncShareAsDelegate();
   4914 
   4915   // The update ought to have applied successfully.
   4916   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4917   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4918   ExpectSyncedAndDeleted();
   4919 
   4920   // Now, encounter a GetUpdates corresponding to the just-committed
   4921   // deletion update.
   4922   mock_server_->AddUpdateFromLastCommit();
   4923   SyncShareAsDelegate();
   4924   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4925   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4926   ExpectSyncedAndDeleted();
   4927 
   4928   // Some other client undeletes the item.
   4929   mock_server_->AddUpdateBookmark(Get(metahandle_, ID),
   4930                                   Get(metahandle_, PARENT_ID),
   4931                                   "Thadeusz", 100, 1000);
   4932   mock_server_->SetLastUpdateClientTag(client_tag_);
   4933   SyncShareAsDelegate();
   4934   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4935   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4936   ExpectSyncedAndCreated();
   4937   EXPECT_EQ("Thadeusz", Get(metahandle_, NON_UNIQUE_NAME));
   4938 }
   4939 
   4940 TEST_F(SyncerUndeletionTest, OtherClientUndeletesImmediately) {
   4941   StatusController* status = session_->status_controller();
   4942 
   4943   Create();
   4944   ExpectUnsyncedCreation();
   4945   SyncShareAsDelegate();
   4946 
   4947   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4948   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4949   ExpectSyncedAndCreated();
   4950 
   4951   // Get the updates of our just-committed entry.
   4952   mock_server_->AddUpdateFromLastCommit();
   4953   SyncShareAsDelegate();
   4954   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4955   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4956   ExpectSyncedAndCreated();
   4957 
   4958   // We delete the item.
   4959   Delete();
   4960   ExpectUnsyncedDeletion();
   4961   SyncShareAsDelegate();
   4962 
   4963   // The update ought to have applied successfully.
   4964   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4965   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4966   ExpectSyncedAndDeleted();
   4967 
   4968   // Some other client undeletes before we see the update from our
   4969   // commit.
   4970   mock_server_->AddUpdateBookmark(Get(metahandle_, ID),
   4971                                   Get(metahandle_, PARENT_ID),
   4972                                   "Thadeusz", 100, 1000);
   4973   mock_server_->SetLastUpdateClientTag(client_tag_);
   4974   SyncShareAsDelegate();
   4975   EXPECT_EQ(0, status->TotalNumConflictingItems());
   4976   EXPECT_EQ(1, mock_server_->GetAndClearNumGetUpdatesRequests());
   4977   ExpectSyncedAndCreated();
   4978   EXPECT_EQ("Thadeusz", Get(metahandle_, NON_UNIQUE_NAME));
   4979 }
   4980 
   4981 // A group of tests exercising the syncer's handling of sibling ordering, as
   4982 // represented in the sync protocol.
   4983 class SyncerPositionUpdateTest : public SyncerTest {
   4984  public:
   4985   SyncerPositionUpdateTest() : next_update_id_(1), next_revision_(1) {}
   4986 
   4987  protected:
   4988   void ExpectLocalItemsInServerOrder() {
   4989     if (position_map_.empty())
   4990       return;
   4991 
   4992     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   4993     EXPECT_TRUE(dir.good());
   4994     ReadTransaction trans(dir, __FILE__, __LINE__);
   4995 
   4996     Id prev_id;
   4997     DCHECK(prev_id.IsRoot());
   4998     PosMap::iterator next = position_map_.begin();
   4999     for (PosMap::iterator i = next++; i != position_map_.end(); ++i) {
   5000       Id id = i->second;
   5001       Entry entry_with_id(&trans, GET_BY_ID, id);
   5002       EXPECT_TRUE(entry_with_id.good());
   5003       EXPECT_EQ(prev_id, entry_with_id.Get(PREV_ID));
   5004       EXPECT_EQ(i->first, entry_with_id.Get(SERVER_POSITION_IN_PARENT));
   5005       if (next == position_map_.end()) {
   5006         EXPECT_EQ(Id(), entry_with_id.Get(NEXT_ID));
   5007       } else {
   5008         EXPECT_EQ(next->second, entry_with_id.Get(NEXT_ID));
   5009         next++;
   5010       }
   5011       prev_id = id;
   5012     }
   5013   }
   5014 
   5015   void AddRootItemWithPosition(int64 position) {
   5016     string id = string("ServerId") + base::Int64ToString(next_update_id_++);
   5017     string name = "my name is my id -- " + id;
   5018     int revision = next_revision_++;
   5019     mock_server_->AddUpdateDirectory(id, kRootId, name, revision, revision);
   5020     mock_server_->SetLastUpdatePosition(position);
   5021     position_map_.insert(
   5022         PosMap::value_type(position, Id::CreateFromServerId(id)));
   5023   }
   5024  private:
   5025   typedef multimap<int64, Id> PosMap;
   5026   PosMap position_map_;
   5027   int next_update_id_;
   5028   int next_revision_;
   5029   DISALLOW_COPY_AND_ASSIGN(SyncerPositionUpdateTest);
   5030 };
   5031 
   5032 TEST_F(SyncerPositionUpdateTest, InOrderPositive) {
   5033   // Add a bunch of items in increasing order, starting with just positive
   5034   // position values.
   5035   AddRootItemWithPosition(100);
   5036   AddRootItemWithPosition(199);
   5037   AddRootItemWithPosition(200);
   5038   AddRootItemWithPosition(201);
   5039   AddRootItemWithPosition(400);
   5040 
   5041   SyncShareAsDelegate();
   5042   ExpectLocalItemsInServerOrder();
   5043 }
   5044 
   5045 TEST_F(SyncerPositionUpdateTest, InOrderNegative) {
   5046   // Test negative position values, but in increasing order.
   5047   AddRootItemWithPosition(-400);
   5048   AddRootItemWithPosition(-201);
   5049   AddRootItemWithPosition(-200);
   5050   AddRootItemWithPosition(-150);
   5051   AddRootItemWithPosition(100);
   5052 
   5053   SyncShareAsDelegate();
   5054   ExpectLocalItemsInServerOrder();
   5055 }
   5056 
   5057 TEST_F(SyncerPositionUpdateTest, ReverseOrder) {
   5058   // Test when items are sent in the reverse order.
   5059   AddRootItemWithPosition(400);
   5060   AddRootItemWithPosition(201);
   5061   AddRootItemWithPosition(200);
   5062   AddRootItemWithPosition(100);
   5063   AddRootItemWithPosition(-150);
   5064   AddRootItemWithPosition(-201);
   5065   AddRootItemWithPosition(-200);
   5066   AddRootItemWithPosition(-400);
   5067 
   5068   SyncShareAsDelegate();
   5069   ExpectLocalItemsInServerOrder();
   5070 }
   5071 
   5072 TEST_F(SyncerPositionUpdateTest, RandomOrderInBatches) {
   5073   // Mix it all up, interleaving position values, and try multiple batches of
   5074   // updates.
   5075   AddRootItemWithPosition(400);
   5076   AddRootItemWithPosition(201);
   5077   AddRootItemWithPosition(-400);
   5078   AddRootItemWithPosition(100);
   5079 
   5080   SyncShareAsDelegate();
   5081   ExpectLocalItemsInServerOrder();
   5082 
   5083   AddRootItemWithPosition(-150);
   5084   AddRootItemWithPosition(-200);
   5085   AddRootItemWithPosition(200);
   5086   AddRootItemWithPosition(-201);
   5087 
   5088   SyncShareAsDelegate();
   5089   ExpectLocalItemsInServerOrder();
   5090 
   5091   AddRootItemWithPosition(-144);
   5092 
   5093   SyncShareAsDelegate();
   5094   ExpectLocalItemsInServerOrder();
   5095 }
   5096 
   5097 class SyncerPositionTiebreakingTest : public SyncerTest {
   5098  public:
   5099   SyncerPositionTiebreakingTest()
   5100       : low_id_(Id::CreateFromServerId("A")),
   5101         mid_id_(Id::CreateFromServerId("M")),
   5102         high_id_(Id::CreateFromServerId("Z")),
   5103         next_revision_(1) {
   5104     DCHECK(low_id_ < mid_id_);
   5105     DCHECK(mid_id_ < high_id_);
   5106     DCHECK(low_id_ < high_id_);
   5107   }
   5108 
   5109   // Adds the item by its Id, using a constant value for the position
   5110   // so that the syncer has to resolve the order some other way.
   5111   void Add(const Id& id) {
   5112     int revision = next_revision_++;
   5113     mock_server_->AddUpdateDirectory(id.GetServerId(), kRootId,
   5114         id.GetServerId(), revision, revision);
   5115     // The update position doesn't vary.
   5116     mock_server_->SetLastUpdatePosition(90210);
   5117   }
   5118 
   5119   void ExpectLocalOrderIsByServerId() {
   5120     ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
   5121     EXPECT_TRUE(dir.good());
   5122     ReadTransaction trans(dir, __FILE__, __LINE__);
   5123     Id null_id;
   5124     Entry low(&trans, GET_BY_ID, low_id_);
   5125     Entry mid(&trans, GET_BY_ID, mid_id_);
   5126     Entry high(&trans, GET_BY_ID, high_id_);
   5127     EXPECT_TRUE(low.good());
   5128     EXPECT_TRUE(mid.good());
   5129     EXPECT_TRUE(high.good());
   5130     EXPECT_TRUE(low.Get(PREV_ID) == null_id);
   5131     EXPECT_TRUE(mid.Get(PREV_ID) == low_id_);
   5132     EXPECT_TRUE(high.Get(PREV_ID) == mid_id_);
   5133     EXPECT_TRUE(high.Get(NEXT_ID) == null_id);
   5134     EXPECT_TRUE(mid.Get(NEXT_ID) == high_id_);
   5135     EXPECT_TRUE(low.Get(NEXT_ID) == mid_id_);
   5136   }
   5137 
   5138  protected:
   5139   // When there's a tiebreak on the numeric position, it's supposed to be
   5140   // broken by string comparison of the ids.  These ids are in increasing
   5141   // order.
   5142   const Id low_id_;
   5143   const Id mid_id_;
   5144   const Id high_id_;
   5145 
   5146  private:
   5147   int next_revision_;
   5148   DISALLOW_COPY_AND_ASSIGN(SyncerPositionTiebreakingTest);
   5149 };
   5150 
   5151 TEST_F(SyncerPositionTiebreakingTest, LowMidHigh) {
   5152   Add(low_id_);
   5153   Add(mid_id_);
   5154   Add(high_id_);
   5155   SyncShareAsDelegate();
   5156   ExpectLocalOrderIsByServerId();
   5157 }
   5158 
   5159 TEST_F(SyncerPositionTiebreakingTest, LowHighMid) {
   5160   Add(low_id_);
   5161   Add(high_id_);
   5162   Add(mid_id_);
   5163   SyncShareAsDelegate();
   5164   ExpectLocalOrderIsByServerId();
   5165 }
   5166 
   5167 TEST_F(SyncerPositionTiebreakingTest, HighMidLow) {
   5168   Add(high_id_);
   5169   Add(mid_id_);
   5170   Add(low_id_);
   5171   SyncShareAsDelegate();
   5172   ExpectLocalOrderIsByServerId();
   5173 }
   5174 
   5175 TEST_F(SyncerPositionTiebreakingTest, HighLowMid) {
   5176   Add(high_id_);
   5177   Add(low_id_);
   5178   Add(mid_id_);
   5179   SyncShareAsDelegate();
   5180   ExpectLocalOrderIsByServerId();
   5181 }
   5182 
   5183 TEST_F(SyncerPositionTiebreakingTest, MidHighLow) {
   5184   Add(mid_id_);
   5185   Add(high_id_);
   5186   Add(low_id_);
   5187   SyncShareAsDelegate();
   5188   ExpectLocalOrderIsByServerId();
   5189 }
   5190 
   5191 TEST_F(SyncerPositionTiebreakingTest, MidLowHigh) {
   5192   Add(mid_id_);
   5193   Add(low_id_);
   5194   Add(high_id_);
   5195   SyncShareAsDelegate();
   5196   ExpectLocalOrderIsByServerId();
   5197 }
   5198 
   5199 const SyncerTest::CommitOrderingTest
   5200 SyncerTest::CommitOrderingTest::LAST_COMMIT_ITEM = {-1, TestIdFactory::root()};
   5201 
   5202 }  // namespace browser_sync
   5203