1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// found in the LICENSE file.
4513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/browser/sync/profile_sync_service_harness.h"
63f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <stddef.h>
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include <algorithm>
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <iterator>
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <ostream>
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <set>
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include <vector>
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/logging.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
16513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/message_loop.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/task.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/tracked.h"
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
20513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/sync/sessions/session_state.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/signin_manager.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing browser_sync::sessions::SyncSessionSnapshot;
24513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
25513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// The amount of time for which we wait for a live sync operation to complete.
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic const int kLiveSyncOperationTimeoutMs = 45000;
27513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
28513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Simple class to implement a timeout using PostDelayedTask.  If it is not
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// aborted before picked up by a message queue, then it asserts with the message
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// provided.  This class is not thread safe.
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdochclass StateChangeTimeoutEvent
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : public base::RefCountedThreadSafe<StateChangeTimeoutEvent> {
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  StateChangeTimeoutEvent(ProfileSyncServiceHarness* caller,
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                          const std::string& message);
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // The entry point to the class from PostDelayedTask.
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  void Callback();
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Cancels the actions of the callback.  Returns true if success, false
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // if the callback has already timed out.
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool Abort();
43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch private:
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  friend class base::RefCountedThreadSafe<StateChangeTimeoutEvent>;
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ~StateChangeTimeoutEvent();
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool aborted_;
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool did_timeout_;
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Due to synchronization of the IO loop, the caller will always be alive
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // if the class is not aborted.
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ProfileSyncServiceHarness* caller_;
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
56513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Informative message to assert in the case of a timeout.
57513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string message_;
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
59513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(StateChangeTimeoutEvent);
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
62513209b27ff55e2841eac0e4120199c23acce758Ben MurdochStateChangeTimeoutEvent::StateChangeTimeoutEvent(
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ProfileSyncServiceHarness* caller,
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& message)
65513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : aborted_(false), did_timeout_(false), caller_(caller), message_(message) {
66513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
68513209b27ff55e2841eac0e4120199c23acce758Ben MurdochStateChangeTimeoutEvent::~StateChangeTimeoutEvent() {
69513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid StateChangeTimeoutEvent::Callback() {
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!aborted_) {
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!caller_->RunStateChangeMachine()) {
74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Report the message.
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      did_timeout_ = true;
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      DCHECK(!aborted_) << message_;
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      caller_->SignalStateComplete();
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
81513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool StateChangeTimeoutEvent::Abort() {
83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  aborted_ = true;
84513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  caller_ = NULL;
85513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return !did_timeout_;
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
88513209b27ff55e2841eac0e4120199c23acce758Ben MurdochProfileSyncServiceHarness::ProfileSyncServiceHarness(
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    Profile* profile,
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& username,
91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& password,
92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int id)
93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : waiting_for_encryption_type_(syncable::UNSPECIFIED),
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      wait_state_(INITIAL_WAIT_STATE),
95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      profile_(profile),
96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      service_(NULL),
973f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      timestamp_match_partner_(NULL),
98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      username_(username),
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      password_(password),
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      id_(id) {
101513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (IsSyncAlreadySetup()) {
102513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service_ = profile_->GetProfileSyncService();
103513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service_->AddObserver(this);
104513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    wait_state_ = FULLY_SYNCED;
105513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
106513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
109513209b27ff55e2841eac0e4120199c23acce758Ben MurdochProfileSyncServiceHarness* ProfileSyncServiceHarness::CreateAndAttach(
110513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    Profile* profile) {
111513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!profile->HasProfileSyncService()) {
112513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NOTREACHED() << "Profile has never signed into sync.";
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return NULL;
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return new ProfileSyncServiceHarness(profile, "", "", 0);
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
118513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::SetCredentials(const std::string& username,
119513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                               const std::string& password) {
120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  username_ = username;
121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  password_ = password;
122513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
123513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
124513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::IsSyncAlreadySetup() {
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return profile_->HasProfileSyncService();
126513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
127513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
128513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::SetupSync() {
129513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  syncable::ModelTypeSet synced_datatypes;
130513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (int i = syncable::FIRST_REAL_MODEL_TYPE;
131513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      i < syncable::MODEL_TYPE_COUNT; ++i) {
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    synced_datatypes.insert(syncable::ModelTypeFromInt(i));
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return SetupSync(synced_datatypes);
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
137513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::SetupSync(
138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const syncable::ModelTypeSet& synced_datatypes) {
139513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Initialize the sync client's profile sync service object.
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  service_ = profile_->GetProfileSyncService("");
141513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (service_ == NULL) {
142513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "SetupSync(): service_ is null.";
143513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
144513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
145513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Subscribe sync client to notifications from the profile sync service.
147513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!service_->HasObserver(this))
148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service_->AddObserver(this);
149513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Authenticate sync client using GAIA credentials.
151513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service_->signin()->StartSignIn(username_, password_, "", "");
152513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
153513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Wait for the OnBackendInitialized() callback.
154513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
155513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
156513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      "Waiting for OnBackendInitialized().")) {
157513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "OnBackendInitialized() not seen after "
158513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch               << kLiveSyncOperationTimeoutMs / 1000
159513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch               << " seconds.";
160513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
161513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
163513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Choose the datatypes to be synced. If all datatypes are to be synced,
164513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // set sync_everything to true; otherwise, set it to false.
165513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool sync_everything = (synced_datatypes.size() ==
166513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      (syncable::MODEL_TYPE_COUNT - syncable::FIRST_REAL_MODEL_TYPE));
167513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
168513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
169201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Wait for initial sync cycle to be completed.
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(wait_state_, WAITING_FOR_INITIAL_SYNC);
171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      "Waiting for initial sync cycle to complete.")) {
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "Initial sync cycle did not complete after "
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch               << kLiveSyncOperationTimeoutMs / 1000
175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch               << " seconds.";
176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
177513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
178513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Indicate to the browser that sync setup is complete.
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service()->SetSyncSetupCompleted();
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return true;
183513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
185513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::SignalStateCompleteWithNextState(
186513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    WaitState next_state) {
187513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  wait_state_ = next_state;
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  SignalStateComplete();
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::SignalStateComplete() {
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MessageLoop::current()->Quit();
193513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
194513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::RunStateChangeMachine() {
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  WaitState original_wait_state = wait_state_;
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  switch (wait_state_) {
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case WAITING_FOR_ON_BACKEND_INITIALIZED: {
199513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("WAITING_FOR_ON_BACKEND_INITIALIZED");
200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (service()->sync_initialized()) {
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // The sync backend is initialized.
202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        SignalStateCompleteWithNextState(WAITING_FOR_INITIAL_SYNC);
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
204201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      break;
205201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case WAITING_FOR_INITIAL_SYNC: {
207513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("WAITING_FOR_INITIAL_SYNC");
208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (IsSynced()) {
209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        // The first sync cycle is now complete. We can start running tests.
210513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        SignalStateCompleteWithNextState(FULLY_SYNCED);
211513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
212513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
213513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case WAITING_FOR_SYNC_TO_FINISH: {
215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("WAITING_FOR_SYNC_TO_FINISH");
216513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (!IsSynced()) {
217513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        // The client is not yet fully synced. Continue waiting.
218513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        if (!GetStatus().server_reachable) {
219513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          // The client cannot reach the sync server because the network is
220513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          // disabled. There is no need to wait anymore.
221513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          SignalStateCompleteWithNextState(SERVER_UNREACHABLE);
222513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        }
223513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        break;
224513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
225513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SignalStateCompleteWithNextState(FULLY_SYNCED);
226513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
227513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
228513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case WAITING_FOR_UPDATES: {
229513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("WAITING_FOR_UPDATES");
2303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      DCHECK(timestamp_match_partner_);
2313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      if (!MatchesOtherClient(timestamp_match_partner_)) {
2323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        // The client is not yet fully synced; keep waiting until we converge.
233513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        break;
234513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
2353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      timestamp_match_partner_->service()->RemoveObserver(this);
2363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      timestamp_match_partner_ = NULL;
2373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
238513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SignalStateCompleteWithNextState(FULLY_SYNCED);
239513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
240513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case WAITING_FOR_PASSPHRASE_ACCEPTED: {
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LogClientInfo("WAITING_FOR_PASSPHRASE_ACCEPTED");
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // TODO(atwilson): After ProfileSyncService::OnPassphraseAccepted() is
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // fixed, add an extra check to make sure that the value of
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // service()->observed_passphrase_required() is false.
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (service()->ShouldPushChanges()) {
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // The passphrase has been accepted, and sync has been restarted.
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        SignalStateCompleteWithNextState(FULLY_SYNCED);
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case WAITING_FOR_ENCRYPTION: {
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LogClientInfo("WAITING_FOR_ENCRYPTION");
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (IsTypeEncrypted(waiting_for_encryption_type_)) {
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // Encryption is complete for the type we are waiting on.
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        SignalStateCompleteWithNextState(FULLY_SYNCED);
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
260513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case SERVER_UNREACHABLE: {
261513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("SERVER_UNREACHABLE");
262513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (GetStatus().server_reachable) {
263513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        // The client was offline due to the network being disabled, but is now
264513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        // back online. Wait for the pending sync cycle to complete.
265513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        SignalStateCompleteWithNextState(WAITING_FOR_SYNC_TO_FINISH);
266513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
267513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
268513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
269513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case FULLY_SYNCED: {
270513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // The client is online and fully synced. There is nothing to do.
271513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("FULLY_SYNCED");
272513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
273513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
274513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    case SYNC_DISABLED: {
275513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Syncing is disabled for the client. There is nothing to do.
276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      LogClientInfo("SYNC_DISABLED");
277513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
278513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
279513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    default:
280513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Invalid state during observer callback which may be triggered by other
281513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // classes using the the UI message loop.  Defer to their handling.
282513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      break;
283513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
284513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return original_wait_state != wait_state_;
285513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
286513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
287513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::OnStateChanged() {
288513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  RunStateChangeMachine();
289513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
290513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
291513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::AwaitPassphraseAccepted() {
292513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("AwaitPassphraseAccepted");
293513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (wait_state_ == SYNC_DISABLED) {
294513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
295513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
296513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(atwilson): After ProfileSyncService::OnPassphraseAccepted() is
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // fixed, add an extra check to make sure that the value of
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // service()->observed_passphrase_required() is false.
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (service()->ShouldPushChanges()) {
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Passphrase is already accepted; don't wait.
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
306513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  wait_state_ = WAITING_FOR_PASSPHRASE_ACCEPTED;
307513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
308513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                      "Waiting for passphrase accepted.");
309513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
310513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
311513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::AwaitSyncCycleCompletion(
312513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& reason) {
313513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("AwaitSyncCycleCompletion");
314513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (wait_state_ == SYNC_DISABLED) {
315513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
316513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
317513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsSynced()) {
320513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Client is already synced; don't wait.
321513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return true;
322513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (wait_state_ == SERVER_UNREACHABLE) {
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Client was offline; wait for it to go online, and then wait for sync.
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK_EQ(wait_state_, WAITING_FOR_SYNC_TO_FINISH);
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(service()->sync_initialized());
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    wait_state_ = WAITING_FOR_SYNC_TO_FINISH;
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (wait_state_ == FULLY_SYNCED) {
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Client is online; sync was successful.
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else if (wait_state_ == SERVER_UNREACHABLE) {
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Client is offline; sync was unsuccessful.
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(ERROR) << "Invalid wait state:" << wait_state_;
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
344513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
345513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
346513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::AwaitMutualSyncCycleCompletion(
347513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ProfileSyncServiceHarness* partner) {
348513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("AwaitMutualSyncCycleCompletion");
349513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!AwaitSyncCycleCompletion("Sync cycle completion on active client."))
350513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
3513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return partner->WaitUntilTimestampMatches(this,
352513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      "Sync cycle completion on passive client.");
353513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
354513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
355513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
356513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    std::vector<ProfileSyncServiceHarness*>& partners) {
357513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("AwaitGroupSyncCycleCompletion");
358513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!AwaitSyncCycleCompletion("Sync cycle completion on active client."))
359513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
360513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool return_value = true;
361513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (std::vector<ProfileSyncServiceHarness*>::iterator it =
362513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      partners.begin(); it != partners.end(); ++it) {
363513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if ((this != *it) && ((*it)->wait_state_ != SYNC_DISABLED)) {
364513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return_value = return_value &&
3653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen          (*it)->WaitUntilTimestampMatches(this,
366513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          "Sync cycle completion on partner client.");
367513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
368513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
369513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return return_value;
370513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
371513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
372513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
373513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::AwaitQuiescence(
374513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    std::vector<ProfileSyncServiceHarness*>& clients) {
375513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  VLOG(1) << "AwaitQuiescence.";
376513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool return_value = true;
377513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (std::vector<ProfileSyncServiceHarness*>::iterator it =
378513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      clients.begin(); it != clients.end(); ++it) {
379513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if ((*it)->wait_state_ != SYNC_DISABLED)
380513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return_value = return_value &&
381513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          (*it)->AwaitGroupSyncCycleCompletion(clients);
382513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
383513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return return_value;
384513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
385513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
3863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool ProfileSyncServiceHarness::WaitUntilTimestampMatches(
3873f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    ProfileSyncServiceHarness* partner, const std::string& reason) {
3883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  LogClientInfo("WaitUntilTimestampMatches");
389513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (wait_state_ == SYNC_DISABLED) {
390513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
391513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
392513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (MatchesOtherClient(partner)) {
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Timestamps already match; don't wait.
396513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return true;
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
3983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!timestamp_match_partner_);
4003f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  timestamp_match_partner_ = partner;
4013f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  partner->service()->AddObserver(this);
4023f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  wait_state_ = WAITING_FOR_UPDATES;
4033f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason);
404513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
405513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
406513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::AwaitStatusChangeWithTimeout(
407513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int timeout_milliseconds,
408513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& reason) {
409513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("AwaitStatusChangeWithTimeout");
410513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (wait_state_ == SYNC_DISABLED) {
411513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
412513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
413513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
414513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<StateChangeTimeoutEvent> timeout_signal(
415513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new StateChangeTimeoutEvent(this, reason));
416513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MessageLoop* loop = MessageLoop::current();
417513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool did_allow_nestable_tasks = loop->NestableTasksAllowed();
418513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  loop->SetNestableTasksAllowed(true);
419513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  loop->PostDelayedTask(
420513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      FROM_HERE,
421513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NewRunnableMethod(timeout_signal.get(),
422513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                        &StateChangeTimeoutEvent::Callback),
423513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      timeout_milliseconds);
424513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  loop->Run();
425513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  loop->SetNestableTasksAllowed(did_allow_nestable_tasks);
4263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (timeout_signal->Abort()) {
4273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    LogClientInfo("AwaitStatusChangeWithTimeout succeeded");
4283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    return true;
4293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  } else {
4303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    LogClientInfo("AwaitStatusChangeWithTimeout timed out");
4313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    return false;
4323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
433513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
434513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
435513209b27ff55e2841eac0e4120199c23acce758Ben MurdochProfileSyncService::Status ProfileSyncServiceHarness::GetStatus() {
436513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(service() != NULL) << "GetStatus(): service() is NULL.";
437513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return service()->QueryDetailedSyncStatus();
438513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
439513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
440513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ProfileSyncServiceHarness::IsSynced() {
441201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  LogClientInfo("IsSynced");
442513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (service() == NULL)
443513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
444513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
445513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // TODO(rsimha): Remove additional checks of snap->has_more_to_sync and
446513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // snap->unsynced_count once http://crbug.com/48989 is fixed.
447513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return (snap &&
4484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          snap->num_conflicting_updates == 0 &&  // We can decrypt everything.
449513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          ServiceIsPushingChanges() &&
450513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          GetStatus().notifications_enabled &&
45172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          !service()->HasUnsyncedItems() &&
452513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          !snap->has_more_to_sync &&
453513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          snap->unsynced_count == 0);
454513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
455513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
4563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool ProfileSyncServiceHarness::MatchesOtherClient(
4573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    ProfileSyncServiceHarness* partner) {
4583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (!IsSynced())
4593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    return false;
4603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
4613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Only look for a match if we have at least one enabled datatype in
4623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // common with the partner client.
4633f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  syncable::ModelTypeSet types, other_types, intersection_types;
4643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  service()->GetPreferredDataTypes(&types);
4653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  partner->service()->GetPreferredDataTypes(&other_types);
4663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  std::set_intersection(types.begin(), types.end(), other_types.begin(),
4673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                        other_types.end(),
4683f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                        inserter(intersection_types,
4693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                                 intersection_types.begin()));
47072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (syncable::ModelTypeSet::iterator i = intersection_types.begin();
47172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       i != intersection_types.end();
47272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       ++i) {
47372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!partner->IsSynced() ||
47472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        partner->GetUpdatedTimestamp(*i) != GetUpdatedTimestamp(*i)) {
47572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
4773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
47872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
4793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
4803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
481513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst SyncSessionSnapshot*
482513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
483513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(service_ != NULL) << "Sync service has not yet been set up.";
48472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (service_->sync_initialized()) {
48572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return service_->GetLastSessionSnapshot();
486513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
487513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return NULL;
488513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
489513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
490513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::EnableSyncForDatatype(
491513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    syncable::ModelType datatype) {
492513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("EnableSyncForDatatype");
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  syncable::ModelTypeSet synced_datatypes;
494513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (wait_state_ == SYNC_DISABLED) {
495513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
496513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    synced_datatypes.insert(datatype);
497513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DCHECK(SetupSync(synced_datatypes)) << "Reinitialization of Client " << id_
498513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                        << " failed.";
499513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
500513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DCHECK(service() != NULL) << "EnableSyncForDatatype(): service() is null.";
501513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service()->GetPreferredDataTypes(&synced_datatypes);
502513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    syncable::ModelTypeSet::iterator it = synced_datatypes.find(
503513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        syncable::ModelTypeFromInt(datatype));
504513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (it == synced_datatypes.end()) {
505513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      synced_datatypes.insert(syncable::ModelTypeFromInt(datatype));
506513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      service()->OnUserChoseDatatypes(false, synced_datatypes);
507513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      wait_state_ = WAITING_FOR_SYNC_TO_FINISH;
508513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      AwaitSyncCycleCompletion("Waiting for datatype configuration.");
509513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      VLOG(1) << "EnableSyncForDatatype(): Enabled sync for datatype "
510513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << syncable::ModelTypeToString(datatype) << " on Client " << id_;
511513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
512513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      VLOG(1) << "EnableSyncForDatatype(): Sync already enabled for datatype "
513513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << syncable::ModelTypeToString(datatype) << " on Client " << id_;
514513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
515513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
516513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
517513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
518513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::DisableSyncForDatatype(
519513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    syncable::ModelType datatype) {
520513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("DisableSyncForDatatype");
521513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  syncable::ModelTypeSet synced_datatypes;
522513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(service() != NULL) << "DisableSyncForDatatype(): service() is null.";
523513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service()->GetPreferredDataTypes(&synced_datatypes);
524513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  syncable::ModelTypeSet::iterator it = synced_datatypes.find(datatype);
525513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (it != synced_datatypes.end()) {
526513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    synced_datatypes.erase(it);
527513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service()->OnUserChoseDatatypes(false, synced_datatypes);
528513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    AwaitSyncCycleCompletion("Waiting for datatype configuration.");
529513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "DisableSyncForDatatype(): Disabled sync for datatype "
530513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            << syncable::ModelTypeToString(datatype) << " on Client " << id_;
531513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
532513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "DisableSyncForDatatype(): Sync already disabled for datatype "
533513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            << syncable::ModelTypeToString(datatype) << " on Client " << id_;
534513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
535513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
536513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
537513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::EnableSyncForAllDatatypes() {
538513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("EnableSyncForAllDatatypes");
539513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (wait_state_ == SYNC_DISABLED) {
540513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    wait_state_ = WAITING_FOR_ON_BACKEND_INITIALIZED;
541513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DCHECK(SetupSync()) << "Reinitialization of Client " << id_ << " failed.";
542513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
543513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    syncable::ModelTypeSet synced_datatypes;
544513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    for (int i = syncable::FIRST_REAL_MODEL_TYPE;
545513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        i < syncable::MODEL_TYPE_COUNT; ++i) {
546513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      synced_datatypes.insert(syncable::ModelTypeFromInt(i));
547513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
548513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    DCHECK(service() != NULL) << "EnableSyncForAllDatatypes(): service() is "
549513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                 " null.";
550513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service()->OnUserChoseDatatypes(true, synced_datatypes);
551513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    wait_state_ = WAITING_FOR_SYNC_TO_FINISH;
552513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    AwaitSyncCycleCompletion("Waiting for datatype configuration.");
553513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "EnableSyncForAllDatatypes(): Enabled sync for all datatypes on "
554513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch               "Client " << id_;
555513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
556513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
557513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
558513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ProfileSyncServiceHarness::DisableSyncForAllDatatypes() {
559513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LogClientInfo("DisableSyncForAllDatatypes");
560513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(service() != NULL) << "EnableSyncForAllDatatypes(): service() is "
561513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                               "null.";
562513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service()->DisableForUser();
563513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  wait_state_ = SYNC_DISABLED;
564513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  VLOG(1) << "DisableSyncForAllDatatypes(): Disabled sync for all datatypes on "
565513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch             "Client " << id_;
566513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
567513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::string ProfileSyncServiceHarness::GetUpdatedTimestamp(
56972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    syncable::ModelType model_type) {
570513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
571513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(snap != NULL) << "GetUpdatedTimestamp(): Sync snapshot is NULL.";
57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return snap->download_progress_markers[model_type];
573513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
574513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ProfileSyncServiceHarness::LogClientInfo(const std::string& message) {
576513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (service()) {
577513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const SyncSessionSnapshot* snap = GetLastSessionSnapshot();
578513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (snap) {
579513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      VLOG(1) << "Client " << id_ << ": " << message
58072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << ": num_updates_downloaded : "
58172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << snap->syncer_status.num_updates_downloaded_total
582513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << ", has_more_to_sync: " << snap->has_more_to_sync
583513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << ", unsynced_count: " << snap->unsynced_count
584201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              << ", num_conflicting_updates: " << snap->num_conflicting_updates
585513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << ", has_unsynced_items: "
58672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << service()->HasUnsyncedItems()
587201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              << ", observed_passphrase_required: "
588201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              << service()->observed_passphrase_required()
589513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << ", notifications_enabled: "
590513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << GetStatus().notifications_enabled
591513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << ", service_is_pushing_changes: " << ServiceIsPushingChanges();
592513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
593513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      VLOG(1) << "Client " << id_ << ": " << message
594513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              << ": Sync session snapshot not available.";
595513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
596513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
597513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "Client " << id_ << ": " << message
598513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            << ": Sync service not available.";
599513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
600513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
601dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
602dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ProfileSyncServiceHarness::EnableEncryptionForType(
603dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    syncable::ModelType type) {
604dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet encrypted_types;
605dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  service_->GetEncryptedDataTypes(&encrypted_types);
606dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (encrypted_types.count(type) > 0)
607dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return true;
608dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  encrypted_types.insert(type);
609dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  service_->EncryptDataTypes(encrypted_types);
610dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
611dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Wait some time to let the enryption finish.
612dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string reason = "Waiting for encryption.";
613dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(FULLY_SYNCED, wait_state_);
614dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  wait_state_ = WAITING_FOR_ENCRYPTION;
615dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  waiting_for_encryption_type_ = type;
616dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs, reason)) {
617dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(ERROR) << "Did not receive EncryptionComplete notification after"
618dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               << kLiveSyncOperationTimeoutMs / 1000
619dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               << " seconds.";
620dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
621dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
622dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
623dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return IsTypeEncrypted(type);
624dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
625dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
626dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ProfileSyncServiceHarness::IsTypeEncrypted(syncable::ModelType type) {
627dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet encrypted_types;
628dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  service_->GetEncryptedDataTypes(&encrypted_types);
629dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (encrypted_types.count(type) == 0) {
630dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
631dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
632dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
633dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
634