OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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 "ios/chrome/browser/browser_state/test_chrome_browser_state.h" |
| 6 |
| 7 #include <utility> |
| 8 |
| 9 #include "base/base_paths.h" |
| 10 #include "base/files/file_util.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/macros.h" |
| 13 #include "base/message_loop/message_loop.h" |
| 14 #include "base/path_service.h" |
| 15 #include "base/run_loop.h" |
| 16 #include "base/thread_task_runner_handle.h" |
| 17 #include "components/bookmarks/browser/bookmark_model.h" |
| 18 #include "components/bookmarks/common/bookmark_constants.h" |
| 19 #include "components/history/core/browser/history_constants.h" |
| 20 #include "components/history/core/browser/history_database_params.h" |
| 21 #include "components/history/core/browser/history_service.h" |
| 22 #include "components/history/core/browser/top_sites.h" |
| 23 #include "components/history/core/browser/visit_delegate.h" |
| 24 #include "components/history/ios/browser/history_database_helper.h" |
| 25 #include "components/keyed_service/core/service_access_type.h" |
| 26 #include "components/keyed_service/ios/browser_state_dependency_manager.h" |
| 27 #include "components/syncable_prefs/pref_service_syncable.h" |
| 28 #include "components/syncable_prefs/testing_pref_service_syncable.h" |
| 29 #include "components/user_prefs/user_prefs.h" |
| 30 #include "components/webdata_services/web_data_service_wrapper.h" |
| 31 #include "ios/chrome/browser/application_context.h" |
| 32 #include "ios/chrome/browser/autocomplete/in_memory_url_index_factory.h" |
| 33 #include "ios/chrome/browser/bookmarks/bookmark_client_impl.h" |
| 34 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" |
| 35 #include "ios/chrome/browser/browser_state/browser_state_keyed_service_factories
.h" |
| 36 #include "ios/chrome/browser/history/history_client_impl.h" |
| 37 #include "ios/chrome/browser/history/history_service_factory.h" |
| 38 #include "ios/chrome/browser/history/top_sites_factory.h" |
| 39 #include "ios/chrome/browser/history/web_history_service_factory.h" |
| 40 #include "ios/chrome/browser/pref_names.h" |
| 41 #include "ios/chrome/browser/prefs/browser_prefs.h" |
| 42 #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h" |
| 43 #include "ios/chrome/browser/sync/glue/sync_start_util.h" |
| 44 #include "ios/chrome/browser/web_data_service_factory.h" |
| 45 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
| 46 #include "ios/web/public/web_thread.h" |
| 47 #include "net/url_request/url_request_test_util.h" |
| 48 |
| 49 namespace { |
| 50 scoped_ptr<KeyedService> BuildHistoryService(web::BrowserState* context) { |
| 51 ios::ChromeBrowserState* browser_state = |
| 52 ios::ChromeBrowserState::FromBrowserState(context); |
| 53 return make_scoped_ptr(new history::HistoryService( |
| 54 make_scoped_ptr(new HistoryClientImpl( |
| 55 ios::BookmarkModelFactory::GetForBrowserState(browser_state))), |
| 56 nullptr)); |
| 57 } |
| 58 |
| 59 scoped_ptr<KeyedService> BuildBookmarkModel(web::BrowserState* context) { |
| 60 ios::ChromeBrowserState* browser_state = |
| 61 ios::ChromeBrowserState::FromBrowserState(context); |
| 62 scoped_ptr<bookmarks::BookmarkModel> bookmark_model( |
| 63 new bookmarks::BookmarkModel( |
| 64 make_scoped_ptr(new BookmarkClientImpl(browser_state)))); |
| 65 bookmark_model->Load( |
| 66 browser_state->GetPrefs(), |
| 67 browser_state->GetPrefs()->GetString(prefs::kAcceptLanguages), |
| 68 browser_state->GetStatePath(), browser_state->GetIOTaskRunner(), |
| 69 web::WebThread::GetTaskRunnerForThread(web::WebThread::UI)); |
| 70 return std::move(bookmark_model); |
| 71 } |
| 72 |
| 73 void NotReachedErrorCallback(WebDataServiceWrapper::ErrorType error_type, |
| 74 sql::InitStatus status) { |
| 75 NOTREACHED(); |
| 76 } |
| 77 |
| 78 scoped_ptr<KeyedService> BuildWebDataService(web::BrowserState* context) { |
| 79 const base::FilePath& browser_state_path = context->GetStatePath(); |
| 80 return make_scoped_ptr(new WebDataServiceWrapper( |
| 81 browser_state_path, GetApplicationContext()->GetApplicationLocale(), |
| 82 web::WebThread::GetTaskRunnerForThread(web::WebThread::UI), |
| 83 web::WebThread::GetTaskRunnerForThread(web::WebThread::DB), |
| 84 ios::sync_start_util::GetFlareForSyncableService(browser_state_path), |
| 85 &NotReachedErrorCallback)); |
| 86 } |
| 87 |
| 88 base::FilePath CreateTempBrowserStateDir(base::ScopedTempDir* temp_dir) { |
| 89 DCHECK(temp_dir); |
| 90 if (!temp_dir->CreateUniqueTempDir()) { |
| 91 // Fallback logic in case we fail to create unique temporary directory. |
| 92 LOG(ERROR) << "Failed to create unique temporary directory."; |
| 93 base::FilePath system_tmp_dir; |
| 94 bool success = PathService::Get(base::DIR_TEMP, &system_tmp_dir); |
| 95 |
| 96 // We're severly screwed if we can't get the system temporary |
| 97 // directory. Die now to avoid writing to the filesystem root |
| 98 // or other bad places. |
| 99 CHECK(success); |
| 100 |
| 101 base::FilePath fallback_dir( |
| 102 system_tmp_dir.Append(FILE_PATH_LITERAL("TestChromeBrowserStatePath"))); |
| 103 base::DeleteFile(fallback_dir, true); |
| 104 base::CreateDirectory(fallback_dir); |
| 105 if (!temp_dir->Set(fallback_dir)) { |
| 106 // That shouldn't happen, but if it does, try to recover. |
| 107 LOG(ERROR) << "Failed to use a fallback temporary directory."; |
| 108 |
| 109 // We're screwed if this fails, see CHECK above. |
| 110 CHECK(temp_dir->Set(system_tmp_dir)); |
| 111 } |
| 112 } |
| 113 return temp_dir->path(); |
| 114 } |
| 115 } // namespace |
| 116 |
| 117 TestChromeBrowserState::TestChromeBrowserState( |
| 118 TestChromeBrowserState* original_browser_state) |
| 119 : testing_prefs_(nullptr), |
| 120 otr_browser_state_(nullptr), |
| 121 original_browser_state_(original_browser_state) { |
| 122 // Not calling Init() here as the bi-directional link between original and |
| 123 // off-the-record TestChromeBrowserState must be established before this |
| 124 // method can be called. |
| 125 DCHECK(original_browser_state_); |
| 126 } |
| 127 |
| 128 TestChromeBrowserState::TestChromeBrowserState( |
| 129 const base::FilePath& path, |
| 130 scoped_ptr<syncable_prefs::PrefServiceSyncable> prefs, |
| 131 const TestingFactories& testing_factories, |
| 132 const RefcountedTestingFactories& refcounted_testing_factories) |
| 133 : state_path_(path), |
| 134 prefs_(std::move(prefs)), |
| 135 testing_prefs_(nullptr), |
| 136 otr_browser_state_(nullptr), |
| 137 original_browser_state_(nullptr) { |
| 138 Init(); |
| 139 |
| 140 for (const auto& pair : testing_factories) { |
| 141 pair.first->SetTestingFactory(this, pair.second); |
| 142 } |
| 143 |
| 144 for (const auto& pair : refcounted_testing_factories) { |
| 145 pair.first->SetTestingFactory(this, pair.second); |
| 146 } |
| 147 } |
| 148 |
| 149 TestChromeBrowserState::~TestChromeBrowserState() { |
| 150 // If this TestChromeBrowserState owns an incognito TestChromeBrowserState, |
| 151 // tear it down first. |
| 152 otr_browser_state_.reset(); |
| 153 |
| 154 BrowserStateDependencyManager::GetInstance()->DestroyBrowserStateServices( |
| 155 this); |
| 156 } |
| 157 |
| 158 void TestChromeBrowserState::Init() { |
| 159 // If threads have been initialized, we should be on the UI thread. |
| 160 DCHECK(!web::WebThread::IsThreadInitialized(web::WebThread::UI) || |
| 161 web::WebThread::CurrentlyOn(web::WebThread::UI)); |
| 162 |
| 163 if (state_path_.empty()) |
| 164 state_path_ = CreateTempBrowserStateDir(&temp_dir_); |
| 165 |
| 166 if (IsOffTheRecord()) |
| 167 state_path_ = state_path_.Append(FILE_PATH_LITERAL("OTR")); |
| 168 |
| 169 if (!base::PathExists(state_path_)) |
| 170 base::CreateDirectory(state_path_); |
| 171 |
| 172 // Normally this would happen during browser startup, but for tests we need to |
| 173 // trigger creation of BrowserState-related services. |
| 174 EnsureBrowserStateKeyedServiceFactoriesBuilt(); |
| 175 if (ios::GetChromeBrowserProvider()) |
| 176 ios::GetChromeBrowserProvider()->AssertBrowserContextKeyedFactoriesBuilt(); |
| 177 |
| 178 if (prefs_) { |
| 179 // If user passed a custom PrefServiceSyncable, then leave |testing_prefs_| |
| 180 // unset as it is not possible to determine its type. |
| 181 } else if (IsOffTheRecord()) { |
| 182 // This leaves |testing_prefs_| unset as CreateIncognitoBrowserStatePrefs() |
| 183 // does not return a TestingPrefServiceSyncable. |
| 184 DCHECK(original_browser_state_); |
| 185 prefs_ = |
| 186 CreateIncognitoBrowserStatePrefs(original_browser_state_->prefs_.get()); |
| 187 } else { |
| 188 testing_prefs_ = new syncable_prefs::TestingPrefServiceSyncable(); |
| 189 RegisterBrowserStatePrefs(testing_prefs_->registry()); |
| 190 prefs_.reset(testing_prefs_); |
| 191 } |
| 192 user_prefs::UserPrefs::Set(this, prefs_.get()); |
| 193 |
| 194 // Prefs for incognito TestChromeBrowserState are set in |
| 195 // CreateIncognitoBrowserStatePrefs(). |
| 196 if (!IsOffTheRecord()) { |
| 197 user_prefs::PrefRegistrySyncable* pref_registry = |
| 198 static_cast<user_prefs::PrefRegistrySyncable*>( |
| 199 prefs_->DeprecatedGetPrefRegistry()); |
| 200 BrowserStateDependencyManager::GetInstance() |
| 201 ->RegisterBrowserStatePrefsForServices(this, pref_registry); |
| 202 } |
| 203 |
| 204 BrowserStateDependencyManager::GetInstance() |
| 205 ->CreateBrowserStateServicesForTest(this); |
| 206 } |
| 207 |
| 208 bool TestChromeBrowserState::IsOffTheRecord() const { |
| 209 return original_browser_state_ != nullptr; |
| 210 } |
| 211 |
| 212 base::FilePath TestChromeBrowserState::GetStatePath() const { |
| 213 if (!IsOffTheRecord()) |
| 214 return state_path_; |
| 215 |
| 216 base::FilePath otr_stash_state_path = |
| 217 state_path_.Append(FILE_PATH_LITERAL("OTR")); |
| 218 if (!base::PathExists(otr_stash_state_path)) |
| 219 base::CreateDirectory(otr_stash_state_path); |
| 220 return otr_stash_state_path; |
| 221 } |
| 222 |
| 223 scoped_refptr<base::SequencedTaskRunner> |
| 224 TestChromeBrowserState::GetIOTaskRunner() { |
| 225 return base::MessageLoop::current()->task_runner(); |
| 226 } |
| 227 |
| 228 ios::ChromeBrowserState* |
| 229 TestChromeBrowserState::GetOriginalChromeBrowserState() { |
| 230 if (IsOffTheRecord()) |
| 231 return original_browser_state_; |
| 232 return this; |
| 233 } |
| 234 |
| 235 bool TestChromeBrowserState::HasOffTheRecordChromeBrowserState() const { |
| 236 return otr_browser_state_ != nullptr; |
| 237 } |
| 238 |
| 239 ios::ChromeBrowserState* |
| 240 TestChromeBrowserState::GetOffTheRecordChromeBrowserState() { |
| 241 if (IsOffTheRecord()) |
| 242 return this; |
| 243 |
| 244 if (!otr_browser_state_) { |
| 245 otr_browser_state_.reset(new TestChromeBrowserState(this)); |
| 246 otr_browser_state_->Init(); |
| 247 } |
| 248 |
| 249 return otr_browser_state_.get(); |
| 250 } |
| 251 |
| 252 PrefProxyConfigTracker* TestChromeBrowserState::GetProxyConfigTracker() { |
| 253 return nullptr; |
| 254 } |
| 255 |
| 256 net::SSLConfigService* TestChromeBrowserState::GetSSLConfigService() { |
| 257 return nullptr; |
| 258 } |
| 259 |
| 260 PrefService* TestChromeBrowserState::GetPrefs() { |
| 261 return prefs_.get(); |
| 262 } |
| 263 |
| 264 PrefService* TestChromeBrowserState::GetOffTheRecordPrefs() { |
| 265 return nullptr; |
| 266 } |
| 267 |
| 268 ChromeBrowserStateIOData* TestChromeBrowserState::GetIOData() { |
| 269 return nullptr; |
| 270 } |
| 271 |
| 272 void TestChromeBrowserState::ClearNetworkingHistorySince( |
| 273 base::Time time, |
| 274 const base::Closure& completion) { |
| 275 if (!completion.is_null()) |
| 276 completion.Run(); |
| 277 } |
| 278 |
| 279 net::URLRequestContextGetter* TestChromeBrowserState::CreateRequestContext( |
| 280 ProtocolHandlerMap* protocol_handlers, |
| 281 URLRequestInterceptorScopedVector request_interceptors) { |
| 282 return new net::TestURLRequestContextGetter( |
| 283 web::WebThread::GetTaskRunnerForThread(web::WebThread::IO)); |
| 284 } |
| 285 |
| 286 net::URLRequestContextGetter* |
| 287 TestChromeBrowserState::CreateIsolatedRequestContext( |
| 288 const base::FilePath& partition_path) { |
| 289 return nullptr; |
| 290 } |
| 291 |
| 292 TestChromeBrowserState* TestChromeBrowserState::AsTestChromeBrowserState() { |
| 293 return this; |
| 294 } |
| 295 |
| 296 void TestChromeBrowserState::CreateWebDataService() { |
| 297 ignore_result( |
| 298 ios::WebDataServiceFactory::GetInstance()->SetTestingFactoryAndUse( |
| 299 this, &BuildWebDataService)); |
| 300 |
| 301 // Wait a bit after creating the WebDataService to allow the initialisation |
| 302 // to complete (otherwise the TestChromeBrowserState may be destroyed before |
| 303 // initialisation of the database is complete which leads to SQL init errors). |
| 304 base::RunLoop run_loop; |
| 305 run_loop.RunUntilIdle(); |
| 306 } |
| 307 |
| 308 void TestChromeBrowserState::CreateBookmarkModel(bool delete_file) { |
| 309 if (delete_file) { |
| 310 base::DeleteFile(GetOriginalChromeBrowserState()->GetStatePath().Append( |
| 311 bookmarks::kBookmarksFileName), |
| 312 false /* recursive */); |
| 313 } |
| 314 ignore_result( |
| 315 ios::BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse( |
| 316 this, &BuildBookmarkModel)); |
| 317 } |
| 318 |
| 319 bool TestChromeBrowserState::CreateHistoryService(bool delete_file) { |
| 320 // Ensure that no HistoryService exists before creating a new one. |
| 321 DestroyHistoryService(); |
| 322 |
| 323 if (delete_file) { |
| 324 base::FilePath path = |
| 325 GetOriginalChromeBrowserState()->GetStatePath().Append( |
| 326 history::kHistoryFilename); |
| 327 if (!base::DeleteFile(path, false) && base::PathExists(path)) |
| 328 return false; |
| 329 } |
| 330 |
| 331 // Create and initialize the HistoryService, but destroy it if the init fails. |
| 332 history::HistoryService* history_service = |
| 333 static_cast<history::HistoryService*>( |
| 334 ios::HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse( |
| 335 this, &BuildHistoryService)); |
| 336 if (!history_service->Init( |
| 337 GetPrefs()->GetString(prefs::kAcceptLanguages), |
| 338 history::HistoryDatabaseParamsForPath( |
| 339 GetOriginalChromeBrowserState()->GetStatePath()))) { |
| 340 ios::HistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr); |
| 341 return false; |
| 342 } |
| 343 |
| 344 // Some tests expect that CreateHistoryService() will also make the |
| 345 // InMemoryURLIndex available. |
| 346 ios::InMemoryURLIndexFactory::GetInstance()->SetTestingFactory( |
| 347 this, ios::InMemoryURLIndexFactory::GetDefaultFactory()); |
| 348 // Disable WebHistoryService by default, since it makes network requests. |
| 349 ios::WebHistoryServiceFactory::GetInstance()->SetTestingFactory(this, |
| 350 nullptr); |
| 351 |
| 352 return true; |
| 353 } |
| 354 |
| 355 void TestChromeBrowserState::DestroyHistoryService() { |
| 356 history::HistoryService* history_service = |
| 357 ios::HistoryServiceFactory::GetInstance()->GetForBrowserStateIfExists( |
| 358 this, ServiceAccessType::EXPLICIT_ACCESS); |
| 359 if (!history_service) |
| 360 return; |
| 361 |
| 362 history_service->ClearCachedDataForContextID(0); |
| 363 history_service->SetOnBackendDestroyTask( |
| 364 base::MessageLoop::QuitWhenIdleClosure()); |
| 365 history_service->Shutdown(); |
| 366 history_service = nullptr; |
| 367 |
| 368 // Resetting the testing factory force the destruction of the current |
| 369 // HistoryService instance associated with the TestChromeBrowserState. |
| 370 ios::HistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr); |
| 371 |
| 372 // Wait for the backend class to terminate before deleting the files and |
| 373 // moving to the next test. Note: if this never terminates, somebody is |
| 374 // probably leaking a reference to the history backend, so it never calls |
| 375 // our destroy task. |
| 376 base::MessageLoop::current()->Run(); |
| 377 |
| 378 // Make sure we don't have any event pending that could disrupt the next |
| 379 // test. |
| 380 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 381 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
| 382 base::MessageLoop::current()->Run(); |
| 383 } |
| 384 |
| 385 syncable_prefs::TestingPrefServiceSyncable* |
| 386 TestChromeBrowserState::GetTestingPrefService() { |
| 387 DCHECK(prefs_); |
| 388 DCHECK(testing_prefs_); |
| 389 return testing_prefs_; |
| 390 } |
| 391 |
| 392 TestChromeBrowserState::Builder::Builder() : build_called_(false) {} |
| 393 |
| 394 TestChromeBrowserState::Builder::~Builder() {} |
| 395 |
| 396 void TestChromeBrowserState::Builder::AddTestingFactory( |
| 397 BrowserStateKeyedServiceFactory* service_factory, |
| 398 BrowserStateKeyedServiceFactory::TestingFactoryFunction cb) { |
| 399 DCHECK(!build_called_); |
| 400 testing_factories_.push_back(std::make_pair(service_factory, cb)); |
| 401 } |
| 402 |
| 403 void TestChromeBrowserState::Builder::AddTestingFactory( |
| 404 RefcountedBrowserStateKeyedServiceFactory* service_factory, |
| 405 RefcountedBrowserStateKeyedServiceFactory::TestingFactoryFunction cb) { |
| 406 DCHECK(!build_called_); |
| 407 refcounted_testing_factories_.push_back(std::make_pair(service_factory, cb)); |
| 408 } |
| 409 |
| 410 void TestChromeBrowserState::Builder::SetPath(const base::FilePath& path) { |
| 411 DCHECK(!build_called_); |
| 412 state_path_ = path; |
| 413 } |
| 414 |
| 415 void TestChromeBrowserState::Builder::SetPrefService( |
| 416 scoped_ptr<syncable_prefs::PrefServiceSyncable> prefs) { |
| 417 DCHECK(!build_called_); |
| 418 pref_service_ = std::move(prefs); |
| 419 } |
| 420 |
| 421 scoped_ptr<TestChromeBrowserState> TestChromeBrowserState::Builder::Build() { |
| 422 DCHECK(!build_called_); |
| 423 return make_scoped_ptr(new TestChromeBrowserState( |
| 424 state_path_, std::move(pref_service_), testing_factories_, |
| 425 refcounted_testing_factories_)); |
| 426 } |
OLD | NEW |