blob: 643a36e1c6b11fef1fc5c835e11bc85a59b22b99 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/test/unittest_test_suite.h"
#include <memory>
#include "base/base_switches.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/rand_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/null_task_runner.h"
#include "base/test/test_suite.h"
#include "build/build_config.h"
#include "components/breadcrumbs/core/breadcrumb_manager.h"
#include "components/breadcrumbs/core/crash_reporter_breadcrumb_observer.h"
#include "content/app/mojo/mojo_init.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/network_service_instance_impl.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/common/content_client.h"
#include "content/public/test/content_test_suite_base.h"
#include "content/public/test/scoped_web_ui_controller_factory_registration.h"
#include "content/public/test/test_host_resolver.h"
#include "content/public/utility/content_utility_client.h"
#include "content/test/test_blink_web_unit_test_support.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_content_client.h"
#include "mojo/core/embedder/embedder.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/web/blink.h"
#include "ui/base/resource/resource_bundle.h"
#if defined(USE_AURA)
#include "ui/aura/env.h"
#endif
namespace content {
class UnitTestTestSuite::UnitTestEventListener
: public testing::EmptyTestEventListener {
public:
UnitTestEventListener(
base::RepeatingCallback<
std::unique_ptr<UnitTestTestSuite::ContentClients>()> create_clients,
base::OnceClosure first_test_start_callback)
: create_clients_(create_clients),
first_test_start_callback_(std::move(first_test_start_callback)) {}
UnitTestEventListener(const UnitTestEventListener&) = delete;
UnitTestEventListener& operator=(const UnitTestEventListener&) = delete;
void InitializeObjects() {
test_network_connection_tracker_ =
network::TestNetworkConnectionTracker::CreateInstance();
SetNetworkConnectionTrackerForTesting(
network::TestNetworkConnectionTracker::GetInstance());
content_clients_ = create_clients_.Run();
CHECK(content_clients_->content_client.get());
SetContentClient(content_clients_->content_client.get());
SetBrowserClientForTesting(content_clients_->content_browser_client.get());
SetUtilityClientForTesting(content_clients_->content_utility_client.get());
browser_accessibility_state_ = BrowserAccessibilityStateImpl::Create();
// Prevent accessibility from being turned on by the platform so that the
// tests can run undisturbed.
browser_accessibility_state_->SetActivationFromPlatformEnabled(false);
if (first_test_start_callback_)
std::move(first_test_start_callback_).Run();
}
void OnTestStart(const testing::TestInfo& test_info) override {
InitializeObjects();
}
void OnTestEnd(const testing::TestInfo& test_info) override {
browser_accessibility_state_.reset();
// Don't call SetUtilityClientForTesting or SetBrowserClientForTesting since
// if a test overrode ContentClient it might already be deleted and setting
// these pointers on it would result in a UAF.
SetContentClient(nullptr);
content_clients_.reset();
SetNetworkConnectionTrackerForTesting(nullptr);
test_network_connection_tracker_.reset();
// If the network::NetworkService object was instantiated during a unit test
// it will be deleted because network_service_instance.cc has it in a
// SequenceLocalStorageSlot. However we want to synchronously destruct the
// InterfacePtr pointing to it to avoid it getting the connection error
// later and have other tests use the InterfacePtr that is invalid.
ResetNetworkServiceForTesting();
breadcrumbs::BreadcrumbManager::GetInstance().ResetForTesting();
}
private:
base::RepeatingCallback<std::unique_ptr<UnitTestTestSuite::ContentClients>()>
create_clients_;
base::OnceClosure first_test_start_callback_;
std::unique_ptr<network::TestNetworkConnectionTracker>
test_network_connection_tracker_;
std::unique_ptr<UnitTestTestSuite::ContentClients> content_clients_;
std::unique_ptr<BrowserAccessibilityStateImpl> browser_accessibility_state_;
};
UnitTestTestSuite::ContentClients::ContentClients() = default;
UnitTestTestSuite::ContentClients::~ContentClients() = default;
std::unique_ptr<UnitTestTestSuite::ContentClients>
UnitTestTestSuite::CreateTestContentClients() {
auto clients = std::make_unique<UnitTestTestSuite::ContentClients>();
clients->content_client = std::make_unique<TestContentClient>();
clients->content_browser_client =
std::make_unique<TestContentBrowserClient>();
return clients;
}
static UnitTestTestSuite* g_test_suite = nullptr;
UnitTestTestSuite::UnitTestTestSuite(
base::TestSuite* test_suite,
base::RepeatingCallback<std::unique_ptr<ContentClients>()> create_clients,
std::optional<mojo::core::Configuration> child_mojo_config)
: test_suite_(test_suite), create_clients_(create_clients) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
std::string enabled =
command_line->GetSwitchValueASCII(switches::kEnableFeatures);
std::string disabled =
command_line->GetSwitchValueASCII(switches::kDisableFeatures);
ForceCreateNetworkServiceDirectlyForTesting();
StoragePartitionImpl::ForceInProcessStorageServiceForTesting();
testing::TestEventListeners& listeners =
testing::UnitTest::GetInstance()->listeners();
listeners.Append(CreateTestEventListener());
listeners.Append(new CheckForLeakedWebUIRegistrations);
scoped_feature_list_.InitFromCommandLine(enabled, disabled);
mojo::core::InitFeatures();
if (command_line->HasSwitch(switches::kTestChildProcess)) {
// Note that in the main test process, TestBlinkWebUnitTestSupport
// initializes Mojo; so we only do this in child processes.
mojo::core::Init(child_mojo_config.value_or(mojo::core::Configuration{}));
} else {
mojo::core::Init(mojo::core::Configuration{.is_broker_process = true});
}
DCHECK(test_suite);
test_host_resolver_ = std::make_unique<TestHostResolver>();
g_test_suite = this;
}
UnitTestTestSuite::~UnitTestTestSuite() {
CHECK(g_test_suite == this);
g_test_suite = nullptr;
}
int UnitTestTestSuite::Run() {
#if defined(USE_AURA)
std::unique_ptr<aura::Env> aura_env = aura::Env::CreateInstance();
#endif
std::unique_ptr<url::ScopedSchemeRegistryForTests> scheme_registry;
// TestEventListeners repeater event propagation is disabled in death test
// child process so create and set the clients here for it.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
"gtest_internal_run_death_test")) {
// TestSuite::Initialize hasn't run yet, which is what initializes the
// ResourceBundle. This will be needed by Blink initialization to load
// resources, so do it temporarily here.
ContentTestSuiteBase::InitializeResourceBundle();
CreateTestEventListener()->InitializeObjects();
// Since Blink initialization ended up using the SchemeRegistry, reset
// that it was accessed before testSuite::Initialize registers its schemes.
scheme_registry = std::make_unique<url::ScopedSchemeRegistryForTests>();
ui::ResourceBundle::CleanupSharedInstance();
}
return test_suite_->Run();
}
UnitTestTestSuite::UnitTestEventListener*
UnitTestTestSuite::CreateTestEventListener() {
return new UnitTestEventListener(
create_clients_,
base::BindOnce(&UnitTestTestSuite::OnFirstTestStartComplete,
base::Unretained(this)));
}
void UnitTestTestSuite::OnFirstTestStartComplete() {
// At this point ContentClient and ResourceBundle will be initialized, which
// this needs.
blink_test_support_ = std::make_unique<TestBlinkWebUnitTestSupport>(
TestBlinkWebUnitTestSupport::SchedulerType::kMockScheduler,
" --single-threaded");
// Dummy task runner is initialized because blink::CreateMainThreadIsolate
// needs the current task runner handle and TestBlinkWebUnitTestSupport
// initialized with kMockScheduler doesn't provide one. There should be no
// task posted to this task runner. The message loop is not created before
// this initialization because some tests need specific kinds of message
// loops, and their types are not known upfront. Some tests also create their
// own thread bundles or message loops, and doing the same in
// TestBlinkWebUnitTestSupport would introduce a conflict.
auto dummy_task_runner = base::MakeRefCounted<base::NullTaskRunner>();
auto dummy_task_runner_handle =
std::make_unique<base::SingleThreadTaskRunner::CurrentDefaultHandle>(
dummy_task_runner);
isolate_ = blink::CreateMainThreadIsolate();
}
v8::Isolate* UnitTestTestSuite::MainThreadIsolateForUnitTestSuite() {
CHECK(g_test_suite);
CHECK(g_test_suite->blink_test_support_);
return g_test_suite->isolate_.get();
}
} // namespace content