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