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