Home | History | Annotate | Download | only in sessions
      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 #include "chrome/browser/sync/sessions/sync_session.h"
      6 
      7 #include "base/memory/ref_counted.h"
      8 #include "chrome/browser/sync/engine/conflict_resolver.h"
      9 #include "chrome/browser/sync/engine/mock_model_safe_workers.h"
     10 #include "chrome/browser/sync/engine/syncer_types.h"
     11 #include "chrome/browser/sync/engine/syncer_util.h"
     12 #include "chrome/browser/sync/syncable/directory_manager.h"
     13 #include "chrome/browser/sync/syncable/model_type.h"
     14 #include "chrome/browser/sync/syncable/syncable.h"
     15 #include "chrome/test/sync/engine/test_directory_setter_upper.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 using syncable::WriteTransaction;
     19 
     20 namespace browser_sync {
     21 namespace sessions {
     22 namespace {
     23 
     24 class SyncSessionTest : public testing::Test,
     25                         public SyncSession::Delegate,
     26                         public ModelSafeWorkerRegistrar {
     27  public:
     28   SyncSessionTest() : controller_invocations_allowed_(false) {
     29     GetModelSafeRoutingInfo(&routes_);
     30   }
     31 
     32   SyncSession* MakeSession() {
     33     return new SyncSession(context_.get(), this, SyncSourceInfo(), routes_,
     34                            std::vector<ModelSafeWorker*>());
     35   }
     36 
     37   virtual void SetUp() {
     38     context_.reset(new SyncSessionContext(NULL, NULL, this,
     39         std::vector<SyncEngineEventListener*>()));
     40     routes_.clear();
     41     routes_[syncable::BOOKMARKS] = GROUP_UI;
     42     routes_[syncable::AUTOFILL] = GROUP_UI;
     43     session_.reset(MakeSession());
     44   }
     45   virtual void TearDown() {
     46     session_.reset();
     47     context_.reset();
     48   }
     49 
     50   virtual void OnSilencedUntil(const base::TimeTicks& silenced_until) {
     51     FailControllerInvocationIfDisabled("OnSilencedUntil");
     52   }
     53   virtual bool IsSyncingCurrentlySilenced() {
     54     FailControllerInvocationIfDisabled("IsSyncingCurrentlySilenced");
     55     return false;
     56   }
     57   virtual void OnReceivedLongPollIntervalUpdate(
     58       const base::TimeDelta& new_interval) {
     59     FailControllerInvocationIfDisabled("OnReceivedLongPollIntervalUpdate");
     60   }
     61   virtual void OnReceivedShortPollIntervalUpdate(
     62       const base::TimeDelta& new_interval) {
     63     FailControllerInvocationIfDisabled("OnReceivedShortPollIntervalUpdate");
     64   }
     65   virtual void OnShouldStopSyncingPermanently() {
     66     FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently");
     67   }
     68 
     69   // ModelSafeWorkerRegistrar implementation.
     70   virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {}
     71   virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
     72     out->swap(routes_);
     73   }
     74 
     75   StatusController* status() { return session_->status_controller(); }
     76  protected:
     77   void FailControllerInvocationIfDisabled(const std::string& msg) {
     78     if (!controller_invocations_allowed_)
     79       FAIL() << msg;
     80   }
     81 
     82   syncable::ModelTypeBitSet ParamsMeaningAllEnabledTypes() {
     83     syncable::ModelTypeBitSet request_params;
     84     request_params[syncable::BOOKMARKS] = true;
     85     request_params[syncable::AUTOFILL] = true;
     86     return request_params;
     87   }
     88 
     89   syncable::ModelTypeBitSet ParamsMeaningJustOneEnabledType() {
     90     syncable::ModelTypeBitSet request_params;
     91     request_params[syncable::AUTOFILL] = true;
     92     return request_params;
     93   }
     94 
     95   bool controller_invocations_allowed_;
     96   scoped_ptr<SyncSession> session_;
     97   scoped_ptr<SyncSessionContext> context_;
     98   ModelSafeRoutingInfo routes_;
     99 };
    100 
    101 TEST_F(SyncSessionTest, ScopedContextHelpers) {
    102   ConflictResolver resolver;
    103   EXPECT_FALSE(context_->resolver());
    104   {
    105     ScopedSessionContextConflictResolver s_resolver(context_.get(), &resolver);
    106     EXPECT_EQ(&resolver, context_->resolver());
    107   }
    108   EXPECT_FALSE(context_->resolver());
    109 }
    110 
    111 TEST_F(SyncSessionTest, SetWriteTransaction) {
    112   TestDirectorySetterUpper db;
    113   db.SetUp();
    114   session_.reset();
    115   context_.reset(new SyncSessionContext(NULL, db.manager(), this,
    116       std::vector<SyncEngineEventListener*>()));
    117   session_.reset(MakeSession());
    118   context_->set_account_name(db.name());
    119   syncable::ScopedDirLookup dir(context_->directory_manager(),
    120                                 context_->account_name());
    121   ASSERT_TRUE(dir.good());
    122 
    123   scoped_ptr<SyncSession> session(MakeSession());
    124   EXPECT_TRUE(NULL == session->write_transaction());
    125   {
    126     WriteTransaction trans(dir, syncable::UNITTEST, __FILE__, __LINE__);
    127     sessions::ScopedSetSessionWriteTransaction set_trans(session.get(), &trans);
    128     EXPECT_TRUE(&trans == session->write_transaction());
    129   }
    130   db.TearDown();
    131 }
    132 
    133 TEST_F(SyncSessionTest, MoreToSyncIfUnsyncedGreaterThanCommitted) {
    134   // If any forward progress was made during the session, and the number of
    135   // unsynced handles still exceeds the number of commit ids we added, there is
    136   // more to sync. For example, this occurs if we had more commit ids
    137   // than could fit in a single commit batch.
    138   EXPECT_FALSE(session_->HasMoreToSync());
    139   OrderedCommitSet commit_set(routes_);
    140   commit_set.AddCommitItem(0, syncable::Id(), syncable::BOOKMARKS);
    141   status()->set_commit_set(commit_set);
    142   EXPECT_FALSE(session_->HasMoreToSync());
    143 
    144   std::vector<int64> unsynced_handles;
    145   unsynced_handles.push_back(1);
    146   unsynced_handles.push_back(2);
    147   status()->set_unsynced_handles(unsynced_handles);
    148   EXPECT_FALSE(session_->HasMoreToSync());
    149   status()->increment_num_successful_commits();
    150   EXPECT_TRUE(session_->HasMoreToSync());
    151 }
    152 
    153 TEST_F(SyncSessionTest, MoreToSyncIfConflictSetsBuilt) {
    154   // If we built conflict sets, then we need to loop back and try
    155   // to get updates & commit again.
    156   status()->update_conflict_sets_built(true);
    157   EXPECT_TRUE(session_->HasMoreToSync());
    158 }
    159 
    160 TEST_F(SyncSessionTest, MoreToDownloadIfDownloadFailed) {
    161   status()->set_updates_request_types(ParamsMeaningAllEnabledTypes());
    162 
    163   // When DownloadUpdatesCommand fails, these should be false.
    164   EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
    165   EXPECT_FALSE(status()->download_updates_succeeded());
    166 
    167   // Download updates has its own loop in the syncer; it shouldn't factor
    168   // into HasMoreToSync.
    169   EXPECT_FALSE(session_->HasMoreToSync());
    170 }
    171 
    172 TEST_F(SyncSessionTest, MoreToDownloadIfGotChangesRemaining) {
    173   status()->set_updates_request_types(ParamsMeaningAllEnabledTypes());
    174 
    175   // When the server returns changes_remaining, that means there's
    176   // more to download.
    177   status()->mutable_updates_response()->mutable_get_updates()
    178      ->set_changes_remaining(1000L);
    179   EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
    180   EXPECT_TRUE(status()->download_updates_succeeded());
    181 
    182   // Download updates has its own loop in the syncer; it shouldn't factor
    183   // into HasMoreToSync.
    184   EXPECT_FALSE(session_->HasMoreToSync());
    185 }
    186 
    187 TEST_F(SyncSessionTest, MoreToDownloadIfGotNoChangesRemaining) {
    188   status()->set_updates_request_types(ParamsMeaningAllEnabledTypes());
    189 
    190   // When the server returns a timestamp, that means we're up to date.
    191   status()->mutable_updates_response()->mutable_get_updates()
    192       ->set_changes_remaining(0);
    193   EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload());
    194   EXPECT_TRUE(status()->download_updates_succeeded());
    195 
    196   // Download updates has its own loop in the syncer; it shouldn't factor
    197   // into HasMoreToSync.
    198   EXPECT_FALSE(session_->HasMoreToSync());
    199 }
    200 
    201 TEST_F(SyncSessionTest, MoreToDownloadIfGotNoChangesRemainingForSubset) {
    202   status()->set_updates_request_types(ParamsMeaningJustOneEnabledType());
    203 
    204   // When the server returns a timestamp, that means we're up to date for that
    205   // type.  But there may still be more to download if there are other
    206   // datatypes that we didn't request on this go-round.
    207   status()->mutable_updates_response()->mutable_get_updates()
    208       ->set_changes_remaining(0);
    209 
    210   EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload());
    211   EXPECT_TRUE(status()->download_updates_succeeded());
    212 
    213   // Download updates has its own loop in the syncer; it shouldn't factor
    214   // into HasMoreToSync.
    215   EXPECT_FALSE(session_->HasMoreToSync());
    216 }
    217 
    218 TEST_F(SyncSessionTest, MoreToDownloadIfGotChangesRemainingAndEntries) {
    219   status()->set_updates_request_types(ParamsMeaningAllEnabledTypes());
    220   // The actual entry count should not factor into the HasMoreToSync
    221   // determination.
    222   status()->mutable_updates_response()->mutable_get_updates()->add_entries();
    223   status()->mutable_updates_response()->mutable_get_updates()
    224       ->set_changes_remaining(1000000L);;
    225   EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
    226   EXPECT_TRUE(status()->download_updates_succeeded());
    227 
    228   // Download updates has its own loop in the syncer; it shouldn't factor
    229   // into HasMoreToSync.
    230   EXPECT_FALSE(session_->HasMoreToSync());
    231 }
    232 
    233 TEST_F(SyncSessionTest, MoreToDownloadIfGotNoChangesRemainingAndEntries) {
    234   status()->set_updates_request_types(ParamsMeaningAllEnabledTypes());
    235   // The actual entry count should not factor into the HasMoreToSync
    236   // determination.
    237   status()->mutable_updates_response()->mutable_get_updates()->add_entries();
    238   status()->mutable_updates_response()->mutable_get_updates()
    239       ->set_changes_remaining(0);
    240   EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload());
    241   EXPECT_TRUE(status()->download_updates_succeeded());
    242 
    243   // Download updates has its own loop in the syncer; it shouldn't factor
    244   // into HasMoreToSync.
    245   EXPECT_FALSE(session_->HasMoreToSync());
    246 }
    247 
    248 TEST_F(SyncSessionTest, MoreToSyncIfConflictsResolved) {
    249   // Conflict resolution happens after get updates and commit,
    250   // so we need to loop back and get updates / commit again now
    251   // that we have made forward progress.
    252   status()->update_conflicts_resolved(true);
    253   EXPECT_TRUE(session_->HasMoreToSync());
    254 }
    255 
    256 TEST_F(SyncSessionTest, ResetTransientState) {
    257   status()->update_conflicts_resolved(true);
    258   status()->increment_num_successful_commits();
    259   EXPECT_TRUE(session_->HasMoreToSync());
    260   session_->ResetTransientState();
    261   EXPECT_FALSE(status()->conflicts_resolved());
    262   EXPECT_FALSE(session_->HasMoreToSync());
    263   EXPECT_FALSE(status()->TestAndClearIsDirty());
    264 }
    265 
    266 TEST_F(SyncSessionTest, Coalesce) {
    267   std::vector<ModelSafeWorker*> workers_one, workers_two;
    268   ModelSafeRoutingInfo routes_one, routes_two;
    269   syncable::ModelTypePayloadMap one_type =
    270       syncable::ModelTypePayloadMapFromBitSet(
    271           ParamsMeaningJustOneEnabledType(),
    272           std::string());
    273   syncable::ModelTypePayloadMap all_types =
    274       syncable::ModelTypePayloadMapFromBitSet(
    275           ParamsMeaningAllEnabledTypes(),
    276           std::string());
    277   SyncSourceInfo source_one(sync_pb::GetUpdatesCallerInfo::PERIODIC, one_type);
    278   SyncSourceInfo source_two(sync_pb::GetUpdatesCallerInfo::LOCAL, all_types);
    279 
    280   scoped_refptr<MockDBModelWorker> db_worker(new MockDBModelWorker());
    281   scoped_refptr<MockUIModelWorker> ui_worker(new MockUIModelWorker());
    282   workers_one.push_back(db_worker);
    283   workers_two.push_back(db_worker);
    284   workers_two.push_back(ui_worker);
    285   routes_one[syncable::AUTOFILL] = GROUP_DB;
    286   routes_two[syncable::AUTOFILL] = GROUP_DB;
    287   routes_two[syncable::BOOKMARKS] = GROUP_UI;
    288   SyncSession one(context_.get(), this, source_one, routes_one, workers_one);
    289   SyncSession two(context_.get(), this, source_two, routes_two, workers_two);
    290 
    291   one.Coalesce(two);
    292 
    293   EXPECT_EQ(two.source().updates_source, one.source().updates_source);
    294   EXPECT_EQ(all_types, one.source().types);
    295   std::vector<ModelSafeWorker*>::const_iterator it_db =
    296       std::find(one.workers().begin(), one.workers().end(), db_worker);
    297   std::vector<ModelSafeWorker*>::const_iterator it_ui =
    298       std::find(one.workers().begin(), one.workers().end(), ui_worker);
    299   EXPECT_NE(it_db, one.workers().end());
    300   EXPECT_NE(it_ui, one.workers().end());
    301   EXPECT_EQ(routes_two, one.routing_info());
    302 }
    303 
    304 TEST_F(SyncSessionTest, MakeTypePayloadMapFromBitSet) {
    305   syncable::ModelTypeBitSet types;
    306   std::string payload = "test";
    307   syncable::ModelTypePayloadMap types_with_payloads =
    308       syncable::ModelTypePayloadMapFromBitSet(types,
    309                                               payload);
    310   EXPECT_TRUE(types_with_payloads.empty());
    311 
    312   types[syncable::BOOKMARKS] = true;
    313   types[syncable::PASSWORDS] = true;
    314   types[syncable::AUTOFILL] = true;
    315   payload = "test2";
    316   types_with_payloads = syncable::ModelTypePayloadMapFromBitSet(types, payload);
    317 
    318   ASSERT_EQ(3U, types_with_payloads.size());
    319   EXPECT_EQ(types_with_payloads[syncable::BOOKMARKS], payload);
    320   EXPECT_EQ(types_with_payloads[syncable::PASSWORDS], payload);
    321   EXPECT_EQ(types_with_payloads[syncable::AUTOFILL], payload);
    322 }
    323 
    324 TEST_F(SyncSessionTest, MakeTypePayloadMapFromRoutingInfo) {
    325   std::string payload = "test";
    326   syncable::ModelTypePayloadMap types_with_payloads
    327       = syncable::ModelTypePayloadMapFromRoutingInfo(routes_, payload);
    328   ASSERT_EQ(routes_.size(), types_with_payloads.size());
    329   for (ModelSafeRoutingInfo::iterator iter = routes_.begin();
    330        iter != routes_.end();
    331        ++iter) {
    332     EXPECT_EQ(payload, types_with_payloads[iter->first]);
    333   }
    334 }
    335 
    336 TEST_F(SyncSessionTest, CoalescePayloads) {
    337   syncable::ModelTypePayloadMap original;
    338   std::string empty_payload;
    339   std::string payload1 = "payload1";
    340   std::string payload2 = "payload2";
    341   std::string payload3 = "payload3";
    342   original[syncable::BOOKMARKS] = empty_payload;
    343   original[syncable::PASSWORDS] = payload1;
    344   original[syncable::AUTOFILL] = payload2;
    345   original[syncable::THEMES] = payload3;
    346 
    347   syncable::ModelTypePayloadMap update;
    348   update[syncable::BOOKMARKS] = empty_payload;  // Same.
    349   update[syncable::PASSWORDS] = empty_payload;  // Overwrite with empty.
    350   update[syncable::AUTOFILL] = payload1;        // Overwrite with non-empty.
    351   update[syncable::SESSIONS] = payload2;        // New.
    352   // Themes untouched.
    353 
    354   CoalescePayloads(&original, update);
    355   ASSERT_EQ(5U, original.size());
    356   EXPECT_EQ(empty_payload, original[syncable::BOOKMARKS]);
    357   EXPECT_EQ(payload1, original[syncable::PASSWORDS]);
    358   EXPECT_EQ(payload1, original[syncable::AUTOFILL]);
    359   EXPECT_EQ(payload2, original[syncable::SESSIONS]);
    360   EXPECT_EQ(payload3, original[syncable::THEMES]);
    361 }
    362 
    363 }  // namespace
    364 }  // namespace sessions
    365 }  // namespace browser_sync
    366