Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / profile_sync_service_harness.cc
blob2f4b4b080443f836d3bc68347d1cb66b1d6be9f9
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 "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/sync/profile_sync_service.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.h"
21 #include "chrome/browser/sync/test/integration/quiesce_status_change_checker.h"
22 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_finder.h"
25 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
26 #include "chrome/common/channel_info.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "components/invalidation/impl/p2p_invalidation_service.h"
29 #include "components/signin/core/browser/profile_oauth2_token_service.h"
30 #include "components/signin/core/browser/signin_manager_base.h"
31 #include "components/sync_driver/about_sync_util.h"
32 #include "google_apis/gaia/gaia_constants.h"
33 #include "sync/internal_api/public/base/progress_marker_map.h"
34 #include "sync/internal_api/public/util/sync_string_conversions.h"
36 using syncer::sessions::SyncSessionSnapshot;
38 namespace {
40 std::string GetGaiaIdForUsername(const std::string& username) {
41 return "gaia-id-" + username;
44 bool HasAuthError(ProfileSyncService* service) {
45 return service->GetAuthError().state() ==
46 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
47 service->GetAuthError().state() ==
48 GoogleServiceAuthError::SERVICE_ERROR ||
49 service->GetAuthError().state() ==
50 GoogleServiceAuthError::REQUEST_CANCELED;
53 class BackendInitializeChecker : public SingleClientStatusChangeChecker {
54 public:
55 explicit BackendInitializeChecker(ProfileSyncService* service)
56 : SingleClientStatusChangeChecker(service) {}
58 bool IsExitConditionSatisfied() override {
59 if (service()->backend_mode() != ProfileSyncService::SYNC)
60 return false;
61 if (service()->backend_initialized())
62 return true;
63 // Backend initialization is blocked by an auth error.
64 if (HasAuthError(service()))
65 return true;
66 // Backend initialization is blocked by a failure to fetch Oauth2 tokens.
67 if (service()->IsRetryingAccessTokenFetchForTest())
68 return true;
69 // Still waiting on backend initialization.
70 return false;
73 std::string GetDebugMessage() const override { return "Backend Initialize"; }
76 class SyncSetupChecker : public SingleClientStatusChangeChecker {
77 public:
78 explicit SyncSetupChecker(ProfileSyncService* service)
79 : SingleClientStatusChangeChecker(service) {}
81 bool IsExitConditionSatisfied() override {
82 if (!service()->IsSyncActive())
83 return false;
84 if (service()->ConfigurationDone())
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 std::string GetDebugMessage() const override { return "Sync Setup"; }
99 } // namespace
101 // static
102 ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create(
103 Profile* profile,
104 const std::string& username,
105 const std::string& password,
106 SigninType signin_type) {
107 return new ProfileSyncServiceHarness(profile,
108 username,
109 password,
110 signin_type);
113 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
114 Profile* profile,
115 const std::string& username,
116 const std::string& password,
117 SigninType signin_type)
118 : profile_(profile),
119 service_(ProfileSyncServiceFactory::GetForProfile(profile)),
120 username_(username),
121 password_(password),
122 signin_type_(signin_type),
123 oauth2_refesh_token_number_(0),
124 profile_debug_name_(profile->GetDebugName()) {
127 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { }
129 void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
130 const std::string& password) {
131 username_ = username;
132 password_ = password;
135 bool ProfileSyncServiceHarness::SetupSync() {
136 bool result = SetupSync(syncer::ModelTypeSet::All());
137 if (result == false) {
138 std::string status = GetServiceStatus();
139 LOG(ERROR) << profile_debug_name_
140 << ": SetupSync failed. Syncer status:\n" << status;
141 } else {
142 DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
144 return result;
147 bool ProfileSyncServiceHarness::SetupSync(
148 syncer::ModelTypeSet synced_datatypes) {
149 DCHECK(!profile_->IsLegacySupervised())
150 << "SetupSync should not be used for legacy supervised users.";
152 // Initialize the sync client's profile sync service object.
153 if (service() == NULL) {
154 LOG(ERROR) << "SetupSync(): service() is null.";
155 return false;
158 // Tell the sync service that setup is in progress so we don't start syncing
159 // until we've finished configuration.
160 service()->SetSetupInProgress(true);
162 DCHECK(!username_.empty());
163 if (signin_type_ == SigninType::UI_SIGNIN) {
164 Browser* browser =
165 FindBrowserWithProfile(profile_, chrome::GetActiveDesktop());
166 DCHECK(browser);
167 if (!login_ui_test_utils::SignInWithUI(browser, username_, password_)) {
168 LOG(ERROR) << "Could not sign in to GAIA servers.";
169 return false;
171 } else if (signin_type_ == SigninType::FAKE_SIGNIN) {
172 // Authenticate sync client using GAIA credentials.
173 std::string gaia_id = GetGaiaIdForUsername(username_);
174 service()->signin()->SetAuthenticatedAccountInfo(gaia_id, username_);
175 std::string account_id = service()->signin()->GetAuthenticatedAccountId();
176 service()->GoogleSigninSucceeded(account_id, username_, password_);
177 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
178 UpdateCredentials(account_id, GenerateFakeOAuth2RefreshTokenString());
179 } else {
180 LOG(ERROR) << "Unsupported profile signin type.";
183 // Now that auth is completed, request that sync actually start.
184 service()->RequestStart();
186 if (!AwaitBackendInitialization()) {
187 return false;
190 // Choose the datatypes to be synced. If all datatypes are to be synced,
191 // set sync_everything to true; otherwise, set it to false.
192 bool sync_everything =
193 synced_datatypes.Equals(syncer::ModelTypeSet::All());
194 service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
196 // Notify ProfileSyncService that we are done with configuration.
197 FinishSyncSetup();
199 // Set an implicit passphrase for encryption if an explicit one hasn't already
200 // been set. If an explicit passphrase has been set, immediately return false,
201 // since a decryption passphrase is required.
202 if (!service()->IsUsingSecondaryPassphrase()) {
203 service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT);
204 } else {
205 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
206 " until SetDecryptionPassphrase is called.";
207 return false;
210 // Wait for initial sync cycle to be completed.
211 if (!AwaitSyncSetupCompletion()) {
212 LOG(ERROR) << "Initial sync cycle timed out.";
213 return false;
216 return true;
219 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
220 ProfileSyncServiceHarness* partner) {
221 std::vector<ProfileSyncServiceHarness*> harnesses;
222 harnesses.push_back(this);
223 harnesses.push_back(partner);
224 return AwaitQuiescence(harnesses);
227 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
228 std::vector<ProfileSyncServiceHarness*>& partners) {
229 return AwaitQuiescence(partners);
232 // static
233 bool ProfileSyncServiceHarness::AwaitQuiescence(
234 std::vector<ProfileSyncServiceHarness*>& clients) {
235 std::vector<ProfileSyncService*> services;
236 if (clients.empty()) {
237 return true;
240 for (std::vector<ProfileSyncServiceHarness*>::iterator it = clients.begin();
241 it != clients.end(); ++it) {
242 services.push_back((*it)->service());
244 QuiesceStatusChangeChecker checker(services);
245 checker.Wait();
246 return !checker.TimedOut();
249 bool ProfileSyncServiceHarness::AwaitBackendInitialization() {
250 BackendInitializeChecker checker(service());
251 checker.Wait();
253 if (checker.TimedOut()) {
254 LOG(ERROR) << "BackendInitializeChecker timed out.";
255 return false;
258 if (!service()->backend_initialized()) {
259 LOG(ERROR) << "Service backend not initialized.";
260 return false;
263 // Make sure that initial sync wasn't blocked by a missing passphrase.
264 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
265 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
266 " until SetDecryptionPassphrase is called.";
267 return false;
270 if (HasAuthError(service())) {
271 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
272 return false;
275 return true;
278 bool ProfileSyncServiceHarness::AwaitSyncSetupCompletion() {
279 SyncSetupChecker checker(service());
280 checker.Wait();
282 if (checker.TimedOut()) {
283 LOG(ERROR) << "SyncSetupChecker timed out.";
284 return false;
287 // Make sure that initial sync wasn't blocked by a missing passphrase.
288 if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
289 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
290 " until SetDecryptionPassphrase is called.";
291 return false;
294 if (HasAuthError(service())) {
295 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
296 return false;
299 return true;
302 std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
303 return base::StringPrintf("oauth2_refresh_token_%d",
304 ++oauth2_refesh_token_number_);
307 bool ProfileSyncServiceHarness::IsSyncDisabled() const {
308 return !service()->setup_in_progress() &&
309 !service()->HasSyncSetupCompleted();
312 void ProfileSyncServiceHarness::FinishSyncSetup() {
313 service()->SetSetupInProgress(false);
314 service()->SetSyncSetupCompleted();
317 SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
318 DCHECK(service() != NULL) << "Sync service has not yet been set up.";
319 if (service()->IsSyncActive()) {
320 return service()->GetLastSessionSnapshot();
322 return SyncSessionSnapshot();
325 bool ProfileSyncServiceHarness::EnableSyncForDatatype(
326 syncer::ModelType datatype) {
327 DVLOG(1) << GetClientInfoString(
328 "EnableSyncForDatatype("
329 + std::string(syncer::ModelTypeToString(datatype)) + ")");
331 if (IsSyncDisabled())
332 return SetupSync(syncer::ModelTypeSet(datatype));
334 if (service() == NULL) {
335 LOG(ERROR) << "EnableSyncForDatatype(): service() is null.";
336 return false;
339 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
340 if (synced_datatypes.Has(datatype)) {
341 DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
342 << syncer::ModelTypeToString(datatype)
343 << " on " << profile_debug_name_ << ".";
344 return true;
347 synced_datatypes.Put(syncer::ModelTypeFromInt(datatype));
348 service()->OnUserChoseDatatypes(false, synced_datatypes);
349 if (AwaitSyncSetupCompletion()) {
350 DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
351 << syncer::ModelTypeToString(datatype)
352 << " on " << profile_debug_name_ << ".";
353 return true;
356 DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
357 return false;
360 bool ProfileSyncServiceHarness::DisableSyncForDatatype(
361 syncer::ModelType datatype) {
362 DVLOG(1) << GetClientInfoString(
363 "DisableSyncForDatatype("
364 + std::string(syncer::ModelTypeToString(datatype)) + ")");
366 if (service() == NULL) {
367 LOG(ERROR) << "DisableSyncForDatatype(): service() is null.";
368 return false;
371 syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
372 if (!synced_datatypes.Has(datatype)) {
373 DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
374 << syncer::ModelTypeToString(datatype)
375 << " on " << profile_debug_name_ << ".";
376 return true;
379 synced_datatypes.RetainAll(syncer::UserSelectableTypes());
380 synced_datatypes.Remove(datatype);
381 service()->OnUserChoseDatatypes(false, synced_datatypes);
382 if (AwaitSyncSetupCompletion()) {
383 DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
384 << syncer::ModelTypeToString(datatype)
385 << " on " << profile_debug_name_ << ".";
386 return true;
389 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
390 return false;
393 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
394 DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
396 if (IsSyncDisabled())
397 return SetupSync();
399 if (service() == NULL) {
400 LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null.";
401 return false;
404 service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All());
405 if (AwaitSyncSetupCompletion()) {
406 DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes "
407 << "on " << profile_debug_name_ << ".";
408 return true;
411 DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
412 return false;
415 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
416 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
418 if (service() == NULL) {
419 LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
420 return false;
423 service()->RequestStop(ProfileSyncService::CLEAR_DATA);
425 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
426 << "datatypes on " << profile_debug_name_;
427 return true;
430 // TODO(sync): Clean up this method in a separate CL. Remove all snapshot fields
431 // and log shorter, more meaningful messages.
432 std::string ProfileSyncServiceHarness::GetClientInfoString(
433 const std::string& message) const {
434 std::stringstream os;
435 os << profile_debug_name_ << ": " << message << ": ";
436 if (service()) {
437 const SyncSessionSnapshot& snap = GetLastSessionSnapshot();
438 ProfileSyncService::Status status;
439 service()->QueryDetailedSyncStatus(&status);
440 // Capture select info from the sync session snapshot and syncer status.
441 os << ", has_unsynced_items: "
442 << (service()->IsSyncActive() ? service()->HasUnsyncedItems() : 0)
443 << ", did_commit: "
444 << (snap.model_neutral_state().num_successful_commits == 0 &&
445 snap.model_neutral_state().commit_result == syncer::SYNCER_OK)
446 << ", encryption conflicts: "
447 << snap.num_encryption_conflicts()
448 << ", hierarchy conflicts: "
449 << snap.num_hierarchy_conflicts()
450 << ", server conflicts: "
451 << snap.num_server_conflicts()
452 << ", num_updates_downloaded : "
453 << snap.model_neutral_state().num_updates_downloaded_total
454 << ", passphrase_required_reason: "
455 << syncer::PassphraseRequiredReasonToString(
456 service()->passphrase_required_reason())
457 << ", notifications_enabled: "
458 << status.notifications_enabled
459 << ", service_is_active: "
460 << service()->IsSyncActive();
461 } else {
462 os << "Sync service not available";
464 return os.str();
467 bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) {
468 return service()->GetPreferredDataTypes().Has(type);
471 std::string ProfileSyncServiceHarness::GetServiceStatus() {
472 scoped_ptr<base::DictionaryValue> value(
473 sync_ui_util::ConstructAboutInformation(
474 service(), service()->signin(), chrome::GetChannel()));
475 std::string service_status;
476 base::JSONWriter::WriteWithOptions(
477 *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status);
478 return service_status;