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