test_profile_sync_service.h revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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#ifndef CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
6#define CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
7#pragma once
8
9#include <string>
10
11#include "base/message_loop.h"
12#include "chrome/browser/sync/engine/syncapi.h"
13#include "chrome/browser/sync/profile_sync_factory.h"
14#include "chrome/browser/sync/profile_sync_service.h"
15#include "chrome/browser/sync/glue/data_type_controller.h"
16#include "chrome/browser/sync/glue/data_type_manager_impl.h"
17#include "chrome/browser/sync/glue/sync_backend_host.h"
18#include "chrome/browser/sync/sessions/session_state.h"
19#include "chrome/browser/sync/syncable/directory_manager.h"
20#include "chrome/browser/sync/syncable/syncable.h"
21#include "chrome/test/profile_mock.h"
22#include "chrome/test/sync/test_http_bridge_factory.h"
23#include "testing/gmock/include/gmock/gmock.h"
24
25class Profile;
26
27using browser_sync::ModelSafeRoutingInfo;
28using browser_sync::sessions::ErrorCounters;
29using browser_sync::sessions::SyncerStatus;
30using browser_sync::sessions::SyncSessionSnapshot;
31using sync_api::UserShare;
32using syncable::DirectoryManager;
33using syncable::ModelType;
34using syncable::ScopedDirLookup;
35
36ACTION_P(CallOnPaused, core) {
37  core->OnPaused();
38};
39
40ACTION_P(CallOnResumed, core) {
41  core->OnResumed();
42}
43
44ACTION(ReturnNewDataTypeManager) {
45  return new browser_sync::DataTypeManagerImpl(arg0, arg1);
46}
47
48namespace browser_sync {
49
50// Mocks out the SyncerThread operations (Pause/Resume) since no thread is
51// running in these tests, and allows tests to provide a task on construction
52// to set up initial nodes to mock out an actual server initial sync
53// download.
54class SyncBackendHostForProfileSyncTest : public SyncBackendHost {
55 public:
56  // |initial_condition_setup_task| can be used to populate nodes before the
57  //     OnBackendInitialized callback fires.
58  // |set_initial_sync_ended_on_init| determines whether we pretend that a full
59  //     initial download has occurred and set bits for enabled data types.  If
60  //     this is false, configuring data types will require a syncer nudge.
61  // |synchronous_init| causes initialization to block until the syncapi has
62  //     completed setting itself up and called us back.
63  SyncBackendHostForProfileSyncTest(SyncFrontend* frontend,
64      Profile* profile,
65      const FilePath& profile_path,
66      const DataTypeController::TypeMap& data_type_controllers,
67      Task* initial_condition_setup_task,
68      int num_expected_resumes,
69      int num_expected_pauses,
70      bool set_initial_sync_ended_on_init,
71      bool synchronous_init)
72      : browser_sync::SyncBackendHost(frontend, profile, profile_path,
73                                      data_type_controllers),
74        initial_condition_setup_task_(initial_condition_setup_task),
75        set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
76        synchronous_init_(synchronous_init) {
77    // By default, the RequestPause and RequestResume methods will
78    // send the confirmation notification and return true.
79    ON_CALL(*this, RequestPause()).
80        WillByDefault(testing::DoAll(CallOnPaused(core_),
81                                     testing::Return(true)));
82    ON_CALL(*this, RequestResume()).
83        WillByDefault(testing::DoAll(CallOnResumed(core_),
84                                     testing::Return(true)));
85    ON_CALL(*this, RequestNudge()).WillByDefault(testing::Invoke(this,
86         &SyncBackendHostForProfileSyncTest::
87             SimulateSyncCycleCompletedInitialSyncEnded));
88
89    EXPECT_CALL(*this, RequestPause()).Times(num_expected_pauses);
90    EXPECT_CALL(*this, RequestResume()).Times(num_expected_resumes);
91    EXPECT_CALL(*this, RequestNudge()).
92        Times(set_initial_sync_ended_on_init ? 0 : 1);
93  }
94
95  MOCK_METHOD0(RequestPause, bool());
96  MOCK_METHOD0(RequestResume, bool());
97  MOCK_METHOD0(RequestNudge, void());
98
99  void SetInitialSyncEndedForEnabledTypes() {
100    UserShare* user_share = core_->syncapi()->GetUserShare();
101    DirectoryManager* dir_manager = user_share->dir_manager.get();
102
103    ScopedDirLookup dir(dir_manager, user_share->name);
104    if (!dir.good())
105      FAIL();
106
107    ModelSafeRoutingInfo enabled_types;
108    GetModelSafeRoutingInfo(&enabled_types);
109    for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
110         i != enabled_types.end(); ++i) {
111      dir->set_initial_sync_ended_for_type(i->first, true);
112    }
113  }
114
115  virtual void ConfigureDataTypes(const syncable::ModelTypeSet& types,
116      CancelableTask* ready_task) {
117    SetAutofillMigrationState(syncable::MIGRATED);
118    SyncBackendHost::ConfigureDataTypes(types, ready_task);
119  }
120
121  virtual void HandleInitializationCompletedOnFrontendLoop() {
122    set_syncapi_initialized();  // Need to do this asap so task below works.
123
124    // Set up any nodes the test wants around before model association.
125    if (initial_condition_setup_task_) {
126      initial_condition_setup_task_->Run();
127    }
128
129    // Pretend we downloaded initial updates and set initial sync ended bits
130    // if we were asked to.
131    if (set_initial_sync_ended_on_init_)
132      SetInitialSyncEndedForEnabledTypes();
133
134    SyncBackendHost::HandleInitializationCompletedOnFrontendLoop();
135  }
136
137  // Called when a nudge comes in.
138  void SimulateSyncCycleCompletedInitialSyncEnded() {
139    syncable::ModelTypeBitSet sync_ended;
140    ModelSafeRoutingInfo enabled_types;
141    GetModelSafeRoutingInfo(&enabled_types);
142    for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
143         i != enabled_types.end(); ++i) {
144      sync_ended.set(i->first);
145    }
146    core_->HandleSyncCycleCompletedOnFrontendLoop(new SyncSessionSnapshot(
147        SyncerStatus(), ErrorCounters(), 0, 0, false,
148        sync_ended, false, false, 0, 0, false));
149  }
150
151  virtual sync_api::HttpPostProviderFactory* MakeHttpBridgeFactory(
152      URLRequestContextGetter* getter) {
153    return new browser_sync::TestHttpBridgeFactory;
154  }
155
156  virtual void InitCore(const Core::DoInitializeOptions& options) {
157    std::wstring user = L"testuser";
158    core_loop()->PostTask(FROM_HERE,
159        NewRunnableMethod(core_.get(),
160        &SyncBackendHost::Core::DoInitializeForTest,
161        user,
162        options.http_bridge_factory,
163        options.delete_sync_data_folder));
164
165    // TODO(akalin): Figure out a better way to do this.
166    if (synchronous_init_) {
167      // The SyncBackend posts a task to the current loop when
168      // initialization completes.
169      MessageLoop::current()->Run();
170    }
171  }
172
173  static void SetDefaultExpectationsForWorkerCreation(ProfileMock* profile) {
174    EXPECT_CALL(*profile, GetPasswordStore(testing::_)).
175        WillOnce(testing::Return((PasswordStore*)NULL));
176    EXPECT_CALL(*profile, GetHistoryService(testing::_)).
177        WillOnce(testing::Return((HistoryService*)NULL));
178  }
179
180 private:
181  Task* initial_condition_setup_task_;
182  bool set_initial_sync_ended_on_init_;
183  bool synchronous_init_;
184};
185
186}  // namespace browser_sync
187
188class TestProfileSyncService : public ProfileSyncService {
189 public:
190  TestProfileSyncService(ProfileSyncFactory* factory,
191                         Profile* profile,
192                         const std::string& test_user,
193                         bool synchronous_backend_initialization,
194                         Task* initial_condition_setup_task)
195      : ProfileSyncService(factory, profile,
196                           !test_user.empty() ?
197                           test_user : ""),
198        synchronous_backend_initialization_(
199            synchronous_backend_initialization),
200        synchronous_sync_configuration_(false),
201        num_expected_resumes_(1),
202        num_expected_pauses_(1),
203        initial_condition_setup_task_(initial_condition_setup_task),
204        set_initial_sync_ended_on_init_(true) {
205    RegisterPreferences();
206    SetSyncSetupCompleted();
207  }
208  virtual ~TestProfileSyncService() { }
209
210  virtual void CreateBackend() {
211    backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
212        this, profile(),
213        profile()->GetPath(), data_type_controllers(),
214        initial_condition_setup_task_.release(),
215        num_expected_resumes_, num_expected_pauses_,
216        set_initial_sync_ended_on_init_,
217        synchronous_backend_initialization_));
218  }
219
220  virtual void OnBackendInitialized() {
221    ProfileSyncService::OnBackendInitialized();
222    // TODO(akalin): Figure out a better way to do this.
223    if (synchronous_backend_initialization_) {
224      MessageLoop::current()->Quit();
225    }
226  }
227
228  virtual void Observe(NotificationType type,
229                      const NotificationSource& source,
230                      const NotificationDetails& details) {
231    ProfileSyncService::Observe(type, source, details);
232    if (type == NotificationType::SYNC_CONFIGURE_DONE &&
233        !synchronous_sync_configuration_) {
234      MessageLoop::current()->Quit();
235    }
236  }
237
238  void set_num_expected_resumes(int times) {
239    num_expected_resumes_ = times;
240  }
241  void set_num_expected_pauses(int num) {
242    num_expected_pauses_ = num;
243  }
244  void dont_set_initial_sync_ended_on_init() {
245    set_initial_sync_ended_on_init_ = false;
246  }
247  void set_synchronous_sync_configuration() {
248    synchronous_sync_configuration_ = true;
249  }
250
251 private:
252  // When testing under ChromiumOS, this method must not return an empty
253  // value value in order for the profile sync service to start.
254  virtual std::string GetLsidForAuthBootstraping() {
255    return "foo";
256  }
257
258  bool synchronous_backend_initialization_;
259
260  // Set to true when a mock data type manager is being used and the configure
261  // step is performed synchronously.
262  bool synchronous_sync_configuration_;
263  bool set_expect_resume_expectations_;
264  int num_expected_resumes_;
265  int num_expected_pauses_;
266
267  scoped_ptr<Task> initial_condition_setup_task_;
268  bool set_initial_sync_ended_on_init_;
269};
270
271#endif  // CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
272