Move Webstore URL concepts to //extensions and out
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / profile_sync_service_harness.cc
blobf145e72d2a1b3bf105ca3833edf3dd4f5aadc3c7
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 <sstream>
11 #include <vector>
13 #include "base/compiler_specific.h"
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/timer/timer.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/sync/about_sync_util.h"
21 #include "chrome/browser/sync/profile_sync_service.h"
22 #include "chrome/browser/sync/profile_sync_service_factory.h"
23 #include "chrome/browser/sync/test/integration/quiesce_status_change_checker.h"
24 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "components/invalidation/p2p_invalidation_service.h"
28 #include "components/signin/core/browser/profile_oauth2_token_service.h"
29 #include "components/signin/core/browser/signin_manager_base.h"
30 #include "components/sync_driver/data_type_controller.h"
31 #include "google_apis/gaia/gaia_constants.h"
32 #include "sync/internal_api/public/base/progress_marker_map.h"
33 #include "sync/internal_api/public/util/sync_string_conversions.h"
35 #if defined(ENABLE_MANAGED_USERS)
36 #include "chrome/browser/supervised_user/supervised_user_constants.h"
37 #endif
39 using syncer::sessions::SyncSessionSnapshot;
41 namespace {
43 bool HasAuthError(ProfileSyncService* service) {
44 return service->GetAuthError().state() ==
45 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
46 service->GetAuthError().state() ==
47 GoogleServiceAuthError::SERVICE_ERROR ||
48 service->GetAuthError().state() ==
49 GoogleServiceAuthError::REQUEST_CANCELED;
52 class BackendInitializeChecker : public SingleClientStatusChangeChecker {
53 public:
54 explicit BackendInitializeChecker(ProfileSyncService* service)
55 : SingleClientStatusChangeChecker(service) {}
57 virtual bool IsExitConditionSatisfied() OVERRIDE {
58 if (service()->backend_mode() != ProfileSyncService::SYNC)
59 return false;
60 if (service()->sync_initialized())
61 return true;
62 // Backend initialization is blocked by an auth error.
63 if (HasAuthError(service()))
64 return true;
65 // Backend initialization is blocked by a failure to fetch Oauth2 tokens.
66 if (service()->IsRetryingAccessTokenFetchForTest())
67 return true;
68 // Still waiting on backend initialization.
69 return false;
72 virtual std::string GetDebugMessage() const OVERRIDE {
73 return "Backend Initialize";
77 class SyncSetupChecker : public SingleClientStatusChangeChecker {
78 public:
79 explicit SyncSetupChecker(ProfileSyncService* service)
80 : SingleClientStatusChangeChecker(service) {}
82 virtual bool IsExitConditionSatisfied() OVERRIDE {
83 // Sync setup is complete, and the client is ready to sync new changes.
84 if (service()->ShouldPushChanges())
85 return true;
86 // Sync is blocked because a custom passphrase is required.
87 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION)
88 return true;
89 // Sync is blocked by an auth error.
90 if (HasAuthError(service()))
91 return true;
92 // Still waiting on sync setup.
93 return false;
96 virtual std::string GetDebugMessage() const OVERRIDE {
97 return "Sync Setup";
101 bool AwaitSyncSetupCompletion(ProfileSyncService* service) {
102 SyncSetupChecker checker(service);
103 checker.Wait();
104 return !checker.TimedOut();
107 } // namespace
109 // static
110 ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create(
111 Profile* profile,
112 const std::string& username,
113 const std::string& password) {
114 return new ProfileSyncServiceHarness(profile, username, password);
117 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
118 Profile* profile,
119 const std::string& username,
120 const std::string& password)
121 : profile_(profile),
122 service_(ProfileSyncServiceFactory::GetForProfile(profile)),
123 username_(username),
124 password_(password),
125 oauth2_refesh_token_number_(0),
126 profile_debug_name_(profile->GetDebugName()) {
129 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { }
131 void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
132 const std::string& password) {
133 username_ = username;
134 password_ = password;
137 bool ProfileSyncServiceHarness::SetupSync() {
138 bool result = SetupSync(syncer::ModelTypeSet::All());
139 if (result == false) {
140 std::string status = GetServiceStatus();
141 LOG(ERROR) << profile_debug_name_
142 << ": SetupSync failed. Syncer status:\n" << status;
143 } else {
144 DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
146 return result;
149 bool ProfileSyncServiceHarness::SetupSync(
150 syncer::ModelTypeSet synced_datatypes) {
151 // Initialize the sync client's profile sync service object.
152 if (service() == NULL) {
153 LOG(ERROR) << "SetupSync(): service() is null.";
154 return false;
157 // Tell the sync service that setup is in progress so we don't start syncing
158 // until we've finished configuration.
159 service()->SetSetupInProgress(true);
161 // Authenticate sync client using GAIA credentials.
162 service()->signin()->SetAuthenticatedUsername(username_);
163 service()->GoogleSigninSucceeded(username_, username_, password_);
165 #if defined(ENABLE_MANAGED_USERS)
166 std::string account_id = profile_->IsSupervised() ?
167 supervised_users::kSupervisedUserPseudoEmail : username_;
168 #else
169 std::string account_id = username_;
170 #endif
171 DCHECK(!account_id.empty());
172 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
173 UpdateCredentials(account_id, GenerateFakeOAuth2RefreshTokenString());
175 // Wait for the OnBackendInitialized() callback.
176 BackendInitializeChecker checker(service());
177 checker.Wait();
179 if (checker.TimedOut()) {
180 LOG(ERROR) << "OnBackendInitialized() timed out.";
181 return false;
184 if (!service()->sync_initialized()) {
185 return false;
188 // Make sure that initial sync wasn't blocked by a missing passphrase.
189 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
190 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
191 " until SetDecryptionPassphrase is called.";
192 return false;
195 // Make sure that initial sync wasn't blocked by rejected credentials.
196 if (HasAuthError(service())) {
197 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
198 return false;
201 // Choose the datatypes to be synced. If all datatypes are to be synced,
202 // set sync_everything to true; otherwise, set it to false.
203 bool sync_everything =
204 synced_datatypes.Equals(syncer::ModelTypeSet::All());
205 service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
207 // Notify ProfileSyncService that we are done with configuration.
208 FinishSyncSetup();
210 // Set an implicit passphrase for encryption if an explicit one hasn't already
211 // been set. If an explicit passphrase has been set, immediately return false,
212 // since a decryption passphrase is required.
213 if (!service()->IsUsingSecondaryPassphrase()) {
214 service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT);
215 } else {
216 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
217 " until SetDecryptionPassphrase is called.";
218 return false;
221 // Wait for initial sync cycle to be completed.
222 DCHECK(service()->sync_initialized());
223 if (!AwaitSyncSetupCompletion(service())) {
224 LOG(ERROR) << "Initial sync cycle timed out.";
225 return false;
228 // Make sure that initial sync wasn't blocked by a missing passphrase.
229 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
230 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
231 " until SetDecryptionPassphrase is called.";
232 return false;
235 // Make sure that initial sync wasn't blocked by rejected credentials.
236 if (service()->GetAuthError().state() ==
237 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
238 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
239 return false;
242 return true;
245 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
246 ProfileSyncServiceHarness* partner) {
247 std::vector<ProfileSyncServiceHarness*> harnesses;
248 harnesses.push_back(this);
249 harnesses.push_back(partner);
250 return AwaitQuiescence(harnesses);
253 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
254 std::vector<ProfileSyncServiceHarness*>& partners) {
255 return AwaitQuiescence(partners);
258 // static
259 bool ProfileSyncServiceHarness::AwaitQuiescence(
260 std::vector<ProfileSyncServiceHarness*>& clients) {
261 std::vector<ProfileSyncService*> services;
262 if (clients.empty()) {
263 return true;
266 for (std::vector<ProfileSyncServiceHarness*>::iterator it = clients.begin();
267 it != clients.end(); ++it) {
268 services.push_back((*it)->service());
270 QuiesceStatusChangeChecker checker(services);
271 checker.Wait();
272 return !checker.TimedOut();
275 std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
276 return base::StringPrintf("oauth2_refresh_token_%d",
277 ++oauth2_refesh_token_number_);
280 bool ProfileSyncServiceHarness::IsSyncDisabled() const {
281 return !service()->setup_in_progress() &&
282 !service()->HasSyncSetupCompleted();
285 void ProfileSyncServiceHarness::FinishSyncSetup() {
286 service()->SetSetupInProgress(false);
287 service()->SetSyncSetupCompleted();
290 SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
291 DCHECK(service() != NULL) << "Sync service has not yet been set up.";
292 if (service()->sync_initialized()) {
293 return service()->GetLastSessionSnapshot();
295 return SyncSessionSnapshot();
298 bool ProfileSyncServiceHarness::EnableSyncForDatatype(
299 syncer::ModelType datatype) {
300 DVLOG(1) << GetClientInfoString(
301 "EnableSyncForDatatype("
302 + std::string(syncer::ModelTypeToString(datatype)) + ")");
304 if (IsSyncDisabled())
305 return SetupSync(syncer::ModelTypeSet(datatype));
307 if (service() == NULL) {
308 LOG(ERROR) << "EnableSyncForDatatype(): service() is null.";
309 return false;
312 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
313 if (synced_datatypes.Has(datatype)) {
314 DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
315 << syncer::ModelTypeToString(datatype)
316 << " on " << profile_debug_name_ << ".";
317 return true;
320 synced_datatypes.Put(syncer::ModelTypeFromInt(datatype));
321 service()->OnUserChoseDatatypes(false, synced_datatypes);
322 if (AwaitSyncSetupCompletion(service())) {
323 DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
324 << syncer::ModelTypeToString(datatype)
325 << " on " << profile_debug_name_ << ".";
326 return true;
329 DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
330 return false;
333 bool ProfileSyncServiceHarness::DisableSyncForDatatype(
334 syncer::ModelType datatype) {
335 DVLOG(1) << GetClientInfoString(
336 "DisableSyncForDatatype("
337 + std::string(syncer::ModelTypeToString(datatype)) + ")");
339 if (service() == NULL) {
340 LOG(ERROR) << "DisableSyncForDatatype(): service() is null.";
341 return false;
344 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
345 if (!synced_datatypes.Has(datatype)) {
346 DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
347 << syncer::ModelTypeToString(datatype)
348 << " on " << profile_debug_name_ << ".";
349 return true;
352 synced_datatypes.RetainAll(syncer::UserSelectableTypes());
353 synced_datatypes.Remove(datatype);
354 service()->OnUserChoseDatatypes(false, synced_datatypes);
355 if (AwaitSyncSetupCompletion(service())) {
356 DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
357 << syncer::ModelTypeToString(datatype)
358 << " on " << profile_debug_name_ << ".";
359 return true;
362 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
363 return false;
366 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
367 DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
369 if (IsSyncDisabled())
370 return SetupSync();
372 if (service() == NULL) {
373 LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null.";
374 return false;
377 service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All());
378 if (AwaitSyncSetupCompletion(service())) {
379 DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes "
380 << "on " << profile_debug_name_ << ".";
381 return true;
384 DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
385 return false;
388 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
389 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
391 if (service() == NULL) {
392 LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
393 return false;
396 service()->DisableForUser();
398 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
399 << "datatypes on " << profile_debug_name_;
400 return true;
403 // TODO(sync): Clean up this method in a separate CL. Remove all snapshot fields
404 // and log shorter, more meaningful messages.
405 std::string ProfileSyncServiceHarness::GetClientInfoString(
406 const std::string& message) const {
407 std::stringstream os;
408 os << profile_debug_name_ << ": " << message << ": ";
409 if (service()) {
410 const SyncSessionSnapshot& snap = GetLastSessionSnapshot();
411 ProfileSyncService::Status status;
412 service()->QueryDetailedSyncStatus(&status);
413 // Capture select info from the sync session snapshot and syncer status.
414 os << ", has_unsynced_items: "
415 << (service()->sync_initialized() ? service()->HasUnsyncedItems() : 0)
416 << ", did_commit: "
417 << (snap.model_neutral_state().num_successful_commits == 0 &&
418 snap.model_neutral_state().commit_result == syncer::SYNCER_OK)
419 << ", encryption conflicts: "
420 << snap.num_encryption_conflicts()
421 << ", hierarchy conflicts: "
422 << snap.num_hierarchy_conflicts()
423 << ", server conflicts: "
424 << snap.num_server_conflicts()
425 << ", num_updates_downloaded : "
426 << snap.model_neutral_state().num_updates_downloaded_total
427 << ", passphrase_required_reason: "
428 << syncer::PassphraseRequiredReasonToString(
429 service()->passphrase_required_reason())
430 << ", notifications_enabled: "
431 << status.notifications_enabled
432 << ", service_is_pushing_changes: "
433 << service()->ShouldPushChanges();
434 } else {
435 os << "Sync service not available";
437 return os.str();
440 bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) {
441 return service()->GetPreferredDataTypes().Has(type);
444 std::string ProfileSyncServiceHarness::GetServiceStatus() {
445 scoped_ptr<base::DictionaryValue> value(
446 sync_ui_util::ConstructAboutInformation(service()));
447 std::string service_status;
448 base::JSONWriter::WriteWithOptions(value.get(),
449 base::JSONWriter::OPTIONS_PRETTY_PRINT,
450 &service_status);
451 return service_status;