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