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.
5 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
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/glue/data_type_controller.h"
34 #include "chrome/browser/sync/profile_sync_service_factory.h"
35 #include "chrome/browser/sync/test/integration/status_change_checker.h"
36 #include "chrome/common/chrome_switches.h"
37 #include "chrome/common/pref_names.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"
44 #if defined(ENABLE_MANAGED_USERS)
45 #include "chrome/browser/managed_mode/managed_user_constants.h"
48 using syncer::sessions::SyncSessionSnapshot
;
49 using invalidation::P2PInvalidationService
;
51 // The amount of time for which we wait for a sync operation to complete.
52 static const int kSyncOperationTimeoutMs
= 45000;
56 // Checks if a desired change in the state of the sync engine has taken place by
57 // running the callback passed to it.
58 class CallbackStatusChecker
: public StatusChangeChecker
{
60 CallbackStatusChecker(base::Callback
<bool()> callback
,
61 const std::string
& source
)
62 : StatusChangeChecker(source
),
66 virtual ~CallbackStatusChecker() {
69 virtual bool IsExitConditionSatisfied() OVERRIDE
{
70 return callback_
.Run();
74 // Callback that evaluates whether the condition we are waiting on has been
76 base::Callback
<bool()> callback_
;
78 DISALLOW_COPY_AND_ASSIGN(CallbackStatusChecker
);
81 // Helper function which returns true if the sync backend has been initialized,
82 // or if backend initialization was blocked for some reason.
83 bool DoneWaitingForBackendInitialization(
84 const ProfileSyncServiceHarness
* harness
) {
86 // Backend is initialized.
87 if (harness
->service()->sync_initialized())
89 // Backend initialization is blocked by an auth error.
90 if (harness
->HasAuthError())
92 // Backend initialization is blocked by a failure to fetch Oauth2 tokens.
93 if (harness
->service()->IsRetryingAccessTokenFetchForTest())
95 // Still waiting on backend initialization.
99 // Helper function which returns true if initial sync is complete, or if the
100 // initial sync is blocked for some reason.
101 bool DoneWaitingForInitialSync(const ProfileSyncServiceHarness
* harness
) {
103 // Initial sync is complete.
104 if (harness
->IsFullySynced())
106 // Initial sync is blocked because custom passphrase is required.
107 if (harness
->service()->passphrase_required_reason() ==
108 syncer::REASON_DECRYPTION
) {
111 // Initial sync is blocked by an auth error.
112 if (harness
->HasAuthError())
114 // Still waiting on initial sync.
118 // Helper function which returns true if the sync client is fully synced, or if
119 // sync is blocked for some reason.
120 bool DoneWaitingForFullSync(const ProfileSyncServiceHarness
* harness
) {
123 if (harness
->IsFullySynced())
125 // Sync is blocked by an auth error.
126 if (harness
->HasAuthError())
128 // Sync is blocked by a failure to fetch Oauth2 tokens.
129 if (harness
->service()->IsRetryingAccessTokenFetchForTest())
131 // Still waiting on sync.
135 // Helper function which returns true if the sync client requires a custom
136 // passphrase to be entered for decryption.
137 bool IsPassphraseRequired(const ProfileSyncServiceHarness
* harness
) {
139 return harness
->service()->IsPassphraseRequired();
142 // Helper function which returns true if the custom passphrase entered was
144 bool IsPassphraseAccepted(const ProfileSyncServiceHarness
* harness
) {
146 return (!harness
->service()->IsPassphraseRequired() &&
147 harness
->service()->IsUsingSecondaryPassphrase());
153 ProfileSyncServiceHarness
* ProfileSyncServiceHarness::Create(
155 const std::string
& username
,
156 const std::string
& password
) {
157 return new ProfileSyncServiceHarness(profile
, username
, password
, NULL
);
161 ProfileSyncServiceHarness
* ProfileSyncServiceHarness::CreateForIntegrationTest(
163 const std::string
& username
,
164 const std::string
& password
,
165 P2PInvalidationService
* p2p_invalidation_service
) {
166 return new ProfileSyncServiceHarness(profile
,
169 p2p_invalidation_service
);
172 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
174 const std::string
& username
,
175 const std::string
& password
,
176 P2PInvalidationService
* p2p_invalidation_service
)
178 service_(ProfileSyncServiceFactory::GetForProfile(profile
)),
179 p2p_invalidation_service_(p2p_invalidation_service
),
180 progress_marker_partner_(NULL
),
183 oauth2_refesh_token_number_(0),
184 profile_debug_name_(profile
->GetDebugName()),
185 status_change_checker_(NULL
) {
188 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() {
189 if (service()->HasObserver(this))
190 service()->RemoveObserver(this);
193 void ProfileSyncServiceHarness::SetCredentials(const std::string
& username
,
194 const std::string
& password
) {
195 username_
= username
;
196 password_
= password
;
199 bool ProfileSyncServiceHarness::SetupSync() {
200 bool result
= SetupSync(syncer::ModelTypeSet::All());
201 if (result
== false) {
202 std::string status
= GetServiceStatus();
203 LOG(ERROR
) << profile_debug_name_
204 << ": SetupSync failed. Syncer status:\n" << status
;
206 DVLOG(1) << profile_debug_name_
<< ": SetupSync successful.";
211 bool ProfileSyncServiceHarness::SetupSync(
212 syncer::ModelTypeSet synced_datatypes
) {
213 // Initialize the sync client's profile sync service object.
214 if (service() == NULL
) {
215 LOG(ERROR
) << "SetupSync(): service() is null.";
219 // Subscribe sync client to notifications from the profile sync service.
220 if (!service()->HasObserver(this))
221 service()->AddObserver(this);
223 // Tell the sync service that setup is in progress so we don't start syncing
224 // until we've finished configuration.
225 service()->SetSetupInProgress(true);
227 // Authenticate sync client using GAIA credentials.
228 service()->signin()->SetAuthenticatedUsername(username_
);
229 profile_
->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
231 GoogleServiceSigninSuccessDetails
details(username_
, password_
);
232 content::NotificationService::current()->Notify(
233 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL
,
234 content::Source
<Profile
>(profile_
),
235 content::Details
<const GoogleServiceSigninSuccessDetails
>(&details
));
237 #if defined(ENABLE_MANAGED_USERS)
238 std::string account_id
= profile_
->IsManaged() ?
239 managed_users::kManagedUserPseudoEmail
: username_
;
241 std::string account_id
= username_
;
243 DCHECK(!account_id
.empty());
244 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
)->
245 UpdateCredentials(account_id
, GenerateFakeOAuth2RefreshTokenString());
247 // Wait for the OnBackendInitialized() callback.
248 if (!AwaitBackendInitialized()) {
249 LOG(ERROR
) << "OnBackendInitialized() not seen after "
250 << kSyncOperationTimeoutMs
/ 1000
255 // Make sure that initial sync wasn't blocked by a missing passphrase.
256 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION
) {
257 LOG(ERROR
) << "A passphrase is required for decryption. Sync cannot proceed"
258 " until SetDecryptionPassphrase is called.";
262 // Make sure that initial sync wasn't blocked by rejected credentials.
263 if (HasAuthError()) {
264 LOG(ERROR
) << "Credentials were rejected. Sync cannot proceed.";
268 // Choose the datatypes to be synced. If all datatypes are to be synced,
269 // set sync_everything to true; otherwise, set it to false.
270 bool sync_everything
=
271 synced_datatypes
.Equals(syncer::ModelTypeSet::All());
272 service()->OnUserChoseDatatypes(sync_everything
, synced_datatypes
);
274 // Notify ProfileSyncService that we are done with configuration.
277 // Set an implicit passphrase for encryption if an explicit one hasn't already
278 // been set. If an explicit passphrase has been set, immediately return false,
279 // since a decryption passphrase is required.
280 if (!service()->IsUsingSecondaryPassphrase()) {
281 service()->SetEncryptionPassphrase(password_
, ProfileSyncService::IMPLICIT
);
283 LOG(ERROR
) << "A passphrase is required for decryption. Sync cannot proceed"
284 " until SetDecryptionPassphrase is called.";
288 // Wait for initial sync cycle to be completed.
289 DCHECK(service()->sync_initialized());
290 CallbackStatusChecker
initial_sync_checker(
291 base::Bind(&DoneWaitingForInitialSync
, base::Unretained(this)),
292 "DoneWaitingForInitialSync");
293 if (!AwaitStatusChange(&initial_sync_checker
, "SetupSync")) {
294 LOG(ERROR
) << "Initial sync cycle did not complete after "
295 << kSyncOperationTimeoutMs
/ 1000
300 // Make sure that initial sync wasn't blocked by a missing passphrase.
301 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION
) {
302 LOG(ERROR
) << "A passphrase is required for decryption. Sync cannot proceed"
303 " until SetDecryptionPassphrase is called.";
307 // Make sure that initial sync wasn't blocked by rejected credentials.
308 if (service()->GetAuthError().state() ==
309 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
) {
310 LOG(ERROR
) << "Credentials were rejected. Sync cannot proceed.";
317 void ProfileSyncServiceHarness::QuitMessageLoop() {
318 base::MessageLoop::current()->QuitWhenIdle();
321 void ProfileSyncServiceHarness::OnStateChanged() {
322 if (!status_change_checker_
)
325 DVLOG(1) << GetClientInfoString(status_change_checker_
->source());
326 if (status_change_checker_
->IsExitConditionSatisfied())
330 void ProfileSyncServiceHarness::OnSyncCycleCompleted() {
331 // Integration tests still use p2p notifications.
332 const SyncSessionSnapshot
& snap
= GetLastSessionSnapshot();
333 bool is_notifiable_commit
=
334 (snap
.model_neutral_state().num_successful_commits
> 0);
335 if (is_notifiable_commit
&& p2p_invalidation_service_
) {
336 syncer::ModelTypeSet model_types
=
337 snap
.model_neutral_state().commit_request_types
;
338 syncer::ObjectIdSet ids
= ModelTypeSetToObjectIdSet(model_types
);
339 p2p_invalidation_service_
->SendInvalidation(ids
);
344 bool ProfileSyncServiceHarness::AwaitPassphraseRequired() {
345 DVLOG(1) << GetClientInfoString("AwaitPassphraseRequired");
346 if (IsSyncDisabled()) {
347 LOG(ERROR
) << "Sync disabled for " << profile_debug_name_
<< ".";
351 if (service()->IsPassphraseRequired()) {
352 // It's already true that a passphrase is required; don't wait.
356 CallbackStatusChecker
passphrase_required_checker(
357 base::Bind(&::IsPassphraseRequired
, base::Unretained(this)),
358 "IsPassphraseRequired");
359 return AwaitStatusChange(&passphrase_required_checker
,
360 "AwaitPassphraseRequired");
363 bool ProfileSyncServiceHarness::AwaitPassphraseAccepted() {
364 DVLOG(1) << GetClientInfoString("AwaitPassphraseAccepted");
365 if (IsSyncDisabled()) {
366 LOG(ERROR
) << "Sync disabled for " << profile_debug_name_
<< ".";
370 if (!service()->IsPassphraseRequired() &&
371 service()->IsUsingSecondaryPassphrase()) {
372 // Passphrase is already accepted; don't wait.
377 CallbackStatusChecker
passphrase_accepted_checker(
378 base::Bind(&::IsPassphraseAccepted
, base::Unretained(this)),
379 "IsPassphraseAccepted");
380 bool return_value
= AwaitStatusChange(&passphrase_accepted_checker
,
381 "AwaitPassphraseAccepted");
387 bool ProfileSyncServiceHarness::AwaitBackendInitialized() {
388 DVLOG(1) << GetClientInfoString("AwaitBackendInitialized");
389 if (service()->sync_initialized()) {
390 // The sync backend host has already been initialized; don't wait.
394 CallbackStatusChecker
backend_initialized_checker(
395 base::Bind(&DoneWaitingForBackendInitialization
,
396 base::Unretained(this)),
397 "DoneWaitingForBackendInitialization");
398 AwaitStatusChange(&backend_initialized_checker
, "AwaitBackendInitialized");
399 return service()->sync_initialized();
402 bool ProfileSyncServiceHarness::AwaitDataSyncCompletion() {
403 DVLOG(1) << GetClientInfoString("AwaitDataSyncCompletion");
405 DCHECK(service()->sync_initialized());
406 DCHECK(!IsSyncDisabled());
408 if (IsDataSynced()) {
409 // Client is already synced; don't wait.
413 CallbackStatusChecker
data_synced_checker(
414 base::Bind(&ProfileSyncServiceHarness::IsDataSynced
,
415 base::Unretained(this)),
417 return AwaitStatusChange(&data_synced_checker
, "AwaitDataSyncCompletion");
420 bool ProfileSyncServiceHarness::AwaitFullSyncCompletion() {
421 DVLOG(1) << GetClientInfoString("AwaitFullSyncCompletion");
422 if (IsSyncDisabled()) {
423 LOG(ERROR
) << "Sync disabled for " << profile_debug_name_
<< ".";
427 if (IsFullySynced()) {
428 // Client is already synced; don't wait.
432 DCHECK(service()->sync_initialized());
433 CallbackStatusChecker
fully_synced_checker(
434 base::Bind(&DoneWaitingForFullSync
, base::Unretained(this)),
435 "DoneWaitingForFullSync");
436 AwaitStatusChange(&fully_synced_checker
, "AwaitFullSyncCompletion");
437 return IsFullySynced();
440 bool ProfileSyncServiceHarness::AwaitSyncDisabled() {
441 DCHECK(service()->HasSyncSetupCompleted());
442 DCHECK(!IsSyncDisabled());
443 CallbackStatusChecker
sync_disabled_checker(
444 base::Bind(&ProfileSyncServiceHarness::IsSyncDisabled
,
445 base::Unretained(this)),
447 return AwaitStatusChange(&sync_disabled_checker
, "AwaitSyncDisabled");
450 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
451 ProfileSyncServiceHarness
* partner
) {
452 DVLOG(1) << GetClientInfoString("AwaitMutualSyncCycleCompletion");
453 if (!AwaitFullSyncCompletion())
455 return partner
->WaitUntilProgressMarkersMatch(this);
458 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
459 std::vector
<ProfileSyncServiceHarness
*>& partners
) {
460 DVLOG(1) << GetClientInfoString("AwaitGroupSyncCycleCompletion");
461 if (!AwaitFullSyncCompletion())
463 bool return_value
= true;
464 for (std::vector
<ProfileSyncServiceHarness
*>::iterator it
=
465 partners
.begin(); it
!= partners
.end(); ++it
) {
466 if ((this != *it
) && (!(*it
)->IsSyncDisabled())) {
467 return_value
= return_value
&&
468 (*it
)->WaitUntilProgressMarkersMatch(this);
475 bool ProfileSyncServiceHarness::AwaitQuiescence(
476 std::vector
<ProfileSyncServiceHarness
*>& clients
) {
477 DVLOG(1) << "AwaitQuiescence.";
478 bool return_value
= true;
479 for (std::vector
<ProfileSyncServiceHarness
*>::iterator it
=
480 clients
.begin(); it
!= clients
.end(); ++it
) {
481 if (!(*it
)->IsSyncDisabled()) {
482 return_value
= return_value
&&
483 (*it
)->AwaitGroupSyncCycleCompletion(clients
);
489 bool ProfileSyncServiceHarness::WaitUntilProgressMarkersMatch(
490 ProfileSyncServiceHarness
* partner
) {
491 DVLOG(1) << GetClientInfoString("WaitUntilProgressMarkersMatch");
492 if (IsSyncDisabled()) {
493 LOG(ERROR
) << "Sync disabled for " << profile_debug_name_
<< ".";
497 // TODO(rsimha): Replace the mechanism of matching up progress markers with
498 // one that doesn't require every client to have the same progress markers.
499 DCHECK(!progress_marker_partner_
);
500 progress_marker_partner_
= partner
;
501 bool return_value
= false;
502 if (MatchesPartnerClient()) {
503 // Progress markers already match; don't wait.
506 partner
->service()->AddObserver(this);
507 CallbackStatusChecker
matches_other_client_checker(
508 base::Bind(&ProfileSyncServiceHarness::MatchesPartnerClient
,
509 base::Unretained(this)),
510 "MatchesPartnerClient");
511 return_value
= AwaitStatusChange(&matches_other_client_checker
,
512 "WaitUntilProgressMarkersMatch");
513 partner
->service()->RemoveObserver(this);
515 progress_marker_partner_
= NULL
;
519 bool ProfileSyncServiceHarness::AwaitStatusChange(
520 StatusChangeChecker
* checker
, const std::string
& source
) {
521 DVLOG(1) << GetClientInfoString("AwaitStatusChange");
523 if (IsSyncDisabled()) {
524 LOG(ERROR
) << "Sync disabled for " << profile_debug_name_
<< ".";
528 DCHECK(status_change_checker_
== NULL
);
529 status_change_checker_
= checker
;
531 base::OneShotTimer
<ProfileSyncServiceHarness
> timer
;
532 timer
.Start(FROM_HERE
,
533 base::TimeDelta::FromMilliseconds(kSyncOperationTimeoutMs
),
534 base::Bind(&ProfileSyncServiceHarness::QuitMessageLoop
,
535 base::Unretained(this)));
537 base::MessageLoop
* loop
= base::MessageLoop::current();
538 base::MessageLoop::ScopedNestableTaskAllower
allow(loop
);
542 status_change_checker_
= NULL
;
544 if (timer
.IsRunning()) {
545 DVLOG(1) << GetClientInfoString("AwaitStatusChange succeeded");
548 DVLOG(0) << GetClientInfoString(base::StringPrintf(
549 "AwaitStatusChange called from %s timed out", source
.c_str()));
554 std::string
ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
555 return base::StringPrintf("oauth2_refresh_token_%d",
556 ++oauth2_refesh_token_number_
);
559 ProfileSyncService::Status
ProfileSyncServiceHarness::GetStatus() const {
560 DCHECK(service() != NULL
) << "GetStatus(): service() is NULL.";
561 ProfileSyncService::Status result
;
562 service()->QueryDetailedSyncStatus(&result
);
566 bool ProfileSyncServiceHarness::IsSyncDisabled() const {
567 return !service()->setup_in_progress() &&
568 !service()->HasSyncSetupCompleted();
571 bool ProfileSyncServiceHarness::HasAuthError() const {
572 return service()->GetAuthError().state() ==
573 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
||
574 service()->GetAuthError().state() ==
575 GoogleServiceAuthError::SERVICE_ERROR
||
576 service()->GetAuthError().state() ==
577 GoogleServiceAuthError::REQUEST_CANCELED
;
580 // We use this function to share code between IsFullySynced and IsDataSynced.
581 bool ProfileSyncServiceHarness::IsDataSyncedImpl() const {
582 return ServiceIsPushingChanges() &&
583 GetStatus().notifications_enabled
&&
584 !service()->HasUnsyncedItems() &&
585 !HasPendingBackendMigration();
588 bool ProfileSyncServiceHarness::IsDataSynced() const {
589 if (service() == NULL
) {
590 DVLOG(1) << GetClientInfoString("IsDataSynced(): false");
594 bool is_data_synced
= IsDataSyncedImpl();
596 DVLOG(1) << GetClientInfoString(
597 is_data_synced
? "IsDataSynced: true" : "IsDataSynced: false");
598 return is_data_synced
;
601 bool ProfileSyncServiceHarness::IsFullySynced() const {
602 if (service() == NULL
) {
603 DVLOG(1) << GetClientInfoString("IsFullySynced: false");
606 // If we didn't try to commit anything in the previous cycle, there's a
607 // good chance that we're now fully up to date.
608 const SyncSessionSnapshot
& snap
= GetLastSessionSnapshot();
609 bool is_fully_synced
=
610 snap
.model_neutral_state().num_successful_commits
== 0
611 && snap
.model_neutral_state().commit_result
== syncer::SYNCER_OK
612 && IsDataSyncedImpl();
614 DVLOG(1) << GetClientInfoString(
615 is_fully_synced
? "IsFullySynced: true" : "IsFullySynced: false");
616 return is_fully_synced
;
619 void ProfileSyncServiceHarness::FinishSyncSetup() {
620 service()->SetSetupInProgress(false);
621 service()->SetSyncSetupCompleted();
624 bool ProfileSyncServiceHarness::HasPendingBackendMigration() const {
625 browser_sync::BackendMigrator
* migrator
=
626 service()->GetBackendMigratorForTest();
627 return migrator
&& migrator
->state() != browser_sync::BackendMigrator::IDLE
;
630 bool ProfileSyncServiceHarness::AutoStartEnabled() {
631 return service()->auto_start_enabled();
634 bool ProfileSyncServiceHarness::MatchesPartnerClient() const {
635 // TODO(akalin): Shouldn't this belong with the intersection check?
636 // Otherwise, this function isn't symmetric.
637 DCHECK(progress_marker_partner_
);
638 if (!IsFullySynced()) {
639 DVLOG(2) << profile_debug_name_
<< ": not synced, assuming doesn't match";
643 // Only look for a match if we have at least one enabled datatype in
644 // common with the partner client.
645 const syncer::ModelTypeSet common_types
=
646 Intersection(service()->GetActiveDataTypes(),
647 progress_marker_partner_
->service()->GetActiveDataTypes());
649 DVLOG(2) << profile_debug_name_
<< ", "
650 << progress_marker_partner_
->profile_debug_name_
651 << ": common types are "
652 << syncer::ModelTypeSetToString(common_types
);
654 if (!common_types
.Empty() && !progress_marker_partner_
->IsFullySynced()) {
655 DVLOG(2) << "non-empty common types and "
656 << progress_marker_partner_
->profile_debug_name_
661 for (syncer::ModelTypeSet::Iterator i
= common_types
.First();
663 const std::string marker
= GetSerializedProgressMarker(i
.Get());
664 const std::string partner_marker
=
665 progress_marker_partner_
->GetSerializedProgressMarker(i
.Get());
666 if (marker
!= partner_marker
) {
668 std::string marker_base64
, partner_marker_base64
;
669 base::Base64Encode(marker
, &marker_base64
);
670 base::Base64Encode(partner_marker
, &partner_marker_base64
);
671 DVLOG(2) << syncer::ModelTypeToString(i
.Get()) << ": "
672 << profile_debug_name_
<< " progress marker = "
673 << marker_base64
<< ", "
674 << progress_marker_partner_
->profile_debug_name_
675 << " partner progress marker = "
676 << partner_marker_base64
;
684 SyncSessionSnapshot
ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
685 DCHECK(service() != NULL
) << "Sync service has not yet been set up.";
686 if (service()->sync_initialized()) {
687 return service()->GetLastSessionSnapshot();
689 return SyncSessionSnapshot();
692 bool ProfileSyncServiceHarness::EnableSyncForDatatype(
693 syncer::ModelType datatype
) {
694 DVLOG(1) << GetClientInfoString(
695 "EnableSyncForDatatype("
696 + std::string(syncer::ModelTypeToString(datatype
)) + ")");
698 if (IsSyncDisabled())
699 return SetupSync(syncer::ModelTypeSet(datatype
));
701 if (service() == NULL
) {
702 LOG(ERROR
) << "EnableSyncForDatatype(): service() is null.";
706 syncer::ModelTypeSet synced_datatypes
= service()->GetPreferredDataTypes();
707 if (synced_datatypes
.Has(datatype
)) {
708 DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
709 << syncer::ModelTypeToString(datatype
)
710 << " on " << profile_debug_name_
<< ".";
714 synced_datatypes
.Put(syncer::ModelTypeFromInt(datatype
));
715 service()->OnUserChoseDatatypes(false, synced_datatypes
);
716 if (AwaitDataSyncCompletion()) {
717 DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
718 << syncer::ModelTypeToString(datatype
)
719 << " on " << profile_debug_name_
<< ".";
723 DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
727 bool ProfileSyncServiceHarness::DisableSyncForDatatype(
728 syncer::ModelType datatype
) {
729 DVLOG(1) << GetClientInfoString(
730 "DisableSyncForDatatype("
731 + std::string(syncer::ModelTypeToString(datatype
)) + ")");
733 if (service() == NULL
) {
734 LOG(ERROR
) << "DisableSyncForDatatype(): service() is null.";
738 syncer::ModelTypeSet synced_datatypes
= service()->GetPreferredDataTypes();
739 if (!synced_datatypes
.Has(datatype
)) {
740 DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
741 << syncer::ModelTypeToString(datatype
)
742 << " on " << profile_debug_name_
<< ".";
746 synced_datatypes
.RetainAll(syncer::UserSelectableTypes());
747 synced_datatypes
.Remove(datatype
);
748 service()->OnUserChoseDatatypes(false, synced_datatypes
);
749 if (AwaitFullSyncCompletion()) {
750 DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
751 << syncer::ModelTypeToString(datatype
)
752 << " on " << profile_debug_name_
<< ".";
756 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
760 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
761 DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
763 if (IsSyncDisabled())
766 if (service() == NULL
) {
767 LOG(ERROR
) << "EnableSyncForAllDatatypes(): service() is null.";
771 service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All());
772 if (AwaitFullSyncCompletion()) {
773 DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes "
774 << "on " << profile_debug_name_
<< ".";
778 DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
782 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
783 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
785 if (service() == NULL
) {
786 LOG(ERROR
) << "DisableSyncForAllDatatypes(): service() is null.";
790 service()->DisableForUser();
792 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
793 << "datatypes on " << profile_debug_name_
;
797 std::string
ProfileSyncServiceHarness::GetSerializedProgressMarker(
798 syncer::ModelType model_type
) const {
799 const SyncSessionSnapshot
& snap
= GetLastSessionSnapshot();
800 const syncer::ProgressMarkerMap
& markers_map
=
801 snap
.download_progress_markers();
803 syncer::ProgressMarkerMap::const_iterator it
=
804 markers_map
.find(model_type
);
805 return (it
!= markers_map
.end()) ? it
->second
: std::string();
808 std::string
ProfileSyncServiceHarness::GetClientInfoString(
809 const std::string
& message
) const {
810 std::stringstream os
;
811 os
<< profile_debug_name_
<< ": " << message
<< ": ";
813 const SyncSessionSnapshot
& snap
= GetLastSessionSnapshot();
814 const ProfileSyncService::Status
& status
= GetStatus();
815 // Capture select info from the sync session snapshot and syncer status.
816 // TODO(rsimha): Audit the list of fields below, and eventually eliminate
817 // the use of the sync session snapshot. See crbug.com/323380.
818 os
<< ", has_unsynced_items: "
819 << (service()->sync_initialized() ? service()->HasUnsyncedItems() : 0)
821 << (snap
.model_neutral_state().num_successful_commits
== 0 &&
822 snap
.model_neutral_state().commit_result
== syncer::SYNCER_OK
)
823 << ", encryption conflicts: "
824 << snap
.num_encryption_conflicts()
825 << ", hierarchy conflicts: "
826 << snap
.num_hierarchy_conflicts()
827 << ", server conflicts: "
828 << snap
.num_server_conflicts()
829 << ", num_updates_downloaded : "
830 << snap
.model_neutral_state().num_updates_downloaded_total
831 << ", passphrase_required_reason: "
832 << syncer::PassphraseRequiredReasonToString(
833 service()->passphrase_required_reason())
834 << ", notifications_enabled: "
835 << status
.notifications_enabled
836 << ", service_is_pushing_changes: "
837 << ServiceIsPushingChanges()
838 << ", has_pending_backend_migration: "
839 << HasPendingBackendMigration();
841 os
<< "Sync service not available";
846 bool ProfileSyncServiceHarness::EnableEncryption() {
847 if (IsEncryptionComplete())
849 service()->EnableEncryptEverything();
851 // In order to kick off the encryption we have to reconfigure. Just grab the
852 // currently synced types and use them.
853 const syncer::ModelTypeSet synced_datatypes
=
854 service()->GetPreferredDataTypes();
855 bool sync_everything
=
856 synced_datatypes
.Equals(syncer::ModelTypeSet::All());
857 service()->OnUserChoseDatatypes(sync_everything
, synced_datatypes
);
859 // Wait some time to let the enryption finish.
860 return WaitForEncryption();
863 bool ProfileSyncServiceHarness::WaitForEncryption() {
864 if (IsEncryptionComplete()) {
865 // Encryption is already complete; do not wait.
869 CallbackStatusChecker
encryption_complete_checker(
870 base::Bind(&ProfileSyncServiceHarness::IsEncryptionComplete
,
871 base::Unretained(this)),
872 "IsEncryptionComplete");
873 return AwaitStatusChange(&encryption_complete_checker
, "WaitForEncryption");
876 bool ProfileSyncServiceHarness::IsEncryptionComplete() const {
877 bool is_encryption_complete
= service()->EncryptEverythingEnabled() &&
878 !service()->encryption_pending();
879 DVLOG(2) << "Encryption is "
880 << (is_encryption_complete
? "" : "not ")
881 << "complete; Encrypted types = "
882 << syncer::ModelTypeSetToString(service()->GetEncryptedDataTypes());
883 return is_encryption_complete
;
886 bool ProfileSyncServiceHarness::IsTypeRunning(syncer::ModelType type
) {
887 browser_sync::DataTypeController::StateMap state_map
;
888 service()->GetDataTypeControllerStates(&state_map
);
889 return (state_map
.count(type
) != 0 &&
890 state_map
[type
] == browser_sync::DataTypeController::RUNNING
);
893 bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type
) {
894 return service()->GetPreferredDataTypes().Has(type
);
897 size_t ProfileSyncServiceHarness::GetNumEntries() const {
898 return GetLastSessionSnapshot().num_entries();
901 size_t ProfileSyncServiceHarness::GetNumDatatypes() const {
902 browser_sync::DataTypeController::StateMap state_map
;
903 service()->GetDataTypeControllerStates(&state_map
);
904 return state_map
.size();
907 std::string
ProfileSyncServiceHarness::GetServiceStatus() {
908 scoped_ptr
<base::DictionaryValue
> value(
909 sync_ui_util::ConstructAboutInformation(service()));
910 std::string service_status
;
911 base::JSONWriter::WriteWithOptions(value
.get(),
912 base::JSONWriter::OPTIONS_PRETTY_PRINT
,
914 return service_status
;