profile_sync_service_harness.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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/bind.h" 15#include "base/command_line.h" 16#include "base/compiler_specific.h" 17#include "base/json/json_writer.h" 18#include "base/location.h" 19#include "base/logging.h" 20#include "base/message_loop/message_loop.h" 21#include "base/prefs/pref_service.h" 22#include "base/strings/stringprintf.h" 23#include "base/timer/timer.h" 24#include "chrome/browser/chrome_notification_types.h" 25#include "chrome/browser/invalidation/p2p_invalidation_service.h" 26#include "chrome/browser/profiles/profile.h" 27#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 28#include "chrome/browser/signin/signin_manager_base.h" 29#include "chrome/browser/sync/about_sync_util.h" 30#include "chrome/browser/sync/backend_migrator.h" 31#include "chrome/browser/sync/profile_sync_service_factory.h" 32#include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h" 33#include "chrome/browser/sync/test/integration/quiesce_status_change_checker.h" 34#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" 35#include "chrome/browser/sync/test/integration/status_change_checker.h" 36#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" 37#include "chrome/common/chrome_switches.h" 38#include "chrome/common/pref_names.h" 39#include "components/signin/core/profile_oauth2_token_service.h" 40#include "components/sync_driver/data_type_controller.h" 41#include "content/public/browser/notification_service.h" 42#include "google_apis/gaia/gaia_constants.h" 43#include "sync/internal_api/public/base/progress_marker_map.h" 44#include "sync/internal_api/public/sessions/sync_session_snapshot.h" 45#include "sync/internal_api/public/util/sync_string_conversions.h" 46 47#if defined(ENABLE_MANAGED_USERS) 48#include "chrome/browser/managed_mode/managed_user_constants.h" 49#endif 50 51using invalidation::P2PInvalidationService; 52using syncer::sessions::SyncSessionSnapshot; 53 54// The amount of time for which we wait for a sync operation to complete. 55// TODO(sync): This timeout must eventually be made less than the default 45 56// second timeout for integration tests so that in case a sync operation times 57// out, it is able to log a useful failure message before the test is killed. 58static const int kSyncOperationTimeoutMs = 45000; 59 60namespace { 61 62// Checks if a desired change in the state of the sync engine has taken place by 63// running the callback passed to it. 64class CallbackStatusChecker : public SingleClientStatusChangeChecker { 65 public: 66 CallbackStatusChecker(ProfileSyncService* service, 67 base::Callback<bool()> callback, 68 const std::string& debug_message) 69 : SingleClientStatusChangeChecker(service), 70 callback_(callback), 71 debug_message_(debug_message) { 72 } 73 74 virtual ~CallbackStatusChecker() { 75 } 76 77 virtual bool IsExitConditionSatisfied() OVERRIDE { 78 return callback_.Run(); 79 } 80 81 virtual std::string GetDebugMessage() const OVERRIDE { 82 return debug_message_; 83 } 84 85 private: 86 // Callback that evaluates whether the condition we are waiting on has been 87 // satisfied. 88 base::Callback<bool()> callback_; 89 90 const std::string debug_message_; 91 92 DISALLOW_COPY_AND_ASSIGN(CallbackStatusChecker); 93}; 94 95// Helper function which returns true if the sync backend has been initialized, 96// or if backend initialization was blocked for some reason. 97bool DoneWaitingForBackendInitialization( 98 const ProfileSyncServiceHarness* harness) { 99 DCHECK(harness); 100 // Backend is initialized. 101 if (harness->service()->sync_initialized()) 102 return true; 103 // Backend initialization is blocked by an auth error. 104 if (harness->HasAuthError()) 105 return true; 106 // Backend initialization is blocked by a failure to fetch Oauth2 tokens. 107 if (harness->service()->IsRetryingAccessTokenFetchForTest()) 108 return true; 109 // Still waiting on backend initialization. 110 return false; 111} 112 113// Helper function which returns true if sync setup is complete, or in case 114// it is blocked for some reason. 115bool DoneWaitingForSyncSetup(const ProfileSyncServiceHarness* harness) { 116 DCHECK(harness); 117 // Sync setup is complete, and the client is ready to sync new changes. 118 if (harness->ServiceIsPushingChanges()) 119 return true; 120 // Sync is blocked because a custom passphrase is required. 121 if (harness->service()->passphrase_required_reason() == 122 syncer::REASON_DECRYPTION) { 123 return true; 124 } 125 // Sync is blocked by an auth error. 126 if (harness->HasAuthError()) 127 return true; 128 // Still waiting on sync setup. 129 return false; 130} 131 132// Helper function which returns true if the sync client requires a custom 133// passphrase to be entered for decryption. 134bool IsPassphraseRequired(const ProfileSyncServiceHarness* harness) { 135 DCHECK(harness); 136 return harness->service()->IsPassphraseRequired(); 137} 138 139// Helper function which returns true if the custom passphrase entered was 140// accepted. 141bool IsPassphraseAccepted(const ProfileSyncServiceHarness* harness) { 142 DCHECK(harness); 143 return (!harness->service()->IsPassphraseRequired() && 144 harness->service()->IsUsingSecondaryPassphrase()); 145} 146 147} // namespace 148 149// static 150ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create( 151 Profile* profile, 152 const std::string& username, 153 const std::string& password) { 154 return new ProfileSyncServiceHarness(profile, username, password, NULL); 155} 156 157// static 158ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateForIntegrationTest( 159 Profile* profile, 160 const std::string& username, 161 const std::string& password, 162 P2PInvalidationService* p2p_invalidation_service) { 163 return new ProfileSyncServiceHarness(profile, 164 username, 165 password, 166 p2p_invalidation_service); 167} 168 169ProfileSyncServiceHarness::ProfileSyncServiceHarness( 170 Profile* profile, 171 const std::string& username, 172 const std::string& password, 173 P2PInvalidationService* p2p_invalidation_service) 174 : profile_(profile), 175 service_(ProfileSyncServiceFactory::GetForProfile(profile)), 176 username_(username), 177 password_(password), 178 oauth2_refesh_token_number_(0), 179 profile_debug_name_(profile->GetDebugName()), 180 status_change_checker_(NULL) { 181 // Start listening for and emitting notifications of commits. 182 p2p_invalidation_forwarder_.reset( 183 new P2PInvalidationForwarder(service_, p2p_invalidation_service)); 184} 185 186ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { } 187 188void ProfileSyncServiceHarness::SetCredentials(const std::string& username, 189 const std::string& password) { 190 username_ = username; 191 password_ = password; 192} 193 194bool ProfileSyncServiceHarness::SetupSync() { 195 bool result = SetupSync(syncer::ModelTypeSet::All()); 196 if (result == false) { 197 std::string status = GetServiceStatus(); 198 LOG(ERROR) << profile_debug_name_ 199 << ": SetupSync failed. Syncer status:\n" << status; 200 } else { 201 DVLOG(1) << profile_debug_name_ << ": SetupSync successful."; 202 } 203 return result; 204} 205 206bool ProfileSyncServiceHarness::SetupSync( 207 syncer::ModelTypeSet synced_datatypes) { 208 // Initialize the sync client's profile sync service object. 209 if (service() == NULL) { 210 LOG(ERROR) << "SetupSync(): service() is null."; 211 return false; 212 } 213 214 // Tell the sync service that setup is in progress so we don't start syncing 215 // until we've finished configuration. 216 service()->SetSetupInProgress(true); 217 218 // Authenticate sync client using GAIA credentials. 219 service()->signin()->SetAuthenticatedUsername(username_); 220 GoogleServiceSigninSuccessDetails details(username_, password_); 221 content::NotificationService::current()->Notify( 222 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, 223 content::Source<Profile>(profile_), 224 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); 225 226#if defined(ENABLE_MANAGED_USERS) 227 std::string account_id = profile_->IsManaged() ? 228 managed_users::kManagedUserPseudoEmail : username_; 229#else 230 std::string account_id = username_; 231#endif 232 DCHECK(!account_id.empty()); 233 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)-> 234 UpdateCredentials(account_id, GenerateFakeOAuth2RefreshTokenString()); 235 236 // Wait for the OnBackendInitialized() callback. 237 if (!AwaitBackendInitialized()) { 238 LOG(ERROR) << "OnBackendInitialized() not seen after " 239 << kSyncOperationTimeoutMs / 1000 240 << " seconds."; 241 return false; 242 } 243 244 // Make sure that initial sync wasn't blocked by a missing passphrase. 245 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) { 246 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" 247 " until SetDecryptionPassphrase is called."; 248 return false; 249 } 250 251 // Make sure that initial sync wasn't blocked by rejected credentials. 252 if (HasAuthError()) { 253 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed."; 254 return false; 255 } 256 257 // Choose the datatypes to be synced. If all datatypes are to be synced, 258 // set sync_everything to true; otherwise, set it to false. 259 bool sync_everything = 260 synced_datatypes.Equals(syncer::ModelTypeSet::All()); 261 service()->OnUserChoseDatatypes(sync_everything, synced_datatypes); 262 263 // Notify ProfileSyncService that we are done with configuration. 264 FinishSyncSetup(); 265 266 // Set an implicit passphrase for encryption if an explicit one hasn't already 267 // been set. If an explicit passphrase has been set, immediately return false, 268 // since a decryption passphrase is required. 269 if (!service()->IsUsingSecondaryPassphrase()) { 270 service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT); 271 } else { 272 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" 273 " until SetDecryptionPassphrase is called."; 274 return false; 275 } 276 277 // Wait for initial sync cycle to be completed. 278 DCHECK(service()->sync_initialized()); 279 if (!AwaitSyncSetupCompletion()) { 280 LOG(ERROR) << "Initial sync cycle did not complete after " 281 << kSyncOperationTimeoutMs / 1000 282 << " seconds."; 283 return false; 284 } 285 286 // Make sure that initial sync wasn't blocked by a missing passphrase. 287 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) { 288 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed" 289 " until SetDecryptionPassphrase is called."; 290 return false; 291 } 292 293 // Make sure that initial sync wasn't blocked by rejected credentials. 294 if (service()->GetAuthError().state() == 295 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) { 296 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed."; 297 return false; 298 } 299 300 return true; 301} 302 303void ProfileSyncServiceHarness::QuitMessageLoop() { 304 base::MessageLoop::current()->QuitWhenIdle(); 305} 306 307void ProfileSyncServiceHarness::OnStateChanged() { 308 if (!status_change_checker_) 309 return; 310 311 DVLOG(1) << GetClientInfoString(status_change_checker_->GetDebugMessage()); 312 if (status_change_checker_->IsExitConditionSatisfied()) 313 QuitMessageLoop(); 314} 315 316void ProfileSyncServiceHarness::OnSyncCycleCompleted() { 317 OnStateChanged(); 318} 319 320bool ProfileSyncServiceHarness::AwaitPassphraseRequired() { 321 DVLOG(1) << GetClientInfoString("AwaitPassphraseRequired"); 322 CallbackStatusChecker passphrase_required_checker( 323 service(), 324 base::Bind(&::IsPassphraseRequired, base::Unretained(this)), 325 "IsPassphraseRequired"); 326 return AwaitStatusChange(&passphrase_required_checker); 327} 328 329bool ProfileSyncServiceHarness::AwaitPassphraseAccepted() { 330 CallbackStatusChecker passphrase_accepted_checker( 331 service(), 332 base::Bind(&::IsPassphraseAccepted, base::Unretained(this)), 333 "IsPassphraseAccepted"); 334 bool return_value = AwaitStatusChange(&passphrase_accepted_checker); 335 if (return_value) 336 FinishSyncSetup(); 337 return return_value; 338} 339 340bool ProfileSyncServiceHarness::AwaitBackendInitialized() { 341 DVLOG(1) << GetClientInfoString("AwaitBackendInitialized"); 342 CallbackStatusChecker backend_initialized_checker( 343 service(), 344 base::Bind(&DoneWaitingForBackendInitialization, 345 base::Unretained(this)), 346 "DoneWaitingForBackendInitialization"); 347 AwaitStatusChange(&backend_initialized_checker); 348 return service()->sync_initialized(); 349} 350 351// TODO(sync): As of today, we wait for a client to finish its commit activity 352// by checking if its progress markers are up to date. In future, once we have 353// an in-process C++ server, this function can be reimplemented without relying 354// on progress markers. 355bool ProfileSyncServiceHarness::AwaitCommitActivityCompletion() { 356 UpdatedProgressMarkerChecker progress_marker_checker(service()); 357 return AwaitStatusChange(&progress_marker_checker); 358} 359 360bool ProfileSyncServiceHarness::AwaitSyncDisabled() { 361 DCHECK(service()->HasSyncSetupCompleted()); 362 DCHECK(!IsSyncDisabled()); 363 CallbackStatusChecker sync_disabled_checker( 364 service(), 365 base::Bind(&ProfileSyncServiceHarness::IsSyncDisabled, 366 base::Unretained(this)), 367 "IsSyncDisabled"); 368 return AwaitStatusChange(&sync_disabled_checker); 369} 370 371bool ProfileSyncServiceHarness::AwaitSyncSetupCompletion() { 372 CallbackStatusChecker sync_setup_complete_checker( 373 service(), 374 base::Bind(&DoneWaitingForSyncSetup, base::Unretained(this)), 375 "DoneWaitingForSyncSetup"); 376 return AwaitStatusChange(&sync_setup_complete_checker); 377} 378 379bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion( 380 ProfileSyncServiceHarness* partner) { 381 std::vector<ProfileSyncServiceHarness*> harnesses; 382 harnesses.push_back(this); 383 harnesses.push_back(partner); 384 return AwaitQuiescence(harnesses); 385} 386 387bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion( 388 std::vector<ProfileSyncServiceHarness*>& partners) { 389 return AwaitQuiescence(partners); 390} 391 392// static 393bool ProfileSyncServiceHarness::AwaitQuiescence( 394 std::vector<ProfileSyncServiceHarness*>& clients) { 395 std::vector<ProfileSyncService*> services; 396 if (clients.empty()) { 397 return true; 398 } 399 400 for (std::vector<ProfileSyncServiceHarness*>::iterator it = clients.begin(); 401 it != clients.end(); ++it) { 402 services.push_back((*it)->service()); 403 } 404 QuiesceStatusChangeChecker checker(services); 405 return clients[0]->AwaitStatusChange(&checker); 406} 407 408bool ProfileSyncServiceHarness::AwaitStatusChange( 409 StatusChangeChecker* checker) { 410 DVLOG(1) << GetClientInfoString("AwaitStatusChange"); 411 412 DCHECK(checker); 413 if (checker->IsExitConditionSatisfied()) { 414 DVLOG(1) << GetClientInfoString("AwaitStatusChange exiting early because " 415 "condition is already satisfied"); 416 return true; 417 } 418 419 DCHECK(status_change_checker_ == NULL); 420 status_change_checker_ = checker; 421 status_change_checker_->InitObserver(this); 422 423 base::OneShotTimer<ProfileSyncServiceHarness> timer; 424 timer.Start(FROM_HERE, 425 base::TimeDelta::FromMilliseconds(kSyncOperationTimeoutMs), 426 base::Bind(&ProfileSyncServiceHarness::QuitMessageLoop, 427 base::Unretained(this))); 428 { 429 base::MessageLoop* loop = base::MessageLoop::current(); 430 base::MessageLoop::ScopedNestableTaskAllower allow(loop); 431 loop->Run(); 432 } 433 434 status_change_checker_->UninitObserver(this); 435 status_change_checker_ = NULL; 436 437 if (timer.IsRunning()) { 438 DVLOG(1) << GetClientInfoString("AwaitStatusChange succeeded"); 439 return true; 440 } else { 441 LOG(ERROR) << GetClientInfoString(base::StringPrintf( 442 "AwaitStatusChange called from %s timed out", 443 checker->GetDebugMessage().c_str())); 444 CHECK(false) << "Ending test because of timeout."; 445 return false; 446 } 447} 448 449std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() { 450 return base::StringPrintf("oauth2_refresh_token_%d", 451 ++oauth2_refesh_token_number_); 452} 453 454ProfileSyncService::Status ProfileSyncServiceHarness::GetStatus() const { 455 DCHECK(service() != NULL) << "GetStatus(): service() is NULL."; 456 ProfileSyncService::Status result; 457 service()->QueryDetailedSyncStatus(&result); 458 return result; 459} 460 461bool ProfileSyncServiceHarness::IsSyncDisabled() const { 462 return !service()->setup_in_progress() && 463 !service()->HasSyncSetupCompleted(); 464} 465 466bool ProfileSyncServiceHarness::HasAuthError() const { 467 return service()->GetAuthError().state() == 468 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS || 469 service()->GetAuthError().state() == 470 GoogleServiceAuthError::SERVICE_ERROR || 471 service()->GetAuthError().state() == 472 GoogleServiceAuthError::REQUEST_CANCELED; 473} 474 475void ProfileSyncServiceHarness::FinishSyncSetup() { 476 service()->SetSetupInProgress(false); 477 service()->SetSyncSetupCompleted(); 478} 479 480bool ProfileSyncServiceHarness::AutoStartEnabled() { 481 return service()->auto_start_enabled(); 482} 483 484SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const { 485 DCHECK(service() != NULL) << "Sync service has not yet been set up."; 486 if (service()->sync_initialized()) { 487 return service()->GetLastSessionSnapshot(); 488 } 489 return SyncSessionSnapshot(); 490} 491 492bool ProfileSyncServiceHarness::EnableSyncForDatatype( 493 syncer::ModelType datatype) { 494 DVLOG(1) << GetClientInfoString( 495 "EnableSyncForDatatype(" 496 + std::string(syncer::ModelTypeToString(datatype)) + ")"); 497 498 if (IsSyncDisabled()) 499 return SetupSync(syncer::ModelTypeSet(datatype)); 500 501 if (service() == NULL) { 502 LOG(ERROR) << "EnableSyncForDatatype(): service() is null."; 503 return false; 504 } 505 506 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes(); 507 if (synced_datatypes.Has(datatype)) { 508 DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype " 509 << syncer::ModelTypeToString(datatype) 510 << " on " << profile_debug_name_ << "."; 511 return true; 512 } 513 514 synced_datatypes.Put(syncer::ModelTypeFromInt(datatype)); 515 service()->OnUserChoseDatatypes(false, synced_datatypes); 516 if (AwaitSyncSetupCompletion()) { 517 DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype " 518 << syncer::ModelTypeToString(datatype) 519 << " on " << profile_debug_name_ << "."; 520 return true; 521 } 522 523 DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed"); 524 return false; 525} 526 527bool ProfileSyncServiceHarness::DisableSyncForDatatype( 528 syncer::ModelType datatype) { 529 DVLOG(1) << GetClientInfoString( 530 "DisableSyncForDatatype(" 531 + std::string(syncer::ModelTypeToString(datatype)) + ")"); 532 533 if (service() == NULL) { 534 LOG(ERROR) << "DisableSyncForDatatype(): service() is null."; 535 return false; 536 } 537 538 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes(); 539 if (!synced_datatypes.Has(datatype)) { 540 DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype " 541 << syncer::ModelTypeToString(datatype) 542 << " on " << profile_debug_name_ << "."; 543 return true; 544 } 545 546 synced_datatypes.RetainAll(syncer::UserSelectableTypes()); 547 synced_datatypes.Remove(datatype); 548 service()->OnUserChoseDatatypes(false, synced_datatypes); 549 if (AwaitSyncSetupCompletion()) { 550 DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype " 551 << syncer::ModelTypeToString(datatype) 552 << " on " << profile_debug_name_ << "."; 553 return true; 554 } 555 556 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed"); 557 return false; 558} 559 560bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() { 561 DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes"); 562 563 if (IsSyncDisabled()) 564 return SetupSync(); 565 566 if (service() == NULL) { 567 LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null."; 568 return false; 569 } 570 571 service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All()); 572 if (AwaitSyncSetupCompletion()) { 573 DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes " 574 << "on " << profile_debug_name_ << "."; 575 return true; 576 } 577 578 DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed"); 579 return false; 580} 581 582bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() { 583 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes"); 584 585 if (service() == NULL) { 586 LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null."; 587 return false; 588 } 589 590 service()->DisableForUser(); 591 592 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all " 593 << "datatypes on " << profile_debug_name_; 594 return true; 595} 596 597std::string ProfileSyncServiceHarness::GetSerializedProgressMarker( 598 syncer::ModelType model_type) const { 599 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 600 const syncer::ProgressMarkerMap& markers_map = 601 snap.download_progress_markers(); 602 603 syncer::ProgressMarkerMap::const_iterator it = 604 markers_map.find(model_type); 605 return (it != markers_map.end()) ? it->second : std::string(); 606} 607 608// TODO(sync): Clean up this method in a separate CL. Remove all snapshot fields 609// and log shorter, more meaningful messages. 610std::string ProfileSyncServiceHarness::GetClientInfoString( 611 const std::string& message) const { 612 std::stringstream os; 613 os << profile_debug_name_ << ": " << message << ": "; 614 if (service()) { 615 const SyncSessionSnapshot& snap = GetLastSessionSnapshot(); 616 const ProfileSyncService::Status& status = GetStatus(); 617 // Capture select info from the sync session snapshot and syncer status. 618 os << ", has_unsynced_items: " 619 << (service()->sync_initialized() ? service()->HasUnsyncedItems() : 0) 620 << ", did_commit: " 621 << (snap.model_neutral_state().num_successful_commits == 0 && 622 snap.model_neutral_state().commit_result == syncer::SYNCER_OK) 623 << ", encryption conflicts: " 624 << snap.num_encryption_conflicts() 625 << ", hierarchy conflicts: " 626 << snap.num_hierarchy_conflicts() 627 << ", server conflicts: " 628 << snap.num_server_conflicts() 629 << ", num_updates_downloaded : " 630 << snap.model_neutral_state().num_updates_downloaded_total 631 << ", passphrase_required_reason: " 632 << syncer::PassphraseRequiredReasonToString( 633 service()->passphrase_required_reason()) 634 << ", notifications_enabled: " 635 << status.notifications_enabled 636 << ", service_is_pushing_changes: " 637 << ServiceIsPushingChanges(); 638 } else { 639 os << "Sync service not available"; 640 } 641 return os.str(); 642} 643 644bool ProfileSyncServiceHarness::EnableEncryption() { 645 if (IsEncryptionComplete()) 646 return true; 647 service()->EnableEncryptEverything(); 648 649 // In order to kick off the encryption we have to reconfigure. Just grab the 650 // currently synced types and use them. 651 const syncer::ModelTypeSet synced_datatypes = 652 service()->GetPreferredDataTypes(); 653 bool sync_everything = 654 synced_datatypes.Equals(syncer::ModelTypeSet::All()); 655 service()->OnUserChoseDatatypes(sync_everything, synced_datatypes); 656 657 // Wait some time to let the enryption finish. 658 return WaitForEncryption(); 659} 660 661bool ProfileSyncServiceHarness::WaitForEncryption() { 662 if (IsEncryptionComplete()) { 663 // Encryption is already complete; do not wait. 664 return true; 665 } 666 667 CallbackStatusChecker encryption_complete_checker( 668 service(), 669 base::Bind(&ProfileSyncServiceHarness::IsEncryptionComplete, 670 base::Unretained(this)), 671 "IsEncryptionComplete"); 672 return AwaitStatusChange(&encryption_complete_checker); 673} 674 675bool ProfileSyncServiceHarness::IsEncryptionComplete() const { 676 bool is_encryption_complete = service()->EncryptEverythingEnabled() && 677 !service()->encryption_pending(); 678 DVLOG(2) << "Encryption is " 679 << (is_encryption_complete ? "" : "not ") 680 << "complete; Encrypted types = " 681 << syncer::ModelTypeSetToString(service()->GetEncryptedDataTypes()); 682 return is_encryption_complete; 683} 684 685bool ProfileSyncServiceHarness::IsTypeRunning(syncer::ModelType type) { 686 browser_sync::DataTypeController::StateMap state_map; 687 service()->GetDataTypeControllerStates(&state_map); 688 return (state_map.count(type) != 0 && 689 state_map[type] == browser_sync::DataTypeController::RUNNING); 690} 691 692bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) { 693 return service()->GetPreferredDataTypes().Has(type); 694} 695 696std::string ProfileSyncServiceHarness::GetServiceStatus() { 697 scoped_ptr<base::DictionaryValue> value( 698 sync_ui_util::ConstructAboutInformation(service())); 699 std::string service_status; 700 base::JSONWriter::WriteWithOptions(value.get(), 701 base::JSONWriter::OPTIONS_PRETTY_PRINT, 702 &service_status); 703 return service_status; 704} 705