Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/backend_migrator.h"
      6 
      7 #include "base/message_loop/message_loop.h"
      8 #include "base/tracked_objects.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/sync/profile_sync_service_mock.h"
     11 #include "components/sync_driver/data_type_manager_mock.h"
     12 #include "sync/internal_api/public/base/model_type_test_util.h"
     13 #include "sync/internal_api/public/test/test_user_share.h"
     14 #include "sync/internal_api/public/write_transaction.h"
     15 #include "sync/protocol/sync.pb.h"
     16 #include "sync/syncable/directory.h"  // TODO(tim): Remove. Bug 131130.
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 using ::testing::_;
     21 using ::testing::Eq;
     22 using ::testing::Mock;
     23 using ::testing::NiceMock;
     24 using ::testing::Return;
     25 
     26 namespace browser_sync {
     27 
     28 using syncer::sessions::SyncSessionSnapshot;
     29 
     30 class SyncBackendMigratorTest : public testing::Test {
     31  public:
     32   SyncBackendMigratorTest() : service_(&profile_) { }
     33   virtual ~SyncBackendMigratorTest() { }
     34 
     35   virtual void SetUp() {
     36     test_user_share_.SetUp();
     37     Mock::VerifyAndClear(manager());
     38     Mock::VerifyAndClear(&service_);
     39     preferred_types_.Put(syncer::BOOKMARKS);
     40     preferred_types_.Put(syncer::PREFERENCES);
     41     preferred_types_.Put(syncer::AUTOFILL);
     42 
     43     ON_CALL(service_, GetPreferredDataTypes()).
     44         WillByDefault(Return(preferred_types_));
     45 
     46     migrator_.reset(
     47         new BackendMigrator(
     48             "Profile0", test_user_share_.user_share(), service(), manager(),
     49             base::Closure()));
     50     SetUnsyncedTypes(syncer::ModelTypeSet());
     51   }
     52 
     53   virtual void TearDown() {
     54     migrator_.reset();
     55     test_user_share_.TearDown();
     56   }
     57 
     58   // Marks all types in |unsynced_types| as unsynced  and all other
     59   // types as synced.
     60   void SetUnsyncedTypes(syncer::ModelTypeSet unsynced_types) {
     61     syncer::WriteTransaction trans(FROM_HERE,
     62                                      test_user_share_.user_share());
     63     for (int i = syncer::FIRST_REAL_MODEL_TYPE;
     64          i < syncer::MODEL_TYPE_COUNT; ++i) {
     65       syncer::ModelType type = syncer::ModelTypeFromInt(i);
     66       sync_pb::DataTypeProgressMarker progress_marker;
     67       if (!unsynced_types.Has(type)) {
     68         progress_marker.set_token("dummy");
     69       }
     70       trans.GetDirectory()->SetDownloadProgress(type, progress_marker);
     71     }
     72   }
     73 
     74   void SendConfigureDone(DataTypeManager::ConfigureStatus status,
     75                          syncer::ModelTypeSet requested_types) {
     76     if (status == DataTypeManager::OK) {
     77       DataTypeManager::ConfigureResult result(status, requested_types);
     78       migrator_->OnConfigureDone(result);
     79     } else {
     80       std::map<syncer::ModelType, syncer::SyncError> errors;
     81       DataTypeManager::ConfigureResult result(
     82           status,
     83           requested_types,
     84           errors,
     85           syncer::ModelTypeSet(),
     86           syncer::ModelTypeSet());
     87       migrator_->OnConfigureDone(result);
     88     }
     89     message_loop_.RunUntilIdle();
     90   }
     91 
     92   ProfileSyncService* service() { return &service_; }
     93   DataTypeManagerMock* manager() { return &manager_; }
     94   syncer::ModelTypeSet preferred_types() { return preferred_types_; }
     95   BackendMigrator* migrator() { return migrator_.get(); }
     96   void RemovePreferredType(syncer::ModelType type) {
     97     preferred_types_.Remove(type);
     98     Mock::VerifyAndClear(&service_);
     99     ON_CALL(service_, GetPreferredDataTypes()).
    100         WillByDefault(Return(preferred_types_));
    101   }
    102 
    103  private:
    104   scoped_ptr<SyncSessionSnapshot> snap_;
    105   base::MessageLoop message_loop_;
    106   syncer::ModelTypeSet preferred_types_;
    107   TestingProfile profile_;
    108   NiceMock<ProfileSyncServiceMock> service_;
    109   NiceMock<DataTypeManagerMock> manager_;
    110   syncer::TestUserShare test_user_share_;
    111   scoped_ptr<BackendMigrator> migrator_;
    112 };
    113 
    114 class MockMigrationObserver : public MigrationObserver {
    115  public:
    116   virtual ~MockMigrationObserver() {}
    117 
    118   MOCK_METHOD0(OnMigrationStateChange, void());
    119 };
    120 
    121 // Test that in the normal case a migration does transition through each state
    122 // and wind up back in IDLE.
    123 TEST_F(SyncBackendMigratorTest, Sanity) {
    124   MockMigrationObserver migration_observer;
    125   migrator()->AddMigrationObserver(&migration_observer);
    126   EXPECT_CALL(migration_observer, OnMigrationStateChange()).Times(4);
    127 
    128   syncer::ModelTypeSet to_migrate, difference;
    129   to_migrate.Put(syncer::PREFERENCES);
    130   difference.Put(syncer::AUTOFILL);
    131   difference.Put(syncer::BOOKMARKS);
    132 
    133   EXPECT_CALL(*manager(), state())
    134       .WillOnce(Return(DataTypeManager::CONFIGURED));
    135   EXPECT_CALL(
    136       *manager(),
    137       PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    138   EXPECT_CALL(
    139       *manager(),
    140       Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    141 
    142   migrator()->MigrateTypes(to_migrate);
    143   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    144 
    145   SetUnsyncedTypes(to_migrate);
    146   SendConfigureDone(DataTypeManager::OK, difference);
    147   EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
    148 
    149   SetUnsyncedTypes(syncer::ModelTypeSet());
    150   SendConfigureDone(DataTypeManager::OK, preferred_types());
    151   EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
    152 
    153   migrator()->RemoveMigrationObserver(&migration_observer);
    154 }
    155 
    156 // Test that in the normal case with Nigori a migration transitions through
    157 // each state and wind up back in IDLE.
    158 TEST_F(SyncBackendMigratorTest, MigrateNigori) {
    159   syncer::ModelTypeSet to_migrate, difference;
    160   to_migrate.Put(syncer::NIGORI);
    161   difference.Put(syncer::AUTOFILL);
    162   difference.Put(syncer::BOOKMARKS);
    163 
    164   EXPECT_CALL(*manager(), state())
    165       .WillOnce(Return(DataTypeManager::CONFIGURED));
    166 
    167   EXPECT_CALL(*manager(), PurgeForMigration(_,
    168       syncer::CONFIGURE_REASON_MIGRATION));
    169 
    170   migrator()->MigrateTypes(to_migrate);
    171   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    172 
    173   SetUnsyncedTypes(to_migrate);
    174   SendConfigureDone(DataTypeManager::OK, difference);
    175   EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
    176 
    177   SetUnsyncedTypes(syncer::ModelTypeSet());
    178   SendConfigureDone(DataTypeManager::OK, preferred_types());
    179   EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
    180 }
    181 
    182 
    183 // Test that the migrator waits for the data type manager to be idle before
    184 // starting a migration.
    185 TEST_F(SyncBackendMigratorTest, WaitToStart) {
    186   syncer::ModelTypeSet to_migrate;
    187   to_migrate.Put(syncer::PREFERENCES);
    188 
    189   EXPECT_CALL(*manager(), state())
    190       .WillOnce(Return(DataTypeManager::CONFIGURING));
    191   EXPECT_CALL(*manager(), Configure(_, _)).Times(0);
    192   migrator()->MigrateTypes(to_migrate);
    193   EXPECT_EQ(BackendMigrator::WAITING_TO_START, migrator()->state());
    194 
    195   Mock::VerifyAndClearExpectations(manager());
    196   EXPECT_CALL(*manager(), state())
    197       .WillOnce(Return(DataTypeManager::CONFIGURED));
    198   EXPECT_CALL(*manager(),
    199               PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION));
    200   SetUnsyncedTypes(syncer::ModelTypeSet());
    201   SendConfigureDone(DataTypeManager::OK, syncer::ModelTypeSet());
    202 
    203   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    204 }
    205 
    206 // Test that the migrator can cope with a migration request while a migration
    207 // is in progress.
    208 TEST_F(SyncBackendMigratorTest, RestartMigration) {
    209   syncer::ModelTypeSet to_migrate1, to_migrate2, to_migrate_union, bookmarks;
    210   to_migrate1.Put(syncer::PREFERENCES);
    211   to_migrate2.Put(syncer::AUTOFILL);
    212   to_migrate_union.Put(syncer::PREFERENCES);
    213   to_migrate_union.Put(syncer::AUTOFILL);
    214   bookmarks.Put(syncer::BOOKMARKS);
    215 
    216   EXPECT_CALL(*manager(), state())
    217       .WillOnce(Return(DataTypeManager::CONFIGURED));
    218   EXPECT_CALL(
    219       *manager(),
    220       PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(2);
    221   migrator()->MigrateTypes(to_migrate1);
    222 
    223   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    224   migrator()->MigrateTypes(to_migrate2);
    225 
    226   const syncer::ModelTypeSet difference1 =
    227       Difference(preferred_types(), to_migrate1);
    228 
    229   Mock::VerifyAndClearExpectations(manager());
    230   EXPECT_CALL(
    231       *manager(),
    232       PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    233   EXPECT_CALL(*manager(), Configure(_, syncer::CONFIGURE_REASON_MIGRATION))
    234       .Times(1);
    235   SetUnsyncedTypes(to_migrate1);
    236   SendConfigureDone(DataTypeManager::OK, difference1);
    237   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    238 
    239   SetUnsyncedTypes(to_migrate_union);
    240   SendConfigureDone(DataTypeManager::OK, bookmarks);
    241   EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
    242 }
    243 
    244 // Test that an external invocation of Configure(...) during a migration results
    245 // in a migration reattempt.
    246 TEST_F(SyncBackendMigratorTest, InterruptedWhileDisablingTypes) {
    247   syncer::ModelTypeSet to_migrate;
    248   syncer::ModelTypeSet difference;
    249   to_migrate.Put(syncer::PREFERENCES);
    250   difference.Put(syncer::AUTOFILL);
    251   difference.Put(syncer::BOOKMARKS);
    252 
    253   EXPECT_CALL(*manager(), state())
    254       .WillOnce(Return(DataTypeManager::CONFIGURED));
    255   EXPECT_CALL(*manager(), PurgeForMigration(HasModelTypes(to_migrate),
    256       syncer::CONFIGURE_REASON_MIGRATION));
    257   migrator()->MigrateTypes(to_migrate);
    258   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    259 
    260   Mock::VerifyAndClearExpectations(manager());
    261   EXPECT_CALL(*manager(), PurgeForMigration(HasModelTypes(to_migrate),
    262       syncer::CONFIGURE_REASON_MIGRATION));
    263   SetUnsyncedTypes(syncer::ModelTypeSet());
    264   SendConfigureDone(DataTypeManager::OK, preferred_types());
    265 
    266   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    267 }
    268 
    269 // Test that spurious OnConfigureDone events don't confuse the
    270 // migrator while it's waiting for disabled types to have been purged
    271 // from the sync db.
    272 TEST_F(SyncBackendMigratorTest, WaitingForPurge) {
    273   syncer::ModelTypeSet to_migrate, difference;
    274   to_migrate.Put(syncer::PREFERENCES);
    275   to_migrate.Put(syncer::AUTOFILL);
    276   difference.Put(syncer::BOOKMARKS);
    277 
    278   EXPECT_CALL(*manager(), state())
    279       .WillOnce(Return(DataTypeManager::CONFIGURED));
    280   EXPECT_CALL(
    281       *manager(),
    282       PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    283   EXPECT_CALL(
    284       *manager(),
    285       Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    286 
    287   migrator()->MigrateTypes(to_migrate);
    288   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    289 
    290   SendConfigureDone(DataTypeManager::OK, difference);
    291   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    292 
    293   syncer::ModelTypeSet prefs;
    294   prefs.Put(syncer::PREFERENCES);
    295   SetUnsyncedTypes(prefs);
    296   SendConfigureDone(DataTypeManager::OK, difference);
    297   EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
    298 
    299   SetUnsyncedTypes(to_migrate);
    300   SendConfigureDone(DataTypeManager::OK, difference);
    301   EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
    302 }
    303 
    304 TEST_F(SyncBackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) {
    305   syncer::ModelTypeSet to_migrate;
    306   to_migrate.Put(syncer::PREFERENCES);
    307 
    308   EXPECT_CALL(*manager(), state())
    309       .WillOnce(Return(DataTypeManager::CONFIGURED));
    310   EXPECT_CALL(
    311       *manager(),
    312       PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    313   EXPECT_CALL(
    314       *manager(),
    315       Configure(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    316   migrator()->MigrateTypes(to_migrate);
    317 
    318   RemovePreferredType(syncer::PREFERENCES);
    319   SetUnsyncedTypes(to_migrate);
    320   SendConfigureDone(DataTypeManager::OK, preferred_types());
    321   EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
    322   SetUnsyncedTypes(syncer::ModelTypeSet());
    323   SendConfigureDone(DataTypeManager::OK, preferred_types());
    324   EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
    325 }
    326 
    327 TEST_F(SyncBackendMigratorTest, ConfigureFailure) {
    328   syncer::ModelTypeSet to_migrate;
    329   to_migrate.Put(syncer::PREFERENCES);
    330 
    331   EXPECT_CALL(*manager(), state())
    332       .WillOnce(Return(DataTypeManager::CONFIGURED));
    333   EXPECT_CALL(
    334       *manager(),
    335       PurgeForMigration(_, syncer::CONFIGURE_REASON_MIGRATION)).Times(1);
    336   migrator()->MigrateTypes(to_migrate);
    337   SetUnsyncedTypes(syncer::ModelTypeSet());
    338   SendConfigureDone(DataTypeManager::ABORTED, syncer::ModelTypeSet());
    339   EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
    340 }
    341 
    342 };  // namespace browser_sync
    343