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