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