test_profile_sync_service.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/test_profile_sync_service.h"
6
7#include "chrome/browser/chrome_notification_types.h"
8#include "chrome/browser/signin/signin_manager.h"
9#include "chrome/browser/signin/signin_manager_factory.h"
10#include "chrome/browser/sync/glue/data_type_controller.h"
11#include "chrome/browser/sync/glue/sync_backend_host.h"
12#include "chrome/browser/sync/profile_sync_components_factory.h"
13#include "chrome/browser/sync/test/test_http_bridge_factory.h"
14#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
15#include "sync/internal_api/public/test/test_user_share.h"
16#include "sync/internal_api/public/user_share.h"
17#include "sync/js/js_reply_handler.h"
18#include "sync/protocol/encryption.pb.h"
19#include "sync/syncable/directory.h"
20
21using syncer::InternalComponentsFactory;
22using syncer::ModelSafeRoutingInfo;
23using syncer::TestInternalComponentsFactory;
24using syncer::sessions::ModelNeutralState;
25using syncer::sessions::SyncSessionSnapshot;
26using syncer::sessions::SyncSourceInfo;
27using syncer::UserShare;
28using syncer::syncable::Directory;
29using syncer::DEVICE_INFO;
30using syncer::EXPERIMENTS;
31using syncer::NIGORI;
32using syncer::PRIORITY_PREFERENCES;
33
34namespace browser_sync {
35
36SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
37    Profile* profile,
38    const base::WeakPtr<SyncPrefs>& sync_prefs,
39    syncer::TestIdFactory& id_factory,
40    base::Closure& callback,
41    bool set_initial_sync_ended_on_init,
42    bool synchronous_init,
43    bool fail_initial_download,
44    syncer::StorageOption storage_option)
45    : browser_sync::SyncBackendHost(
46        profile->GetDebugName(), profile, sync_prefs),
47      weak_ptr_factory_(this),
48      id_factory_(id_factory),
49      callback_(callback),
50      fail_initial_download_(fail_initial_download),
51      set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
52      synchronous_init_(synchronous_init),
53      storage_option_(storage_option) {}
54
55SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}
56
57namespace {
58
59scoped_ptr<syncer::HttpPostProviderFactory> MakeTestHttpBridgeFactory() {
60  return scoped_ptr<syncer::HttpPostProviderFactory>(
61      new browser_sync::TestHttpBridgeFactory());
62}
63
64}  // namespace
65
66void SyncBackendHostForProfileSyncTest::InitCore(
67    const DoInitializeOptions& options) {
68  DoInitializeOptions test_options = options;
69  test_options.make_http_bridge_factory_fn =
70      base::Bind(&MakeTestHttpBridgeFactory);
71  test_options.credentials.email = "testuser@gmail.com";
72  test_options.credentials.sync_token = "token";
73  test_options.restored_key_for_bootstrapping = "";
74  syncer::StorageOption storage = storage_option_;
75
76  // It'd be nice if we avoided creating the InternalComponentsFactory in the
77  // first place, but SyncBackendHost will have created one by now so we must
78  // free it. Grab the switches to pass on first.
79  InternalComponentsFactory::Switches factory_switches =
80      test_options.internal_components_factory->GetSwitches();
81  delete test_options.internal_components_factory;
82
83  test_options.internal_components_factory =
84      new TestInternalComponentsFactory(factory_switches, storage);
85
86  SyncBackendHost::InitCore(test_options);
87  if (synchronous_init_ && !base::MessageLoop::current()->is_running()) {
88    // The SyncBackend posts a task to the current loop when
89    // initialization completes.
90    base::MessageLoop::current()->Run();
91  }
92}
93
94void SyncBackendHostForProfileSyncTest::UpdateCredentials(
95      const syncer::SyncCredentials& credentials) {
96  // If we had failed the initial download, complete initialization now.
97  if (!initial_download_closure_.is_null()) {
98    initial_download_closure_.Run();
99    initial_download_closure_.Reset();
100  }
101}
102
103void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
104    syncer::ConfigureReason reason,
105    syncer::ModelTypeSet to_download,
106    syncer::ModelTypeSet to_purge,
107    syncer::ModelTypeSet to_journal,
108    syncer::ModelTypeSet to_unapply,
109    syncer::ModelTypeSet to_ignore,
110    const syncer::ModelSafeRoutingInfo& routing_info,
111    const base::Callback<void(syncer::ModelTypeSet,
112                              syncer::ModelTypeSet)>& ready_task,
113    const base::Closure& retry_callback) {
114  syncer::ModelTypeSet failed_configuration_types;
115  if (fail_initial_download_)
116    failed_configuration_types = to_download;
117
118  // The first parameter there should be the set of enabled types.  That's not
119  // something we have access to from this strange test harness.  We'll just
120  // send back the list of newly configured types instead and hope it doesn't
121  // break anything.
122  FinishConfigureDataTypesOnFrontendLoop(
123      syncer::Difference(to_download, failed_configuration_types),
124      syncer::Difference(to_download, failed_configuration_types),
125      failed_configuration_types,
126      ready_task);
127}
128
129void SyncBackendHostForProfileSyncTest
130    ::HandleSyncManagerInitializationOnFrontendLoop(
131    const syncer::WeakHandle<syncer::JsBackend>& js_backend,
132    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
133        debug_info_listener,
134    syncer::ModelTypeSet restored_types) {
135  // Here's our opportunity to pretend to do things that the SyncManager would
136  // normally do during initialization, but can't because this is a test.
137  // Set up any nodes the test wants around before model association.
138  if (!callback_.is_null()) {
139    callback_.Run();
140  }
141
142  // Pretend we downloaded initial updates and set initial sync ended bits
143  // if we were asked to.
144  if (set_initial_sync_ended_on_init_) {
145    UserShare* user_share = GetUserShare();
146    Directory* directory = user_share->directory.get();
147
148    if (!directory->InitialSyncEndedForType(NIGORI)) {
149      syncer::TestUserShare::CreateRoot(NIGORI, user_share);
150
151      // A side effect of adding the NIGORI node (normally done by the
152      // syncer) is a decryption attempt, which will fail the first time.
153    }
154
155    if (!directory->InitialSyncEndedForType(DEVICE_INFO)) {
156      syncer::TestUserShare::CreateRoot(DEVICE_INFO, user_share);
157    }
158
159    if (!directory->InitialSyncEndedForType(EXPERIMENTS)) {
160      syncer::TestUserShare::CreateRoot(EXPERIMENTS, user_share);
161    }
162
163    if (!directory->InitialSyncEndedForType(PRIORITY_PREFERENCES)) {
164      syncer::TestUserShare::CreateRoot(PRIORITY_PREFERENCES, user_share);
165    }
166
167    restored_types = syncer::ModelTypeSet::All();
168  }
169
170  initial_download_closure_ = base::Bind(
171      &SyncBackendHostForProfileSyncTest::ContinueInitialization,
172      weak_ptr_factory_.GetWeakPtr(),
173      js_backend,
174      debug_info_listener,
175      restored_types);
176  if (fail_initial_download_) {
177    frontend()->OnSyncConfigureRetry();
178    if (synchronous_init_)
179      base::MessageLoop::current()->Quit();
180  } else {
181    initial_download_closure_.Run();
182    initial_download_closure_.Reset();
183  }
184}
185
186void SyncBackendHostForProfileSyncTest::ContinueInitialization(
187    const syncer::WeakHandle<syncer::JsBackend>& js_backend,
188    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
189        debug_info_listener,
190    syncer::ModelTypeSet restored_types) {
191  SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop(
192      js_backend, debug_info_listener, restored_types);
193}
194
195}  // namespace browser_sync
196
197syncer::TestIdFactory* TestProfileSyncService::id_factory() {
198  return &id_factory_;
199}
200
201browser_sync::SyncBackendHostForProfileSyncTest*
202    TestProfileSyncService::GetBackendForTest() {
203  return static_cast<browser_sync::SyncBackendHostForProfileSyncTest*>(
204      ProfileSyncService::GetBackendForTest());
205}
206
207TestProfileSyncService::TestProfileSyncService(
208    ProfileSyncComponentsFactory* factory,
209    Profile* profile,
210    SigninManagerBase* signin,
211    ProfileSyncService::StartBehavior behavior,
212    bool synchronous_backend_initialization)
213        : ProfileSyncService(factory,
214                             profile,
215                             signin,
216                             behavior),
217    synchronous_backend_initialization_(
218        synchronous_backend_initialization),
219    synchronous_sync_configuration_(false),
220    set_initial_sync_ended_on_init_(true),
221    fail_initial_download_(false),
222    storage_option_(syncer::STORAGE_IN_MEMORY) {
223  SetSyncSetupCompleted();
224}
225
226TestProfileSyncService::~TestProfileSyncService() {
227}
228
229// static
230BrowserContextKeyedService* TestProfileSyncService::BuildAutoStartAsyncInit(
231    content::BrowserContext* context) {
232  Profile* profile = static_cast<Profile*>(context);
233  SigninManagerBase* signin =
234      SigninManagerFactory::GetForProfile(profile);
235  ProfileSyncComponentsFactoryMock* factory =
236      new ProfileSyncComponentsFactoryMock();
237  return new TestProfileSyncService(
238      factory, profile, signin, ProfileSyncService::AUTO_START, false);
239}
240
241ProfileSyncComponentsFactoryMock*
242TestProfileSyncService::components_factory_mock() {
243  // We always create a mock factory, see Build* routines.
244  return static_cast<ProfileSyncComponentsFactoryMock*>(factory());
245}
246
247void TestProfileSyncService::RequestAccessToken() {
248  ProfileSyncService::RequestAccessToken();
249  if (synchronous_backend_initialization_) {
250    base::MessageLoop::current()->Run();
251  }
252}
253
254void TestProfileSyncService::OnGetTokenFailure(
255    const OAuth2TokenService::Request* request,
256    const GoogleServiceAuthError& error) {
257  ProfileSyncService::OnGetTokenFailure(request, error);
258  if (synchronous_backend_initialization_) {
259    base::MessageLoop::current()->Quit();
260  }
261}
262
263
264void TestProfileSyncService::OnBackendInitialized(
265    const syncer::WeakHandle<syncer::JsBackend>& backend,
266    const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
267        debug_info_listener,
268    bool success) {
269  ProfileSyncService::OnBackendInitialized(backend,
270                                           debug_info_listener,
271                                           success);
272
273  // TODO(akalin): Figure out a better way to do this.
274  if (synchronous_backend_initialization_) {
275    base::MessageLoop::current()->Quit();
276  }
277}
278
279void TestProfileSyncService::OnConfigureDone(
280    const browser_sync::DataTypeManager::ConfigureResult& result) {
281  ProfileSyncService::OnConfigureDone(result);
282  if (!synchronous_sync_configuration_)
283    base::MessageLoop::current()->Quit();
284}
285
286UserShare* TestProfileSyncService::GetUserShare() const {
287  return backend_->GetUserShare();
288}
289
290void TestProfileSyncService::dont_set_initial_sync_ended_on_init() {
291  set_initial_sync_ended_on_init_ = false;
292}
293void TestProfileSyncService::set_synchronous_sync_configuration() {
294  synchronous_sync_configuration_ = true;
295}
296void TestProfileSyncService::fail_initial_download() {
297  fail_initial_download_ = true;
298}
299void TestProfileSyncService::set_storage_option(
300    syncer::StorageOption storage_option) {
301  storage_option_ = storage_option;
302}
303
304void TestProfileSyncService::CreateBackend() {
305  backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
306      profile(),
307      sync_prefs_.AsWeakPtr(),
308      id_factory_,
309      callback_,
310      set_initial_sync_ended_on_init_,
311      synchronous_backend_initialization_,
312      fail_initial_download_,
313      storage_option_));
314}
315
316scoped_ptr<OAuth2TokenService::Request> FakeOAuth2TokenService::StartRequest(
317    const OAuth2TokenService::ScopeSet& scopes,
318    OAuth2TokenService::Consumer* consumer) {
319  // Ensure token in question is cached and never expires. Request will succeed
320  // without network IO.
321  RegisterCacheEntry(GetRefreshToken(), scopes, "access_token",
322      base::Time::Max());
323  return ProfileOAuth2TokenService::StartRequest(scopes, consumer);
324}
325
326BrowserContextKeyedService* FakeOAuth2TokenService::BuildTokenService(
327    content::BrowserContext* context) {
328  Profile* profile = static_cast<Profile*>(context);
329
330  FakeOAuth2TokenService* service =
331      new FakeOAuth2TokenService(context->GetRequestContext());
332  service->Initialize(profile);
333  return service;
334}
335