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 <sstream>
9 #include <utility>
10
11 #include "base/command_line.h"
12 #include "base/feature_list.h"
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/test/bind.h"
17 #include "build/build_config.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/signin/identity_manager_factory.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/sync/test/integration/sync_signin_delegate.h"
24 #include "chrome/common/channel_info.h"
25 #include "components/signin/public/identity_manager/identity_manager.h"
26 #include "components/signin/public/identity_manager/identity_test_utils.h"
27 #include "components/sync/driver/sync_driver_switches.h"
28 #include "components/sync/driver/sync_internals_util.h"
29 #include "components/sync/engine/sync_string_conversions.h"
30 #include "components/sync/engine_impl/net/url_translator.h"
31 #include "components/sync/engine_impl/traffic_logger.h"
32 #include "components/sync/protocol/sync.pb.h"
33 #include "content/public/browser/browser_context.h"
34 #include "content/public/test/simple_url_loader_test_helper.h"
35 #include "google_apis/google_api_keys.h"
36 #include "net/base/net_errors.h"
37 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
38 #include "services/network/public/cpp/resource_request.h"
39 #include "services/network/public/cpp/shared_url_loader_factory.h"
40 #include "services/network/public/cpp/simple_url_loader.h"
41 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
42 #include "third_party/zlib/google/compression_utils.h"
43
44 using syncer::ProfileSyncService;
45 using syncer::SyncCycleSnapshot;
46
47 const char* kSyncUrlClearServerDataKey = "sync-url-clear-server-data";
48
49 namespace {
50
HasAuthError(ProfileSyncService * service)51 bool HasAuthError(ProfileSyncService* service) {
52 return service->GetAuthError().state() ==
53 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
54 service->GetAuthError().state() ==
55 GoogleServiceAuthError::SERVICE_ERROR ||
56 service->GetAuthError().state() ==
57 GoogleServiceAuthError::REQUEST_CANCELED;
58 }
59
60 class EngineInitializeChecker : public SingleClientStatusChangeChecker {
61 public:
EngineInitializeChecker(ProfileSyncService * service)62 explicit EngineInitializeChecker(ProfileSyncService* service)
63 : SingleClientStatusChangeChecker(service) {}
64
IsExitConditionSatisfied(std::ostream * os)65 bool IsExitConditionSatisfied(std::ostream* os) override {
66 *os << "Waiting for sync engine initialization to complete";
67 if (service()->IsEngineInitialized())
68 return true;
69 // Engine initialization is blocked by an auth error.
70 if (HasAuthError(service())) {
71 LOG(WARNING) << "Sync engine initialization blocked by auth error";
72 return true;
73 }
74 // Engine initialization is blocked by a failure to fetch Oauth2 tokens.
75 if (service()->IsRetryingAccessTokenFetchForTest()) {
76 LOG(WARNING) << "Sync engine initialization blocked by failure to fetch "
77 "access tokens";
78 return true;
79 }
80 // Still waiting on engine initialization.
81 return false;
82 }
83 };
84
85 class SyncSetupChecker : public SingleClientStatusChangeChecker {
86 public:
87 enum class State { kTransportActive, kFeatureActive };
88
SyncSetupChecker(ProfileSyncService * service,State wait_for_state)89 SyncSetupChecker(ProfileSyncService* service, State wait_for_state)
90 : SingleClientStatusChangeChecker(service),
91 wait_for_state_(wait_for_state) {}
92
IsExitConditionSatisfied(std::ostream * os)93 bool IsExitConditionSatisfied(std::ostream* os) override {
94 *os << "Waiting for sync setup to complete";
95
96 syncer::SyncService::TransportState transport_state =
97 service()->GetTransportState();
98 if (transport_state == syncer::SyncService::TransportState::ACTIVE &&
99 (wait_for_state_ != State::kFeatureActive ||
100 service()->IsSyncFeatureActive())) {
101 return true;
102 }
103 // Sync is blocked by an auth error.
104 if (HasAuthError(service())) {
105 return true;
106 }
107 // TODO(crbug.com/1010397): The verification of INITIALIZING is only needed
108 // due to SyncEncryptionHandlerImpl issuing an unnecessary
109 // OnPassphraseRequired() during initialization.
110 if (service()
111 ->GetUserSettings()
112 ->IsPassphraseRequiredForPreferredDataTypes() &&
113 transport_state != syncer::SyncService::TransportState::INITIALIZING) {
114 LOG(FATAL)
115 << "A passphrase is required for decryption but was not provided. "
116 "Waiting for sync to become available won't succeed. Make sure "
117 "to pass it when setting up sync.";
118 }
119 // Still waiting on sync setup.
120 return false;
121 }
122
123 private:
124 const State wait_for_state_;
125 };
126
127 } // namespace
128
129 // static
Create(Profile * profile,const std::string & username,const std::string & password,SigninType signin_type)130 std::unique_ptr<ProfileSyncServiceHarness> ProfileSyncServiceHarness::Create(
131 Profile* profile,
132 const std::string& username,
133 const std::string& password,
134 SigninType signin_type) {
135 return base::WrapUnique(
136 new ProfileSyncServiceHarness(profile, username, password, signin_type));
137 }
138
ProfileSyncServiceHarness(Profile * profile,const std::string & username,const std::string & password,SigninType signin_type)139 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
140 Profile* profile,
141 const std::string& username,
142 const std::string& password,
143 SigninType signin_type)
144 : profile_(profile),
145 service_(ProfileSyncServiceFactory::GetAsProfileSyncServiceForProfile(
146 profile)),
147 username_(username),
148 password_(password),
149 signin_type_(signin_type),
150 profile_debug_name_(profile->GetDebugName()),
151 signin_delegate_(CreateSyncSigninDelegate()) {}
152
153 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() = default;
154
SignInPrimaryAccount()155 bool ProfileSyncServiceHarness::SignInPrimaryAccount() {
156 // TODO(crbug.com/871221): This function should distinguish primary account
157 // (aka sync account) from secondary accounts (content area signin). Let's
158 // migrate tests that exercise transport-only sync to secondary accounts.
159 DCHECK(!username_.empty());
160
161 switch (signin_type_) {
162 case SigninType::UI_SIGNIN: {
163 return signin_delegate_->SigninUI(profile_, username_, password_);
164 }
165
166 case SigninType::FAKE_SIGNIN: {
167 signin_delegate_->SigninFake(profile_, username_);
168 return true;
169 }
170 }
171
172 NOTREACHED();
173 return false;
174 }
175
176 // Same as reset on chrome.google.com/sync.
177 // This function will wait until the reset is done. If error occurs,
178 // it will log error messages.
ResetAccount(network::SharedURLLoaderFactory * url_loader_factory,const std::string & access_token,const GURL & url,const std::string & username,const std::string & birthday)179 void ResetAccount(network::SharedURLLoaderFactory* url_loader_factory,
180 const std::string& access_token,
181 const GURL& url,
182 const std::string& username,
183 const std::string& birthday) {
184 // Generate https POST payload.
185 sync_pb::ClientToServerMessage message;
186 message.set_share(username);
187 message.set_message_contents(
188 sync_pb::ClientToServerMessage::CLEAR_SERVER_DATA);
189 message.set_store_birthday(birthday);
190 message.set_api_key(google_apis::GetAPIKey());
191 syncer::LogClientToServerMessage(message);
192 std::string payload;
193 message.SerializeToString(&payload);
194 std::string request_to_send;
195 compression::GzipCompress(payload, &request_to_send);
196
197 auto resource_request = std::make_unique<network::ResourceRequest>();
198 resource_request->url = url;
199 resource_request->method = "POST";
200 resource_request->headers.SetHeader("Authorization",
201 "Bearer " + access_token);
202 resource_request->headers.SetHeader("Content-Encoding", "gzip");
203 resource_request->headers.SetHeader("Accept-Language", "en-US,en");
204 resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
205 auto simple_loader = network::SimpleURLLoader::Create(
206 std::move(resource_request), TRAFFIC_ANNOTATION_FOR_TESTS);
207 simple_loader->AttachStringForUpload(request_to_send,
208 "application/octet-stream");
209 simple_loader->SetTimeoutDuration(base::TimeDelta::FromSeconds(10));
210 content::SimpleURLLoaderTestHelper url_loader_helper;
211 simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
212 url_loader_factory, url_loader_helper.GetCallback());
213 url_loader_helper.WaitForCallback();
214 if (simple_loader->NetError() != 0) {
215 LOG(ERROR) << "Reset account failed with error "
216 << net::ErrorToString(simple_loader->NetError())
217 << ". The account will remain dirty and may cause test fail.";
218 }
219 }
220
ResetSyncForPrimaryAccount()221 void ProfileSyncServiceHarness::ResetSyncForPrimaryAccount() {
222 syncer::SyncPrefs sync_prefs(profile_->GetPrefs());
223 // Generate the https url.
224 // CLEAR_SERVER_DATA isn't enabled on the prod Sync server,
225 // so --sync-url-clear-server-data can be used to specify an
226 // alternative endpoint.
227 // Note: Any OTA(Owned Test Account) tries to clear data need to be
228 // whitelisted.
229 auto* cmd_line = base::CommandLine::ForCurrentProcess();
230 DCHECK(cmd_line->HasSwitch(kSyncUrlClearServerDataKey))
231 << "Missing switch " << kSyncUrlClearServerDataKey;
232 GURL base_url(cmd_line->GetSwitchValueASCII(kSyncUrlClearServerDataKey) +
233 "/command/?");
234 GURL url = syncer::AppendSyncQueryString(base_url, sync_prefs.GetCacheGuid());
235
236 // Call sync server to clear sync data.
237 std::string access_token = service()->GetAccessTokenForTest();
238 DCHECK(access_token.size()) << "Access token is not available.";
239 ResetAccount(profile_->GetURLLoaderFactory().get(), access_token, url,
240 username_, sync_prefs.GetBirthday());
241 }
242
243 #if !defined(OS_CHROMEOS)
SignOutPrimaryAccount()244 void ProfileSyncServiceHarness::SignOutPrimaryAccount() {
245 DCHECK(!username_.empty());
246 signin::ClearPrimaryAccount(
247 IdentityManagerFactory::GetForProfile(profile_),
248 signin::ClearPrimaryAccountPolicy::REMOVE_ALL_ACCOUNTS);
249 }
250 #endif // !OS_CHROMEOS
251
EnterSyncPausedStateForPrimaryAccount()252 void ProfileSyncServiceHarness::EnterSyncPausedStateForPrimaryAccount() {
253 DCHECK(service_->IsSyncFeatureActive());
254 signin::SetInvalidRefreshTokenForPrimaryAccount(
255 IdentityManagerFactory::GetForProfile(profile_));
256 }
257
ExitSyncPausedStateForPrimaryAccount()258 void ProfileSyncServiceHarness::ExitSyncPausedStateForPrimaryAccount() {
259 signin::SetRefreshTokenForPrimaryAccount(
260 IdentityManagerFactory::GetForProfile(profile_));
261 if (base::FeatureList::IsEnabled(switches::kStopSyncInPausedState)) {
262 // The engine was off in the sync-paused state, so wait for it to start.
263 AwaitSyncSetupCompletion();
264 }
265 }
266
SetupSync()267 bool ProfileSyncServiceHarness::SetupSync() {
268 bool result =
269 SetupSyncNoWaitForCompletion(
270 service()->GetUserSettings()->GetRegisteredSelectableTypes()) &&
271 AwaitSyncSetupCompletion();
272 if (!result) {
273 LOG(ERROR) << profile_debug_name_ << ": SetupSync failed. Syncer status:\n"
274 << GetServiceStatus();
275 } else {
276 DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
277 }
278 return result;
279 }
280
SetupSyncNoWaitForCompletion(syncer::UserSelectableTypeSet selected_types)281 bool ProfileSyncServiceHarness::SetupSyncNoWaitForCompletion(
282 syncer::UserSelectableTypeSet selected_types) {
283 return SetupSyncImpl(selected_types, EncryptionSetupMode::kNoEncryption,
284 /*encryption_passphrase=*/base::nullopt);
285 }
286
287 bool ProfileSyncServiceHarness::
SetupSyncWithEncryptionPassphraseNoWaitForCompletion(syncer::UserSelectableTypeSet selected_types,const std::string & passphrase)288 SetupSyncWithEncryptionPassphraseNoWaitForCompletion(
289 syncer::UserSelectableTypeSet selected_types,
290 const std::string& passphrase) {
291 return SetupSyncImpl(selected_types, EncryptionSetupMode::kEncryption,
292 passphrase);
293 }
294
295 bool ProfileSyncServiceHarness::
SetupSyncWithDecryptionPassphraseNoWaitForCompletion(syncer::UserSelectableTypeSet selected_types,const std::string & passphrase)296 SetupSyncWithDecryptionPassphraseNoWaitForCompletion(
297 syncer::UserSelectableTypeSet selected_types,
298 const std::string& passphrase) {
299 return SetupSyncImpl(selected_types, EncryptionSetupMode::kDecryption,
300 passphrase);
301 }
302
SetupSyncImpl(syncer::UserSelectableTypeSet selected_types,EncryptionSetupMode encryption_mode,const base::Optional<std::string> & passphrase)303 bool ProfileSyncServiceHarness::SetupSyncImpl(
304 syncer::UserSelectableTypeSet selected_types,
305 EncryptionSetupMode encryption_mode,
306 const base::Optional<std::string>& passphrase) {
307 DCHECK(encryption_mode == EncryptionSetupMode::kNoEncryption ||
308 passphrase.has_value());
309 DCHECK(!profile_->IsLegacySupervised())
310 << "SetupSync should not be used for legacy supervised users.";
311
312 if (service() == nullptr) {
313 LOG(ERROR) << "SetupSync(): service() is null.";
314 return false;
315 }
316
317 // Tell the sync service that setup is in progress so we don't start syncing
318 // until we've finished configuration.
319 sync_blocker_ = service()->GetSetupInProgressHandle();
320
321 if (!SignInPrimaryAccount()) {
322 return false;
323 }
324
325 // Now that auth is completed, request that sync actually start.
326 service()->GetUserSettings()->SetSyncRequested(true);
327
328 if (!AwaitEngineInitialization()) {
329 return false;
330 }
331 // Choose the datatypes to be synced. If all registered datatypes are to be
332 // synced, set sync_everything to true; otherwise, set it to false.
333 bool sync_everything =
334 (selected_types ==
335 service()->GetUserSettings()->GetRegisteredSelectableTypes());
336 service()->GetUserSettings()->SetSelectedTypes(sync_everything,
337 selected_types);
338
339 if (encryption_mode == EncryptionSetupMode::kEncryption) {
340 service()->GetUserSettings()->SetEncryptionPassphrase(passphrase.value());
341 } else if (encryption_mode == EncryptionSetupMode::kDecryption) {
342 if (!service()->GetUserSettings()->SetDecryptionPassphrase(
343 passphrase.value())) {
344 LOG(ERROR) << "WARNING: provided passphrase could not decrypt locally "
345 "present data.";
346 }
347 }
348 // Notify ProfileSyncService that we are done with configuration.
349 FinishSyncSetup();
350
351 if (signin_type_ == SigninType::UI_SIGNIN)
352 return signin_delegate_->ConfirmSigninUI(profile_);
353 return true;
354 }
355
FinishSyncSetup()356 void ProfileSyncServiceHarness::FinishSyncSetup() {
357 sync_blocker_.reset();
358 service()->GetUserSettings()->SetFirstSetupComplete(
359 syncer::SyncFirstSetupCompleteSource::BASIC_FLOW);
360 }
361
StopSyncServiceAndClearData()362 void ProfileSyncServiceHarness::StopSyncServiceAndClearData() {
363 DVLOG(1) << "Requesting stop for service and clearing data.";
364 service()->StopAndClear();
365 }
366
StopSyncServiceWithoutClearingData()367 void ProfileSyncServiceHarness::StopSyncServiceWithoutClearingData() {
368 DVLOG(1) << "Requesting stop for service without clearing data.";
369 service()->GetUserSettings()->SetSyncRequested(false);
370 }
371
StartSyncService()372 bool ProfileSyncServiceHarness::StartSyncService() {
373 std::unique_ptr<syncer::SyncSetupInProgressHandle> blocker =
374 service()->GetSetupInProgressHandle();
375 DVLOG(1) << "Requesting start for service";
376 service()->GetUserSettings()->SetSyncRequested(true);
377
378 if (!AwaitEngineInitialization()) {
379 LOG(ERROR) << "AwaitEngineInitialization failed.";
380 return false;
381 }
382 DVLOG(1) << "Engine Initialized successfully.";
383
384 if (service()->GetUserSettings()->IsUsingSecondaryPassphrase()) {
385 LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
386 " until SetDecryptionPassphrase is called.";
387 return false;
388 }
389 DVLOG(1) << "Passphrase decryption success.";
390
391 blocker.reset();
392 service()->GetUserSettings()->SetFirstSetupComplete(
393 syncer::SyncFirstSetupCompleteSource::BASIC_FLOW);
394
395 if (!AwaitSyncSetupCompletion()) {
396 LOG(FATAL) << "AwaitSyncSetupCompletion failed.";
397 return false;
398 }
399
400 return true;
401 }
402
AwaitMutualSyncCycleCompletion(ProfileSyncServiceHarness * partner)403 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
404 ProfileSyncServiceHarness* partner) {
405 std::vector<ProfileSyncServiceHarness*> harnesses;
406 harnesses.push_back(this);
407 harnesses.push_back(partner);
408 return AwaitQuiescence(harnesses);
409 }
410
411 // static
AwaitQuiescence(const std::vector<ProfileSyncServiceHarness * > & clients)412 bool ProfileSyncServiceHarness::AwaitQuiescence(
413 const std::vector<ProfileSyncServiceHarness*>& clients) {
414 if (clients.empty()) {
415 return true;
416 }
417
418 std::vector<ProfileSyncService*> services;
419 for (const ProfileSyncServiceHarness* harness : clients) {
420 services.push_back(harness->service());
421 }
422 return QuiesceStatusChangeChecker(services).Wait();
423 }
424
AwaitEngineInitialization()425 bool ProfileSyncServiceHarness::AwaitEngineInitialization() {
426 if (!EngineInitializeChecker(service()).Wait()) {
427 LOG(ERROR) << "EngineInitializeChecker timed out.";
428 return false;
429 }
430
431 if (HasAuthError(service())) {
432 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
433 return false;
434 }
435
436 if (service()->IsRetryingAccessTokenFetchForTest()) {
437 LOG(ERROR) << "Failed to fetch access token. Sync cannot proceed.";
438 return false;
439 }
440
441 if (!service()->IsEngineInitialized()) {
442 LOG(ERROR) << "Service engine not initialized.";
443 return false;
444 }
445
446 return true;
447 }
448
AwaitSyncSetupCompletion()449 bool ProfileSyncServiceHarness::AwaitSyncSetupCompletion() {
450 CHECK(service()->GetUserSettings()->IsFirstSetupComplete())
451 << "Waiting for setup completion can only succeed after the first setup "
452 << "got marked complete. Did you call SetupSync on this client?";
453 if (!SyncSetupChecker(service(), SyncSetupChecker::State::kFeatureActive)
454 .Wait()) {
455 LOG(ERROR) << "SyncSetupChecker timed out.";
456 return false;
457 }
458 // Signal an error if the initial sync wasn't successful.
459 if (HasAuthError(service())) {
460 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
461 return false;
462 }
463
464 return true;
465 }
466
AwaitSyncTransportActive()467 bool ProfileSyncServiceHarness::AwaitSyncTransportActive() {
468 if (!SyncSetupChecker(service(), SyncSetupChecker::State::kTransportActive)
469 .Wait()) {
470 LOG(ERROR) << "SyncSetupChecker timed out.";
471 return false;
472 }
473 // Signal an error if the initial sync wasn't successful.
474 if (HasAuthError(service())) {
475 LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
476 return false;
477 }
478
479 return true;
480 }
481
EnableSyncForType(syncer::UserSelectableType type)482 bool ProfileSyncServiceHarness::EnableSyncForType(
483 syncer::UserSelectableType type) {
484 DVLOG(1) << GetClientInfoString(
485 "EnableSyncForType(" +
486 std::string(syncer::GetUserSelectableTypeName(type)) + ")");
487
488 if (!IsSyncEnabledByUser()) {
489 bool result =
490 SetupSyncNoWaitForCompletion({type}) && AwaitSyncSetupCompletion();
491 // If SetupSync() succeeded, then Sync must now be enabled.
492 DCHECK(!result || IsSyncEnabledByUser());
493 return result;
494 }
495
496 if (service() == nullptr) {
497 LOG(ERROR) << "EnableSyncForType(): service() is null.";
498 return false;
499 }
500
501 syncer::UserSelectableTypeSet selected_types =
502 service()->GetUserSettings()->GetSelectedTypes();
503 if (selected_types.Has(type)) {
504 DVLOG(1) << "EnableSyncForType(): Sync already enabled for type "
505 << syncer::GetUserSelectableTypeName(type) << " on "
506 << profile_debug_name_ << ".";
507 return true;
508 }
509
510 selected_types.Put(type);
511 service()->GetUserSettings()->SetSelectedTypes(false, selected_types);
512 if (AwaitSyncSetupCompletion()) {
513 DVLOG(1) << "EnableSyncForType(): Enabled sync for type "
514 << syncer::GetUserSelectableTypeName(type) << " on "
515 << profile_debug_name_ << ".";
516 return true;
517 }
518
519 DVLOG(0) << GetClientInfoString("EnableSyncForType failed");
520 return false;
521 }
522
DisableSyncForType(syncer::UserSelectableType type)523 bool ProfileSyncServiceHarness::DisableSyncForType(
524 syncer::UserSelectableType type) {
525 DVLOG(1) << GetClientInfoString(
526 "DisableSyncForType(" +
527 std::string(syncer::GetUserSelectableTypeName(type)) + ")");
528
529 if (service() == nullptr) {
530 LOG(ERROR) << "DisableSyncForType(): service() is null.";
531 return false;
532 }
533
534 syncer::UserSelectableTypeSet selected_types =
535 service()->GetUserSettings()->GetSelectedTypes();
536 if (!selected_types.Has(type)) {
537 DVLOG(1) << "DisableSyncForType(): Sync already disabled for type "
538 << syncer::GetUserSelectableTypeName(type) << " on "
539 << profile_debug_name_ << ".";
540 return true;
541 }
542
543 selected_types.Remove(type);
544 service()->GetUserSettings()->SetSelectedTypes(false, selected_types);
545 if (AwaitSyncSetupCompletion()) {
546 DVLOG(1) << "DisableSyncForType(): Disabled sync for type "
547 << syncer::GetUserSelectableTypeName(type) << " on "
548 << profile_debug_name_ << ".";
549 return true;
550 }
551
552 DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
553 return false;
554 }
555
EnableSyncForRegisteredDatatypes()556 bool ProfileSyncServiceHarness::EnableSyncForRegisteredDatatypes() {
557 DVLOG(1) << GetClientInfoString("EnableSyncForRegisteredDatatypes");
558
559 if (!IsSyncEnabledByUser()) {
560 bool result = SetupSync();
561 // If SetupSync() succeeded, then Sync must now be enabled.
562 DCHECK(!result || IsSyncEnabledByUser());
563 return result;
564 }
565
566 if (service() == nullptr) {
567 LOG(ERROR) << "EnableSyncForRegisteredDatatypes(): service() is null.";
568 return false;
569 }
570
571 service()->GetUserSettings()->SetSelectedTypes(
572 true, service()->GetUserSettings()->GetRegisteredSelectableTypes());
573
574 if (AwaitSyncSetupCompletion()) {
575 DVLOG(1)
576 << "EnableSyncForRegisteredDatatypes(): Enabled sync for all datatypes "
577 << "on " << profile_debug_name_ << ".";
578 return true;
579 }
580
581 DVLOG(0) << GetClientInfoString("EnableSyncForRegisteredDatatypes failed");
582 return false;
583 }
584
DisableSyncForAllDatatypes()585 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
586 DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
587
588 if (service() == nullptr) {
589 LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
590 return false;
591 }
592
593 service()->StopAndClear();
594
595 DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
596 << "datatypes on " << profile_debug_name_;
597 return true;
598 }
599
GetLastCycleSnapshot() const600 SyncCycleSnapshot ProfileSyncServiceHarness::GetLastCycleSnapshot() const {
601 DCHECK(service() != nullptr) << "Sync service has not yet been set up.";
602 if (service()->IsSyncFeatureActive()) {
603 return service()->GetLastCycleSnapshotForDebugging();
604 }
605 return SyncCycleSnapshot();
606 }
607
GetServiceStatus()608 std::string ProfileSyncServiceHarness::GetServiceStatus() {
609 // This method is only used in test code for debugging purposes, so it's fine
610 // to include sensitive data in ConstructAboutInformation().
611 std::unique_ptr<base::DictionaryValue> value(
612 syncer::sync_ui_util::ConstructAboutInformation(
613 syncer::sync_ui_util::IncludeSensitiveData(true), service(),
614 chrome::GetChannel()));
615 std::string service_status;
616 base::JSONWriter::WriteWithOptions(
617 *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status);
618 return service_status;
619 }
620
621 // TODO(sync): Clean up this method in a separate CL. Remove all snapshot fields
622 // and log shorter, more meaningful messages.
GetClientInfoString(const std::string & message) const623 std::string ProfileSyncServiceHarness::GetClientInfoString(
624 const std::string& message) const {
625 std::stringstream os;
626 os << profile_debug_name_ << ": " << message << ": ";
627 if (service()) {
628 const SyncCycleSnapshot& snap = GetLastCycleSnapshot();
629 syncer::SyncStatus status;
630 service()->QueryDetailedSyncStatusForDebugging(&status);
631 // Capture select info from the sync session snapshot and syncer status.
632 os << ", has_unsynced_items: " << snap.has_remaining_local_changes()
633 << ", did_commit: "
634 << (snap.model_neutral_state().num_successful_commits == 0 &&
635 snap.model_neutral_state().commit_result.value() ==
636 syncer::SyncerError::SYNCER_OK)
637 << ", encryption conflicts: " << snap.num_encryption_conflicts()
638 << ", hierarchy conflicts: " << snap.num_hierarchy_conflicts()
639 << ", server conflicts: " << snap.num_server_conflicts()
640 << ", num_updates_downloaded : "
641 << snap.model_neutral_state().num_updates_downloaded_total
642 << ", passphrase_required: "
643 << service()->GetUserSettings()->IsPassphraseRequired()
644 << ", notifications_enabled: " << status.notifications_enabled
645 << ", service_is_active: " << service()->IsSyncFeatureActive();
646 } else {
647 os << "Sync service not available";
648 }
649 return os.str();
650 }
651
IsSyncEnabledByUser() const652 bool ProfileSyncServiceHarness::IsSyncEnabledByUser() const {
653 return service()->GetUserSettings()->IsFirstSetupComplete() &&
654 !service()->HasDisableReason(
655 ProfileSyncService::DISABLE_REASON_USER_CHOICE);
656 }
657