[Sync] Make BackendMigrator not wait for full sync cycles
Make sure that scheduling data type cleanup before scheduling start
implies that the cleanup happes before the start.
Make BackendMigrator simply wait for configuration to be done,
since data type cleanup is done before configuration.
Make BackendMigrator always preempt any existing migration.
Make DataTypeManagerImpl configuration handle being preempted
with enable_nigori set (since BackendMigrator can now do that).
Make DataTypeManagerImpl check for pending reconfigure on DownloadReady,
ignoring download success if so (since a migration may cause a download
failure, now that we don't wait for a full sync cycle).
Re-enable and rewrite failing MigrationCycle tests.
Fix subtle bug in SyncBackendHost where types_to_remove is used
where types_to_remove_with_nigori should be used instead.
Make syncer_end_command propagate up all download progress markers,
as that is needed by migration tests.
Add integration test methods for migration.
BUG=92928
TEST=
Review URL: http://codereview.chromium.org/7655055
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99265 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/sync/backend_migrator_unittest.cc b/chrome/browser/sync/backend_migrator_unittest.cc
index 9498392..3d254b8e 100644
--- a/chrome/browser/sync/backend_migrator_unittest.cc
+++ b/chrome/browser/sync/backend_migrator_unittest.cc
@@ -4,10 +4,16 @@
#include "chrome/browser/sync/backend_migrator.h"
+#include "base/message_loop.h"
+#include "base/tracked_objects.h"
#include "chrome/browser/sync/glue/data_type_manager_mock.h"
+#include "chrome/browser/sync/internal_api/write_transaction.h"
#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/browser/sync/protocol/sync.pb.h"
#include "chrome/browser/sync/sessions/session_state.h"
+#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/common/chrome_notification_types.h"
+#include "chrome/test/sync/engine/test_user_share.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,6 +36,7 @@
virtual ~BackendMigratorTest() { }
virtual void SetUp() {
+ test_user_share_.SetUp();
Mock::VerifyAndClear(manager());
Mock::VerifyAndClear(&service_);
preferred_types_.insert(syncable::BOOKMARKS);
@@ -38,32 +45,38 @@
ON_CALL(service_, GetPreferredDataTypes(_)).
WillByDefault(SetArgumentPointee<0>(preferred_types_));
+
+ migrator_.reset(
+ new BackendMigrator(
+ "Profile0", test_user_share_.user_share(), service(), manager()));
+ SetUnsyncedTypes(syncable::ModelTypeSet());
}
- void ReturnEmptyProgressMarkersInSnapshot() {
- ReturnNonEmptyProgressMarkersInSnapshot(syncable::ModelTypeSet());
+ virtual void TearDown() {
+ migrator_.reset();
+ test_user_share_.TearDown();
}
- void ReturnNonEmptyProgressMarkersInSnapshot(
- const syncable::ModelTypeSet& for_types) {
- std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
- for (syncable::ModelTypeSet::const_iterator it = for_types.begin();
- it != for_types.end(); ++it) {
- download_progress_markers[*it] = "foobar";
+ // Marks all types in |unsynced_types| as unsynced and all other
+ // types as synced.
+ void SetUnsyncedTypes(const syncable::ModelTypeSet& unsynced_types) {
+ sync_api::WriteTransaction trans(FROM_HERE,
+ test_user_share_.user_share());
+ for (int i = syncable::FIRST_REAL_MODEL_TYPE;
+ i < syncable::MODEL_TYPE_COUNT; ++i) {
+ syncable::ModelType type = syncable::ModelTypeFromInt(i);
+ sync_pb::DataTypeProgressMarker progress_marker;
+ if (unsynced_types.count(type) == 0) {
+ progress_marker.set_token("dummy");
+ }
+ trans.GetLookup()->SetDownloadProgress(type, progress_marker);
}
-
- snap_.reset(new SyncSessionSnapshot(SyncerStatus(), ErrorCounters(),
- 0, false, syncable::ModelTypeBitSet(), download_progress_markers,
- false, false, 0, 0, 0, false, sessions::SyncSourceInfo(), 0,
- base::Time::Now()));
- EXPECT_CALL(service_, GetLastSessionSnapshot())
- .WillOnce(Return(snap_.get()));
}
void SendConfigureDone(DataTypeManager::ConfigureStatus status,
- const syncable::ModelTypeSet& types) {
+ const syncable::ModelTypeSet& requested_types) {
if (status == DataTypeManager::OK) {
- DataTypeManager::ConfigureResult result(status, types);
+ DataTypeManager::ConfigureResult result(status, requested_types);
NotificationService::current()->Notify(
chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
Source<DataTypeManager>(&manager_),
@@ -71,7 +84,7 @@
} else {
DataTypeManager::ConfigureResult result(
status,
- types,
+ requested_types,
syncable::ModelTypeSet(),
FROM_HERE);
NotificationService::current()->Notify(
@@ -79,28 +92,44 @@
Source<DataTypeManager>(&manager_),
Details<const DataTypeManager::ConfigureResult>(&result));
}
+ message_loop_.RunAllPending();
}
ProfileSyncService* service() { return &service_; }
DataTypeManagerMock* manager() { return &manager_; }
const syncable::ModelTypeSet& preferred_types() { return preferred_types_; }
+ BackendMigrator* migrator() { return migrator_.get(); }
void RemovePreferredType(syncable::ModelType type) {
preferred_types_.erase(type);
Mock::VerifyAndClear(&service_);
ON_CALL(service_, GetPreferredDataTypes(_)).
WillByDefault(SetArgumentPointee<0>(preferred_types_));
}
+
private:
scoped_ptr<SyncSessionSnapshot> snap_;
+ MessageLoop message_loop_;
syncable::ModelTypeSet preferred_types_;
NiceMock<ProfileSyncServiceMock> service_;
NiceMock<DataTypeManagerMock> manager_;
+ TestUserShare test_user_share_;
+ scoped_ptr<BackendMigrator> migrator_;
+};
+
+class MockMigrationObserver : public MigrationObserver {
+ public:
+ virtual ~MockMigrationObserver() {}
+
+ MOCK_METHOD0(OnMigrationStateChange, void());
};
// Test that in the normal case a migration does transition through each state
// and wind up back in IDLE.
TEST_F(BackendMigratorTest, Sanity) {
- BackendMigrator migrator(service(), manager());
+ MockMigrationObserver migration_observer;
+ migrator()->AddMigrationObserver(&migration_observer);
+ EXPECT_CALL(migration_observer, OnMigrationStateChange()).Times(4);
+
syncable::ModelTypeSet to_migrate, difference;
to_migrate.insert(syncable::PREFERENCES);
difference.insert(syncable::AUTOFILL);
@@ -108,28 +137,26 @@
EXPECT_CALL(*manager(), state())
.WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION));
+ EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
+ .Times(2);
- migrator.MigrateTypes(to_migrate);
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
+ migrator()->MigrateTypes(to_migrate);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
+ SetUnsyncedTypes(to_migrate);
SendConfigureDone(DataTypeManager::OK, difference);
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
+ EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
- ReturnEmptyProgressMarkersInSnapshot();
- EXPECT_CALL(*manager(), Configure(preferred_types(),
- sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.OnStateChanged();
- EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
-
+ SetUnsyncedTypes(syncable::ModelTypeSet());
SendConfigureDone(DataTypeManager::OK, preferred_types());
- EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
+ EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
+
+ migrator()->RemoveMigrationObserver(&migration_observer);
}
// Test that in the normal case with Nigori a migration transitions through
// each state and wind up back in IDLE.
TEST_F(BackendMigratorTest, MigrateNigori) {
- BackendMigrator migrator(service(), manager());
syncable::ModelTypeSet to_migrate, difference;
to_migrate.insert(syncable::NIGORI);
difference.insert(syncable::AUTOFILL);
@@ -141,62 +168,59 @@
EXPECT_CALL(*manager(), ConfigureWithoutNigori(_,
sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.MigrateTypes(to_migrate);
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
+ migrator()->MigrateTypes(to_migrate);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
+ SetUnsyncedTypes(to_migrate);
SendConfigureDone(DataTypeManager::OK, difference);
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
+ EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
- ReturnEmptyProgressMarkersInSnapshot();
- EXPECT_CALL(*manager(), Configure(preferred_types(),
- sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.OnStateChanged();
- EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
-
+ SetUnsyncedTypes(syncable::ModelTypeSet());
SendConfigureDone(DataTypeManager::OK, preferred_types());
- EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
+ EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
}
// Test that the migrator waits for the data type manager to be idle before
// starting a migration.
TEST_F(BackendMigratorTest, WaitToStart) {
- BackendMigrator migrator(service(), manager());
syncable::ModelTypeSet to_migrate;
to_migrate.insert(syncable::PREFERENCES);
EXPECT_CALL(*manager(), state())
.WillOnce(Return(DataTypeManager::CONFIGURING));
EXPECT_CALL(*manager(), Configure(_, _)).Times(0);
- migrator.MigrateTypes(to_migrate);
- EXPECT_EQ(BackendMigrator::WAITING_TO_START, migrator.state());
+ migrator()->MigrateTypes(to_migrate);
+ EXPECT_EQ(BackendMigrator::WAITING_TO_START, migrator()->state());
Mock::VerifyAndClearExpectations(manager());
EXPECT_CALL(*manager(), state())
.WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION));
+ SetUnsyncedTypes(syncable::ModelTypeSet());
SendConfigureDone(DataTypeManager::OK, syncable::ModelTypeSet());
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
}
// Test that the migrator can cope with a migration request while a migration
// is in progress.
TEST_F(BackendMigratorTest, RestartMigration) {
- BackendMigrator migrator(service(), manager());
- syncable::ModelTypeSet to_migrate1, to_migrate2, bookmarks;
+ syncable::ModelTypeSet to_migrate1, to_migrate2, to_migrate_union, bookmarks;
to_migrate1.insert(syncable::PREFERENCES);
to_migrate2.insert(syncable::AUTOFILL);
+ to_migrate_union.insert(syncable::PREFERENCES);
+ to_migrate_union.insert(syncable::AUTOFILL);
bookmarks.insert(syncable::BOOKMARKS);
EXPECT_CALL(*manager(), state())
.WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
- .Times(1);
- migrator.MigrateTypes(to_migrate1);
+ .Times(2);
+ migrator()->MigrateTypes(to_migrate1);
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
- migrator.MigrateTypes(to_migrate2);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
+ migrator()->MigrateTypes(to_migrate2);
syncable::ModelTypeSet difference1;
std::set_difference(preferred_types().begin(), preferred_types().end(),
@@ -204,21 +228,20 @@
std::inserter(difference1, difference1.end()));
Mock::VerifyAndClearExpectations(manager());
- EXPECT_CALL(*manager(), state())
- .WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*manager(), Configure(bookmarks,
- sync_api::CONFIGURE_REASON_MIGRATION));
+ EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
+ .Times(2);
+ SetUnsyncedTypes(to_migrate1);
SendConfigureDone(DataTypeManager::OK, difference1);
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
+ SetUnsyncedTypes(to_migrate_union);
SendConfigureDone(DataTypeManager::OK, bookmarks);
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
+ EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
}
// Test that an external invocation of Configure(...) during a migration results
// in a migration reattempt.
TEST_F(BackendMigratorTest, InterruptedWhileDisablingTypes) {
- BackendMigrator migrator(service(), manager());
syncable::ModelTypeSet to_migrate;
syncable::ModelTypeSet difference;
to_migrate.insert(syncable::PREFERENCES);
@@ -229,23 +252,22 @@
.WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*manager(), Configure(difference,
sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.MigrateTypes(to_migrate);
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
+ migrator()->MigrateTypes(to_migrate);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
Mock::VerifyAndClearExpectations(manager());
- EXPECT_CALL(*manager(), state())
- .WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*manager(), Configure(difference,
sync_api::CONFIGURE_REASON_MIGRATION));
+ SetUnsyncedTypes(syncable::ModelTypeSet());
SendConfigureDone(DataTypeManager::OK, preferred_types());
- EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
}
-// Test that spurious OnStateChanged events don't confuse the migrator while
-// it's waiting for disabled types to have been purged from the sync db.
+// Test that spurious OnConfigureDone events don't confuse the
+// migrator while it's waiting for disabled types to have been purged
+// from the sync db.
TEST_F(BackendMigratorTest, WaitingForPurge) {
- BackendMigrator migrator(service(), manager());
syncable::ModelTypeSet to_migrate, difference;
to_migrate.insert(syncable::PREFERENCES);
to_migrate.insert(syncable::AUTOFILL);
@@ -253,57 +275,46 @@
EXPECT_CALL(*manager(), state())
.WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.MigrateTypes(to_migrate);
- SendConfigureDone(DataTypeManager::OK, difference);
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
+ EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
+ .Times(2);
- ReturnNonEmptyProgressMarkersInSnapshot(to_migrate);
- migrator.OnStateChanged();
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
+ migrator()->MigrateTypes(to_migrate);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
+
+ SendConfigureDone(DataTypeManager::OK, difference);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
syncable::ModelTypeSet prefs;
prefs.insert(syncable::PREFERENCES);
- ReturnNonEmptyProgressMarkersInSnapshot(prefs);
- migrator.OnStateChanged();
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
+ SetUnsyncedTypes(prefs);
+ SendConfigureDone(DataTypeManager::OK, difference);
+ EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator()->state());
- syncable::ModelTypeSet bookmarks;
- bookmarks.insert(syncable::BOOKMARKS);
- ReturnNonEmptyProgressMarkersInSnapshot(bookmarks);
- EXPECT_CALL(*manager(), Configure(preferred_types(),
- sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.OnStateChanged();
- EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
+ SetUnsyncedTypes(to_migrate);
+ SendConfigureDone(DataTypeManager::OK, difference);
+ EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
}
TEST_F(BackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) {
- BackendMigrator migrator(service(), manager());
syncable::ModelTypeSet to_migrate;
to_migrate.insert(syncable::PREFERENCES);
EXPECT_CALL(*manager(), state())
.WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.MigrateTypes(to_migrate);
+ EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
+ .Times(2);
+ migrator()->MigrateTypes(to_migrate);
RemovePreferredType(syncable::PREFERENCES);
+ SetUnsyncedTypes(to_migrate);
SendConfigureDone(DataTypeManager::OK, preferred_types());
- EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
-
- Mock::VerifyAndClearExpectations(manager());
- ReturnEmptyProgressMarkersInSnapshot();
- EXPECT_CALL(*manager(), Configure(preferred_types(),
- sync_api::CONFIGURE_REASON_MIGRATION));
- migrator.OnStateChanged();
-
- EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
+ EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator()->state());
+ SetUnsyncedTypes(syncable::ModelTypeSet());
SendConfigureDone(DataTypeManager::OK, preferred_types());
- EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
+ EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
}
TEST_F(BackendMigratorTest, ConfigureFailure) {
- BackendMigrator migrator(service(), manager());
syncable::ModelTypeSet to_migrate;
to_migrate.insert(syncable::PREFERENCES);
@@ -311,9 +322,10 @@
.WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
.Times(1);
- migrator.MigrateTypes(to_migrate);
+ migrator()->MigrateTypes(to_migrate);
+ SetUnsyncedTypes(syncable::ModelTypeSet());
SendConfigureDone(DataTypeManager::ABORTED, syncable::ModelTypeSet());
- EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
+ EXPECT_EQ(BackendMigrator::IDLE, migrator()->state());
}
}; // namespace browser_sync