Chromium Code Reviews| Index: chrome/browser/sync/profile_sync_service_harness.cc |
| diff --git a/chrome/browser/sync/profile_sync_service_harness.cc b/chrome/browser/sync/profile_sync_service_harness.cc |
| index dcd5ed51a4eacbf710283a58f2c3814e4bcd1b2b..56b3d5f017b8ce53dcc90d0d8b30012dcd714972 100644 |
| --- a/chrome/browser/sync/profile_sync_service_harness.cc |
| +++ b/chrome/browser/sync/profile_sync_service_harness.cc |
| @@ -12,6 +12,8 @@ |
| #include <sstream> |
| #include <vector> |
| +#include "base/base64.h" |
| +#include "base/compiler_specific.h" |
| #include "base/json/json_writer.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| @@ -107,6 +109,7 @@ ProfileSyncServiceHarness::ProfileSyncServiceHarness( |
| if (IsSyncAlreadySetup()) { |
| service_ = profile_->GetProfileSyncService(); |
| service_->AddObserver(this); |
| + ignore_result(TryListeningToMigrationEvents()); |
| wait_state_ = FULLY_SYNCED; |
| } |
| } |
| @@ -180,6 +183,10 @@ bool ProfileSyncServiceHarness::SetupSync( |
| (syncable::MODEL_TYPE_COUNT - syncable::FIRST_REAL_MODEL_TYPE)); |
| service()->OnUserChoseDatatypes(sync_everything, synced_datatypes); |
| + // Subscribe sync client to notifications from the backend migrator |
| + // (possible only choosing data types). |
| + DCHECK(TryListeningToMigrationEvents()); |
|
Raghu Simha
2011/09/01 04:23:59
DCHECKs don't get run on the main waterfall, since
akalin
2011/09/01 04:39:05
Done.
|
| + |
| // Make sure that a partner client hasn't already set an explicit passphrase. |
| if (wait_state_ == SET_PASSPHRASE_FAILED) { |
| LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" |
| @@ -210,6 +217,16 @@ bool ProfileSyncServiceHarness::SetupSync( |
| return true; |
| } |
| +bool ProfileSyncServiceHarness::TryListeningToMigrationEvents() { |
| + browser_sync::BackendMigrator* migrator = |
| + service_->GetBackendMigratorForTest(); |
| + if (migrator && !migrator->HasMigrationObserver(this)) { |
| + migrator->AddMigrationObserver(this); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| void ProfileSyncServiceHarness::SignalStateCompleteWithNextState( |
| WaitState next_state) { |
| wait_state_ = next_state; |
| @@ -344,6 +361,20 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() { |
| SignalStateCompleteWithNextState(WAITING_FOR_NOTHING); |
| break; |
| } |
| + case WAITING_FOR_MIGRATION_TO_START: { |
| + VLOG(1) << GetClientInfoString("WAITING_FOR_MIGRATION_TO_START"); |
| + if (HasPendingBackendMigration()) { |
| + SignalStateCompleteWithNextState(WAITING_FOR_MIGRATION_TO_FINISH); |
| + } |
| + break; |
| + } |
| + case WAITING_FOR_MIGRATION_TO_FINISH: { |
| + VLOG(1) << GetClientInfoString("WAITING_FOR_MIGRATION_TO_FINISH"); |
| + if (!HasPendingBackendMigration()) { |
| + SignalStateCompleteWithNextState(WAITING_FOR_NOTHING); |
| + } |
| + break; |
| + } |
| case SERVER_UNREACHABLE: { |
| VLOG(1) << GetClientInfoString("SERVER_UNREACHABLE"); |
| if (GetStatus().server_reachable) { |
| @@ -387,6 +418,40 @@ void ProfileSyncServiceHarness::OnStateChanged() { |
| RunStateChangeMachine(); |
| } |
| +void ProfileSyncServiceHarness::OnMigrationStateChange() { |
| + // Update migration state. |
| + if (HasPendingBackendMigration()) { |
| + // Merge current pending migration types into |
| + // |pending_migration_types_|. |
| + syncable::ModelTypeSet new_pending_migration_types = |
| + service()->GetBackendMigratorForTest()-> |
| + GetPendingMigrationTypesForTest(); |
| + syncable::ModelTypeSet temp; |
| + std::set_union(pending_migration_types_.begin(), |
| + pending_migration_types_.end(), |
| + new_pending_migration_types.begin(), |
| + new_pending_migration_types.end(), |
| + std::inserter(temp, temp.end())); |
| + std::swap(pending_migration_types_, temp); |
| + VLOG(1) << profile_debug_name_ << ": new pending migration types " |
| + << syncable::ModelTypeSetToString(pending_migration_types_); |
| + } else { |
| + // Merge just-finished pending migration types into |
| + // |migration_types_|. |
| + syncable::ModelTypeSet temp; |
| + std::set_union(pending_migration_types_.begin(), |
| + pending_migration_types_.end(), |
| + migrated_types_.begin(), |
| + migrated_types_.end(), |
| + std::inserter(temp, temp.end())); |
| + std::swap(migrated_types_, temp); |
| + pending_migration_types_.clear(); |
| + VLOG(1) << profile_debug_name_ << ": new migrated types " |
| + << syncable::ModelTypeSetToString(migrated_types_); |
| + } |
| + RunStateChangeMachine(); |
| +} |
| + |
| bool ProfileSyncServiceHarness::AwaitPassphraseRequired() { |
| VLOG(1) << GetClientInfoString("AwaitPassphraseRequired"); |
| if (wait_state_ == SYNC_DISABLED) { |
| @@ -469,17 +534,6 @@ bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion( |
| return true; |
| } |
| - return AwaitSyncCycleCompletionHelper(reason); |
| -} |
| - |
| -bool ProfileSyncServiceHarness::AwaitNextSyncCycleCompletion( |
| - const std::string& reason) { |
| - VLOG(1) << GetClientInfoString("AwaitNextSyncCycleCompletion"); |
| - return AwaitSyncCycleCompletionHelper(reason); |
| -} |
| - |
| -bool ProfileSyncServiceHarness::AwaitSyncCycleCompletionHelper( |
| - const std::string& reason) { |
| if (wait_state_ == SERVER_UNREACHABLE) { |
| // Client was offline; wait for it to go online, and then wait for sync. |
| AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason); |
| @@ -522,6 +576,53 @@ bool ProfileSyncServiceHarness::AwaitExponentialBackoffVerification() { |
| return (retry_verifier_.Succeeded()); |
| } |
| +bool ProfileSyncServiceHarness::AwaitMigration( |
| + const syncable::ModelTypeSet& expected_migrated_types) { |
| + VLOG(1) << GetClientInfoString("AwaitMigration"); |
| + VLOG(1) << profile_debug_name_ << ": waiting until migration is done for " |
| + << syncable::ModelTypeSetToString(expected_migrated_types); |
| + while (true) { |
| + bool migration_finished = |
| + std::includes(migrated_types_.begin(), migrated_types_.end(), |
| + expected_migrated_types.begin(), |
| + expected_migrated_types.end()); |
| + VLOG(1) << "Migrated types " |
| + << syncable::ModelTypeSetToString(migrated_types_) |
| + << (migration_finished ? " contains " : " does not contain ") |
| + << syncable::ModelTypeSetToString(expected_migrated_types); |
| + if (migration_finished) { |
| + return true; |
| + } |
| + |
| + if (HasPendingBackendMigration()) { |
| + wait_state_ = WAITING_FOR_MIGRATION_TO_FINISH; |
| + } else { |
| + wait_state_ = WAITING_FOR_MIGRATION_TO_START; |
| + AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, |
| + "Wait for migration to start"); |
| + if (wait_state_ != WAITING_FOR_MIGRATION_TO_FINISH) { |
| + VLOG(1) << profile_debug_name_ |
| + << ": wait state = " << wait_state_ |
| + << " after migration start is not " |
| + << "WAITING_FOR_MIGRATION_TO_FINISH"; |
| + return false; |
| + } |
| + } |
| + AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, |
| + "Wait for migration to finish"); |
| + if (wait_state_ != WAITING_FOR_NOTHING) { |
| + VLOG(1) << profile_debug_name_ |
| + << ": wait state = " << wait_state_ |
| + << " after migration finish is not WAITING_FOR_NOTHING"; |
| + return false; |
| + } |
| + if (!AwaitSyncCycleCompletion( |
| + "Config sync cycle after migration cycle")) { |
| + return false; |
| + } |
| + } |
| +} |
| + |
| bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion( |
| ProfileSyncServiceHarness* partner) { |
| VLOG(1) << GetClientInfoString("AwaitMutualSyncCycleCompletion"); |
| @@ -631,7 +732,7 @@ bool ProfileSyncServiceHarness::IsSynced() { |
| !service()->HasUnsyncedItems() && |
| !snap->has_more_to_sync && |
| snap->unsynced_count == 0 && |
| - !service()->HasPendingBackendMigration() && |
| + !HasPendingBackendMigration() && |
| service()->passphrase_required_reason() != |
| sync_api::REASON_SET_PASSPHRASE_FAILED; |
| VLOG(1) << GetClientInfoString( |
| @@ -639,10 +740,20 @@ bool ProfileSyncServiceHarness::IsSynced() { |
| return is_synced; |
| } |
| +bool ProfileSyncServiceHarness::HasPendingBackendMigration() { |
| + browser_sync::BackendMigrator* migrator = |
| + service()->GetBackendMigratorForTest(); |
| + return migrator && migrator->state() != browser_sync::BackendMigrator::IDLE; |
| +} |
| + |
| bool ProfileSyncServiceHarness::MatchesOtherClient( |
| ProfileSyncServiceHarness* partner) { |
| - if (!IsSynced()) |
| + // TODO(akalin): Shouldn't this belong with the intersection check? |
| + // Otherwise, this function isn't symmetric. |
| + if (!IsSynced()) { |
| + VLOG(2) << profile_debug_name_ << ": not synced, assuming doesn't match"; |
| return false; |
| + } |
| // Only look for a match if we have at least one enabled datatype in |
| // common with the partner client. |
| @@ -653,11 +764,38 @@ bool ProfileSyncServiceHarness::MatchesOtherClient( |
| other_types.end(), |
| inserter(intersection_types, |
| intersection_types.begin())); |
| + |
| + VLOG(2) << profile_debug_name_ << ", " << partner->profile_debug_name_ |
| + << ": common types are " |
| + << syncable::ModelTypeSetToString(intersection_types); |
| + |
| + if (!intersection_types.empty() && !partner->IsSynced()) { |
| + VLOG(2) << "non-empty common types and " |
| + << partner->profile_debug_name_ << " isn't synced"; |
| + return false; |
| + } |
| + |
| for (syncable::ModelTypeSet::iterator i = intersection_types.begin(); |
| - i != intersection_types.end(); |
| - ++i) { |
| - if (!partner->IsSynced() || |
| - partner->GetUpdatedTimestamp(*i) != GetUpdatedTimestamp(*i)) { |
| + i != intersection_types.end(); ++i) { |
| + const std::string timestamp = GetUpdatedTimestamp(*i); |
| + const std::string partner_timestamp = partner->GetUpdatedTimestamp(*i); |
| + if (timestamp != partner_timestamp) { |
| + if (VLOG_IS_ON(2)) { |
| + std::string timestamp_base64, partner_timestamp_base64; |
| + if (!base::Base64Encode(timestamp, ×tamp_base64)) { |
| + NOTREACHED(); |
| + } |
| + if (!base::Base64Encode( |
| + partner_timestamp, &partner_timestamp_base64)) { |
| + NOTREACHED(); |
| + } |
| + VLOG(2) << syncable::ModelTypeToString(*i) << ": " |
| + << profile_debug_name_ << " timestamp = " |
| + << timestamp_base64 << ", " |
| + << partner->profile_debug_name_ |
| + << " partner timestamp = " |
| + << partner_timestamp_base64; |
| + } |
| return false; |
| } |
| } |
| @@ -824,7 +962,7 @@ std::string ProfileSyncServiceHarness::GetClientInfoString( |
| << ", service_is_pushing_changes: " |
| << ServiceIsPushingChanges() |
| << ", has_pending_backend_migration: " |
| - << service()->HasPendingBackendMigration(); |
| + << HasPendingBackendMigration(); |
| } else { |
| os << "Sync session snapshot not available"; |
| } |