• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/profile_sync_service_harness.h"
6 
7 #include <stddef.h>
8 #include <algorithm>
9 #include <iterator>
10 #include <ostream>
11 #include <set>
12 #include <vector>
13 
14 #include "base/logging.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/message_loop.h"
17 #include "base/task.h"
18 #include "base/tracked.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sync/sessions/session_state.h"
21 #include "chrome/browser/sync/signin_manager.h"
22 
23 using browser_sync::sessions::SyncSessionSnapshot;
24 
25 // The amount of time for which we wait for a live sync operation to complete.
26 static const int kLiveSyncOperationTimeoutMs = 45000;
27 
28 // Simple class to implement a timeout using PostDelayedTask.  If it is not
29 // aborted before picked up by a message queue, then it asserts with the message
30 // provided.  This class is not thread safe.
31 class StateChangeTimeoutEvent
32     : public base::RefCountedThreadSafe<StateChangeTimeoutEvent> {
33  public:
34   StateChangeTimeoutEvent(ProfileSyncServiceHarness* caller,
35                           const std::string& message);
36 
37   // The entry point to the class from PostDelayedTask.
38   void Callback();
39 
40   // Cancels the actions of the callback.  Returns true if success, false
41   // if the callback has already timed out.
42   bool Abort();
43 
44  private:
45   friend class base::RefCountedThreadSafe<StateChangeTimeoutEvent>;
46 
47   ~StateChangeTimeoutEvent();
48 
49   bool aborted_;
50   bool did_timeout_;
51 
52   // Due to synchronization of the IO loop, the caller will always be alive
53   // if the class is not aborted.
54   ProfileSyncServiceHarness* caller_;
55 
56   // Informative message to assert in the case of a timeout.
57   std::string message_;
58 
59   DISALLOW_COPY_AND_ASSIGN(StateChangeTimeoutEvent);
60 };
61 
StateChangeTimeoutEvent(ProfileSyncServiceHarness * caller,const std::string & message)62 StateChangeTimeoutEvent::StateChangeTimeoutEvent(
63     ProfileSyncServiceHarness* caller,
64     const std::string& message)
65     : aborted_(false), did_timeout_(false), caller_(caller), message_(message) {
66 }
67 
~StateChangeTimeoutEvent()68 StateChangeTimeoutEvent::~StateChangeTimeoutEvent() {
69 }
70 
Callback()71 void StateChangeTimeoutEvent::Callback() {
72   if (!aborted_) {
73     if (!caller_->RunStateChangeMachine()) {
74       // Report the message.
75       did_timeout_ = true;
76       DCHECK(!aborted_) << message_;
77       caller_->SignalStateComplete();
78     }
79   }
80 }
81 
Abort()82 bool StateChangeTimeoutEvent::Abort() {
83   aborted_ = true;
84   caller_ = NULL;
85   return !did_timeout_;
86 }
87 
ProfileSyncServiceHarness(Profile * profile,const std::string & username,const std::string & password,int id)88 ProfileSyncServiceHarness::ProfileSyncServiceHarness(
89     Profile* profile,
90     const std::string& username,
91     const std::string& password,
92     int id)
93     : waiting_for_encryption_type_(syncable::UNSPECIFIED),
94       wait_state_(INITIAL_WAIT_STATE),
95       profile_(profile),
96       service_(NULL),
97       timestamp_match_partner_(NULL),
98       username_(username),
99       password_(password),
100       id_(id) {
101   if (IsSyncAlreadySetup()) {
102     service_ = profile_->GetProfileSyncService();
103     service_->AddObserver(this);
104     wait_state_ = FULLY_SYNCED;
105   }
106 }
107 
108 // static
CreateAndAttach(Profile * profile)109 ProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateAndAttach(
110     Profile* profile) {
111   if (!profile->HasProfileSyncService()) {
112     NOTREACHED() << "Profile has never signed into sync.";
113     return NULL;
114   }
115   return new ProfileSyncServiceHarness(profile, "", "", 0);
116 }
117 
SetCredentials(const std::string & username,const std::string & password)118 void ProfileSyncServiceHarness::SetCredentials(const std::string& username,
119                                                const std::string& password) {
120   username_ = username;
121   password_ = password;
122 }
123 
IsSyncAlreadySetup()124 bool ProfileSyncServiceHarness::IsSyncAlreadySetup() {
125   return profile_->HasProfileSyncService();
126 }
127 
SetupSync()128 bool ProfileSyncServiceHarness::SetupSync() {
129   syncable::ModelTypeSet synced_datatypes;
130   for (int i = syncable::FIRST_REAL_MODEL_TYPE;
131       i < syncable::MODEL_TYPE_COUNT; ++i) {
132     synced_datatypes.insert(syncable::ModelTypeFromInt(i));
133   }
134   return SetupSync(synced_datatypes);
135 }
136 
SetupSync(const syncable::ModelTypeSet & synced_datatypes)137 bool ProfileSyncServiceHarness::SetupSync(
138     const syncable::ModelTypeSet& synced_datatypes) {
139   // Initialize the sync client's profile sync service object.
140   service_ = profile_->GetProfileSyncService("");
141   if (service_ == NULL) {
142     LOG(ERROR) << "SetupSync(): service_ is null.";
143     return false;
144   }
145 
146   // Subscribe sync client to notifications from the profile sync service.
147   if (!service_->HasObserver(this))
148     service_->AddObserver(this);
149 
150   // Authenticate sync client using GAIA credentials.
151   service_->signin()->StartSignIn(username_, password_, "", "");
152 
153   // Wait for the OnBackendInitialized() callback.
154   wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
155   if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
156       "Waiting for OnBackendInitialized().")) {
157     LOG(ERROR) << "OnBackendInitialized() not seen after "
158                << kLiveSyncOperationTimeoutMs / 1000
159                << " seconds.";
160     return false;
161   }
162 
163   // Choose the datatypes to be synced. If all datatypes are to be synced,
164   // set sync_everything to true; otherwise, set it to false.
165   bool sync_everything = (synced_datatypes.size() ==
166       (syncable::MODEL_TYPE_COUNT - syncable::FIRST_REAL_MODEL_TYPE));
167   service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
168 
169   // Wait for initial sync cycle to be completed.
170   DCHECK_EQ(wait_state_, WAITING_FOR_INITIAL_SYNC);
171   if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
172       "Waiting for initial sync cycle to complete.")) {
173     LOG(ERROR) << "Initial sync cycle did not complete after "
174                << kLiveSyncOperationTimeoutMs / 1000
175                << " seconds.";
176     return false;
177   }
178 
179   // Indicate to the browser that sync setup is complete.
180   service()->SetSyncSetupCompleted();
181 
182   return true;
183 }
184 
SignalStateCompleteWithNextState(WaitState next_state)185 void ProfileSyncServiceHarness::SignalStateCompleteWithNextState(
186     WaitState next_state) {
187   wait_state_ = next_state;
188   SignalStateComplete();
189 }
190 
SignalStateComplete()191 void ProfileSyncServiceHarness::SignalStateComplete() {
192   MessageLoop::current()->Quit();
193 }
194 
RunStateChangeMachine()195 bool ProfileSyncServiceHarness::RunStateChangeMachine() {
196   WaitState original_wait_state = wait_state_;
197   switch (wait_state_) {
198     case WAITING_FOR_ON_BACKEND_INITIALIZED: {
199       LogClientInfo("WAITING_FOR_ON_BACKEND_INITIALIZED");
200       if (service()->sync_initialized()) {
201         // The sync backend is initialized.
202         SignalStateCompleteWithNextState(WAITING_FOR_INITIAL_SYNC);
203       }
204       break;
205     }
206     case WAITING_FOR_INITIAL_SYNC: {
207       LogClientInfo("WAITING_FOR_INITIAL_SYNC");
208       if (IsSynced()) {
209         // The first sync cycle is now complete. We can start running tests.
210         SignalStateCompleteWithNextState(FULLY_SYNCED);
211       }
212       break;
213     }
214     case WAITING_FOR_SYNC_TO_FINISH: {
215       LogClientInfo("WAITING_FOR_SYNC_TO_FINISH");
216       if (!IsSynced()) {
217         // The client is not yet fully synced. Continue waiting.
218         if (!GetStatus().server_reachable) {
219           // The client cannot reach the sync server because the network is
220           // disabled. There is no need to wait anymore.
221           SignalStateCompleteWithNextState(SERVER_UNREACHABLE);
222         }
223         break;
224       }
225       SignalStateCompleteWithNextState(FULLY_SYNCED);
226       break;
227     }
228     case WAITING_FOR_UPDATES: {
229       LogClientInfo("WAITING_FOR_UPDATES");
230       DCHECK(timestamp_match_partner_);
231       if (!MatchesOtherClient(timestamp_match_partner_)) {
232         // The client is not yet fully synced; keep waiting until we converge.
233         break;
234       }
235       timestamp_match_partner_->service()->RemoveObserver(this);
236       timestamp_match_partner_ = NULL;
237 
238       SignalStateCompleteWithNextState(FULLY_SYNCED);
239       break;
240     }
241     case WAITING_FOR_PASSPHRASE_ACCEPTED: {
242       LogClientInfo("WAITING_FOR_PASSPHRASE_ACCEPTED");
243       // TODO(atwilson): After ProfileSyncService::OnPassphraseAccepted() is
244       // fixed, add an extra check to make sure that the value of
245       // service()->observed_passphrase_required() is false.
246       if (service()->ShouldPushChanges()) {
247         // The passphrase has been accepted, and sync has been restarted.
248         SignalStateCompleteWithNextState(FULLY_SYNCED);
249       }
250       break;
251     }
252     case WAITING_FOR_ENCRYPTION: {
253       LogClientInfo("WAITING_FOR_ENCRYPTION");
254       if (IsTypeEncrypted(waiting_for_encryption_type_)) {
255         // Encryption is complete for the type we are waiting on.
256         SignalStateCompleteWithNextState(FULLY_SYNCED);
257       }
258       break;
259     }
260     case SERVER_UNREACHABLE: {
261       LogClientInfo("SERVER_UNREACHABLE");
262       if (GetStatus().server_reachable) {
263         // The client was offline due to the network being disabled, but is now
264         // back online. Wait for the pending sync cycle to complete.
265         SignalStateCompleteWithNextState(WAITING_FOR_SYNC_TO_FINISH);
266       }
267       break;
268     }
269     case FULLY_SYNCED: {
270       // The client is online and fully synced. There is nothing to do.
271       LogClientInfo("FULLY_SYNCED");
272       break;
273     }
274     case SYNC_DISABLED: {
275       // Syncing is disabled for the client. There is nothing to do.
276       LogClientInfo("SYNC_DISABLED");
277       break;
278     }
279     default:
280       // Invalid state during observer callback which may be triggered by other
281       // classes using the the UI message loop.  Defer to their handling.
282       break;
283   }
284   return original_wait_state != wait_state_;
285 }
286 
OnStateChanged()287 void ProfileSyncServiceHarness::OnStateChanged() {
288   RunStateChangeMachine();
289 }
290 
AwaitPassphraseAccepted()291 bool ProfileSyncServiceHarness::AwaitPassphraseAccepted() {
292   LogClientInfo("AwaitPassphraseAccepted");
293   if (wait_state_ == SYNC_DISABLED) {
294     LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
295     return false;
296   }
297 
298   // TODO(atwilson): After ProfileSyncService::OnPassphraseAccepted() is
299   // fixed, add an extra check to make sure that the value of
300   // service()->observed_passphrase_required() is false.
301   if (service()->ShouldPushChanges()) {
302     // Passphrase is already accepted; don't wait.
303     return true;
304   }
305 
306   wait_state_ = WAITING_FOR_PASSPHRASE_ACCEPTED;
307   return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
308                                       "Waiting for passphrase accepted.");
309 }
310 
AwaitSyncCycleCompletion(const std::string & reason)311 bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion(
312     const std::string& reason) {
313   LogClientInfo("AwaitSyncCycleCompletion");
314   if (wait_state_ == SYNC_DISABLED) {
315     LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
316     return false;
317   }
318 
319   if (IsSynced()) {
320     // Client is already synced; don't wait.
321     return true;
322   }
323 
324   if (wait_state_ == SERVER_UNREACHABLE) {
325     // Client was offline; wait for it to go online, and then wait for sync.
326     AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
327     DCHECK_EQ(wait_state_, WAITING_FOR_SYNC_TO_FINISH);
328     return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
329   } else {
330     DCHECK(service()->sync_initialized());
331     wait_state_ = WAITING_FOR_SYNC_TO_FINISH;
332     AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
333     if (wait_state_ == FULLY_SYNCED) {
334       // Client is online; sync was successful.
335       return true;
336     } else if (wait_state_ == SERVER_UNREACHABLE) {
337       // Client is offline; sync was unsuccessful.
338       return false;
339     } else {
340       LOG(ERROR) << "Invalid wait state:" << wait_state_;
341       return false;
342     }
343   }
344 }
345 
AwaitMutualSyncCycleCompletion(ProfileSyncServiceHarness * partner)346 bool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
347     ProfileSyncServiceHarness* partner) {
348   LogClientInfo("AwaitMutualSyncCycleCompletion");
349   if (!AwaitSyncCycleCompletion("Sync cycle completion on active client."))
350     return false;
351   return partner->WaitUntilTimestampMatches(this,
352       "Sync cycle completion on passive client.");
353 }
354 
AwaitGroupSyncCycleCompletion(std::vector<ProfileSyncServiceHarness * > & partners)355 bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
356     std::vector<ProfileSyncServiceHarness*>& partners) {
357   LogClientInfo("AwaitGroupSyncCycleCompletion");
358   if (!AwaitSyncCycleCompletion("Sync cycle completion on active client."))
359     return false;
360   bool return_value = true;
361   for (std::vector<ProfileSyncServiceHarness*>::iterator it =
362       partners.begin(); it != partners.end(); ++it) {
363     if ((this != *it) && ((*it)->wait_state_ != SYNC_DISABLED)) {
364       return_value = return_value &&
365           (*it)->WaitUntilTimestampMatches(this,
366           "Sync cycle completion on partner client.");
367     }
368   }
369   return return_value;
370 }
371 
372 // static
AwaitQuiescence(std::vector<ProfileSyncServiceHarness * > & clients)373 bool ProfileSyncServiceHarness::AwaitQuiescence(
374     std::vector<ProfileSyncServiceHarness*>& clients) {
375   VLOG(1) << "AwaitQuiescence.";
376   bool return_value = true;
377   for (std::vector<ProfileSyncServiceHarness*>::iterator it =
378       clients.begin(); it != clients.end(); ++it) {
379     if ((*it)->wait_state_ != SYNC_DISABLED)
380       return_value = return_value &&
381           (*it)->AwaitGroupSyncCycleCompletion(clients);
382   }
383   return return_value;
384 }
385 
WaitUntilTimestampMatches(ProfileSyncServiceHarness * partner,const std::string & reason)386 bool ProfileSyncServiceHarness::WaitUntilTimestampMatches(
387     ProfileSyncServiceHarness* partner, const std::string& reason) {
388   LogClientInfo("WaitUntilTimestampMatches");
389   if (wait_state_ == SYNC_DISABLED) {
390     LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
391     return false;
392   }
393 
394   if (MatchesOtherClient(partner)) {
395     // Timestamps already match; don't wait.
396     return true;
397   }
398 
399   DCHECK(!timestamp_match_partner_);
400   timestamp_match_partner_ = partner;
401   partner->service()->AddObserver(this);
402   wait_state_ = WAITING_FOR_UPDATES;
403   return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
404 }
405 
AwaitStatusChangeWithTimeout(int timeout_milliseconds,const std::string & reason)406 bool ProfileSyncServiceHarness::AwaitStatusChangeWithTimeout(
407     int timeout_milliseconds,
408     const std::string& reason) {
409   LogClientInfo("AwaitStatusChangeWithTimeout");
410   if (wait_state_ == SYNC_DISABLED) {
411     LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
412     return false;
413   }
414   scoped_refptr<StateChangeTimeoutEvent> timeout_signal(
415       new StateChangeTimeoutEvent(this, reason));
416   MessageLoop* loop = MessageLoop::current();
417   bool did_allow_nestable_tasks = loop->NestableTasksAllowed();
418   loop->SetNestableTasksAllowed(true);
419   loop->PostDelayedTask(
420       FROM_HERE,
421       NewRunnableMethod(timeout_signal.get(),
422                         &StateChangeTimeoutEvent::Callback),
423       timeout_milliseconds);
424   loop->Run();
425   loop->SetNestableTasksAllowed(did_allow_nestable_tasks);
426   if (timeout_signal->Abort()) {
427     LogClientInfo("AwaitStatusChangeWithTimeout succeeded");
428     return true;
429   } else {
430     LogClientInfo("AwaitStatusChangeWithTimeout timed out");
431     return false;
432   }
433 }
434 
GetStatus()435 ProfileSyncService::Status ProfileSyncServiceHarness::GetStatus() {
436   DCHECK(service() != NULL) << "GetStatus(): service() is NULL.";
437   return service()->QueryDetailedSyncStatus();
438 }
439 
IsSynced()440 bool ProfileSyncServiceHarness::IsSynced() {
441   LogClientInfo("IsSynced");
442   if (service() == NULL)
443     return false;
444   const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
445   // TODO(rsimha): Remove additional checks of snap->has_more_to_sync and
446   // snap->unsynced_count once http://crbug.com/48989 is fixed.
447   return (snap &&
448           snap->num_conflicting_updates == 0 &&  // We can decrypt everything.
449           ServiceIsPushingChanges() &&
450           GetStatus().notifications_enabled &&
451           !service()->HasUnsyncedItems() &&
452           !snap->has_more_to_sync &&
453           snap->unsynced_count == 0);
454 }
455 
MatchesOtherClient(ProfileSyncServiceHarness * partner)456 bool ProfileSyncServiceHarness::MatchesOtherClient(
457     ProfileSyncServiceHarness* partner) {
458   if (!IsSynced())
459     return false;
460 
461   // Only look for a match if we have at least one enabled datatype in
462   // common with the partner client.
463   syncable::ModelTypeSet types, other_types, intersection_types;
464   service()->GetPreferredDataTypes(&types);
465   partner->service()->GetPreferredDataTypes(&other_types);
466   std::set_intersection(types.begin(), types.end(), other_types.begin(),
467                         other_types.end(),
468                         inserter(intersection_types,
469                                  intersection_types.begin()));
470   for (syncable::ModelTypeSet::iterator i = intersection_types.begin();
471        i != intersection_types.end();
472        ++i) {
473     if (!partner->IsSynced() ||
474         partner->GetUpdatedTimestamp(*i) != GetUpdatedTimestamp(*i)) {
475       return false;
476     }
477   }
478   return true;
479 }
480 
481 const SyncSessionSnapshot*
GetLastSessionSnapshot() const482     ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
483   DCHECK(service_ != NULL) << "Sync service has not yet been set up.";
484   if (service_->sync_initialized()) {
485     return service_->GetLastSessionSnapshot();
486   }
487   return NULL;
488 }
489 
EnableSyncForDatatype(syncable::ModelType datatype)490 void ProfileSyncServiceHarness::EnableSyncForDatatype(
491     syncable::ModelType datatype) {
492   LogClientInfo("EnableSyncForDatatype");
493   syncable::ModelTypeSet synced_datatypes;
494   if (wait_state_ == SYNC_DISABLED) {
495     wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
496     synced_datatypes.insert(datatype);
497     DCHECK(SetupSync(synced_datatypes)) << "Reinitialization of Client " << id_
498                                         << " failed.";
499   } else {
500     DCHECK(service() != NULL) << "EnableSyncForDatatype(): service() is null.";
501     service()->GetPreferredDataTypes(&synced_datatypes);
502     syncable::ModelTypeSet::iterator it = synced_datatypes.find(
503         syncable::ModelTypeFromInt(datatype));
504     if (it == synced_datatypes.end()) {
505       synced_datatypes.insert(syncable::ModelTypeFromInt(datatype));
506       service()->OnUserChoseDatatypes(false, synced_datatypes);
507       wait_state_ = WAITING_FOR_SYNC_TO_FINISH;
508       AwaitSyncCycleCompletion("Waiting for datatype configuration.");
509       VLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
510               << syncable::ModelTypeToString(datatype) << " on Client " << id_;
511     } else {
512       VLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
513               << syncable::ModelTypeToString(datatype) << " on Client " << id_;
514     }
515   }
516 }
517 
DisableSyncForDatatype(syncable::ModelType datatype)518 void ProfileSyncServiceHarness::DisableSyncForDatatype(
519     syncable::ModelType datatype) {
520   LogClientInfo("DisableSyncForDatatype");
521   syncable::ModelTypeSet synced_datatypes;
522   DCHECK(service() != NULL) << "DisableSyncForDatatype(): service() is null.";
523   service()->GetPreferredDataTypes(&synced_datatypes);
524   syncable::ModelTypeSet::iterator it = synced_datatypes.find(datatype);
525   if (it != synced_datatypes.end()) {
526     synced_datatypes.erase(it);
527     service()->OnUserChoseDatatypes(false, synced_datatypes);
528     AwaitSyncCycleCompletion("Waiting for datatype configuration.");
529     VLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
530             << syncable::ModelTypeToString(datatype) << " on Client " << id_;
531   } else {
532     VLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
533             << syncable::ModelTypeToString(datatype) << " on Client " << id_;
534   }
535 }
536 
EnableSyncForAllDatatypes()537 void ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
538   LogClientInfo("EnableSyncForAllDatatypes");
539   if (wait_state_ == SYNC_DISABLED) {
540     wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
541     DCHECK(SetupSync()) << "Reinitialization of Client " << id_ << " failed.";
542   } else {
543     syncable::ModelTypeSet synced_datatypes;
544     for (int i = syncable::FIRST_REAL_MODEL_TYPE;
545         i < syncable::MODEL_TYPE_COUNT; ++i) {
546       synced_datatypes.insert(syncable::ModelTypeFromInt(i));
547     }
548     DCHECK(service() != NULL) << "EnableSyncForAllDatatypes(): service() is "
549                                  " null.";
550     service()->OnUserChoseDatatypes(true, synced_datatypes);
551     wait_state_ = WAITING_FOR_SYNC_TO_FINISH;
552     AwaitSyncCycleCompletion("Waiting for datatype configuration.");
553     VLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes on "
554                "Client " << id_;
555   }
556 }
557 
DisableSyncForAllDatatypes()558 void ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
559   LogClientInfo("DisableSyncForAllDatatypes");
560   DCHECK(service() != NULL) << "EnableSyncForAllDatatypes(): service() is "
561                                "null.";
562   service()->DisableForUser();
563   wait_state_ = SYNC_DISABLED;
564   VLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all datatypes on "
565              "Client " << id_;
566 }
567 
GetUpdatedTimestamp(syncable::ModelType model_type)568 std::string ProfileSyncServiceHarness::GetUpdatedTimestamp(
569     syncable::ModelType model_type) {
570   const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
571   DCHECK(snap != NULL) << "GetUpdatedTimestamp(): Sync snapshot is NULL.";
572   return snap->download_progress_markers[model_type];
573 }
574 
LogClientInfo(const std::string & message)575 void ProfileSyncServiceHarness::LogClientInfo(const std::string& message) {
576   if (service()) {
577     const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
578     if (snap) {
579       VLOG(1) << "Client " << id_ << ": " << message
580               << ": num_updates_downloaded : "
581               << snap->syncer_status.num_updates_downloaded_total
582               << ", has_more_to_sync: " << snap->has_more_to_sync
583               << ", unsynced_count: " << snap->unsynced_count
584               << ", num_conflicting_updates: " << snap->num_conflicting_updates
585               << ", has_unsynced_items: "
586               << service()->HasUnsyncedItems()
587               << ", observed_passphrase_required: "
588               << service()->observed_passphrase_required()
589               << ", notifications_enabled: "
590               << GetStatus().notifications_enabled
591               << ", service_is_pushing_changes: " << ServiceIsPushingChanges();
592     } else {
593       VLOG(1) << "Client " << id_ << ": " << message
594               << ": Sync session snapshot not available.";
595     }
596   } else {
597     VLOG(1) << "Client " << id_ << ": " << message
598             << ": Sync service not available.";
599   }
600 }
601 
EnableEncryptionForType(syncable::ModelType type)602 bool ProfileSyncServiceHarness::EnableEncryptionForType(
603     syncable::ModelType type) {
604   syncable::ModelTypeSet encrypted_types;
605   service_->GetEncryptedDataTypes(&encrypted_types);
606   if (encrypted_types.count(type) > 0)
607     return true;
608   encrypted_types.insert(type);
609   service_->EncryptDataTypes(encrypted_types);
610 
611   // Wait some time to let the enryption finish.
612   std::string reason = "Waiting for encryption.";
613   DCHECK_EQ(FULLY_SYNCED, wait_state_);
614   wait_state_ = WAITING_FOR_ENCRYPTION;
615   waiting_for_encryption_type_ = type;
616   if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason)) {
617     LOG(ERROR) << "Did not receive EncryptionComplete notification after"
618                << kLiveSyncOperationTimeoutMs / 1000
619                << " seconds.";
620     return false;
621   }
622 
623   return IsTypeEncrypted(type);
624 }
625 
IsTypeEncrypted(syncable::ModelType type)626 bool ProfileSyncServiceHarness::IsTypeEncrypted(syncable::ModelType type) {
627   syncable::ModelTypeSet encrypted_types;
628   service_->GetEncryptedDataTypes(&encrypted_types);
629   if (encrypted_types.count(type) == 0) {
630     return false;
631   }
632   return true;
633 }
634