// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_HARNESS_H_ #define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_HARNESS_H_ #pragma once #include #include #include "base/basictypes.h" #include "base/compiler_specific.h" #include "chrome/browser/sync/backend_migrator.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_service_observer.h" #include "chrome/browser/sync/retry_verifier.h" #include "chrome/browser/sync/syncable/model_type.h" class Profile; namespace browser_sync { namespace sessions { struct SyncSessionSnapshot; } } // An instance of this class is basically our notion of a "sync client" for // automation purposes. It harnesses the ProfileSyncService member of the // profile passed to it on construction and automates certain things like setup // and authentication. It provides ways to "wait" adequate periods of time for // several clients to get to the same state. class ProfileSyncServiceHarness : public ProfileSyncServiceObserver, public browser_sync::MigrationObserver { public: ProfileSyncServiceHarness(Profile* profile, const std::string& username, const std::string& password); virtual ~ProfileSyncServiceHarness(); // Creates a ProfileSyncServiceHarness object and attaches it to |profile|, a // profile that is assumed to have been signed into sync in the past. Caller // takes ownership. static ProfileSyncServiceHarness* CreateAndAttach(Profile* profile); // Sets the GAIA credentials with which to sign in to sync. void SetCredentials(const std::string& username, const std::string& password); // Returns true if sync has been enabled on |profile_|. bool IsSyncAlreadySetup(); // Creates a ProfileSyncService for the profile passed at construction and // enables sync for all available datatypes. Returns true only after sync has // been fully initialized and authenticated, and we are ready to process // changes. bool SetupSync(); // Same as the above method, but enables sync only for the datatypes contained // in |synced_datatypes|. bool SetupSync(const syncable::ModelTypeSet& synced_datatypes); // ProfileSyncServiceObserver implementation. virtual void OnStateChanged() OVERRIDE; // MigrationObserver implementation. virtual void OnMigrationStateChange() OVERRIDE; // Blocks the caller until the sync backend host associated with this harness // has been initialized. Returns true if the wait was successful. bool AwaitBackendInitialized(); // Blocks the caller until the datatype manager is configured and sync has // been initialized (for example, after a browser restart). Returns true if // the wait was successful. bool AwaitSyncRestart(); // Blocks the caller until this harness has completed a single sync cycle // since the previous one. Returns true if a sync cycle has completed. bool AwaitDataSyncCompletion(const std::string& reason); // Blocks the caller until this harness has completed as many sync cycles as // are required to ensure its progress marker matches the latest available on // the server. // // Note: When other clients are committing changes this will not be reliable. // If your test involves changes to multiple clients, you should use one of // the other Await* functions, such as AwaitMutualSyncCycleComplete. Refer to // the documentation of those functions for more details. bool AwaitFullSyncCompletion(const std::string& reason); // Blocks the caller until sync has been disabled for this client. Returns // true if sync is disabled. bool AwaitSyncDisabled(const std::string& reason); // Blocks the caller until exponential backoff has been verified to happen. bool AwaitExponentialBackoffVerification(); // Blocks the caller until the syncer receives an actionable error. // Returns true if the sync client received an actionable error. bool AwaitActionableError(); // Blocks until the given set of data types are migrated. bool AwaitMigration(const syncable::ModelTypeSet& expected_migrated_types); // Blocks the caller until this harness has observed that the sync engine // has downloaded all the changes seen by the |partner| harness's client. bool WaitUntilTimestampMatches( ProfileSyncServiceHarness* partner, const std::string& reason); // Calling this acts as a barrier and blocks the caller until |this| and // |partner| have both completed a sync cycle. When calling this method, // the |partner| should be the passive responder who responds to the actions // of |this|. This method relies upon the synchronization of callbacks // from the message queue. Returns true if two sync cycles have completed. // Note: Use this method when exactly one client makes local change(s), and // exactly one client is waiting to receive those changes. bool AwaitMutualSyncCycleCompletion(ProfileSyncServiceHarness* partner); // Blocks the caller until |this| completes its ongoing sync cycle and every // other client in |partners| have achieved identical download progresses. // Note: Use this method when exactly one client makes local change(s), // and more than one client is waiting to receive those changes. bool AwaitGroupSyncCycleCompletion( std::vector& partners); // Blocks the caller until every client in |clients| completes its ongoing // sync cycle and all the clients' timestamps match. Note: Use this method // when more than one client makes local change(s), and more than one client // is waiting to receive those changes. static bool AwaitQuiescence( std::vector& clients); // Blocks the caller until |service_| indicates that a passphrase is required. bool AwaitPassphraseRequired(); // Blocks the caller until |service_| indicates that the passphrase set by // calling SetPassphrase has been accepted. bool AwaitPassphraseAccepted(); // Returns the ProfileSyncService member of the sync client. ProfileSyncService* service() { return service_; } // Returns the status of the ProfileSyncService member of the sync client. ProfileSyncService::Status GetStatus(); // See ProfileSyncService::ShouldPushChanges(). bool ServiceIsPushingChanges() { return service_->ShouldPushChanges(); } // Enables sync for a particular sync datatype. Returns true on success. bool EnableSyncForDatatype(syncable::ModelType datatype); // Disables sync for a particular sync datatype. Returns true on success. bool DisableSyncForDatatype(syncable::ModelType datatype); // Enables sync for all sync datatypes. Returns true on success. bool EnableSyncForAllDatatypes(); // Disables sync for all sync datatypes. Returns true on success. bool DisableSyncForAllDatatypes(); // Returns a snapshot of the current sync session. const browser_sync::sessions::SyncSessionSnapshot* GetLastSessionSnapshot() const; // Encrypt the datatype |type|. This method will block while the sync backend // host performs the encryption or a timeout is reached. // PostCondition: // returns: True if |type| was encrypted and we are fully synced. // False if we timed out. bool EnableEncryptionForType(syncable::ModelType type); // Wait until |type| is encrypted or we time out. // PostCondition: // returns: True if |type| is currently encrypted and we are fully synced. // False if we timed out. bool WaitForTypeEncryption(syncable::ModelType type); // Check if |type| is encrypted. bool IsTypeEncrypted(syncable::ModelType type); // Check if |type| is registered and the controller is running. bool IsTypeRunning(syncable::ModelType type); // Check if |type| is being synced. bool IsTypePreferred(syncable::ModelType type); private: friend class StateChangeTimeoutEvent; enum WaitState { // The sync client has just been initialized. INITIAL_WAIT_STATE = 0, // The sync client awaits the OnBackendInitialized() callback. WAITING_FOR_ON_BACKEND_INITIALIZED, // The sync client is waiting for the first sync cycle to complete. WAITING_FOR_INITIAL_SYNC, // The sync client is waiting for data to be synced. WAITING_FOR_DATA_SYNC, // The sync client is waiting for data and progress markers to be synced. WAITING_FOR_FULL_SYNC, // The sync client anticipates incoming updates leading to a new sync cycle. WAITING_FOR_UPDATES, // The sync client is waiting for a passphrase to be required by the // cryptographer. WAITING_FOR_PASSPHRASE_REQUIRED, // The sync client is waiting for its passphrase to be accepted by the // cryptographer. WAITING_FOR_PASSPHRASE_ACCEPTED, // The sync client anticipates encryption of new datatypes. WAITING_FOR_ENCRYPTION, // The sync client is waiting for the datatype manager to be configured and // for sync to be fully initialized. Used after a browser restart, where a // full sync cycle is not expected to occur. WAITING_FOR_SYNC_CONFIGURATION, // The sync client is waiting for sync to be disabled for this client. WAITING_FOR_SYNC_DISABLED, // The sync client is in the exponential backoff mode. Verify that // backoffs are triggered correctly. WAITING_FOR_EXPONENTIAL_BACKOFF_VERIFICATION, // The sync client is waiting for migration to start. WAITING_FOR_MIGRATION_TO_START, // The sync client is waiting for migration to finish. WAITING_FOR_MIGRATION_TO_FINISH, // The sync client is waiting for an actionable error from the server. WAITING_FOR_ACTIONABLE_ERROR, // The client verification is complete. We don't care about the state of // the syncer any more. WAITING_FOR_NOTHING, // The sync client needs a passphrase in order to decrypt data. SET_PASSPHRASE_FAILED, // The sync client cannot reach the server. SERVER_UNREACHABLE, // The sync client is fully synced and there are no pending updates. FULLY_SYNCED, // Syncing is disabled for the client. SYNC_DISABLED, NUMBER_OF_STATES, }; // Listen to migration events if the migrator has been initialized // and we're not already listening. Returns true if we started // listening. bool TryListeningToMigrationEvents(); // Called from the observer when the current wait state has been completed. void SignalStateCompleteWithNextState(WaitState next_state); // Indicates that the operation being waited on is complete. void SignalStateComplete(); // Finite state machine for controlling state. Returns true only if a state // change has taken place. bool RunStateChangeMachine(); // Returns true if a status change took place, false on timeout. bool AwaitStatusChangeWithTimeout(int timeout_milliseconds, const std::string& reason); // A helper for implementing IsDataSynced() and IsFullySynced(). bool IsDataSyncedImpl(const browser_sync::sessions::SyncSessionSnapshot*); // Returns true if the sync client has no unsynced items. bool IsDataSynced(); // Returns true if the sync client has no unsynced items and its progress // markers are believed to be up to date. // // Although we can't detect when commits from other clients invalidate our // local progress markers, we do know when our own commits have invalidated // our timestmaps. This check returns true when this client has, to the best // of its knowledge, downloaded the latest progress markers. bool IsFullySynced(); // Returns true if there is a backend migration in progress. bool HasPendingBackendMigration(); // Returns true if this client has downloaded all the items that the // other client has. bool MatchesOtherClient(ProfileSyncServiceHarness* partner); // Returns a string with relevant info about client's sync state (if // available), annotated with |message|. Useful for logging. std::string GetClientInfoString(const std::string& message); // Gets the current progress indicator of the current sync session // for a particular datatype. std::string GetUpdatedTimestamp(syncable::ModelType model_type); // Gets detailed status from |service_| in pretty-printable form. std::string GetServiceStatus(); // When in WAITING_FOR_ENCRYPTION state, we check to see if this type is now // encrypted to determine if we're done. syncable::ModelType waiting_for_encryption_type_; // The WaitState in which the sync client currently is. Helps determine what // action to take when RunStateChangeMachine() is called. WaitState wait_state_; // Sync profile associated with this sync client. Profile* profile_; // ProfileSyncService object associated with |profile_|. ProfileSyncService* service_; // The harness of the client whose update progress marker we're expecting // eventually match. ProfileSyncServiceHarness* timestamp_match_partner_; // Credentials used for GAIA authentication. std::string username_; std::string password_; // The current set of data types pending migration. Used by // AwaitMigration(). syncable::ModelTypeSet pending_migration_types_; // The set of data types that have undergone migration. Used by // AwaitMigration(). syncable::ModelTypeSet migrated_types_; // Used for logging. const std::string profile_debug_name_; // Keeps track of the number of attempts at exponential backoff and its // related bookkeeping information for verification. browser_sync::RetryVerifier retry_verifier_; DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceHarness); }; #endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_HARNESS_H_