| Index: ios/chrome/browser/browser_state/test_chrome_browser_state.cc
|
| diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.cc b/ios/chrome/browser/browser_state/test_chrome_browser_state.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..236bf2b94d11cc279760d1a2ea66c2957b4c2cc2
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.cc
|
| @@ -0,0 +1,426 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
|
| +
|
| +#include <utility>
|
| +
|
| +#include "base/base_paths.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/macros.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/path_service.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "components/bookmarks/browser/bookmark_model.h"
|
| +#include "components/bookmarks/common/bookmark_constants.h"
|
| +#include "components/history/core/browser/history_constants.h"
|
| +#include "components/history/core/browser/history_database_params.h"
|
| +#include "components/history/core/browser/history_service.h"
|
| +#include "components/history/core/browser/top_sites.h"
|
| +#include "components/history/core/browser/visit_delegate.h"
|
| +#include "components/history/ios/browser/history_database_helper.h"
|
| +#include "components/keyed_service/core/service_access_type.h"
|
| +#include "components/keyed_service/ios/browser_state_dependency_manager.h"
|
| +#include "components/syncable_prefs/pref_service_syncable.h"
|
| +#include "components/syncable_prefs/testing_pref_service_syncable.h"
|
| +#include "components/user_prefs/user_prefs.h"
|
| +#include "components/webdata_services/web_data_service_wrapper.h"
|
| +#include "ios/chrome/browser/application_context.h"
|
| +#include "ios/chrome/browser/autocomplete/in_memory_url_index_factory.h"
|
| +#include "ios/chrome/browser/bookmarks/bookmark_client_impl.h"
|
| +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
|
| +#include "ios/chrome/browser/browser_state/browser_state_keyed_service_factories.h"
|
| +#include "ios/chrome/browser/history/history_client_impl.h"
|
| +#include "ios/chrome/browser/history/history_service_factory.h"
|
| +#include "ios/chrome/browser/history/top_sites_factory.h"
|
| +#include "ios/chrome/browser/history/web_history_service_factory.h"
|
| +#include "ios/chrome/browser/pref_names.h"
|
| +#include "ios/chrome/browser/prefs/browser_prefs.h"
|
| +#include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
|
| +#include "ios/chrome/browser/sync/glue/sync_start_util.h"
|
| +#include "ios/chrome/browser/web_data_service_factory.h"
|
| +#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
|
| +#include "ios/web/public/web_thread.h"
|
| +#include "net/url_request/url_request_test_util.h"
|
| +
|
| +namespace {
|
| +scoped_ptr<KeyedService> BuildHistoryService(web::BrowserState* context) {
|
| + ios::ChromeBrowserState* browser_state =
|
| + ios::ChromeBrowserState::FromBrowserState(context);
|
| + return make_scoped_ptr(new history::HistoryService(
|
| + make_scoped_ptr(new HistoryClientImpl(
|
| + ios::BookmarkModelFactory::GetForBrowserState(browser_state))),
|
| + nullptr));
|
| +}
|
| +
|
| +scoped_ptr<KeyedService> BuildBookmarkModel(web::BrowserState* context) {
|
| + ios::ChromeBrowserState* browser_state =
|
| + ios::ChromeBrowserState::FromBrowserState(context);
|
| + scoped_ptr<bookmarks::BookmarkModel> bookmark_model(
|
| + new bookmarks::BookmarkModel(
|
| + make_scoped_ptr(new BookmarkClientImpl(browser_state))));
|
| + bookmark_model->Load(
|
| + browser_state->GetPrefs(),
|
| + browser_state->GetPrefs()->GetString(prefs::kAcceptLanguages),
|
| + browser_state->GetStatePath(), browser_state->GetIOTaskRunner(),
|
| + web::WebThread::GetTaskRunnerForThread(web::WebThread::UI));
|
| + return std::move(bookmark_model);
|
| +}
|
| +
|
| +void NotReachedErrorCallback(WebDataServiceWrapper::ErrorType error_type,
|
| + sql::InitStatus status) {
|
| + NOTREACHED();
|
| +}
|
| +
|
| +scoped_ptr<KeyedService> BuildWebDataService(web::BrowserState* context) {
|
| + const base::FilePath& browser_state_path = context->GetStatePath();
|
| + return make_scoped_ptr(new WebDataServiceWrapper(
|
| + browser_state_path, GetApplicationContext()->GetApplicationLocale(),
|
| + web::WebThread::GetTaskRunnerForThread(web::WebThread::UI),
|
| + web::WebThread::GetTaskRunnerForThread(web::WebThread::DB),
|
| + ios::sync_start_util::GetFlareForSyncableService(browser_state_path),
|
| + &NotReachedErrorCallback));
|
| +}
|
| +
|
| +base::FilePath CreateTempBrowserStateDir(base::ScopedTempDir* temp_dir) {
|
| + DCHECK(temp_dir);
|
| + if (!temp_dir->CreateUniqueTempDir()) {
|
| + // Fallback logic in case we fail to create unique temporary directory.
|
| + LOG(ERROR) << "Failed to create unique temporary directory.";
|
| + base::FilePath system_tmp_dir;
|
| + bool success = PathService::Get(base::DIR_TEMP, &system_tmp_dir);
|
| +
|
| + // We're severly screwed if we can't get the system temporary
|
| + // directory. Die now to avoid writing to the filesystem root
|
| + // or other bad places.
|
| + CHECK(success);
|
| +
|
| + base::FilePath fallback_dir(
|
| + system_tmp_dir.Append(FILE_PATH_LITERAL("TestChromeBrowserStatePath")));
|
| + base::DeleteFile(fallback_dir, true);
|
| + base::CreateDirectory(fallback_dir);
|
| + if (!temp_dir->Set(fallback_dir)) {
|
| + // That shouldn't happen, but if it does, try to recover.
|
| + LOG(ERROR) << "Failed to use a fallback temporary directory.";
|
| +
|
| + // We're screwed if this fails, see CHECK above.
|
| + CHECK(temp_dir->Set(system_tmp_dir));
|
| + }
|
| + }
|
| + return temp_dir->path();
|
| +}
|
| +} // namespace
|
| +
|
| +TestChromeBrowserState::TestChromeBrowserState(
|
| + TestChromeBrowserState* original_browser_state)
|
| + : testing_prefs_(nullptr),
|
| + otr_browser_state_(nullptr),
|
| + original_browser_state_(original_browser_state) {
|
| + // Not calling Init() here as the bi-directional link between original and
|
| + // off-the-record TestChromeBrowserState must be established before this
|
| + // method can be called.
|
| + DCHECK(original_browser_state_);
|
| +}
|
| +
|
| +TestChromeBrowserState::TestChromeBrowserState(
|
| + const base::FilePath& path,
|
| + scoped_ptr<syncable_prefs::PrefServiceSyncable> prefs,
|
| + const TestingFactories& testing_factories,
|
| + const RefcountedTestingFactories& refcounted_testing_factories)
|
| + : state_path_(path),
|
| + prefs_(std::move(prefs)),
|
| + testing_prefs_(nullptr),
|
| + otr_browser_state_(nullptr),
|
| + original_browser_state_(nullptr) {
|
| + Init();
|
| +
|
| + for (const auto& pair : testing_factories) {
|
| + pair.first->SetTestingFactory(this, pair.second);
|
| + }
|
| +
|
| + for (const auto& pair : refcounted_testing_factories) {
|
| + pair.first->SetTestingFactory(this, pair.second);
|
| + }
|
| +}
|
| +
|
| +TestChromeBrowserState::~TestChromeBrowserState() {
|
| + // If this TestChromeBrowserState owns an incognito TestChromeBrowserState,
|
| + // tear it down first.
|
| + otr_browser_state_.reset();
|
| +
|
| + BrowserStateDependencyManager::GetInstance()->DestroyBrowserStateServices(
|
| + this);
|
| +}
|
| +
|
| +void TestChromeBrowserState::Init() {
|
| + // If threads have been initialized, we should be on the UI thread.
|
| + DCHECK(!web::WebThread::IsThreadInitialized(web::WebThread::UI) ||
|
| + web::WebThread::CurrentlyOn(web::WebThread::UI));
|
| +
|
| + if (state_path_.empty())
|
| + state_path_ = CreateTempBrowserStateDir(&temp_dir_);
|
| +
|
| + if (IsOffTheRecord())
|
| + state_path_ = state_path_.Append(FILE_PATH_LITERAL("OTR"));
|
| +
|
| + if (!base::PathExists(state_path_))
|
| + base::CreateDirectory(state_path_);
|
| +
|
| + // Normally this would happen during browser startup, but for tests we need to
|
| + // trigger creation of BrowserState-related services.
|
| + EnsureBrowserStateKeyedServiceFactoriesBuilt();
|
| + if (ios::GetChromeBrowserProvider())
|
| + ios::GetChromeBrowserProvider()->AssertBrowserContextKeyedFactoriesBuilt();
|
| +
|
| + if (prefs_) {
|
| + // If user passed a custom PrefServiceSyncable, then leave |testing_prefs_|
|
| + // unset as it is not possible to determine its type.
|
| + } else if (IsOffTheRecord()) {
|
| + // This leaves |testing_prefs_| unset as CreateIncognitoBrowserStatePrefs()
|
| + // does not return a TestingPrefServiceSyncable.
|
| + DCHECK(original_browser_state_);
|
| + prefs_ =
|
| + CreateIncognitoBrowserStatePrefs(original_browser_state_->prefs_.get());
|
| + } else {
|
| + testing_prefs_ = new syncable_prefs::TestingPrefServiceSyncable();
|
| + RegisterBrowserStatePrefs(testing_prefs_->registry());
|
| + prefs_.reset(testing_prefs_);
|
| + }
|
| + user_prefs::UserPrefs::Set(this, prefs_.get());
|
| +
|
| + // Prefs for incognito TestChromeBrowserState are set in
|
| + // CreateIncognitoBrowserStatePrefs().
|
| + if (!IsOffTheRecord()) {
|
| + user_prefs::PrefRegistrySyncable* pref_registry =
|
| + static_cast<user_prefs::PrefRegistrySyncable*>(
|
| + prefs_->DeprecatedGetPrefRegistry());
|
| + BrowserStateDependencyManager::GetInstance()
|
| + ->RegisterBrowserStatePrefsForServices(this, pref_registry);
|
| + }
|
| +
|
| + BrowserStateDependencyManager::GetInstance()
|
| + ->CreateBrowserStateServicesForTest(this);
|
| +}
|
| +
|
| +bool TestChromeBrowserState::IsOffTheRecord() const {
|
| + return original_browser_state_ != nullptr;
|
| +}
|
| +
|
| +base::FilePath TestChromeBrowserState::GetStatePath() const {
|
| + if (!IsOffTheRecord())
|
| + return state_path_;
|
| +
|
| + base::FilePath otr_stash_state_path =
|
| + state_path_.Append(FILE_PATH_LITERAL("OTR"));
|
| + if (!base::PathExists(otr_stash_state_path))
|
| + base::CreateDirectory(otr_stash_state_path);
|
| + return otr_stash_state_path;
|
| +}
|
| +
|
| +scoped_refptr<base::SequencedTaskRunner>
|
| +TestChromeBrowserState::GetIOTaskRunner() {
|
| + return base::MessageLoop::current()->task_runner();
|
| +}
|
| +
|
| +ios::ChromeBrowserState*
|
| +TestChromeBrowserState::GetOriginalChromeBrowserState() {
|
| + if (IsOffTheRecord())
|
| + return original_browser_state_;
|
| + return this;
|
| +}
|
| +
|
| +bool TestChromeBrowserState::HasOffTheRecordChromeBrowserState() const {
|
| + return otr_browser_state_ != nullptr;
|
| +}
|
| +
|
| +ios::ChromeBrowserState*
|
| +TestChromeBrowserState::GetOffTheRecordChromeBrowserState() {
|
| + if (IsOffTheRecord())
|
| + return this;
|
| +
|
| + if (!otr_browser_state_) {
|
| + otr_browser_state_.reset(new TestChromeBrowserState(this));
|
| + otr_browser_state_->Init();
|
| + }
|
| +
|
| + return otr_browser_state_.get();
|
| +}
|
| +
|
| +PrefProxyConfigTracker* TestChromeBrowserState::GetProxyConfigTracker() {
|
| + return nullptr;
|
| +}
|
| +
|
| +net::SSLConfigService* TestChromeBrowserState::GetSSLConfigService() {
|
| + return nullptr;
|
| +}
|
| +
|
| +PrefService* TestChromeBrowserState::GetPrefs() {
|
| + return prefs_.get();
|
| +}
|
| +
|
| +PrefService* TestChromeBrowserState::GetOffTheRecordPrefs() {
|
| + return nullptr;
|
| +}
|
| +
|
| +ChromeBrowserStateIOData* TestChromeBrowserState::GetIOData() {
|
| + return nullptr;
|
| +}
|
| +
|
| +void TestChromeBrowserState::ClearNetworkingHistorySince(
|
| + base::Time time,
|
| + const base::Closure& completion) {
|
| + if (!completion.is_null())
|
| + completion.Run();
|
| +}
|
| +
|
| +net::URLRequestContextGetter* TestChromeBrowserState::CreateRequestContext(
|
| + ProtocolHandlerMap* protocol_handlers,
|
| + URLRequestInterceptorScopedVector request_interceptors) {
|
| + return new net::TestURLRequestContextGetter(
|
| + web::WebThread::GetTaskRunnerForThread(web::WebThread::IO));
|
| +}
|
| +
|
| +net::URLRequestContextGetter*
|
| +TestChromeBrowserState::CreateIsolatedRequestContext(
|
| + const base::FilePath& partition_path) {
|
| + return nullptr;
|
| +}
|
| +
|
| +TestChromeBrowserState* TestChromeBrowserState::AsTestChromeBrowserState() {
|
| + return this;
|
| +}
|
| +
|
| +void TestChromeBrowserState::CreateWebDataService() {
|
| + ignore_result(
|
| + ios::WebDataServiceFactory::GetInstance()->SetTestingFactoryAndUse(
|
| + this, &BuildWebDataService));
|
| +
|
| + // Wait a bit after creating the WebDataService to allow the initialisation
|
| + // to complete (otherwise the TestChromeBrowserState may be destroyed before
|
| + // initialisation of the database is complete which leads to SQL init errors).
|
| + base::RunLoop run_loop;
|
| + run_loop.RunUntilIdle();
|
| +}
|
| +
|
| +void TestChromeBrowserState::CreateBookmarkModel(bool delete_file) {
|
| + if (delete_file) {
|
| + base::DeleteFile(GetOriginalChromeBrowserState()->GetStatePath().Append(
|
| + bookmarks::kBookmarksFileName),
|
| + false /* recursive */);
|
| + }
|
| + ignore_result(
|
| + ios::BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse(
|
| + this, &BuildBookmarkModel));
|
| +}
|
| +
|
| +bool TestChromeBrowserState::CreateHistoryService(bool delete_file) {
|
| + // Ensure that no HistoryService exists before creating a new one.
|
| + DestroyHistoryService();
|
| +
|
| + if (delete_file) {
|
| + base::FilePath path =
|
| + GetOriginalChromeBrowserState()->GetStatePath().Append(
|
| + history::kHistoryFilename);
|
| + if (!base::DeleteFile(path, false) && base::PathExists(path))
|
| + return false;
|
| + }
|
| +
|
| + // Create and initialize the HistoryService, but destroy it if the init fails.
|
| + history::HistoryService* history_service =
|
| + static_cast<history::HistoryService*>(
|
| + ios::HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
|
| + this, &BuildHistoryService));
|
| + if (!history_service->Init(
|
| + GetPrefs()->GetString(prefs::kAcceptLanguages),
|
| + history::HistoryDatabaseParamsForPath(
|
| + GetOriginalChromeBrowserState()->GetStatePath()))) {
|
| + ios::HistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr);
|
| + return false;
|
| + }
|
| +
|
| + // Some tests expect that CreateHistoryService() will also make the
|
| + // InMemoryURLIndex available.
|
| + ios::InMemoryURLIndexFactory::GetInstance()->SetTestingFactory(
|
| + this, ios::InMemoryURLIndexFactory::GetDefaultFactory());
|
| + // Disable WebHistoryService by default, since it makes network requests.
|
| + ios::WebHistoryServiceFactory::GetInstance()->SetTestingFactory(this,
|
| + nullptr);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void TestChromeBrowserState::DestroyHistoryService() {
|
| + history::HistoryService* history_service =
|
| + ios::HistoryServiceFactory::GetInstance()->GetForBrowserStateIfExists(
|
| + this, ServiceAccessType::EXPLICIT_ACCESS);
|
| + if (!history_service)
|
| + return;
|
| +
|
| + history_service->ClearCachedDataForContextID(0);
|
| + history_service->SetOnBackendDestroyTask(
|
| + base::MessageLoop::QuitWhenIdleClosure());
|
| + history_service->Shutdown();
|
| + history_service = nullptr;
|
| +
|
| + // Resetting the testing factory force the destruction of the current
|
| + // HistoryService instance associated with the TestChromeBrowserState.
|
| + ios::HistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr);
|
| +
|
| + // Wait for the backend class to terminate before deleting the files and
|
| + // moving to the next test. Note: if this never terminates, somebody is
|
| + // probably leaking a reference to the history backend, so it never calls
|
| + // our destroy task.
|
| + base::MessageLoop::current()->Run();
|
| +
|
| + // Make sure we don't have any event pending that could disrupt the next
|
| + // test.
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
|
| + base::MessageLoop::current()->Run();
|
| +}
|
| +
|
| +syncable_prefs::TestingPrefServiceSyncable*
|
| +TestChromeBrowserState::GetTestingPrefService() {
|
| + DCHECK(prefs_);
|
| + DCHECK(testing_prefs_);
|
| + return testing_prefs_;
|
| +}
|
| +
|
| +TestChromeBrowserState::Builder::Builder() : build_called_(false) {}
|
| +
|
| +TestChromeBrowserState::Builder::~Builder() {}
|
| +
|
| +void TestChromeBrowserState::Builder::AddTestingFactory(
|
| + BrowserStateKeyedServiceFactory* service_factory,
|
| + BrowserStateKeyedServiceFactory::TestingFactoryFunction cb) {
|
| + DCHECK(!build_called_);
|
| + testing_factories_.push_back(std::make_pair(service_factory, cb));
|
| +}
|
| +
|
| +void TestChromeBrowserState::Builder::AddTestingFactory(
|
| + RefcountedBrowserStateKeyedServiceFactory* service_factory,
|
| + RefcountedBrowserStateKeyedServiceFactory::TestingFactoryFunction cb) {
|
| + DCHECK(!build_called_);
|
| + refcounted_testing_factories_.push_back(std::make_pair(service_factory, cb));
|
| +}
|
| +
|
| +void TestChromeBrowserState::Builder::SetPath(const base::FilePath& path) {
|
| + DCHECK(!build_called_);
|
| + state_path_ = path;
|
| +}
|
| +
|
| +void TestChromeBrowserState::Builder::SetPrefService(
|
| + scoped_ptr<syncable_prefs::PrefServiceSyncable> prefs) {
|
| + DCHECK(!build_called_);
|
| + pref_service_ = std::move(prefs);
|
| +}
|
| +
|
| +scoped_ptr<TestChromeBrowserState> TestChromeBrowserState::Builder::Build() {
|
| + DCHECK(!build_called_);
|
| + return make_scoped_ptr(new TestChromeBrowserState(
|
| + state_path_, std::move(pref_service_), testing_factories_,
|
| + refcounted_testing_factories_));
|
| +}
|
|
|