This source file includes following definitions.
- HasAuthError
- IsExitConditionSatisfied
- GetDebugMessage
- IsExitConditionSatisfied
- GetDebugMessage
- AwaitSyncSetupCompletion
- Create
- profile_debug_name_
- SetCredentials
- SetupSync
- SetupSync
- AwaitMutualSyncCycleCompletion
- AwaitGroupSyncCycleCompletion
- AwaitQuiescence
- GenerateFakeOAuth2RefreshTokenString
- IsSyncDisabled
- FinishSyncSetup
- GetLastSessionSnapshot
- EnableSyncForDatatype
- DisableSyncForDatatype
- EnableSyncForAllDatatypes
- DisableSyncForAllDatatypes
- GetClientInfoString
- IsTypePreferred
- GetServiceStatus
#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
#include <cstddef>
#include <iterator>
#include <ostream>
#include <sstream>
#include <vector>
#include "base/compiler_specific.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/timer/timer.h"
#include "chrome/browser/invalidation/p2p_invalidation_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/sync/about_sync_util.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/sync/test/integration/quiesce_status_change_checker.h"
#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "components/sync_driver/data_type_controller.h"
#include "google_apis/gaia/gaia_constants.h"
#include "sync/internal_api/public/base/progress_marker_map.h"
#include "sync/internal_api/public/util/sync_string_conversions.h"
#if defined(ENABLE_MANAGED_USERS)
#include "chrome/browser/managed_mode/managed_user_constants.h"
#endif
using syncer::sessions::SyncSessionSnapshot;
namespace {
bool HasAuthError(ProfileSyncService* service) {
return service->GetAuthError().state() ==
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
service->GetAuthError().state() ==
GoogleServiceAuthError::SERVICE_ERROR ||
service->GetAuthError().state() ==
GoogleServiceAuthError::REQUEST_CANCELED;
}
class BackendInitializeChecker : public SingleClientStatusChangeChecker {
public:
explicit BackendInitializeChecker(ProfileSyncService* service)
: SingleClientStatusChangeChecker(service) {}
virtual bool IsExitConditionSatisfied() OVERRIDE {
if (service()->sync_initialized())
return true;
if (HasAuthError(service()))
return true;
if (service()->IsRetryingAccessTokenFetchForTest())
return true;
return false;
}
virtual std::string GetDebugMessage() const OVERRIDE {
return "Backend Initialize";
}
};
class SyncSetupChecker : public SingleClientStatusChangeChecker {
public:
explicit SyncSetupChecker(ProfileSyncService* service)
: SingleClientStatusChangeChecker(service) {}
virtual bool IsExitConditionSatisfied() OVERRIDE {
if (service()->ShouldPushChanges())
return true;
if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION)
return true;
if (HasAuthError(service()))
return true;
return false;
}
virtual std::string GetDebugMessage() const OVERRIDE {
return "Sync Setup";
}
};
bool AwaitSyncSetupCompletion(ProfileSyncService* service) {
SyncSetupChecker checker(service);
checker.Wait();
return !checker.TimedOut();
}
}
ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create(
Profile* profile,
const std::string& username,
const std::string& password) {
return new ProfileSyncServiceHarness(profile, username, password);
}
ProfileSyncServiceHarness::ProfileSyncServiceHarness(
Profile* profile,
const std::string& username,
const std::string& password)
: profile_(profile),
service_(ProfileSyncServiceFactory::GetForProfile(profile)),
username_(username),
password_(password),
oauth2_refesh_token_number_(0),
profile_debug_name_(profile->GetDebugName()) {
}
ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { }
void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
const std::string& password) {
username_ = username;
password_ = password;
}
bool ProfileSyncServiceHarness::SetupSync() {
bool result = SetupSync(syncer::ModelTypeSet::All());
if (result == false) {
std::string status = GetServiceStatus();
LOG(ERROR) << profile_debug_name_
<< ": SetupSync failed. Syncer status:\n" << status;
} else {
DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
}
return result;
}
bool ProfileSyncServiceHarness::SetupSync(
syncer::ModelTypeSet synced_datatypes) {
if (service() == NULL) {
LOG(ERROR) << "SetupSync(): service() is null.";
return false;
}
service()->SetSetupInProgress(true);
service()->signin()->SetAuthenticatedUsername(username_);
service()->GoogleSigninSucceeded(username_, password_);
#if defined(ENABLE_MANAGED_USERS)
std::string account_id = profile_->IsManaged() ?
managed_users::kManagedUserPseudoEmail : username_;
#else
std::string account_id = username_;
#endif
DCHECK(!account_id.empty());
ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
UpdateCredentials(account_id, GenerateFakeOAuth2RefreshTokenString());
BackendInitializeChecker checker(service());
checker.Wait();
if (checker.TimedOut()) {
LOG(ERROR) << "OnBackendInitialized() timed out.";
return false;
}
if (!service()->sync_initialized()) {
return false;
}
if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
" until SetDecryptionPassphrase is called.";
return false;
}
if (HasAuthError(service())) {
LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
return false;
}
bool sync_everything =
synced_datatypes.Equals(syncer::ModelTypeSet::All());
service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
FinishSyncSetup();
if (!service()->IsUsingSecondaryPassphrase()) {
service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT);
} else {
LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
" until SetDecryptionPassphrase is called.";
return false;
}
DCHECK(service()->sync_initialized());
if (!AwaitSyncSetupCompletion(service())) {
LOG(ERROR) << "Initial sync cycle timed out.";
return false;
}
if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
" until SetDecryptionPassphrase is called.";
return false;
}
if (service()->GetAuthError().state() ==
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
return false;
}
return true;
}
bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
ProfileSyncServiceHarness* partner) {
std::vector<ProfileSyncServiceHarness*> harnesses;
harnesses.push_back(this);
harnesses.push_back(partner);
return AwaitQuiescence(harnesses);
}
bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
std::vector<ProfileSyncServiceHarness*>& partners) {
return AwaitQuiescence(partners);
}
bool ProfileSyncServiceHarness::AwaitQuiescence(
std::vector<ProfileSyncServiceHarness*>& clients) {
std::vector<ProfileSyncService*> services;
if (clients.empty()) {
return true;
}
for (std::vector<ProfileSyncServiceHarness*>::iterator it = clients.begin();
it != clients.end(); ++it) {
services.push_back((*it)->service());
}
QuiesceStatusChangeChecker checker(services);
checker.Wait();
return !checker.TimedOut();
}
std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
return base::StringPrintf("oauth2_refresh_token_%d",
++oauth2_refesh_token_number_);
}
bool ProfileSyncServiceHarness::IsSyncDisabled() const {
return !service()->setup_in_progress() &&
!service()->HasSyncSetupCompleted();
}
void ProfileSyncServiceHarness::FinishSyncSetup() {
service()->SetSetupInProgress(false);
service()->SetSyncSetupCompleted();
}
SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
DCHECK(service() != NULL) << "Sync service has not yet been set up.";
if (service()->sync_initialized()) {
return service()->GetLastSessionSnapshot();
}
return SyncSessionSnapshot();
}
bool ProfileSyncServiceHarness::EnableSyncForDatatype(
syncer::ModelType datatype) {
DVLOG(1) << GetClientInfoString(
"EnableSyncForDatatype("
+ std::string(syncer::ModelTypeToString(datatype)) + ")");
if (IsSyncDisabled())
return SetupSync(syncer::ModelTypeSet(datatype));
if (service() == NULL) {
LOG(ERROR) << "EnableSyncForDatatype(): service() is null.";
return false;
}
syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
if (synced_datatypes.Has(datatype)) {
DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
<< syncer::ModelTypeToString(datatype)
<< " on " << profile_debug_name_ << ".";
return true;
}
synced_datatypes.Put(syncer::ModelTypeFromInt(datatype));
service()->OnUserChoseDatatypes(false, synced_datatypes);
if (AwaitSyncSetupCompletion(service())) {
DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
<< syncer::ModelTypeToString(datatype)
<< " on " << profile_debug_name_ << ".";
return true;
}
DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
return false;
}
bool ProfileSyncServiceHarness::DisableSyncForDatatype(
syncer::ModelType datatype) {
DVLOG(1) << GetClientInfoString(
"DisableSyncForDatatype("
+ std::string(syncer::ModelTypeToString(datatype)) + ")");
if (service() == NULL) {
LOG(ERROR) << "DisableSyncForDatatype(): service() is null.";
return false;
}
syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
if (!synced_datatypes.Has(datatype)) {
DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
<< syncer::ModelTypeToString(datatype)
<< " on " << profile_debug_name_ << ".";
return true;
}
synced_datatypes.RetainAll(syncer::UserSelectableTypes());
synced_datatypes.Remove(datatype);
service()->OnUserChoseDatatypes(false, synced_datatypes);
if (AwaitSyncSetupCompletion(service())) {
DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
<< syncer::ModelTypeToString(datatype)
<< " on " << profile_debug_name_ << ".";
return true;
}
DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
return false;
}
bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
if (IsSyncDisabled())
return SetupSync();
if (service() == NULL) {
LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null.";
return false;
}
service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All());
if (AwaitSyncSetupCompletion(service())) {
DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes "
<< "on " << profile_debug_name_ << ".";
return true;
}
DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
return false;
}
bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
if (service() == NULL) {
LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
return false;
}
service()->DisableForUser();
DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
<< "datatypes on " << profile_debug_name_;
return true;
}
std::string ProfileSyncServiceHarness::GetClientInfoString(
const std::string& message) const {
std::stringstream os;
os << profile_debug_name_ << ": " << message << ": ";
if (service()) {
const SyncSessionSnapshot& snap = GetLastSessionSnapshot();
ProfileSyncService::Status status;
service()->QueryDetailedSyncStatus(&status);
os << ", has_unsynced_items: "
<< (service()->sync_initialized() ? service()->HasUnsyncedItems() : 0)
<< ", did_commit: "
<< (snap.model_neutral_state().num_successful_commits == 0 &&
snap.model_neutral_state().commit_result == syncer::SYNCER_OK)
<< ", encryption conflicts: "
<< snap.num_encryption_conflicts()
<< ", hierarchy conflicts: "
<< snap.num_hierarchy_conflicts()
<< ", server conflicts: "
<< snap.num_server_conflicts()
<< ", num_updates_downloaded : "
<< snap.model_neutral_state().num_updates_downloaded_total
<< ", passphrase_required_reason: "
<< syncer::PassphraseRequiredReasonToString(
service()->passphrase_required_reason())
<< ", notifications_enabled: "
<< status.notifications_enabled
<< ", service_is_pushing_changes: "
<< service()->ShouldPushChanges();
} else {
os << "Sync service not available";
}
return os.str();
}
bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) {
return service()->GetPreferredDataTypes().Has(type);
}
std::string ProfileSyncServiceHarness::GetServiceStatus() {
scoped_ptr<base::DictionaryValue> value(
sync_ui_util::ConstructAboutInformation(service()));
std::string service_status;
base::JSONWriter::WriteWithOptions(value.get(),
base::JSONWriter::OPTIONS_PRETTY_PRINT,
&service_status);
return service_status;
}