1 // Copyright 2013 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/test/integration/profile_sync_service_harness.h" 6 7 #include <cstddef> 8 #include <iterator> 9 #include <ostream> 10 #include <set> 11 #include <sstream> 12 #include <vector> 13 14 #include "base/base64.h" 15 #include "base/bind.h" 16 #include "base/command_line.h" 17 #include "base/compiler_specific.h" 18 #include "base/json/json_writer.h" 19 #include "base/location.h" 20 #include "base/logging.h" 21 #include "base/memory/ref_counted.h" 22 #include "base/message_loop/message_loop.h" 23 #include "base/prefs/pref_service.h" 24 #include "base/strings/stringprintf.h" 25 #include "chrome/browser/chrome_notification_types.h" 26 #include "chrome/browser/invalidation/p2p_invalidation_service.h" 27 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/signin/profile_oauth2_token_service.h" 29 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 30 #include "chrome/browser/signin/signin_manager_base.h" 31 #include "chrome/browser/sync/about_sync_util.h" 32 #include "chrome/browser/sync/glue/data_type_controller.h" 33 #include "chrome/browser/sync/profile_sync_service_factory.h" 34 #include "chrome/browser/sync/test/integration/status_change_checker.h" 35 #include "chrome/common/chrome_switches.h" 36 #include "chrome/common/pref_names.h" 37 #include "content/public/browser/notification_service.h" 38 #include "google_apis/gaia/gaia_constants.h" 39 #include "sync/internal_api/public/base/progress_marker_map.h" 40 #include "sync/internal_api/public/sessions/sync_session_snapshot.h" 41 #include "sync/internal_api/public/util/sync_string_conversions.h" 42 43 #if defined(ENABLE_MANAGED_USERS) 44 #include "chrome/browser/managed_mode/managed_user_constants.h" 45 #endif 46 47 using syncer::sessions::SyncSessionSnapshot; 48 using invalidation::P2PInvalidationService; 49 50 // The amount of time for which we wait for a sync operation to complete. 51 static const int kSyncOperationTimeoutMs = 45000; 52 53 // Simple class to implement a timeout using PostDelayedTask. If it is not 54 // aborted before picked up by a message queue, then it asserts. This class is 55 // not thread safe. 56 class StateChangeTimeoutEvent 57 : public base::RefCountedThreadSafe<StateChangeTimeoutEvent> { 58 public: 59 explicit StateChangeTimeoutEvent(ProfileSyncServiceHarness* caller); 60 61 // The entry point to the class from PostDelayedTask. 62 void Callback(); 63 64 // Cancels the actions of the callback. Returns true if success, false 65 // if the callback has already timed out. 66 bool Abort(); 67 68 private: 69 friend class base::RefCountedThreadSafe<StateChangeTimeoutEvent>; 70 71 ~StateChangeTimeoutEvent(); 72 73 bool aborted_; 74 bool did_timeout_; 75 76 // Due to synchronization of the IO loop, the caller will always be alive 77 // if the class is not aborted. 78 ProfileSyncServiceHarness* caller_; 79 80 DISALLOW_COPY_AND_ASSIGN(StateChangeTimeoutEvent); 81 }; 82 83 StateChangeTimeoutEvent::StateChangeTimeoutEvent( 84 ProfileSyncServiceHarness* caller) 85 : aborted_(false), did_timeout_(false), caller_(caller) { 86 } 87 88 StateChangeTimeoutEvent::~StateChangeTimeoutEvent() { 89 } 90 91 void StateChangeTimeoutEvent::Callback() { 92 if (!aborted_) { 93 DCHECK(caller_->status_change_checker_); 94 // TODO(rsimha): Simply return false on timeout instead of repeating the 95 // exit condition check. 96 if (!caller_->status_change_checker_->IsExitConditionSatisfied()) { 97 did_timeout_ = true; 98 DCHECK(!aborted_); 99 caller_->SignalStateComplete(); 100 } 101 } 102 } 103 104 bool StateChangeTimeoutEvent::Abort() { 105 aborted_ = true; 106 caller_ = NULL; 107 return !did_timeout_; 108 } 109 110 namespace { 111 112 // Helper function which returns true if the sync backend has been initialized, 113 // or if backend initialization was blocked for some reason. 114 bool DoneWaitingForBackendInitialization( 115 const ProfileSyncServiceHarness* harness) { 116 DCHECK(harness); 117 // Backend is initialized. 118 if (harness->service()->sync_initialized()) 119 return true; 120 // Backend initialization is blocked by an auth error. 121 if (harness->HasAuthError()) 122 return true; 123 // Backend initialization is blocked by a failure to fetch Oauth2 tokens. 124 if (harness->service()->IsRetryingAccessTokenFetchForTest()) 125 return true; 126 // Still waiting on backend initialization. 127 return false; 128 } 129 130 // Helper function which returns true if initial sync is complete, or if the 131 // initial sync is blocked for some reason. 132 bool DoneWaitingForInitialSync(const ProfileSyncServiceHarness* harness) { 133 DCHECK(harness); 134 // Initial sync is complete. 135 if (harness->IsFullySynced()) 136 return true; 137 // Initial sync is blocked because custom passphrase is required. 138 if (harness->service()->passphrase_required_reason() == 139 syncer::REASON_DECRYPTION) { 140 return true; 141 } 142 // Initial sync is blocked by an auth error. 143 if (harness->HasAuthError()) 144 return true; 145 // Still waiting on initial sync. 146 return false; 147 } 148 149 // Helper function which returns true if the sync client is fully synced, or if 150 // sync is blocked for some reason. 151 bool DoneWaitingForFullSync(const ProfileSyncServiceHarness* harness) { 152 DCHECK(harness); 153 // Sync is complete. 154 if (harness->IsFullySynced()) 155 return true; 156 // Sync is blocked by an auth error. 157 if (harness->HasAuthError()) 158 return true; 159 // Sync is blocked by a failure to fetch Oauth2 tokens. 160 if (harness->service()->IsRetryingAccessTokenFetchForTest()) 161 return true; 162 // Still waiting on sync. 163 return false; 164 } 165 166 // Helper function which returns true if the sync client requires a custom 167 // passphrase to be entered for decryption. 168 bool IsPassphraseRequired(const ProfileSyncServiceHarness* harness) { 169 DCHECK(harness); 170 return harness->service()->IsPassphraseRequired(); 171 } 172 173 // Helper function which returns true if the custom passphrase entered was 174 // accepted. 175 bool IsPassphraseAccepted(const ProfileSyncServiceHarness* harness) { 176 DCHECK(harness); 177 return (!harness->service()->IsPassphraseRequired() && 178 harness->service()->IsUsingSecondaryPassphrase()); 179 } 180 181 // Helper function which returns true if the sync client no longer has a pending 182 // backend migration. 183 bool NoPendingBackendMigration(const ProfileSyncServiceHarness* harness) { 184 DCHECK(harness); 185 return !harness->HasPendingBackendMigration(); 186 } 187 188 // Helper function which returns true if the client has detected an actionable 189 // error. 190 bool HasActionableError(const ProfileSyncServiceHarness* harness) { 191 DCHECK(harness); 192 ProfileSyncService::Status status = harness->GetStatus(); 193 return (status.sync_protocol_error.action != syncer::UNKNOWN_ACTION && 194 harness->service()->HasUnrecoverableError() == true); 195 } 196 197 } // namespace 198 199 // static 200 ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create( 201 Profile* profile, 202 const std::string& username, 203 const std::string& password) { 204 return new ProfileSyncServiceHarness(profile, username, password, NULL); 205 } 206 207 // static 208 ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateForIntegrationTest( 209 Profile* profile, 210 const std::string& username, 211 const std::string& password, 212 P2PInvalidationService* p2p_invalidation_service) { 213 return new ProfileSyncServiceHarness(profile, 214 username, 215 password, 216 p2p_invalidation_service); 217 } 218 219 ProfileSyncServiceHarness::ProfileSyncServiceHarness( 220 Profile* profile, 221 const std::string& username, 222 const std::string& password, 223 P2PInvalidationService* p2p_invalidation_service) 224 : profile_(profile), 225 service_(ProfileSyncServiceFactory::GetForProfile(profile)), 226 p2p_invalidation_service_(p2p_invalidation_service), 227 progress_marker_partner_(NULL), 228 username_(username), 229 password_(password), 230 oauth2_refesh_token_number_(0), 231 profile_debug_name_(profile->GetDebugName()), 232 status_change_checker_(NULL) { 233 } 234 235 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { 236 if (service()->HasObserver(this)) 237 service()->RemoveObserver(this); 238 } 239 240 void ProfileSyncServiceHarness::SetCredentials(const std::string& username, 241 const std::string& password) { 242 username_ = username; 243 password_ = password; 244 } 245 246 bool ProfileSyncServiceHarness::SetupSync() { 247 bool result = SetupSync(syncer::ModelTypeSet::All()); 248 if (result == false) { 249 std::string status = GetServiceStatus(); 250 LOG(ERROR) << profile_debug_name_ 251 << ": SetupSync failed. Syncer status:\n" << status; 252 } else { 253 DVLOG(1) << profile_debug_name_ << ": SetupSync successful."; 254 } 255 return result; 256 } 257 258 bool ProfileSyncServiceHarness::SetupSync( 259 syncer::ModelTypeSet synced_datatypes) { 260 // Initialize the sync client's profile sync service object. 261 if (service() == NULL) { 262 LOG(ERROR) << "SetupSync(): service() is null."; 263 return false; 264 } 265 266 // Subscribe sync client to notifications from the profile sync service. 267 if (!service()->HasObserver(this)) 268 service()->AddObserver(this); 269 270 // Tell the sync service that setup is in progress so we don't start syncing 271 // until we've finished configuration. 272 service()->SetSetupInProgress(true); 273 274 // Authenticate sync client using GAIA credentials. 275 service()->signin()->SetAuthenticatedUsername(username_); 276 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 277 username_); 278 GoogleServiceSigninSuccessDetails details(username_, password_); 279 content::NotificationService::current()->Notify( 280 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, 281 content::Source<Profile>(profile_), 282 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); 283 284 #if defined(ENABLE_MANAGED_USERS) 285 std::string account_id = profile_->IsManaged() ? 286 managed_users::kManagedUserPseudoEmail : username_; 287 #else 288 std::string account_id = username_; 289 #endif 290 DCHECK(!account_id.empty()); 291 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)-> 292 UpdateCredentials(account_id, GenerateFakeOAuth2RefreshTokenString()); 293 294 // Wait for the OnBackendInitialized() callback. 295 if (!AwaitBackendInitialized()) { 296 LOG(ERROR) << "OnBackendInitialized() not seen after " 297 << kSyncOperationTimeoutMs / 1000 298 << " seconds."; 299 return false; 300 } 301 302 // Make sure that initial sync wasn't blocked by a missing passphrase. 303 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) { 304 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" 305 " until SetDecryptionPassphrase is called."; 306 return false; 307 } 308 309 // Make sure that initial sync wasn't blocked by rejected credentials. 310 if (HasAuthError()) { 311 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed."; 312 return false; 313 } 314 315 // Choose the datatypes to be synced. If all datatypes are to be synced, 316 // set sync_everything to true; otherwise, set it to false. 317 bool sync_everything = 318 synced_datatypes.Equals(syncer::ModelTypeSet::All()); 319 service()->OnUserChoseDatatypes(sync_everything, synced_datatypes); 320 321 // Notify ProfileSyncService that we are done with configuration. 322 FinishSyncSetup(); 323 324 // Subscribe sync client to notifications from the backend migrator 325 // (possible only after choosing data types). 326 if (!TryListeningToMigrationEvents()) { 327 NOTREACHED(); 328 return false; 329 } 330 331 // Set an implicit passphrase for encryption if an explicit one hasn't already 332 // been set. If an explicit passphrase has been set, immediately return false, 333 // since a decryption passphrase is required. 334 if (!service()->IsUsingSecondaryPassphrase()) { 335 service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT); 336 } else { 337 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" 338 " until SetDecryptionPassphrase is called."; 339 return false; 340 } 341 342 // Wait for initial sync cycle to be completed. 343 DCHECK(service()->sync_initialized()); 344 StatusChangeChecker initial_sync_checker( 345 base::Bind(&DoneWaitingForInitialSync, base::Unretained(this)), 346 "DoneWaitingForInitialSync"); 347 if (!AwaitStatusChange(&initial_sync_checker, "SetupSync")) { 348 LOG(ERROR) << "Initial sync cycle did not complete after " 349 << kSyncOperationTimeoutMs / 1000 350 << " seconds."; 351 return false; 352 } 353 354 // Make sure that initial sync wasn't blocked by a missing passphrase. 355 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) { 356 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" 357 " until SetDecryptionPassphrase is called."; 358 return false; 359 } 360 361 // Make sure that initial sync wasn't blocked by rejected credentials. 362 if (service()->GetAuthError().state() == 363 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) { 364 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed."; 365 return false; 366 } 367 368 return true; 369 } 370 371 bool ProfileSyncServiceHarness::TryListeningToMigrationEvents() { 372 browser_sync::BackendMigrator* migrator = 373 service()->GetBackendMigratorForTest(); 374 if (migrator && !migrator->HasMigrationObserver(this)) { 375 migrator->AddMigrationObserver(this); 376 return true; 377 } 378 return false; 379 } 380 381 void ProfileSyncServiceHarness::SignalStateComplete() { 382 base::MessageLoop::current()->QuitWhenIdle(); 383 } 384 385 void ProfileSyncServiceHarness::OnStateChanged() { 386 if (!status_change_checker_) 387 return; 388 389 DVLOG(1) << GetClientInfoString(status_change_checker_->callback_name()); 390 if (status_change_checker_->IsExitConditionSatisfied()) 391 base::MessageLoop::current()->QuitWhenIdle(); 392 } 393 394 void ProfileSyncServiceHarness::OnSyncCycleCompleted() { 395 // Integration tests still use p2p notifications. 396 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 397 bool is_notifiable_commit = 398 (snap.model_neutral_state().num_successful_commits > 0); 399 if (is_notifiable_commit && p2p_invalidation_service_) { 400 syncer::ModelTypeSet model_types = 401 snap.model_neutral_state().commit_request_types; 402 syncer::ObjectIdSet ids = ModelTypeSetToObjectIdSet(model_types); 403 p2p_invalidation_service_->SendInvalidation(ids); 404 } 405 OnStateChanged(); 406 } 407 408 void ProfileSyncServiceHarness::OnMigrationStateChange() { 409 // Update migration state. 410 if (HasPendingBackendMigration()) { 411 // Merge current pending migration types into 412 // |pending_migration_types_|. 413 pending_migration_types_.PutAll( 414 service()->GetBackendMigratorForTest()-> 415 GetPendingMigrationTypesForTest()); 416 DVLOG(1) << profile_debug_name_ << ": new pending migration types " 417 << syncer::ModelTypeSetToString(pending_migration_types_); 418 } else { 419 // Merge just-finished pending migration types into 420 // |migration_types_|. 421 migrated_types_.PutAll(pending_migration_types_); 422 pending_migration_types_.Clear(); 423 DVLOG(1) << profile_debug_name_ << ": new migrated types " 424 << syncer::ModelTypeSetToString(migrated_types_); 425 } 426 OnStateChanged(); 427 } 428 429 bool ProfileSyncServiceHarness::AwaitPassphraseRequired() { 430 DVLOG(1) << GetClientInfoString("AwaitPassphraseRequired"); 431 if (IsSyncDisabled()) { 432 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << "."; 433 return false; 434 } 435 436 if (service()->IsPassphraseRequired()) { 437 // It's already true that a passphrase is required; don't wait. 438 return true; 439 } 440 441 StatusChangeChecker passphrase_required_checker( 442 base::Bind(&::IsPassphraseRequired, base::Unretained(this)), 443 "IsPassphraseRequired"); 444 return AwaitStatusChange(&passphrase_required_checker, 445 "AwaitPassphraseRequired"); 446 } 447 448 bool ProfileSyncServiceHarness::AwaitPassphraseAccepted() { 449 DVLOG(1) << GetClientInfoString("AwaitPassphraseAccepted"); 450 if (IsSyncDisabled()) { 451 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << "."; 452 return false; 453 } 454 455 if (!service()->IsPassphraseRequired() && 456 service()->IsUsingSecondaryPassphrase()) { 457 // Passphrase is already accepted; don't wait. 458 FinishSyncSetup(); 459 return true; 460 } 461 462 StatusChangeChecker passphrase_accepted_checker( 463 base::Bind(&::IsPassphraseAccepted, base::Unretained(this)), 464 "IsPassphraseAccepted"); 465 bool return_value = AwaitStatusChange(&passphrase_accepted_checker, 466 "AwaitPassphraseAccepted"); 467 if (return_value) 468 FinishSyncSetup(); 469 return return_value; 470 } 471 472 bool ProfileSyncServiceHarness::AwaitBackendInitialized() { 473 DVLOG(1) << GetClientInfoString("AwaitBackendInitialized"); 474 if (service()->sync_initialized()) { 475 // The sync backend host has already been initialized; don't wait. 476 return true; 477 } 478 479 StatusChangeChecker backend_initialized_checker( 480 base::Bind(&DoneWaitingForBackendInitialization, 481 base::Unretained(this)), 482 "DoneWaitingForBackendInitialization"); 483 AwaitStatusChange(&backend_initialized_checker, "AwaitBackendInitialized"); 484 return service()->sync_initialized(); 485 } 486 487 bool ProfileSyncServiceHarness::AwaitDataSyncCompletion() { 488 DVLOG(1) << GetClientInfoString("AwaitDataSyncCompletion"); 489 490 DCHECK(service()->sync_initialized()); 491 DCHECK(!IsSyncDisabled()); 492 493 if (IsDataSynced()) { 494 // Client is already synced; don't wait. 495 return true; 496 } 497 498 StatusChangeChecker data_synced_checker( 499 base::Bind(&ProfileSyncServiceHarness::IsDataSynced, 500 base::Unretained(this)), 501 "IsDataSynced"); 502 return AwaitStatusChange(&data_synced_checker, "AwaitDataSyncCompletion"); 503 } 504 505 bool ProfileSyncServiceHarness::AwaitFullSyncCompletion() { 506 DVLOG(1) << GetClientInfoString("AwaitFullSyncCompletion"); 507 if (IsSyncDisabled()) { 508 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << "."; 509 return false; 510 } 511 512 if (IsFullySynced()) { 513 // Client is already synced; don't wait. 514 return true; 515 } 516 517 DCHECK(service()->sync_initialized()); 518 StatusChangeChecker fully_synced_checker( 519 base::Bind(&DoneWaitingForFullSync, base::Unretained(this)), 520 "DoneWaitingForFullSync"); 521 AwaitStatusChange(&fully_synced_checker, "AwaitFullSyncCompletion"); 522 return IsFullySynced(); 523 } 524 525 bool ProfileSyncServiceHarness::AwaitSyncDisabled() { 526 DCHECK(service()->HasSyncSetupCompleted()); 527 DCHECK(!IsSyncDisabled()); 528 StatusChangeChecker sync_disabled_checker( 529 base::Bind(&ProfileSyncServiceHarness::IsSyncDisabled, 530 base::Unretained(this)), 531 "IsSyncDisabled"); 532 return AwaitStatusChange(&sync_disabled_checker, "AwaitSyncDisabled"); 533 } 534 535 // TODO(rsimha): Move this method from PSSHarness to the class that uses it. 536 bool ProfileSyncServiceHarness::AwaitExponentialBackoffVerification() { 537 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 538 retry_verifier_.reset(new RetryVerifier()); 539 retry_verifier_->Initialize(snap); 540 StatusChangeChecker exponential_backoff_checker( 541 base::Bind(&ProfileSyncServiceHarness::IsExponentialBackoffDone, 542 base::Unretained(this)), 543 "IsExponentialBackoffDone"); 544 AwaitStatusChange(&exponential_backoff_checker, 545 "AwaitExponentialBackoffVerification"); 546 return retry_verifier_->Succeeded(); 547 } 548 549 bool ProfileSyncServiceHarness::AwaitActionableError() { 550 ProfileSyncService::Status status = GetStatus(); 551 CHECK(status.sync_protocol_error.action == syncer::UNKNOWN_ACTION); 552 StatusChangeChecker actionable_error_checker( 553 base::Bind(&HasActionableError, base::Unretained(this)), 554 "HasActionableError"); 555 return AwaitStatusChange(&actionable_error_checker, "AwaitActionableError"); 556 } 557 558 bool ProfileSyncServiceHarness::AwaitMigration( 559 syncer::ModelTypeSet expected_migrated_types) { 560 DVLOG(1) << GetClientInfoString("AwaitMigration"); 561 DVLOG(1) << profile_debug_name_ << ": waiting until migration is done for " 562 << syncer::ModelTypeSetToString(expected_migrated_types); 563 while (true) { 564 bool migration_finished = migrated_types_.HasAll(expected_migrated_types); 565 DVLOG(1) << "Migrated types " 566 << syncer::ModelTypeSetToString(migrated_types_) 567 << (migration_finished ? " contains " : " does not contain ") 568 << syncer::ModelTypeSetToString(expected_migrated_types); 569 if (migration_finished) { 570 return true; 571 } 572 573 if (!HasPendingBackendMigration()) { 574 StatusChangeChecker pending_migration_checker( 575 base::Bind(&ProfileSyncServiceHarness::HasPendingBackendMigration, 576 base::Unretained(this)), 577 "HasPendingBackendMigration"); 578 if (!AwaitStatusChange(&pending_migration_checker, 579 "AwaitMigration Start")) { 580 DVLOG(1) << profile_debug_name_ << ": Migration did not start"; 581 return false; 582 } 583 } 584 585 StatusChangeChecker migration_finished_checker( 586 base::Bind(&::NoPendingBackendMigration, base::Unretained(this)), 587 "NoPendingBackendMigration"); 588 if (!AwaitStatusChange(&migration_finished_checker, 589 "AwaitMigration Finish")) { 590 DVLOG(1) << profile_debug_name_ << ": Migration did not finish"; 591 return false; 592 } 593 594 // We must use AwaitDataSyncCompletion rather than the more common 595 // AwaitFullSyncCompletion. As long as crbug.com/97780 is open, we will 596 // rely on self-notifications to ensure that progress markers are updated, 597 // which allows AwaitFullSyncCompletion to return. However, in some 598 // migration tests these notifications are completely disabled, so the 599 // progress markers do not get updated. This is why we must use the less 600 // strict condition, AwaitDataSyncCompletion. 601 if (!AwaitDataSyncCompletion()) 602 return false; 603 } 604 } 605 606 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion( 607 ProfileSyncServiceHarness* partner) { 608 DVLOG(1) << GetClientInfoString("AwaitMutualSyncCycleCompletion"); 609 if (!AwaitFullSyncCompletion()) 610 return false; 611 return partner->WaitUntilProgressMarkersMatch(this); 612 } 613 614 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion( 615 std::vector<ProfileSyncServiceHarness*>& partners) { 616 DVLOG(1) << GetClientInfoString("AwaitGroupSyncCycleCompletion"); 617 if (!AwaitFullSyncCompletion()) 618 return false; 619 bool return_value = true; 620 for (std::vector<ProfileSyncServiceHarness*>::iterator it = 621 partners.begin(); it != partners.end(); ++it) { 622 if ((this != *it) && (!(*it)->IsSyncDisabled())) { 623 return_value = return_value && 624 (*it)->WaitUntilProgressMarkersMatch(this); 625 } 626 } 627 return return_value; 628 } 629 630 // static 631 bool ProfileSyncServiceHarness::AwaitQuiescence( 632 std::vector<ProfileSyncServiceHarness*>& clients) { 633 DVLOG(1) << "AwaitQuiescence."; 634 bool return_value = true; 635 for (std::vector<ProfileSyncServiceHarness*>::iterator it = 636 clients.begin(); it != clients.end(); ++it) { 637 if (!(*it)->IsSyncDisabled()) { 638 return_value = return_value && 639 (*it)->AwaitGroupSyncCycleCompletion(clients); 640 } 641 } 642 return return_value; 643 } 644 645 bool ProfileSyncServiceHarness::WaitUntilProgressMarkersMatch( 646 ProfileSyncServiceHarness* partner) { 647 DVLOG(1) << GetClientInfoString("WaitUntilProgressMarkersMatch"); 648 if (IsSyncDisabled()) { 649 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << "."; 650 return false; 651 } 652 653 // TODO(rsimha): Replace the mechanism of matching up progress markers with 654 // one that doesn't require every client to have the same progress markers. 655 DCHECK(!progress_marker_partner_); 656 progress_marker_partner_ = partner; 657 bool return_value = false; 658 if (MatchesPartnerClient()) { 659 // Progress markers already match; don't wait. 660 return_value = true; 661 } else { 662 partner->service()->AddObserver(this); 663 StatusChangeChecker matches_other_client_checker( 664 base::Bind(&ProfileSyncServiceHarness::MatchesPartnerClient, 665 base::Unretained(this)), 666 "MatchesPartnerClient"); 667 return_value = AwaitStatusChange(&matches_other_client_checker, 668 "WaitUntilProgressMarkersMatch"); 669 partner->service()->RemoveObserver(this); 670 } 671 progress_marker_partner_ = NULL; 672 return return_value; 673 } 674 675 bool ProfileSyncServiceHarness::AwaitStatusChange( 676 StatusChangeChecker* checker, const std::string& source) { 677 DVLOG(1) << GetClientInfoString("AwaitStatusChange"); 678 679 if (IsSyncDisabled()) { 680 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << "."; 681 return false; 682 } 683 684 DCHECK(status_change_checker_ == NULL); 685 status_change_checker_ = checker; 686 687 scoped_refptr<StateChangeTimeoutEvent> timeout_signal( 688 new StateChangeTimeoutEvent(this)); 689 { 690 base::MessageLoop* loop = base::MessageLoop::current(); 691 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 692 loop->PostDelayedTask( 693 FROM_HERE, 694 base::Bind(&StateChangeTimeoutEvent::Callback, 695 timeout_signal.get()), 696 base::TimeDelta::FromMilliseconds(kSyncOperationTimeoutMs)); 697 loop->Run(); 698 } 699 700 status_change_checker_ = NULL; 701 702 if (timeout_signal->Abort()) { 703 DVLOG(1) << GetClientInfoString("AwaitStatusChange succeeded"); 704 return true; 705 } else { 706 DVLOG(0) << GetClientInfoString(base::StringPrintf( 707 "AwaitStatusChange called from %s timed out", source.c_str())); 708 return false; 709 } 710 } 711 712 std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() { 713 return base::StringPrintf("oauth2_refresh_token_%d", 714 ++oauth2_refesh_token_number_); 715 } 716 717 ProfileSyncService::Status ProfileSyncServiceHarness::GetStatus() const { 718 DCHECK(service() != NULL) << "GetStatus(): service() is NULL."; 719 ProfileSyncService::Status result; 720 service()->QueryDetailedSyncStatus(&result); 721 return result; 722 } 723 724 bool ProfileSyncServiceHarness::IsExponentialBackoffDone() const { 725 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 726 retry_verifier_->VerifyRetryInterval(snap); 727 return (retry_verifier_->done()); 728 } 729 730 bool ProfileSyncServiceHarness::IsSyncDisabled() const { 731 return !service()->setup_in_progress() && 732 !service()->HasSyncSetupCompleted(); 733 } 734 735 bool ProfileSyncServiceHarness::HasAuthError() const { 736 return service()->GetAuthError().state() == 737 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS || 738 service()->GetAuthError().state() == 739 GoogleServiceAuthError::SERVICE_ERROR || 740 service()->GetAuthError().state() == 741 GoogleServiceAuthError::REQUEST_CANCELED; 742 } 743 744 // We use this function to share code between IsFullySynced and IsDataSynced. 745 bool ProfileSyncServiceHarness::IsDataSyncedImpl() const { 746 return ServiceIsPushingChanges() && 747 GetStatus().notifications_enabled && 748 !service()->HasUnsyncedItems() && 749 !HasPendingBackendMigration(); 750 } 751 752 bool ProfileSyncServiceHarness::IsDataSynced() const { 753 if (service() == NULL) { 754 DVLOG(1) << GetClientInfoString("IsDataSynced(): false"); 755 return false; 756 } 757 758 bool is_data_synced = IsDataSyncedImpl(); 759 760 DVLOG(1) << GetClientInfoString( 761 is_data_synced ? "IsDataSynced: true" : "IsDataSynced: false"); 762 return is_data_synced; 763 } 764 765 bool ProfileSyncServiceHarness::IsFullySynced() const { 766 if (service() == NULL) { 767 DVLOG(1) << GetClientInfoString("IsFullySynced: false"); 768 return false; 769 } 770 // If we didn't try to commit anything in the previous cycle, there's a 771 // good chance that we're now fully up to date. 772 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 773 bool is_fully_synced = 774 snap.model_neutral_state().num_successful_commits == 0 775 && snap.model_neutral_state().commit_result == syncer::SYNCER_OK 776 && IsDataSyncedImpl(); 777 778 DVLOG(1) << GetClientInfoString( 779 is_fully_synced ? "IsFullySynced: true" : "IsFullySynced: false"); 780 return is_fully_synced; 781 } 782 783 void ProfileSyncServiceHarness::FinishSyncSetup() { 784 service()->SetSetupInProgress(false); 785 service()->SetSyncSetupCompleted(); 786 } 787 788 bool ProfileSyncServiceHarness::HasPendingBackendMigration() const { 789 browser_sync::BackendMigrator* migrator = 790 service()->GetBackendMigratorForTest(); 791 return migrator && migrator->state() != browser_sync::BackendMigrator::IDLE; 792 } 793 794 bool ProfileSyncServiceHarness::AutoStartEnabled() { 795 return service()->auto_start_enabled(); 796 } 797 798 bool ProfileSyncServiceHarness::MatchesPartnerClient() const { 799 // TODO(akalin): Shouldn't this belong with the intersection check? 800 // Otherwise, this function isn't symmetric. 801 DCHECK(progress_marker_partner_); 802 if (!IsFullySynced()) { 803 DVLOG(2) << profile_debug_name_ << ": not synced, assuming doesn't match"; 804 return false; 805 } 806 807 // Only look for a match if we have at least one enabled datatype in 808 // common with the partner client. 809 const syncer::ModelTypeSet common_types = 810 Intersection(service()->GetActiveDataTypes(), 811 progress_marker_partner_->service()->GetActiveDataTypes()); 812 813 DVLOG(2) << profile_debug_name_ << ", " 814 << progress_marker_partner_->profile_debug_name_ 815 << ": common types are " 816 << syncer::ModelTypeSetToString(common_types); 817 818 if (!common_types.Empty() && !progress_marker_partner_->IsFullySynced()) { 819 DVLOG(2) << "non-empty common types and " 820 << progress_marker_partner_->profile_debug_name_ 821 << " isn't synced"; 822 return false; 823 } 824 825 for (syncer::ModelTypeSet::Iterator i = common_types.First(); 826 i.Good(); i.Inc()) { 827 const std::string marker = GetSerializedProgressMarker(i.Get()); 828 const std::string partner_marker = 829 progress_marker_partner_->GetSerializedProgressMarker(i.Get()); 830 if (marker != partner_marker) { 831 if (VLOG_IS_ON(2)) { 832 std::string marker_base64, partner_marker_base64; 833 base::Base64Encode(marker, &marker_base64); 834 base::Base64Encode(partner_marker, &partner_marker_base64); 835 DVLOG(2) << syncer::ModelTypeToString(i.Get()) << ": " 836 << profile_debug_name_ << " progress marker = " 837 << marker_base64 << ", " 838 << progress_marker_partner_->profile_debug_name_ 839 << " partner progress marker = " 840 << partner_marker_base64; 841 } 842 return false; 843 } 844 } 845 return true; 846 } 847 848 SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const { 849 DCHECK(service() != NULL) << "Sync service has not yet been set up."; 850 if (service()->sync_initialized()) { 851 return service()->GetLastSessionSnapshot(); 852 } 853 return SyncSessionSnapshot(); 854 } 855 856 bool ProfileSyncServiceHarness::EnableSyncForDatatype( 857 syncer::ModelType datatype) { 858 DVLOG(1) << GetClientInfoString( 859 "EnableSyncForDatatype(" 860 + std::string(syncer::ModelTypeToString(datatype)) + ")"); 861 862 if (IsSyncDisabled()) 863 return SetupSync(syncer::ModelTypeSet(datatype)); 864 865 if (service() == NULL) { 866 LOG(ERROR) << "EnableSyncForDatatype(): service() is null."; 867 return false; 868 } 869 870 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes(); 871 if (synced_datatypes.Has(datatype)) { 872 DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype " 873 << syncer::ModelTypeToString(datatype) 874 << " on " << profile_debug_name_ << "."; 875 return true; 876 } 877 878 synced_datatypes.Put(syncer::ModelTypeFromInt(datatype)); 879 service()->OnUserChoseDatatypes(false, synced_datatypes); 880 if (AwaitDataSyncCompletion()) { 881 DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype " 882 << syncer::ModelTypeToString(datatype) 883 << " on " << profile_debug_name_ << "."; 884 return true; 885 } 886 887 DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed"); 888 return false; 889 } 890 891 bool ProfileSyncServiceHarness::DisableSyncForDatatype( 892 syncer::ModelType datatype) { 893 DVLOG(1) << GetClientInfoString( 894 "DisableSyncForDatatype(" 895 + std::string(syncer::ModelTypeToString(datatype)) + ")"); 896 897 if (service() == NULL) { 898 LOG(ERROR) << "DisableSyncForDatatype(): service() is null."; 899 return false; 900 } 901 902 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes(); 903 if (!synced_datatypes.Has(datatype)) { 904 DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype " 905 << syncer::ModelTypeToString(datatype) 906 << " on " << profile_debug_name_ << "."; 907 return true; 908 } 909 910 synced_datatypes.RetainAll(syncer::UserSelectableTypes()); 911 synced_datatypes.Remove(datatype); 912 service()->OnUserChoseDatatypes(false, synced_datatypes); 913 if (AwaitFullSyncCompletion()) { 914 DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype " 915 << syncer::ModelTypeToString(datatype) 916 << " on " << profile_debug_name_ << "."; 917 return true; 918 } 919 920 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed"); 921 return false; 922 } 923 924 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() { 925 DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes"); 926 927 if (IsSyncDisabled()) 928 return SetupSync(); 929 930 if (service() == NULL) { 931 LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null."; 932 return false; 933 } 934 935 service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All()); 936 if (AwaitFullSyncCompletion()) { 937 DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes " 938 << "on " << profile_debug_name_ << "."; 939 return true; 940 } 941 942 DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed"); 943 return false; 944 } 945 946 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() { 947 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes"); 948 949 if (service() == NULL) { 950 LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null."; 951 return false; 952 } 953 954 service()->DisableForUser(); 955 956 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all " 957 << "datatypes on " << profile_debug_name_; 958 return true; 959 } 960 961 std::string ProfileSyncServiceHarness::GetSerializedProgressMarker( 962 syncer::ModelType model_type) const { 963 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 964 const syncer::ProgressMarkerMap& markers_map = 965 snap.download_progress_markers(); 966 967 syncer::ProgressMarkerMap::const_iterator it = 968 markers_map.find(model_type); 969 return (it != markers_map.end()) ? it->second : std::string(); 970 } 971 972 std::string ProfileSyncServiceHarness::GetClientInfoString( 973 const std::string& message) const { 974 std::stringstream os; 975 os << profile_debug_name_ << ": " << message << ": "; 976 if (service()) { 977 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 978 const ProfileSyncService::Status& status = GetStatus(); 979 // Capture select info from the sync session snapshot and syncer status. 980 // TODO(rsimha): Audit the list of fields below, and eventually eliminate 981 // the use of the sync session snapshot. See crbug.com/323380. 982 os << ", has_unsynced_items: " 983 << (service()->sync_initialized() ? service()->HasUnsyncedItems() : 0) 984 << ", did_commit: " 985 << (snap.model_neutral_state().num_successful_commits == 0 && 986 snap.model_neutral_state().commit_result == syncer::SYNCER_OK) 987 << ", encryption conflicts: " 988 << snap.num_encryption_conflicts() 989 << ", hierarchy conflicts: " 990 << snap.num_hierarchy_conflicts() 991 << ", server conflicts: " 992 << snap.num_server_conflicts() 993 << ", num_updates_downloaded : " 994 << snap.model_neutral_state().num_updates_downloaded_total 995 << ", passphrase_required_reason: " 996 << syncer::PassphraseRequiredReasonToString( 997 service()->passphrase_required_reason()) 998 << ", notifications_enabled: " 999 << status.notifications_enabled 1000 << ", service_is_pushing_changes: " 1001 << ServiceIsPushingChanges() 1002 << ", has_pending_backend_migration: " 1003 << HasPendingBackendMigration(); 1004 } else { 1005 os << "Sync service not available"; 1006 } 1007 return os.str(); 1008 } 1009 1010 bool ProfileSyncServiceHarness::EnableEncryption() { 1011 if (IsEncryptionComplete()) 1012 return true; 1013 service()->EnableEncryptEverything(); 1014 1015 // In order to kick off the encryption we have to reconfigure. Just grab the 1016 // currently synced types and use them. 1017 const syncer::ModelTypeSet synced_datatypes = 1018 service()->GetPreferredDataTypes(); 1019 bool sync_everything = 1020 synced_datatypes.Equals(syncer::ModelTypeSet::All()); 1021 service()->OnUserChoseDatatypes(sync_everything, synced_datatypes); 1022 1023 // Wait some time to let the enryption finish. 1024 return WaitForEncryption(); 1025 } 1026 1027 bool ProfileSyncServiceHarness::WaitForEncryption() { 1028 if (IsEncryptionComplete()) { 1029 // Encryption is already complete; do not wait. 1030 return true; 1031 } 1032 1033 StatusChangeChecker encryption_complete_checker( 1034 base::Bind(&ProfileSyncServiceHarness::IsEncryptionComplete, 1035 base::Unretained(this)), 1036 "IsEncryptionComplete"); 1037 return AwaitStatusChange(&encryption_complete_checker, "WaitForEncryption"); 1038 } 1039 1040 bool ProfileSyncServiceHarness::IsEncryptionComplete() const { 1041 bool is_encryption_complete = service()->EncryptEverythingEnabled() && 1042 !service()->encryption_pending(); 1043 DVLOG(2) << "Encryption is " 1044 << (is_encryption_complete ? "" : "not ") 1045 << "complete; Encrypted types = " 1046 << syncer::ModelTypeSetToString(service()->GetEncryptedDataTypes()); 1047 return is_encryption_complete; 1048 } 1049 1050 bool ProfileSyncServiceHarness::IsTypeRunning(syncer::ModelType type) { 1051 browser_sync::DataTypeController::StateMap state_map; 1052 service()->GetDataTypeControllerStates(&state_map); 1053 return (state_map.count(type) != 0 && 1054 state_map[type] == browser_sync::DataTypeController::RUNNING); 1055 } 1056 1057 bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) { 1058 return service()->GetPreferredDataTypes().Has(type); 1059 } 1060 1061 size_t ProfileSyncServiceHarness::GetNumEntries() const { 1062 return GetLastSessionSnapshot().num_entries(); 1063 } 1064 1065 size_t ProfileSyncServiceHarness::GetNumDatatypes() const { 1066 browser_sync::DataTypeController::StateMap state_map; 1067 service()->GetDataTypeControllerStates(&state_map); 1068 return state_map.size(); 1069 } 1070 1071 std::string ProfileSyncServiceHarness::GetServiceStatus() { 1072 scoped_ptr<DictionaryValue> value( 1073 sync_ui_util::ConstructAboutInformation(service())); 1074 std::string service_status; 1075 base::JSONWriter::WriteWithOptions(value.get(), 1076 base::JSONWriter::OPTIONS_PRETTY_PRINT, 1077 &service_status); 1078 return service_status; 1079 } 1080