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