Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / profile_sync_service_harness.cc
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
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:
54   explicit BackendInitializeChecker(ProfileSyncService* service)
55       : SingleClientStatusChangeChecker(service) {}
56
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;
70   }
71
72   virtual std::string GetDebugMessage() const OVERRIDE {
73     return "Backend Initialize";
74   }
75 };
76
77 class SyncSetupChecker : public SingleClientStatusChangeChecker {
78  public:
79   explicit SyncSetupChecker(ProfileSyncService* service)
80       : SingleClientStatusChangeChecker(service) {}
81
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;
94   }
95
96   virtual std::string GetDebugMessage() const OVERRIDE {
97     return "Sync Setup";
98   }
99 };
100
101 bool AwaitSyncSetupCompletion(ProfileSyncService* service) {
102   SyncSetupChecker checker(service);
103   checker.Wait();
104   return !checker.TimedOut();
105 }
106
107 }  // namespace
108
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);
115 }
116
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()) {
127 }
128
129 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { }
130
131 void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
132                                                const std::string& password) {
133   username_ = username;
134   password_ = password;
135 }
136
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.";
145   }
146   return result;
147 }
148
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;
155   }
156
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);
160
161   // Authenticate sync client using GAIA credentials.
162   service()->signin()->SetAuthenticatedUsername(username_);
163   service()->GoogleSigninSucceeded(username_, password_);
164
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());
174
175   // Wait for the OnBackendInitialized() callback.
176   BackendInitializeChecker checker(service());
177   checker.Wait();
178
179   if (checker.TimedOut()) {
180     LOG(ERROR) << "OnBackendInitialized() timed out.";
181     return false;
182   }
183
184   if (!service()->sync_initialized()) {
185     return false;
186   }
187
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;
193   }
194
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;
199   }
200
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);
206
207   // Notify ProfileSyncService that we are done with configuration.
208   FinishSyncSetup();
209
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;
219   }
220
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;
226   }
227
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;
233   }
234
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;
240   }
241
242   return true;
243 }
244
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);
251 }
252
253 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
254     std::vector<ProfileSyncServiceHarness*>& partners) {
255   return AwaitQuiescence(partners);
256 }
257
258 // static
259 bool ProfileSyncServiceHarness::AwaitQuiescence(
260     std::vector<ProfileSyncServiceHarness*>& clients) {
261   std::vector<ProfileSyncService*> services;
262   if (clients.empty()) {
263     return true;
264   }
265
266   for (std::vector<ProfileSyncServiceHarness*>::iterator it = clients.begin();
267        it != clients.end(); ++it) {
268     services.push_back((*it)->service());
269   }
270   QuiesceStatusChangeChecker checker(services);
271   checker.Wait();
272   return !checker.TimedOut();
273 }
274
275 std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
276   return base::StringPrintf("oauth2_refresh_token_%d",
277                             ++oauth2_refesh_token_number_);
278 }
279
280 bool ProfileSyncServiceHarness::IsSyncDisabled() const {
281   return !service()->setup_in_progress() &&
282          !service()->HasSyncSetupCompleted();
283 }
284
285 void ProfileSyncServiceHarness::FinishSyncSetup() {
286   service()->SetSetupInProgress(false);
287   service()->SetSyncSetupCompleted();
288 }
289
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();
294   }
295   return SyncSessionSnapshot();
296 }
297
298 bool ProfileSyncServiceHarness::EnableSyncForDatatype(
299     syncer::ModelType datatype) {
300   DVLOG(1) << GetClientInfoString(
301       "EnableSyncForDatatype("
302       + std::string(syncer::ModelTypeToString(datatype)) + ")");
303
304   if (IsSyncDisabled())
305     return SetupSync(syncer::ModelTypeSet(datatype));
306
307   if (service() == NULL) {
308     LOG(ERROR) << "EnableSyncForDatatype(): service() is null.";
309     return false;
310   }
311
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;
318   }
319
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;
327   }
328
329   DVLOG(0) << GetClientInfoString("EnableSyncForDatatype failed");
330   return false;
331 }
332
333 bool ProfileSyncServiceHarness::DisableSyncForDatatype(
334     syncer::ModelType datatype) {
335   DVLOG(1) << GetClientInfoString(
336       "DisableSyncForDatatype("
337       + std::string(syncer::ModelTypeToString(datatype)) + ")");
338
339   if (service() == NULL) {
340     LOG(ERROR) << "DisableSyncForDatatype(): service() is null.";
341     return false;
342   }
343
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;
350   }
351
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;
360   }
361
362   DVLOG(0) << GetClientInfoString("DisableSyncForDatatype failed");
363   return false;
364 }
365
366 bool ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
367   DVLOG(1) << GetClientInfoString("EnableSyncForAllDatatypes");
368
369   if (IsSyncDisabled())
370     return SetupSync();
371
372   if (service() == NULL) {
373     LOG(ERROR) << "EnableSyncForAllDatatypes(): service() is null.";
374     return false;
375   }
376
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;
382   }
383
384   DVLOG(0) << GetClientInfoString("EnableSyncForAllDatatypes failed");
385   return false;
386 }
387
388 bool ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
389   DVLOG(1) << GetClientInfoString("DisableSyncForAllDatatypes");
390
391   if (service() == NULL) {
392     LOG(ERROR) << "DisableSyncForAllDatatypes(): service() is null.";
393     return false;
394   }
395
396   service()->DisableForUser();
397
398   DVLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all "
399            << "datatypes on " << profile_debug_name_;
400   return true;
401 }
402
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";
436   }
437   return os.str();
438 }
439
440 bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) {
441   return service()->GetPreferredDataTypes().Has(type);
442 }
443
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;
452 }