[go: nahoru, domu]

blob: 06baa8a5e54f4636393425690568993707768682 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_service_test_base.h"
#include <utility>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_garbage_collector_factory.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/load_error_reporter.h"
#include "chrome/browser/extensions/shared_module_service.h"
#include "chrome/browser/extensions/test_extension_system.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/signin/test_signin_client_builder.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/crx_file/crx_verifier.h"
#include "components/policy/core/common/policy_service_impl.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/supervised_user/core/common/buildflags.h"
#include "components/sync_preferences/pref_service_mock_factory.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/pref_names.h"
#include "extensions/common/extensions_client.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/extensions/install_limiter.h"
#endif
namespace extensions {
namespace {
// Create a testing profile according to |params|.
std::unique_ptr<TestingProfile> BuildTestingProfile(
const ExtensionServiceTestBase::ExtensionServiceInitParams& params,
base::ScopedTempDir& temp_dir,
policy::PolicyService* policy_service) {
TestingProfile::Builder profile_builder;
if (!temp_dir.CreateUniqueTempDir()) {
return nullptr;
}
base::FilePath profile_dir =
temp_dir.GetPath().Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
if (base::File::Error error = base::File::FILE_OK;
!base::CreateDirectoryAndGetError(profile_dir, &error)) {
LOG(ERROR) << "Failed to create profile directory: " << error;
return nullptr;
}
// If pref_file is empty, TestingProfile automatically creates
// sync_preferences::TestingPrefServiceSyncable instance.
if (params.prefs_content.has_value()) {
base::FilePath prefs_path =
profile_dir.Append(chrome::kPreferencesFilename);
if (!base::WriteFile(prefs_path, params.prefs_content.value())) {
LOG(ERROR) << "Failed to write a prefs file";
return nullptr;
}
// Create a PrefService that only contains user defined preference values
// and policies.
sync_preferences::PrefServiceMockFactory factory;
factory.SetUserPrefsFile(
prefs_path, base::SingleThreadTaskRunner::GetCurrentDefault().get());
factory.SetManagedPolicies(policy_service,
g_browser_process->browser_policy_connector());
scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
new user_prefs::PrefRegistrySyncable);
std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs(
factory.CreateSyncable(registry.get()));
RegisterUserProfilePrefs(registry.get());
profile_builder.SetPrefService(std::move(prefs));
}
base::FilePath extensions_install_dir =
profile_dir.AppendASCII(extensions::kInstallDirectoryName);
if (!base::DeletePathRecursively(extensions_install_dir)) {
LOG(ERROR) << "Failed to clean extensions directory";
return nullptr;
}
if (params.extensions_dir.empty()) {
if (base::File::Error error = base::File::FILE_OK;
!base::CreateDirectoryAndGetError(extensions_install_dir, &error)) {
LOG(ERROR) << "Failed to create extensions directory: " << error;
return nullptr;
}
} else {
if (!base::CopyDirectory(params.extensions_dir, extensions_install_dir,
true)) {
LOG(ERROR) << "Failed to copy extensions directory";
return nullptr;
}
}
if (params.profile_is_supervised) {
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
profile_builder.SetIsSupervisedProfile();
#endif
}
if (params.profile_is_guest) {
profile_builder.SetGuestSession();
}
if (params.enable_bookmark_model) {
profile_builder.AddTestingFactory(
BookmarkModelFactory::GetInstance(),
BookmarkModelFactory::GetDefaultFactory());
profile_builder.AddTestingFactory(
ManagedBookmarkServiceFactory::GetInstance(),
ManagedBookmarkServiceFactory::GetDefaultFactory());
}
profile_builder.AddTestingFactory(
ChromeSigninClientFactory::GetInstance(),
base::BindRepeating(&signin::BuildTestSigninClient));
profile_builder.AddTestingFactories(
IdentityTestEnvironmentProfileAdaptor::
GetIdentityTestEnvironmentFactories());
// TODO(crbug.com/1222596): SyncService instantiation can be scoped down to
// a few derived fixtures.
profile_builder.AddTestingFactory(SyncServiceFactory::GetInstance(),
SyncServiceFactory::GetDefaultFactory());
profile_builder.SetPath(profile_dir);
return profile_builder.Build();
}
} // namespace
ExtensionServiceTestBase::ExtensionServiceInitParams::
ExtensionServiceInitParams() = default;
ExtensionServiceTestBase::ExtensionServiceInitParams::
ExtensionServiceInitParams(const ExtensionServiceInitParams& other) =
default;
ExtensionServiceTestBase::ExtensionServiceInitParams::
~ExtensionServiceInitParams() = default;
bool ExtensionServiceTestBase::ExtensionServiceInitParams::
SetPrefsContentFromFile(const base::FilePath& filepath) {
std::string content;
if (!base::ReadFileToString(filepath, &content)) {
return false;
}
prefs_content.emplace(std::move(content));
return true;
}
bool ExtensionServiceTestBase::ExtensionServiceInitParams::
ConfigureByTestDataDirectory(const base::FilePath& filepath) {
if (!SetPrefsContentFromFile(filepath.Append(chrome::kPreferencesFilename))) {
return false;
}
extensions_dir = filepath.AppendASCII(extensions::kInstallDirectoryName);
return true;
}
ExtensionServiceTestBase::ExtensionServiceTestBase()
: ExtensionServiceTestBase(
std::make_unique<content::BrowserTaskEnvironment>(
base::test::TaskEnvironment::MainThreadType::IO)) {}
ExtensionServiceTestBase::ExtensionServiceTestBase(
std::unique_ptr<content::BrowserTaskEnvironment> task_environment)
: task_environment_(std::move(task_environment)),
service_(nullptr),
testing_local_state_(TestingBrowserProcess::GetGlobal()),
registry_(nullptr),
verifier_format_override_(crx_file::VerifierFormat::CRX3) {
base::FilePath test_data_dir;
if (!base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)) {
ADD_FAILURE();
return;
}
data_dir_ = test_data_dir.AppendASCII("extensions");
policy_service_ = std::make_unique<policy::PolicyServiceImpl>(
std::vector<policy::ConfigurationPolicyProvider*>{&policy_provider_});
}
ExtensionServiceTestBase::~ExtensionServiceTestBase() {
// Why? Because |profile_| has to be destroyed before |at_exit_manager_|, but
// is declared above it in the class definition since it's protected.
// TODO(1269752): Since we're getting rid of at_exit_manager_, perhaps
// we don't need this call?
profile_.reset();
}
void ExtensionServiceTestBase::InitializeExtensionService(
const ExtensionServiceTestBase::ExtensionServiceInitParams& params) {
profile_ = BuildTestingProfile(params, temp_dir_, policy_service_.get());
extensions_install_dir_ =
profile_->GetPath().AppendASCII(extensions::kInstallDirectoryName);
CreateExtensionService(params);
registry_ = ExtensionRegistry::Get(profile());
// Garbage collector is typically NULL during tests, so give it a build.
ExtensionGarbageCollectorFactory::GetInstance()->SetTestingFactoryAndUse(
profile(),
base::BindRepeating(&ExtensionGarbageCollectorFactory::BuildInstanceFor));
}
void ExtensionServiceTestBase::InitializeEmptyExtensionService() {
ExtensionServiceInitParams params;
params.prefs_content = "";
InitializeExtensionService(params);
}
void ExtensionServiceTestBase::InitializeGoodInstalledExtensionService() {
ExtensionServiceInitParams params;
ASSERT_TRUE(
params.ConfigureByTestDataDirectory(data_dir().AppendASCII("good")));
InitializeExtensionService(params);
}
void ExtensionServiceTestBase::InitializeExtensionServiceWithUpdater() {
ExtensionServiceInitParams params;
params.autoupdate_enabled = true;
InitializeExtensionService(params);
service_->updater()->Start();
}
void ExtensionServiceTestBase::
InitializeExtensionServiceWithExtensionsDisabled() {
ExtensionServiceInitParams params;
params.extensions_enabled = false;
InitializeExtensionService(params);
}
size_t ExtensionServiceTestBase::GetPrefKeyCount() {
const base::Value::Dict& dict =
profile()->GetPrefs()->GetDict(pref_names::kExtensions);
return dict.size();
}
void ExtensionServiceTestBase::ValidatePrefKeyCount(size_t count) {
EXPECT_EQ(count, GetPrefKeyCount());
}
testing::AssertionResult ExtensionServiceTestBase::ValidateBooleanPref(
const std::string& extension_id,
const std::string& pref_path,
bool expected_val) {
std::string msg = base::StringPrintf("while checking: %s %s == %s",
extension_id.c_str(), pref_path.c_str(),
expected_val ? "true" : "false");
PrefService* prefs = profile()->GetPrefs();
const base::Value::Dict& dict = prefs->GetDict(pref_names::kExtensions);
const base::Value::Dict* pref = dict.FindDict(extension_id);
if (!pref) {
return testing::AssertionFailure()
<< "extension pref does not exist " << msg;
}
absl::optional<bool> val = pref->FindBoolByDottedPath(pref_path);
if (!val.has_value()) {
return testing::AssertionFailure()
<< pref_path << " pref not found " << msg;
}
return expected_val == val.value() ? testing::AssertionSuccess()
: testing::AssertionFailure()
<< "base::Value is incorrect "
<< msg;
}
void ExtensionServiceTestBase::ValidateIntegerPref(
const std::string& extension_id,
const std::string& pref_path,
int expected_val) {
std::string msg = base::StringPrintf(
"while checking: %s %s == %s", extension_id.c_str(), pref_path.c_str(),
base::NumberToString(expected_val).c_str());
PrefService* prefs = profile()->GetPrefs();
const base::Value::Dict& dict = prefs->GetDict(pref_names::kExtensions);
const base::Value::Dict* pref = dict.FindDict(extension_id);
ASSERT_TRUE(pref) << msg;
EXPECT_EQ(expected_val, pref->FindIntByDottedPath(pref_path)) << msg;
}
void ExtensionServiceTestBase::ValidateStringPref(
const std::string& extension_id,
const std::string& pref_path,
const std::string& expected_val) {
std::string msg = base::StringPrintf("while checking: %s.manifest.%s == %s",
extension_id.c_str(), pref_path.c_str(),
expected_val.c_str());
const base::Value::Dict& dict =
profile()->GetPrefs()->GetDict(pref_names::kExtensions);
std::string manifest_path = extension_id + ".manifest";
const base::Value::Dict* pref = dict.FindDictByDottedPath(manifest_path);
ASSERT_TRUE(pref) << msg;
const std::string* val = pref->FindStringByDottedPath(pref_path);
ASSERT_TRUE(val) << msg;
EXPECT_EQ(expected_val, *val) << msg;
}
void ExtensionServiceTestBase::SetUp() {
LoadErrorReporter::GetInstance()->ClearErrors();
// Force TabManager/TabLifecycleUnitSource creation.
g_browser_process->resource_coordinator_parts();
// Update the webstore update url. Some tests leave it set to a non-default
// webstore_update_url_. This can make extension_urls::IsWebstoreUpdateUrl
// return a false negative.
ExtensionsClient::Get()->InitializeWebStoreUrls(
base::CommandLine::ForCurrentProcess());
#if BUILDFLAG(IS_CHROMEOS_ASH)
kiosk_app_manager_ = std::make_unique<ash::KioskAppManager>();
#endif
}
void ExtensionServiceTestBase::TearDown() {
if (profile_) {
content::StoragePartitionConfig default_storage_partition_config =
content::StoragePartitionConfig::CreateDefault(profile());
auto* partition = profile_->GetStoragePartition(
default_storage_partition_config, /*can_create=*/false);
if (partition)
partition->WaitForDeletionTasksForTesting();
}
policy_provider_.Shutdown();
#if BUILDFLAG(IS_CHROMEOS_ASH)
kiosk_app_manager_.reset();
#endif
}
void ExtensionServiceTestBase::SetUpTestCase() {
// Safe to call multiple times.
LoadErrorReporter::Init(false); // no noisy errors.
}
// These are declared in the .cc so that all inheritors don't need to know
// that TestingProfile derives Profile derives BrowserContext.
content::BrowserContext* ExtensionServiceTestBase::browser_context() {
return profile();
}
Profile* ExtensionServiceTestBase::profile() {
// TODO(crbug.com/1414225): Refactor this convenience upstream to test callers.
// Possibly just BuiltInAppTest.BuildGuestMode.
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (profile_->IsGuestSession())
return profile_->GetPrimaryOTRProfile(/*create_if_needed=*/true);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
return profile_.get();
}
sync_preferences::TestingPrefServiceSyncable*
ExtensionServiceTestBase::testing_pref_service() {
return profile_->GetTestingPrefService();
}
void ExtensionServiceTestBase::CreateExtensionService(
const ExtensionServiceInitParams& params) {
TestExtensionSystem* system =
static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile()));
if (!params.is_first_run)
ExtensionPrefs::Get(profile())->SetAlertSystemFirstRun();
service_ = system->CreateExtensionService(
base::CommandLine::ForCurrentProcess(), extensions_install_dir_,
params.autoupdate_enabled, params.extensions_enabled);
service_->component_loader()->set_ignore_allowlist_for_testing(true);
// When we start up, we want to make sure there is no external provider,
// since the ExtensionService on Windows will use the Registry as a default
// provider and if there is something already registered there then it will
// interfere with the tests. Those tests that need an external provider
// will register one specifically.
service_->ClearProvidersForTesting();
service_->RegisterInstallGate(ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS,
service_->shared_module_service());
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!params.enable_install_limiter)
InstallLimiter::Get(profile())->DisableForTest();
#endif
}
} // namespace extensions