• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <iterator>
9 #include <ostream>
10 #include <sstream>
11 #include <vector>
12 
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"
34 
35 #if defined(ENABLE_MANAGED_USERS)
36 #include "chrome/browser/supervised_user/supervised_user_constants.h"
37 #endif
38 
39 using syncer::sessions::SyncSessionSnapshot;
40 
41 namespace {
42 
HasAuthError(ProfileSyncService * service)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;
50 }
51 
52 class BackendInitializeChecker : public SingleClientStatusChangeChecker {
53  public:
BackendInitializeChecker(ProfileSyncService * service)54   explicit BackendInitializeChecker(ProfileSyncService* service)
55       : SingleClientStatusChangeChecker(service) {}
56 
IsExitConditionSatisfied()57   virtual bool IsExitConditionSatisfied() OVERRIDE {
58     if (service()->sync_initialized())
59       return true;
60     // Backend initialization is blocked by an auth error.
61     if (HasAuthError(service()))
62       return true;
63     // Backend initialization is blocked by a failure to fetch Oauth2 tokens.
64     if (service()->IsRetryingAccessTokenFetchForTest())
65       return true;
66     // Still waiting on backend initialization.
67     return false;
68   }
69 
GetDebugMessage() const70   virtual std::string GetDebugMessage() const OVERRIDE {
71     return "Backend Initialize";
72   }
73 };
74 
75 class SyncSetupChecker : public SingleClientStatusChangeChecker {
76  public:
SyncSetupChecker(ProfileSyncService * service)77   explicit SyncSetupChecker(ProfileSyncService* service)
78       : SingleClientStatusChangeChecker(service) {}
79 
IsExitConditionSatisfied()80   virtual bool IsExitConditionSatisfied() OVERRIDE {
81     // Sync setup is complete, and the client is ready to sync new changes.
82     if (service()->ShouldPushChanges())
83       return true;
84     // Sync is blocked because a custom passphrase is required.
85     if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION)
86       return true;
87     // Sync is blocked by an auth error.
88     if (HasAuthError(service()))
89       return true;
90     // Still waiting on sync setup.
91     return false;
92   }
93 
GetDebugMessage() const94   virtual std::string GetDebugMessage() const OVERRIDE {
95     return "Sync Setup";
96   }
97 };
98 
AwaitSyncSetupCompletion(ProfileSyncService * service)99 bool AwaitSyncSetupCompletion(ProfileSyncService* service) {
100   SyncSetupChecker checker(service);
101   checker.Wait();
102   return !checker.TimedOut();
103 }
104 
105 }  // namespace
106 
107 // static
Create(Profile * profile,const std::string & username,const std::string & password)108 ProfileSyncServiceHarness* ProfileSyncServiceHarness::Create(
109     Profile* profile,
110     const std::string& username,
111     const std::string& password) {
112   return new ProfileSyncServiceHarness(profile, username, password);
113 }
114 
ProfileSyncServiceHarness(Profile * profile,const std::string & username,const std::string & password)115 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
116     Profile* profile,
117     const std::string& username,
118     const std::string& password)
119     : profile_(profile),
120       service_(ProfileSyncServiceFactory::GetForProfile(profile)),
121       username_(username),
122       password_(password),
123       oauth2_refesh_token_number_(0),
124       profile_debug_name_(profile->GetDebugName()) {
125 }
126 
~ProfileSyncServiceHarness()127 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { }
128 
SetCredentials(const std::string & username,const std::string & password)129 void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
130                                                const std::string& password) {
131   username_ = username;
132   password_ = password;
133 }
134 
SetupSync()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.";
143   }
144   return result;
145 }
146 
SetupSync(syncer::ModelTypeSet synced_datatypes)147 bool ProfileSyncServiceHarness::SetupSync(
148     syncer::ModelTypeSet synced_datatypes) {
149   // Initialize the sync client's profile sync service object.
150   if (service() == NULL) {
151     LOG(ERROR) << "SetupSync(): service() is null.";
152     return false;
153   }
154 
155   // Tell the sync service that setup is in progress so we don't start syncing
156   // until we've finished configuration.
157   service()->SetSetupInProgress(true);
158 
159   // Authenticate sync client using GAIA credentials.
160   service()->signin()->SetAuthenticatedUsername(username_);
161   service()->GoogleSigninSucceeded(username_, password_);
162 
163 #if defined(ENABLE_MANAGED_USERS)
164   std::string account_id = profile_->IsSupervised() ?
165       supervised_users::kSupervisedUserPseudoEmail : username_;
166 #else
167   std::string account_id = username_;
168 #endif
169   DCHECK(!account_id.empty());
170   ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
171       UpdateCredentials(account_id, GenerateFakeOAuth2RefreshTokenString());
172 
173   // Wait for the OnBackendInitialized() callback.
174   BackendInitializeChecker checker(service());
175   checker.Wait();
176 
177   if (checker.TimedOut()) {
178     LOG(ERROR) << "OnBackendInitialized() timed out.";
179     return false;
180   }
181 
182   if (!service()->sync_initialized()) {
183     return false;
184   }
185 
186   // Make sure that initial sync wasn't blocked by a missing passphrase.
187   if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
188     LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
189                   " until SetDecryptionPassphrase is called.";
190     return false;
191   }
192 
193   // Make sure that initial sync wasn't blocked by rejected credentials.
194   if (HasAuthError(service())) {
195     LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
196     return false;
197   }
198 
199   // Choose the datatypes to be synced. If all datatypes are to be synced,
200   // set sync_everything to true; otherwise, set it to false.
201   bool sync_everything =
202       synced_datatypes.Equals(syncer::ModelTypeSet::All());
203   service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
204 
205   // Notify ProfileSyncService that we are done with configuration.
206   FinishSyncSetup();
207 
208   // Set an implicit passphrase for encryption if an explicit one hasn't already
209   // been set. If an explicit passphrase has been set, immediately return false,
210   // since a decryption passphrase is required.
211   if (!service()->IsUsingSecondaryPassphrase()) {
212     service()->SetEncryptionPassphrase(password_, ProfileSyncService::IMPLICIT);
213   } else {
214     LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
215                   " until SetDecryptionPassphrase is called.";
216     return false;
217   }
218 
219   // Wait for initial sync cycle to be completed.
220   DCHECK(service()->sync_initialized());
221   if (!AwaitSyncSetupCompletion(service())) {
222     LOG(ERROR) << "Initial sync cycle timed out.";
223     return false;
224   }
225 
226   // Make sure that initial sync wasn't blocked by a missing passphrase.
227   if (service()->passphrase_required_reason() == syncer::REASON_DECRYPTION) {
228     LOG(ERROR) << "A passphrase is required for decryption. Sync cannot proceed"
229                   " until SetDecryptionPassphrase is called.";
230     return false;
231   }
232 
233   // Make sure that initial sync wasn't blocked by rejected credentials.
234   if (service()->GetAuthError().state() ==
235       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
236     LOG(ERROR) << "Credentials were rejected. Sync cannot proceed.";
237     return false;
238   }
239 
240   return true;
241 }
242 
AwaitMutualSyncCycleCompletion(ProfileSyncServiceHarness * partner)243 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
244     ProfileSyncServiceHarness* partner) {
245   std::vector<ProfileSyncServiceHarness*> harnesses;
246   harnesses.push_back(this);
247   harnesses.push_back(partner);
248   return AwaitQuiescence(harnesses);
249 }
250 
AwaitGroupSyncCycleCompletion(std::vector<ProfileSyncServiceHarness * > & partners)251 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
252     std::vector<ProfileSyncServiceHarness*>& partners) {
253   return AwaitQuiescence(partners);
254 }
255 
256 // static
AwaitQuiescence(std::vector<ProfileSyncServiceHarness * > & clients)257 bool ProfileSyncServiceHarness::AwaitQuiescence(
258     std::vector<ProfileSyncServiceHarness*>& clients) {
259   std::vector<ProfileSyncService*> services;
260   if (clients.empty()) {
261     return true;
262   }
263 
264   for (std::vector<ProfileSyncServiceHarness*>::iterator it = clients.begin();
265        it != clients.end(); ++it) {
266     services.push_back((*it)->service());
267   }
268   QuiesceStatusChangeChecker checker(services);
269   checker.Wait();
270   return !checker.TimedOut();
271 }
272 
GenerateFakeOAuth2RefreshTokenString()273 std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
274   return base::StringPrintf("oauth2_refresh_token_%d",
275                             ++oauth2_refesh_token_number_);
276 }
277 
IsSyncDisabled() const278 bool ProfileSyncServiceHarness::IsSyncDisabled() const {
279   return !service()->setup_in_progress() &&
280          !service()->HasSyncSetupCompleted();
281 }
282 
FinishSyncSetup()283 void ProfileSyncServiceHarness::FinishSyncSetup() {
284   service()->SetSetupInProgress(false);
285   service()->SetSyncSetupCompleted();
286 }
287 
GetLastSessionSnapshot() const288 SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
289   DCHECK(service() != NULL) << "Sync service has not yet been set up.";
290   if (service()->sync_initialized()) {
291     return service()->GetLastSessionSnapshot();
292   }
293   return SyncSessionSnapshot();
294 }
295 
EnableSyncForDatatype(syncer::ModelType datatype)296 bool ProfileSyncServiceHarness::EnableSyncForDatatype(
297     syncer::ModelType datatype) {
298   DVLOG(1) << GetClientInfoString(
299       "EnableSyncForDatatype("
300       + std::string(syncer::ModelTypeToString(datatype)) + ")");
301 
302   if (IsSyncDisabled())
303     return SetupSync(syncer::ModelTypeSet(datatype));
304 
305   if (service() == NULL) {
306     LOG(ERROR) << "EnableSyncForDatatype(): service() is null.";
307     return false;
308   }
309 
310   syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
311   if (synced_datatypes.Has(datatype)) {
312     DVLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
313              << syncer::ModelTypeToString(datatype)
314              << " on " << profile_debug_name_ << ".";
315     return true;
316   }
317 
318   synced_datatypes.Put(syncer::ModelTypeFromInt(datatype));
319   service()->OnUserChoseDatatypes(false, synced_datatypes);
320   if (AwaitSyncSetupCompletion(service())) {
321     DVLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
322              << syncer::ModelTypeToString(datatype)
323              << " on " << profile_debug_name_ << ".";
324     return true;
325   }
326 
327   DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
328   return false;
329 }
330 
DisableSyncForDatatype(syncer::ModelType datatype)331 bool ProfileSyncServiceHarness::DisableSyncForDatatype(
332     syncer::ModelType datatype) {
333   DVLOG(1) << GetClientInfoString(
334       "DisableSyncForDatatype("
335       + std::string(syncer::ModelTypeToString(datatype)) + ")");
336 
337   if (service() == NULL) {
338     LOG(ERROR) << "DisableSyncForDatatype(): service() is null.";
339     return false;
340   }
341 
342   syncer::ModelTypeSet synced_datatypes = service()->GetPreferredDataTypes();
343   if (!synced_datatypes.Has(datatype)) {
344     DVLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
345              << syncer::ModelTypeToString(datatype)
346              << " on " << profile_debug_name_ << ".";
347     return true;
348   }
349 
350   synced_datatypes.RetainAll(syncer::UserSelectableTypes());
351   synced_datatypes.Remove(datatype);
352   service()->OnUserChoseDatatypes(false, synced_datatypes);
353   if (AwaitSyncSetupCompletion(service())) {
354     DVLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
355              << syncer::ModelTypeToString(datatype)
356              << " on " << profile_debug_name_ << ".";
357     return true;
358   }
359 
360   DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
361   return false;
362 }
363 
EnableSyncForAllDatatypes()364 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
365   DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
366 
367   if (IsSyncDisabled())
368     return SetupSync();
369 
370   if (service() == NULL) {
371     LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null.";
372     return false;
373   }
374 
375   service()->OnUserChoseDatatypes(true, syncer::ModelTypeSet::All());
376   if (AwaitSyncSetupCompletion(service())) {
377     DVLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes "
378              << "on " << profile_debug_name_ << ".";
379     return true;
380   }
381 
382   DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
383   return false;
384 }
385 
DisableSyncForAllDatatypes()386 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
387   DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
388 
389   if (service() == NULL) {
390     LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
391     return false;
392   }
393 
394   service()->DisableForUser();
395 
396   DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
397            << "datatypes on " << profile_debug_name_;
398   return true;
399 }
400 
401 // TODO(sync): Clean up this method in a separate CL. Remove all snapshot fields
402 // and log shorter, more meaningful messages.
GetClientInfoString(const std::string & message) const403 std::string ProfileSyncServiceHarness::GetClientInfoString(
404     const std::string& message) const {
405   std::stringstream os;
406   os << profile_debug_name_ << ": " << message << ": ";
407   if (service()) {
408     const SyncSessionSnapshot& snap = GetLastSessionSnapshot();
409     ProfileSyncService::Status status;
410     service()->QueryDetailedSyncStatus(&status);
411     // Capture select info from the sync session snapshot and syncer status.
412     os << ", has_unsynced_items: "
413        << (service()->sync_initialized() ? service()->HasUnsyncedItems() : 0)
414        << ", did_commit: "
415        << (snap.model_neutral_state().num_successful_commits == 0 &&
416            snap.model_neutral_state().commit_result == syncer::SYNCER_OK)
417        << ", encryption conflicts: "
418        << snap.num_encryption_conflicts()
419        << ", hierarchy conflicts: "
420        << snap.num_hierarchy_conflicts()
421        << ", server conflicts: "
422        << snap.num_server_conflicts()
423        << ", num_updates_downloaded : "
424        << snap.model_neutral_state().num_updates_downloaded_total
425        << ", passphrase_required_reason: "
426        << syncer::PassphraseRequiredReasonToString(
427            service()->passphrase_required_reason())
428        << ", notifications_enabled: "
429        << status.notifications_enabled
430        << ", service_is_pushing_changes: "
431        << service()->ShouldPushChanges();
432   } else {
433     os << "Sync service not available";
434   }
435   return os.str();
436 }
437 
IsTypePreferred(syncer::ModelType type)438 bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) {
439   return service()->GetPreferredDataTypes().Has(type);
440 }
441 
GetServiceStatus()442 std::string ProfileSyncServiceHarness::GetServiceStatus() {
443   scoped_ptr<base::DictionaryValue> value(
444       sync_ui_util::ConstructAboutInformation(service()));
445   std::string service_status;
446   base::JSONWriter::WriteWithOptions(value.get(),
447                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
448                                      &service_status);
449   return service_status;
450 }
451