Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / profile_sync_service_harness.cc
blob80478dbeace80dd5ee496c30d5218c58382fb185
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"
7 #include <cstddef>
8 #include <iterator>
9 #include <ostream>
10 #include <set>
11 #include <sstream>
12 #include <vector>
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"
46 #endif
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;
54 namespace {
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 {
59 public:
60 CallbackStatusChecker(base::Callback<bool()> callback,
61 const std::string& source)
62 : StatusChangeChecker(source),
63 callback_(callback) {
66 virtual ~CallbackStatusChecker() {
69 virtual bool IsExitConditionSatisfied() OVERRIDE {
70 return callback_.Run();
73 private:
74 // Callback that evaluates whether the condition we are waiting on has been
75 // satisfied.
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) {
85 DCHECK(harness);
86 // Backend is initialized.
87 if (harness->service()->sync_initialized())
88 return true;
89 // Backend initialization is blocked by an auth error.
90 if (harness->HasAuthError())
91 return true;
92 // Backend initialization is blocked by a failure to fetch Oauth2 tokens.
93 if (harness->service()->IsRetryingAccessTokenFetchForTest())
94 return true;
95 // Still waiting on backend initialization.
96 return false;
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) {
102 DCHECK(harness);
103 // Initial sync is complete.
104 if (harness->IsFullySynced())
105 return true;
106 // Initial sync is blocked because custom passphrase is required.
107 if (harness->service()->passphrase_required_reason() ==
108 syncer::REASON_DECRYPTION) {
109 return true;
111 // Initial sync is blocked by an auth error.
112 if (harness->HasAuthError())
113 return true;
114 // Still waiting on initial sync.
115 return false;
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) {
121 DCHECK(harness);
122 // Sync is complete.
123 if (harness->IsFullySynced())
124 return true;
125 // Sync is blocked by an auth error.
126 if (harness->HasAuthError())
127 return true;
128 // Sync is blocked by a failure to fetch Oauth2 tokens.
129 if (harness->service()->IsRetryingAccessTokenFetchForTest())
130 return true;
131 // Still waiting on sync.
132 return false;
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) {
138 DCHECK(harness);
139 return harness->service()->IsPassphraseRequired();
142 // Helper function which returns true if the custom passphrase entered was
143 // accepted.
144 bool IsPassphraseAccepted(const ProfileSyncServiceHarness* harness) {
145 DCHECK(harness);
146 return (!harness->service()->IsPassphraseRequired() &&
147 harness->service()->IsUsingSecondaryPassphrase());
150 } // namespace
152 // static
153 ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create(
154 Profile* profile,
155 const std::string& username,
156 const std::string& password) {
157 return new ProfileSyncServiceHarness(profile, username, password, NULL);
160 // static
161 ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateForIntegrationTest(
162 Profile* profile,
163 const std::string& username,
164 const std::string& password,
165 P2PInvalidationService* p2p_invalidation_service) {
166 return new ProfileSyncServiceHarness(profile,
167 username,
168 password,
169 p2p_invalidation_service);
172 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
173 Profile* profile,
174 const std::string& username,
175 const std::string& password,
176 P2PInvalidationService* p2p_invalidation_service)
177 : profile_(profile),
178 service_(ProfileSyncServiceFactory::GetForProfile(profile)),
179 p2p_invalidation_service_(p2p_invalidation_service),
180 progress_marker_partner_(NULL),
181 username_(username),
182 password_(password),
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;
205 } else {
206 DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
208 return result;
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.";
216 return false;
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,
230 username_);
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_;
240 #else
241 std::string account_id = username_;
242 #endif
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
251 << " seconds.";
252 return false;
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.";
259 return false;
262 // Make sure that initial sync wasn't blocked by rejected credentials.
263 if (HasAuthError()) {
264 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
265 return false;
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.
275 FinishSyncSetup();
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);
282 } else {
283 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
284 " until SetDecryptionPassphrase is called.";
285 return false;
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
296 << " seconds.";
297 return false;
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.";
304 return false;
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.";
311 return false;
314 return true;
317 void ProfileSyncServiceHarness::QuitMessageLoop() {
318 base::MessageLoop::current()->QuitWhenIdle();
321 void ProfileSyncServiceHarness::OnStateChanged() {
322 if (!status_change_checker_)
323 return;
325 DVLOG(1) << GetClientInfoString(status_change_checker_->source());
326 if (status_change_checker_->IsExitConditionSatisfied())
327 QuitMessageLoop();
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);
341 OnStateChanged();
344 bool ProfileSyncServiceHarness::AwaitPassphraseRequired() {
345 DVLOG(1) << GetClientInfoString("AwaitPassphraseRequired");
346 if (IsSyncDisabled()) {
347 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << ".";
348 return false;
351 if (service()->IsPassphraseRequired()) {
352 // It's already true that a passphrase is required; don't wait.
353 return true;
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_ << ".";
367 return false;
370 if (!service()->IsPassphraseRequired() &&
371 service()->IsUsingSecondaryPassphrase()) {
372 // Passphrase is already accepted; don't wait.
373 FinishSyncSetup();
374 return true;
377 CallbackStatusChecker passphrase_accepted_checker(
378 base::Bind(&::IsPassphraseAccepted, base::Unretained(this)),
379 "IsPassphraseAccepted");
380 bool return_value = AwaitStatusChange(&passphrase_accepted_checker,
381 "AwaitPassphraseAccepted");
382 if (return_value)
383 FinishSyncSetup();
384 return return_value;
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.
391 return true;
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.
410 return true;
413 CallbackStatusChecker data_synced_checker(
414 base::Bind(&ProfileSyncServiceHarness::IsDataSynced,
415 base::Unretained(this)),
416 "IsDataSynced");
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_ << ".";
424 return false;
427 if (IsFullySynced()) {
428 // Client is already synced; don't wait.
429 return true;
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)),
446 "IsSyncDisabled");
447 return AwaitStatusChange(&sync_disabled_checker, "AwaitSyncDisabled");
450 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
451 ProfileSyncServiceHarness* partner) {
452 DVLOG(1) << GetClientInfoString("AwaitMutualSyncCycleCompletion");
453 if (!AwaitFullSyncCompletion())
454 return false;
455 return partner->WaitUntilProgressMarkersMatch(this);
458 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
459 std::vector<ProfileSyncServiceHarness*>& partners) {
460 DVLOG(1) << GetClientInfoString("AwaitGroupSyncCycleCompletion");
461 if (!AwaitFullSyncCompletion())
462 return false;
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);
471 return return_value;
474 // static
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);
486 return return_value;
489 bool ProfileSyncServiceHarness::WaitUntilProgressMarkersMatch(
490 ProfileSyncServiceHarness* partner) {
491 DVLOG(1) << GetClientInfoString("WaitUntilProgressMarkersMatch");
492 if (IsSyncDisabled()) {
493 LOG(ERROR) << "Sync disabled for " << profile_debug_name_ << ".";
494 return false;
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.
504 return_value = true;
505 } else {
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;
516 return return_value;
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_ << ".";
525 return false;
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);
539 loop->Run();
542 status_change_checker_ = NULL;
544 if (timer.IsRunning()) {
545 DVLOG(1) << GetClientInfoString("AwaitStatusChange succeeded");
546 return true;
547 } else {
548 DVLOG(0) << GetClientInfoString(base::StringPrintf(
549 "AwaitStatusChange called from %s timed out", source.c_str()));
550 return false;
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);
563 return 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");
591 return 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");
604 return 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";
640 return false;
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_
657 << " isn't synced";
658 return false;
661 for (syncer::ModelTypeSet::Iterator i = common_types.First();
662 i.Good(); i.Inc()) {
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) {
667 if (VLOG_IS_ON(2)) {
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;
678 return false;
681 return true;
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.";
703 return false;
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_ << ".";
711 return true;
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_ << ".";
720 return true;
723 DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
724 return false;
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.";
735 return false;
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_ << ".";
743 return true;
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_ << ".";
753 return true;
756 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
757 return false;
760 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
761 DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
763 if (IsSyncDisabled())
764 return SetupSync();
766 if (service() == NULL) {
767 LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null.";
768 return false;
771 service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All());
772 if (AwaitFullSyncCompletion()) {
773 DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes "
774 << "on " << profile_debug_name_ << ".";
775 return true;
778 DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
779 return false;
782 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
783 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
785 if (service() == NULL) {
786 LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
787 return false;
790 service()->DisableForUser();
792 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
793 << "datatypes on " << profile_debug_name_;
794 return true;
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 << ": ";
812 if (service()) {
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)
820 << ", did_commit: "
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();
840 } else {
841 os << "Sync service not available";
843 return os.str();
846 bool ProfileSyncServiceHarness::EnableEncryption() {
847 if (IsEncryptionComplete())
848 return true;
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.
866 return true;
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,
913 &service_status);
914 return service_status;