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 c25ec5424830f0c3454cb91ff42260064c137976..b1b0dd6b4134d2eb39e2957d184dc31eab5b7248 100644 |
--- a/chrome/browser/sync/profile_sync_service_harness.cc |
+++ b/chrome/browser/sync/profile_sync_service_harness.cc |
@@ -256,7 +256,7 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() { |
} |
case WAITING_FOR_INITIAL_SYNC: { |
VLOG(1) << GetClientInfoString("WAITING_FOR_INITIAL_SYNC"); |
- if (IsSynced()) { |
+ if (IsFullySynced()) { |
// The first sync cycle is now complete. We can start running tests. |
SignalStateCompleteWithNextState(FULLY_SYNCED); |
break; |
@@ -270,9 +270,9 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() { |
} |
break; |
} |
- case WAITING_FOR_SYNC_TO_FINISH: { |
- VLOG(1) << GetClientInfoString("WAITING_FOR_SYNC_TO_FINISH"); |
- if (IsSynced()) { |
+ case WAITING_FOR_FULL_SYNC: { |
+ VLOG(1) << GetClientInfoString("WAITING_FOR_FULL_SYNC"); |
+ if (IsFullySynced()) { |
// The sync cycle we were waiting for is complete. |
SignalStateCompleteWithNextState(FULLY_SYNCED); |
break; |
@@ -292,6 +292,13 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() { |
} |
break; |
} |
+ case WAITING_FOR_DATA_SYNC: { |
+ if (IsDataSynced()) { |
+ SignalStateCompleteWithNextState(FULLY_SYNCED); |
+ break; |
+ } |
+ break; |
+ } |
case WAITING_FOR_UPDATES: { |
VLOG(1) << GetClientInfoString("WAITING_FOR_UPDATES"); |
DCHECK(timestamp_match_partner_); |
@@ -329,7 +336,7 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() { |
// sub-expressions. See crbug.com/98607, crbug.com/95619. |
// TODO(rlarocque): Figure out a less brittle way of detecting this. |
if (IsTypeEncrypted(waiting_for_encryption_type_) && |
- IsSynced() && |
+ IsFullySynced() && |
GetLastSessionSnapshot()->num_conflicting_updates == 0) { |
// Encryption is now complete for the the type in which we were waiting. |
SignalStateCompleteWithNextState(FULLY_SYNCED); |
@@ -403,7 +410,7 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() { |
if (GetStatus().server_reachable) { |
// The client was offline due to the network being disabled, but is now |
// back online. Wait for the pending sync cycle to complete. |
- SignalStateCompleteWithNextState(WAITING_FOR_SYNC_TO_FINISH); |
+ SignalStateCompleteWithNextState(WAITING_FOR_FULL_SYNC); |
} |
break; |
} |
@@ -544,15 +551,38 @@ bool ProfileSyncServiceHarness::AwaitSyncRestart() { |
"Waiting for sync configuration."); |
} |
-bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion( |
+bool ProfileSyncServiceHarness::AwaitDataSyncCompletion( |
+ const std::string& reason) { |
+ VLOG(1) << GetClientInfoString("AwaitDataSyncCompletion"); |
+ |
+ DCHECK(service()->sync_initialized()); |
+ DCHECK_NE(wait_state_, SYNC_DISABLED); |
+ DCHECK_NE(wait_state_, SERVER_UNREACHABLE); |
+ |
+ if (IsDataSynced()) { |
+ // Client is already synced; don't wait. |
+ return true; |
+ } |
+ |
+ wait_state_ = WAITING_FOR_DATA_SYNC; |
+ AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason); |
+ if (wait_state_ == FULLY_SYNCED) { |
+ return true; |
+ } else { |
+ LOG(ERROR) << "AwaitDataSyncCompletion failed, state is now: " << wait_state_; |
+ return false; |
+ } |
+} |
+ |
+bool ProfileSyncServiceHarness::AwaitFullSyncCompletion( |
const std::string& reason) { |
- VLOG(1) << GetClientInfoString("AwaitSyncCycleCompletion"); |
+ VLOG(1) << GetClientInfoString("AwaitFullSyncCompletion"); |
if (wait_state_ == SYNC_DISABLED) { |
LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << "."; |
return false; |
} |
- if (IsSynced()) { |
+ if (IsFullySynced()) { |
// Client is already synced; don't wait. |
return true; |
} |
@@ -560,12 +590,12 @@ bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion( |
if (wait_state_ == SERVER_UNREACHABLE) { |
// Client was offline; wait for it to go online, and then wait for sync. |
AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason); |
- DCHECK_EQ(wait_state_, WAITING_FOR_SYNC_TO_FINISH); |
+ DCHECK_EQ(wait_state_, WAITING_FOR_FULL_SYNC); |
return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason); |
} |
DCHECK(service()->sync_initialized()); |
- wait_state_ = WAITING_FOR_SYNC_TO_FINISH; |
+ wait_state_ = WAITING_FOR_FULL_SYNC; |
AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason); |
if (wait_state_ == FULLY_SYNCED) { |
// Client is online; sync was successful. |
@@ -650,7 +680,14 @@ bool ProfileSyncServiceHarness::AwaitMigration( |
<< " after migration finish is not WAITING_FOR_NOTHING"; |
return false; |
} |
- if (!AwaitSyncCycleCompletion( |
+ // We must use AwaitDataSyncCompletion rather than the more common |
+ // AwaitFullSyncCompletion. As long as crbug.com/97780 is open, we will |
+ // rely on self-notifiations to ensure that timestamps are udpated, which |
+ // allows AwaitFullSyncCompletion to return. However, in some migration |
+ // tests these notifications are completely disabled, so the timestamps do |
+ // not get updated. This is why we must use the less strict condition, |
+ // AwaitDataSyncCompletion. |
+ if (!AwaitDataSyncCompletion( |
"Config sync cycle after migration cycle")) { |
return false; |
} |
@@ -660,7 +697,7 @@ bool ProfileSyncServiceHarness::AwaitMigration( |
bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion( |
ProfileSyncServiceHarness* partner) { |
VLOG(1) << GetClientInfoString("AwaitMutualSyncCycleCompletion"); |
- if (!AwaitSyncCycleCompletion("Sync cycle completion on active client.")) |
+ if (!AwaitFullSyncCompletion("Sync cycle completion on active client.")) |
return false; |
return partner->WaitUntilTimestampMatches(this, |
"Sync cycle completion on passive client."); |
@@ -669,7 +706,7 @@ bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion( |
bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion( |
std::vector<ProfileSyncServiceHarness*>& partners) { |
VLOG(1) << GetClientInfoString("AwaitGroupSyncCycleCompletion"); |
- if (!AwaitSyncCycleCompletion("Sync cycle completion on active client.")) |
+ if (!AwaitFullSyncCompletion("Sync cycle completion on active client.")) |
return false; |
bool return_value = true; |
for (std::vector<ProfileSyncServiceHarness*>::iterator it = |
@@ -751,27 +788,49 @@ ProfileSyncService::Status ProfileSyncServiceHarness::GetStatus() { |
return service()->QueryDetailedSyncStatus(); |
} |
-bool ProfileSyncServiceHarness::IsSynced() { |
- if (service() == NULL) { |
- VLOG(1) << GetClientInfoString("IsSynced: false"); |
- return false; |
- } |
- const SyncSessionSnapshot* snap = GetLastSessionSnapshot(); |
- // TODO(rsimha): Remove additional checks of snap->has_more_to_sync and |
- // snap->unsynced_count once http://crbug.com/48989 is fixed. |
- bool is_synced = snap && |
+// We use this function to share code between IsFullySynced and IsDataSynced |
+// while ensuring that all conditions are evaluated using on the same snapshot. |
+bool ProfileSyncServiceHarness::IsDataSyncedImpl( |
+ const browser_sync::sessions::SyncSessionSnapshot *snap) { |
+ return snap && |
snap->num_blocking_conflicting_updates == 0 && |
ServiceIsPushingChanges() && |
GetStatus().notifications_enabled && |
!service()->HasUnsyncedItems() && |
!snap->has_more_to_sync && |
- snap->unsynced_count == 0 && |
!HasPendingBackendMigration() && |
service()->passphrase_required_reason() != |
- sync_api::REASON_SET_PASSPHRASE_FAILED; |
+ sync_api::REASON_SET_PASSPHRASE_FAILED; |
+} |
+ |
+bool ProfileSyncServiceHarness::IsDataSynced() { |
+ if (service() == NULL) { |
+ VLOG(1) << GetClientInfoString("IsDataSynced(): false"); |
+ return false; |
+ } |
+ |
+ const SyncSessionSnapshot* snap = GetLastSessionSnapshot(); |
+ bool is_data_synced = IsDataSyncedImpl(snap); |
+ |
+ VLOG(1) << GetClientInfoString( |
+ is_data_synced ? "IsDataSynced: true" : "IsDataSynced: false"); |
+ return is_data_synced; |
+} |
+ |
+bool ProfileSyncServiceHarness::IsFullySynced() { |
+ if (service() == NULL) { |
+ VLOG(1) << GetClientInfoString("IsFullySynced: false"); |
+ return false; |
+ } |
+ const SyncSessionSnapshot* snap = GetLastSessionSnapshot(); |
+ // snap->unsynced_count == 0 is a fairly reliable indicator of whether or not |
+ // our timestamp is in sync with the server. |
+ bool is_fully_synced = IsDataSyncedImpl(snap) && |
+ snap->unsynced_count == 0; |
+ |
VLOG(1) << GetClientInfoString( |
- is_synced ? "IsSynced: true" : "IsSynced: false"); |
- return is_synced; |
+ is_fully_synced ? "IsFullySynced: true" : "IsFullySynced: false"); |
+ return is_fully_synced; |
} |
bool ProfileSyncServiceHarness::HasPendingBackendMigration() { |
@@ -784,7 +843,7 @@ bool ProfileSyncServiceHarness::MatchesOtherClient( |
ProfileSyncServiceHarness* partner) { |
// TODO(akalin): Shouldn't this belong with the intersection check? |
// Otherwise, this function isn't symmetric. |
- if (!IsSynced()) { |
+ if (!IsFullySynced()) { |
VLOG(2) << profile_debug_name_ << ": not synced, assuming doesn't match"; |
return false; |
} |
@@ -803,7 +862,7 @@ bool ProfileSyncServiceHarness::MatchesOtherClient( |
<< ": common types are " |
<< syncable::ModelTypeSetToString(intersection_types); |
- if (!intersection_types.empty() && !partner->IsSynced()) { |
+ if (!intersection_types.empty() && !partner->IsFullySynced()) { |
VLOG(2) << "non-empty common types and " |
<< partner->profile_debug_name_ << " isn't synced"; |
return false; |
@@ -872,7 +931,7 @@ bool ProfileSyncServiceHarness::EnableSyncForDatatype( |
synced_datatypes.insert(syncable::ModelTypeFromInt(datatype)); |
service()->OnUserChoseDatatypes(false, synced_datatypes); |
- if (AwaitSyncCycleCompletion("Datatype configuration.")) { |
+ if (AwaitFullSyncCompletion("Datatype configuration.")) { |
VLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype " |
<< syncable::ModelTypeToString(datatype) |
<< " on " << profile_debug_name_ << "."; |
@@ -905,7 +964,7 @@ bool ProfileSyncServiceHarness::DisableSyncForDatatype( |
synced_datatypes.erase(it); |
service()->OnUserChoseDatatypes(false, synced_datatypes); |
- if (AwaitSyncCycleCompletion("Datatype reconfiguration.")) { |
+ if (AwaitFullSyncCompletion("Datatype reconfiguration.")) { |
VLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype " |
<< syncable::ModelTypeToString(datatype) |
<< " on " << profile_debug_name_ << "."; |
@@ -935,7 +994,7 @@ bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() { |
synced_datatypes.insert(syncable::ModelTypeFromInt(i)); |
} |
service()->OnUserChoseDatatypes(true, synced_datatypes); |
- if (AwaitSyncCycleCompletion("Datatype reconfiguration.")) { |
+ if (AwaitFullSyncCompletion("Datatype reconfiguration.")) { |
VLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes on " |
<< profile_debug_name_ << "."; |
return true; |
@@ -1035,7 +1094,7 @@ bool ProfileSyncServiceHarness::WaitForTypeEncryption( |
// sub-expressions. See crbug.com/95619. |
// TODO(rlarocque): Figure out a less brittle way of detecting this. |
if (IsTypeEncrypted(type) && |
- IsSynced() && |
+ IsFullySynced() && |
GetLastSessionSnapshot()->num_conflicting_updates == 0) { |
// Encryption is already complete for |type|; do not wait. |
return true; |