#include "content/public/test/browser_test_base.h"
#include <fcntl.h>
#include <stddef.h>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "base/base_switches.h"
#include "base/callback_list.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "base/trace_event/typed_macros.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
#include "components/tracing/common/tracing_switches.h"
#include "components/variations/variations_ids_provider.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/network_service_instance_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/scheduler/browser_task_executor.h"
#include "content/browser/startup_data_impl.h"
#include "content/browser/startup_helper.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/tracing/background_tracing_manager_impl.h"
#include "content/browser/tracing/memory_instrumentation_util.h"
#include "content/browser/tracing/startup_tracing_controller.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/app/content_main.h"
#include "content/public/app/initialize_mojo_core.h"
#include "content/public/browser/browser_main_parts.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/network_service_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/no_renderer_crashes_assertion.h"
#include "content/public/test/test_launcher.h"
#include "content/public/test/test_utils.h"
#include "content/test/content_browser_consistency_checker.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_switches.h"
#include "media/base/media_switches.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "mojo/public/cpp/platform/named_platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "net/dns/mock_host_resolver.h"
#include "net/dns/public/dns_over_https_server_config.h"
#include "net/dns/public/secure_dns_mode.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#include "services/tracing/public/cpp/trace_startup.h"
#include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
#include "ui/base/ui_base_features.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/display/display_switches.h"
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/gfx/scoped_animation_duration_scale_mode.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "ui/platform_window/common/platform_window_defaults.h"
#endif
#if BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE)
#include "ui/events/ozone/events_ozone.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "base/android/task_scheduler/post_task_android.h"
#include "base/memory_coordinator/memory_consumer_registry.h"
#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "content/app/content_main_runner_impl.h"
#include "content/app/mojo/mojo_init.h"
#include "content/app/mojo_ipc_support.h"
#include "content/browser/memory_coordinator/browser_memory_consumer_registry.h"
#include "content/public/app/content_main_delegate.h"
#include "content/public/common/content_paths.h"
#include "testing/android/native_test/native_browser_test_support.h"
#include "ui/base/ui_base_paths.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "content/browser/sandbox_parameters_mac.h"
#include "net/test/test_data_directory.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/test/event_generator_delegate_mac.h"
#endif
#if BUILDFLAG(IS_POSIX)
#include "base/process/process_handle.h"
#endif
#if defined(USE_AURA)
#include "content/browser/compositor/image_transport_factory.h"
#include "ui/aura/test/event_generator_delegate_aura.h"
#endif
#if BUILDFLAG(IS_FUCHSIA)
#include "base/fuchsia/system_info.h"
#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <shlobj.h>
#include "base/test/test_reg_util_win.h"
#endif
namespace content {
namespace {
bool g_instance_already_created = false;
#if BUILDFLAG(IS_POSIX)
int g_browser_process_pid;
base::OnceCallback<void(int)> ShutdownHandler;
void SignalHandler(int signal) {
std::move(ShutdownHandler).Run(signal);
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableInProcessStackTraces) &&
g_browser_process_pid == base::GetCurrentProcId()) {
std::string message("BrowserTestBase received signal: ");
message += strsignal(signal);
message += ". Backtrace:\n";
logging::RawLog(logging::LOGGING_ERROR, message.c_str());
auto stack_trace = base::debug::StackTrace();
stack_trace.OutputToStream(&std::cerr);
#if BUILDFLAG(IS_ANDROID)
stack_trace.Print();
#endif
}
_exit(128 + signal);
}
#endif
void RunTaskOnRendererThread(base::OnceClosure task,
base::OnceClosure quit_task) {
std::move(task).Run();
GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(quit_task));
}
enum class TraceBasenameType {
kWithoutTestStatus,
kWithTestStatus,
};
std::string GetDefaultTraceBasename(TraceBasenameType type) {
const testing::TestInfo* test_info =
::testing::UnitTest::GetInstance()->current_test_info();
std::string test_suite_name = "<unknown>";
std::string test_name = "<unknown>";
if (test_info) {
test_suite_name = test_info->test_suite_name();
test_name = test_info->name();
}
base::ReplaceChars(test_suite_name, "/", "_", &test_suite_name);
base::ReplaceChars(test_name, "/", "_", &test_name);
static std::string random_seed =
base::NumberToString(base::RandInt(1e7, 1e8 - 1));
std::string status;
if (type == TraceBasenameType::kWithTestStatus) {
if (test_info) {
status = test_info->result()->Passed() ? "OK" : "FAIL";
} else {
status = "UNKNOWN";
}
} else {
status = "NOT_FINISHED";
}
return "trace_test_" + test_suite_name + "_" + test_name + "_" + random_seed +
"_" + status;
}
class InitialNavigationObserver : public WebContentsObserver {
public:
InitialNavigationObserver(WebContents* web_contents,
base::OnceClosure callback)
: WebContentsObserver(web_contents), callback_(std::move(callback)) {}
InitialNavigationObserver(const InitialNavigationObserver&) = delete;
InitialNavigationObserver& operator=(const InitialNavigationObserver&) =
delete;
void DidStartNavigation(NavigationHandle* navigation_handle) override {
if (callback_)
std::move(callback_).Run();
}
private:
base::OnceClosure callback_;
};
}
BrowserTestBase::BrowserTestBase() {
CHECK(!g_instance_already_created)
<< "Each browser test should be run in a new process. If you are adding "
"a new browser test suite that runs on Android, please add it to "
"//build/android/pylib/gtest/gtest_test_instance.py.";
g_instance_already_created = true;
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ui::test::EnableTestConfigForPlatformWindows();
#endif
#if BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE)
ui::DisableNativeUiEventDispatchForTest();
#endif
#if BUILDFLAG(IS_POSIX)
handle_sigterm_ = true;
#endif
#if BUILDFLAG(IS_WIN)
registry_util::RegistryOverrideManager::
SetAllowHKLMRegistryOverrideForIntegrationTests(false);
#endif
embedded_test_server_ = std::make_unique<net::EmbeddedTestServer>();
#if BUILDFLAG(IS_WIN)
if (::IsUserAnAdmin()) {
system_temp_override_.emplace(base::DIR_SYSTEM_TEMP,
base::PathService::CheckedGet(base::DIR_TEMP),
true, false);
}
#endif
#if defined(USE_AURA)
ui::test::EventGeneratorDelegate::SetFactoryFunction(
base::BindRepeating(&aura::test::EventGeneratorDelegateAura::Create));
#elif BUILDFLAG(IS_MAC)
ui::test::EventGeneratorDelegate::SetFactoryFunction(
base::BindRepeating(&views::test::CreateEventGeneratorDelegateMac));
EnableNativeWindowActivation();
#endif
}
BrowserTestBase::~BrowserTestBase() {
CHECK(set_up_called_ || IsSkipped() || HasFatalFailure())
<< "SetUp was not called. This probably means that the "
"developer has overridden the method and not called "
"the superclass version. In this case, the test "
"does not run and reports a false positive result.";
}
void BrowserTestBase::SetUp() {
set_up_called_ = true;
if (!UseProductionQuotaSettings()) {
const int kQuota = 5 * 1024 * 1024;
quota_settings_ =
std::make_unique<storage::QuotaSettings>(kQuota * 5, kQuota, 0, 0);
StoragePartitionImpl::SetDefaultQuotaSettingsForTesting(
quota_settings_.get());
}
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(network::switches::kIpAddressSpaceOverrides)) {
command_line->AppendSwitchASCII(network::switches::kIpAddressSpaceOverrides,
"127.0.0.1:0=public,[::1]:0=public");
}
if (use_fake_media_stream_devices_ &&
!command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) {
command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
}
command_line->AppendSwitch(switches::kBrowserTest);
command_line->AppendSwitchASCII(
switches::kIPCConnectionTimeout,
base::NumberToString(TestTimeouts::action_max_timeout().InSeconds()));
command_line->AppendSwitch(switches::kLogMissingUnloadACK);
command_line->AppendSwitch(switches::kDomAutomationController);
command_line->AppendSwitch(switches::kLogGpuControlListDecisions);
if (use_software_compositing_) {
command_line->AppendSwitch(switches::kDisableGpu);
command_line->RemoveSwitch(switches::kDisableSoftwareCompositingFallback);
}
command_line->AppendSwitch(switches::kDisableD3D11Warp);
command_line->AppendSwitch(
switches::kDisableBackgroundingOccludedWindowsForTesting);
command_line->AppendSwitch(switches::kDisableIgnoreDuplicateNavsForTesting);
if (enable_pixel_output_) {
DCHECK(!command_line->HasSwitch(switches::kForceDeviceScaleFactor))
<< "--force-device-scale-factor flag already present. Tests using "
<< "EnablePixelOutput should specify a forced device scale factor by "
<< "passing it as an argument to EnblePixelOutput.";
DCHECK(force_device_scale_factor_);
command_line->AppendSwitchASCII(
switches::kForceDeviceScaleFactor,
base::StringPrintf("%f", force_device_scale_factor_));
}
#if defined(USE_AURA)
if (command_line->HasSwitch(switches::kEnablePixelOutputInTests))
enable_pixel_output_ = true;
if (command_line->HasSwitch(switches::kDisableGLDrawingForTests)) {
NOTREACHED() << "kDisableGLDrawingForTests should not be used as it "
"is chosen by tests. Use kEnablePixelOutputInTests "
"to enable pixel output.";
}
if (!enable_pixel_output_ && !use_software_compositing_)
command_line->AppendSwitch(switches::kDisableGLDrawingForTests);
#endif
if (command_line->HasSwitch(switches::kVerifyPixels)) {
disable_layer_animations_ =
std::make_unique<gfx::ScopedAnimationDurationScaleMode>(
gfx::ScopedAnimationDurationScaleMode::ZERO_DURATION);
disable_rich_animations_ =
gfx::AnimationTestApi::SetRichAnimationRenderMode(
gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED);
}
bool use_software_gl = true;
if (command_line->HasSwitch(switches::kUseGpuInTests))
use_software_gl = false;
if (command_line->HasSwitch("enable-gpu"))
use_software_gl = false;
#if BUILDFLAG(IS_APPLE)
use_software_gl = false;
#endif
#if BUILDFLAG(IS_MAC)
SetNetworkTestCertsDirectoryForTesting(net::GetTestCertsDirectory());
#endif
#if BUILDFLAG(IS_ANDROID)
use_software_gl = false;
#endif
#if BUILDFLAG(IS_FUCHSIA)
command_line->AppendSwitch(switches::kDisableGpu);
ui::fuchsia::IgnorePresentCallsForTest();
base::ClearCachedSystemInfoForTesting();
#endif
if (use_software_gl && !use_software_compositing_)
command_line->AppendSwitch(switches::kOverrideUseSoftwareGLForTests);
command_line->AppendSwitchASCII(switches::kForceDisplayColorProfile, "srgb");
if (!allow_network_access_to_host_resolutions_)
test_host_resolver_ = std::make_unique<TestHostResolver>();
ContentBrowserConsistencyChecker scoped_enable_consistency_checks;
SetUpInProcessBrowserTestFixture();
std::string command_line_enable_features;
std::string command_line_disable_features;
if (allow_features_switches_) {
if (command_line->HasSwitch(switches::kEnableFeatures)) {
command_line_enable_features =
command_line->GetSwitchValueASCII(switches::kEnableFeatures);
command_line->RemoveSwitch(switches::kEnableFeatures);
}
if (command_line->HasSwitch(switches::kDisableFeatures)) {
command_line_disable_features =
command_line->GetSwitchValueASCII(switches::kDisableFeatures);
command_line->RemoveSwitch(switches::kDisableFeatures);
}
} else {
DCHECK(!command_line->HasSwitch(switches::kEnableFeatures));
DCHECK(!command_line->HasSwitch(switches::kDisableFeatures));
}
std::string enabled_features;
std::string disabled_features;
if (base::FeatureList::GetInstance()) {
base::FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
&disabled_features);
}
if (!command_line_enable_features.empty()) {
enabled_features =
base::StrCat({command_line_enable_features, ",", enabled_features});
}
if (!command_line_disable_features.empty()) {
disabled_features =
base::StrCat({command_line_disable_features, ",", disabled_features});
}
if (!enabled_features.empty()) {
command_line->AppendSwitchASCII(switches::kEnableFeatures,
enabled_features);
}
if (!disabled_features.empty()) {
command_line->AppendSwitchASCII(switches::kDisableFeatures,
disabled_features);
}
command_line->AppendSwitch(switches::kDisableGpuProcessForDX12InfoCollection);
command_line->AppendSwitch(
switches::kDisablePlatformAccessibilityIntegration);
std::string field_trial_states;
base::FieldTrialList::AllStatesToString(&field_trial_states);
if (!field_trial_states.empty()) {
DCHECK(!command_line->HasSwitch(switches::kForceFieldTrials));
command_line->AppendSwitchASCII(switches::kForceFieldTrials,
field_trial_states);
}
base::FeatureList::ClearInstanceForTesting();
auto created_main_parts_closure = base::BindOnce(
&BrowserTestBase::CreatedBrowserMainPartsImpl, base::Unretained(this));
StartupTracingController::GetInstance().SetDefaultBasename(
GetDefaultTraceBasename(TraceBasenameType::kWithoutTestStatus),
StartupTracingController::ExtensionType::kAppendAppropriate);
StartupTracingController::GetInstance().SetUsingTemporaryFile(
StartupTracingController::TempFilePolicy::kWriteDirectly);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableTracing)) {
DCHECK(!logging::GetLogMessageHandler());
logging::SetLogMessageHandler([](int severity, const char* file, int line,
size_t message_start,
const std::string& str) {
if (severity == logging::LOGGING_FATAL)
StartupTracingController::EmergencyStop();
return false;
});
}
auto content_main_params = CopyContentMainParams();
content_main_params.created_main_parts_closure =
std::move(created_main_parts_closure);
content_main_params.ui_task = base::BindOnce(
&BrowserTestBase::ProxyRunTestOnMainThreadLoop, base::Unretained(this));
ContentMainDelegate* overridden_delegate =
GetOptionalContentMainDelegateOverride();
if (overridden_delegate)
content_main_params.delegate = overridden_delegate;
#if !BUILDFLAG(IS_ANDROID)
EXPECT_EQ(expected_exit_code_, ContentMain(std::move(content_main_params)));
#else
base::ScopedMemoryConsumerRegistry<BrowserMemoryConsumerRegistry> registry;
startup_metric_utils::GetBrowser().ResetSessionForTesting();
ContentMainDelegate* delegate = content_main_params.delegate;
ASSERT_TRUE(delegate);
ASSERT_TRUE(GetContentClientForTesting());
delegate->CreateThreadPool("Browser");
std::optional<int> startup_error = delegate->BasicStartupComplete();
ASSERT_FALSE(startup_error.has_value());
{
ContentClient::SetBrowserClientAlwaysAllowForTesting(
delegate->CreateContentBrowserClient());
if (command_line->HasSwitch(switches::kSingleProcess))
SetRendererClientForTesting(delegate->CreateContentRendererClient());
content::RegisterPathProvider();
ui::RegisterPathProvider();
delegate->PreSandboxStartup();
delegate->SandboxInitialized("");
const ContentMainDelegate::InvokedInBrowserProcess invoked_in_browser{
.is_running_test = true};
DCHECK(!field_trial_list_);
if (delegate->ShouldCreateFeatureList(invoked_in_browser))
field_trial_list_ = SetUpFieldTrialsAndFeatureList();
if (delegate->ShouldInitializeMojo(invoked_in_browser))
InitializeMojoCore();
std::optional<int> pre_browser_main_exit_code = delegate->PreBrowserMain();
ASSERT_FALSE(pre_browser_main_exit_code.has_value());
BrowserTaskExecutor::Create();
auto* provider = delegate->CreateVariationsIdsProvider();
if (!provider) {
variations::VariationsIdsProvider::CreateInstance(
variations::VariationsIdsProvider::Mode::kUseSignedInState,
std::make_unique<base::DefaultClock>());
}
std::optional<int> post_early_initialization_exit_code =
delegate->PostEarlyInitialization(invoked_in_browser);
ASSERT_FALSE(post_early_initialization_exit_code.has_value());
tracing::InitTracingPostFeatureList(true,
false);
StartBrowserThreadPool();
InitializeBrowserMemoryInstrumentationClient();
}
blink::TrialTokenValidator::SetOriginTrialPolicyGetter(
base::BindRepeating([]() -> blink::OriginTrialPolicy* {
ContentClient* client = GetContentClientForTesting();
return client ? client->GetOriginTrialPolicy() : nullptr;
}));
base::FeatureList::ScopedDisallowOverrides disallow_feature_overrides(
"FeatureList overrides must happen in the test constructor, before "
"BrowserTestBase::SetUp() has run.");
discardable_shared_memory_manager_ =
std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
auto ipc_support =
std::make_unique<MojoIpcSupport>(BrowserTaskExecutor::CreateIOThread());
std::unique_ptr<StartupDataImpl> startup_data =
ipc_support->CreateBrowserStartupData();
{
base::RunLoop loop{base::RunLoop::Type::kNestableTasksAllowed};
MainFunctionParams params(command_line);
params.created_main_parts_closure =
std::move(content_main_params.created_main_parts_closure);
params.startup_data = std::move(startup_data);
params.ui_task = base::BindOnce(&BrowserTestBase::WaitUntilJavaIsReady,
base::Unretained(this), loop.QuitClosure(),
TestTimeouts::action_max_timeout());
auto exit_code = delegate->RunProcess("", std::move(params));
DCHECK(std::holds_alternative<int>(exit_code));
DCHECK_EQ(std::get<int>(exit_code), 0);
loop.Run();
}
{
base::ScopedAllowUnresponsiveTasksForTesting allow_unresponsive;
std::move(content_main_params.ui_task).Run();
}
{
base::RunLoop loop{base::RunLoop::Type::kNestableTasksAllowed};
testing::android::RunActivityTeardownCallback();
WaitUntilActivityTeardownIsFinished(loop.QuitClosure(),
TestTimeouts::action_max_timeout());
loop.Run();
}
{
base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
ShutDownNetworkService();
ipc_support.reset();
}
base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
discardable_shared_memory_manager_.reset();
base::PermanentThreadAllowance::AllowBlocking();
BrowserTaskExecutor::Shutdown();
#endif
TearDownInProcessBrowserTestFixture();
}
void BrowserTestBase::TearDown() {
if (embedded_test_server()->Started()) {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
}
if (embedded_https_test_server_ && embedded_https_test_server_->Started()) {
ASSERT_TRUE(embedded_https_test_server_->ShutdownAndWaitUntilComplete());
}
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
ui::test::EventGeneratorDelegate::SetFactoryFunction(
ui::test::EventGeneratorDelegate::FactoryFunction());
#endif
StoragePartitionImpl::SetDefaultQuotaSettingsForTesting(nullptr);
}
bool BrowserTestBase::UseProductionQuotaSettings() {
return false;
}
void BrowserTestBase::SimulateNetworkServiceCrash() {
CHECK(!IsInProcessNetworkService())
<< "Can't crash the network service if it's running in-process!";
AssertThatNetworkServiceDidNotCrash();
mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
content::GetNetworkService()->BindTestInterfaceForTesting(
network_service_test.BindNewPipeAndPassReceiver());
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
network_service_test.set_disconnect_handler(run_loop.QuitClosure());
network_service_test->SimulateCrash();
run_loop.Run();
FlushNetworkServiceInstanceForTesting();
ForceInitializeNetworkProcess();
}
void BrowserTestBase::IgnoreNetworkServiceCrashes() {
network_service_test_.reset();
}
#if BUILDFLAG(IS_ANDROID)
void BrowserTestBase::WaitUntilJavaIsReady(
base::OnceClosure quit_closure,
const base::TimeDelta& wait_retry_left) {
CHECK_GE(wait_retry_left.InMilliseconds(), 0)
<< "WaitUntilJavaIsReady() timed out.";
if (testing::android::JavaAsyncStartupTasksCompleteForBrowserTests()) {
std::move(quit_closure).Run();
return;
}
base::TimeDelta retry_interval = base::Milliseconds(100);
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&BrowserTestBase::WaitUntilJavaIsReady,
base::Unretained(this), std::move(quit_closure),
wait_retry_left - retry_interval),
retry_interval);
}
void BrowserTestBase::WaitUntilActivityTeardownIsFinished(
base::OnceClosure quit_closure,
const base::TimeDelta& wait_retry_left) {
CHECK_GE(wait_retry_left.InMilliseconds(), 0)
<< "WaitUntilActivityTeardownIsFinished() timed out.";
if (testing::android::JavaActivityTeardownCompleteForBrowserTests()) {
std::move(quit_closure).Run();
return;
}
base::TimeDelta retry_interval = base::Milliseconds(100);
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&BrowserTestBase::WaitUntilActivityTeardownIsFinished,
base::Unretained(this), std::move(quit_closure),
wait_retry_left - retry_interval),
retry_interval);
}
#endif
void BrowserTestBase::ProxyRunTestOnMainThreadLoop() {
base::ScopedAllowUnresponsiveTasksForTesting allow_for_init;
#if !BUILDFLAG(IS_ANDROID)
base::FeatureList::ScopedDisallowOverrides disallow_feature_overrides(
"FeatureList overrides must happen in the test constructor, before "
"BrowserTestBase::SetUp() has run.");
#endif
std::optional<base::test::ScopedRunLoopTimeout> scoped_run_timeout;
if (!base::test::ScopedRunLoopTimeout::ExistsForCurrentThread()) {
scoped_run_timeout.emplace(FROM_HERE, TestTimeouts::action_max_timeout());
}
#if BUILDFLAG(IS_POSIX)
g_browser_process_pid = base::GetCurrentProcId();
struct sigaction action;
action.sa_handler = SignalHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
struct sigaction old_action;
std::optional<struct sigaction> old_sigsegv_action =
sigaction(SIGSEGV, &action, &old_action) == 0 ? std::optional(old_action)
: std::nullopt;
std::optional<struct sigaction> old_sigterm_action =
handle_sigterm_ && sigaction(SIGTERM, &action, &old_action) == 0
? std::optional(old_action)
: std::nullopt;
absl::Cleanup restore_signal_handlers = [&old_sigsegv_action,
&old_sigterm_action] {
if (old_sigsegv_action) {
sigaction(SIGSEGV, &*old_sigsegv_action, nullptr);
}
if (old_sigterm_action) {
sigaction(SIGTERM, &*old_sigterm_action, nullptr);
}
};
ShutdownHandler = base::BindOnce(&BrowserTestBase::SignalRunTestOnMainThread,
base::Unretained(this));
#endif
{
DCHECK(!base::RunLoop::IsRunningOnCurrentThread());
#if !BUILDFLAG(IS_ANDROID)
no_renderer_crashes_assertion_ =
std::make_unique<NoRendererCrashesAssertion>();
#endif
PreRunTestOnMainThread();
{
TRACE_EVENT0("test", "FlushStartupTasks");
base::ScopedDisallowBlocking disallow_blocking;
base::RunLoop flush_startup_tasks;
flush_startup_tasks.RunUntilIdle();
DCHECK(!flush_startup_tasks.AnyQuitCalled());
}
std::unique_ptr<InitialNavigationObserver> initial_navigation_observer;
if (initial_web_contents_) {
initial_navigation_observer = std::make_unique<InitialNavigationObserver>(
initial_web_contents_.get(),
base::BindOnce(&BrowserTestBase::InitializeNetworkProcess,
base::Unretained(this)));
}
initial_web_contents_.reset();
base::CallbackListSubscription on_network_service_restarted_subscription =
RegisterNetworkServiceProcessGoneHandler(base::BindRepeating(
[](BrowserTestBase* browser_test_base, bool crashed) {
if (!crashed) {
browser_test_base->ForceInitializeNetworkProcess();
}
},
base::Unretained(this)));
SetUpOnMainThread();
#if BUILDFLAG(IS_WIN)
registry_util::RegistryOverrideManager::
SetAllowHKLMRegistryOverrideForIntegrationTests(true);
#endif
if (!IsSkipped()) {
initial_navigation_observer.reset();
InitializeNetworkProcess();
{
auto* test = ::testing::UnitTest::GetInstance()->current_test_info();
if (test) {
TRACE_EVENT_BEGIN(
"test", "RunTestOnMainThread", "test_name",
base::StrCat({test->test_suite_name(), ".", test->name()}),
"file", test->file(), "line", test->line());
}
base::ScopedDisallowBlocking disallow_blocking;
RunTestOnMainThread();
if (test) {
TRACE_EVENT_END("test");
}
}
}
TearDownOnMainThread();
AssertThatNetworkServiceDidNotCrash();
on_network_service_restarted_subscription = {};
}
PostRunTestOnMainThread();
content::RunAllPendingInMessageLoop();
StartupTracingController::GetInstance().SetDefaultBasename(
GetDefaultTraceBasename(TraceBasenameType::kWithTestStatus),
StartupTracingController::ExtensionType::kAppendAppropriate);
#if BUILDFLAG(IS_ANDROID)
StartupTracingController::GetInstance().WaitUntilStopped();
#endif
}
void BrowserTestBase::SetAllowNetworkAccessToHostResolutions() {
CHECK(!set_up_called_);
#if BUILDFLAG(IS_CHROMEOS_DEVICE)
CHECK(base::SysInfo::IsRunningOnChromeOS())
<< "External network access is only allowed for on device ChromeOS "
"integration tests";
#else
const char kManualTestPrefix[] = "MANUAL_";
CHECK(base::StartsWith(
testing::UnitTest::GetInstance()->current_test_info()->name(),
kManualTestPrefix, base::CompareCase::SENSITIVE));
#endif
LOG(WARNING) << "External network access is allowed. "
<< "This could lead to DoS on web sites and is normally only "
<< "allowed for manual tests and ChromeOS integration tests on "
<< "devices.";
allow_network_access_to_host_resolutions_ = true;
}
void BrowserTestBase::SetReplaceSystemDnsConfig() {
replace_system_dns_config_ = true;
}
void BrowserTestBase::SetTestDohConfig(net::SecureDnsMode secure_dns_mode,
net::DnsOverHttpsConfig config) {
DCHECK(!test_doh_config_.has_value());
test_doh_config_ = std::make_pair(secure_dns_mode, std::move(config));
}
void BrowserTestBase::InitializeHTTPSTestServer() {
CHECK(!embedded_https_test_server_)
<< "HTTPS test server already initialized";
embedded_https_test_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
embedded_https_test_server_->SetCertHostnames(
{"example.com", "*.example.com", "foo.com", "*.foo.com", "bar.com",
"*.bar.com", "a.com", "*.a.com", "b.com", "*.b.com", "c.com",
"*.c.com"});
}
void BrowserTestBase::CreateTestServer(const base::FilePath& test_server_base) {
embedded_test_server()->AddDefaultHandlers(test_server_base);
}
void BrowserTestBase::PostTaskToInProcessRendererAndWait(
base::OnceClosure task) {
CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess));
scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner =
RenderProcessHostImpl::GetInProcessRendererThreadTaskRunnerForTesting();
CHECK(renderer_task_runner);
base::RunLoop run_loop;
renderer_task_runner->PostTask(
FROM_HERE, base::BindOnce(&RunTaskOnRendererThread, std::move(task),
run_loop.QuitClosure()));
run_loop.Run();
}
void BrowserTestBase::EnablePixelOutput(float force_device_scale_factor) {
enable_pixel_output_ = true;
force_device_scale_factor_ = force_device_scale_factor;
}
void BrowserTestBase::SetUseFakeMediaStreamDevices(
bool use_fake_media_stream_devices) {
use_fake_media_stream_devices_ = use_fake_media_stream_devices;
}
void BrowserTestBase::UseSoftwareCompositing() {
use_software_compositing_ = true;
}
void BrowserTestBase::SetInitialWebContents(WebContents* web_contents) {
DCHECK(!initial_web_contents_);
initial_web_contents_ = web_contents->GetWeakPtr();
}
void BrowserTestBase::SetAllowFeaturesSwitches(bool allow) {
DCHECK(!set_up_called_);
allow_features_switches_ = allow;
}
void BrowserTestBase::AssertThatNetworkServiceDidNotCrash() {
if (!IsOutOfProcessNetworkService()) {
return;
}
#if !BUILDFLAG(IS_FUCHSIA)
if (initialized_network_process_ && network_service_test_.is_bound()) {
network_service_test_.FlushForTesting();
EXPECT_TRUE(network_service_test_.is_connected())
<< "Expecting no NetworkService crashes";
}
#endif
}
void BrowserTestBase::ForceInitializeNetworkProcess() {
initialized_network_process_ = false;
InitializeNetworkProcess();
}
void BrowserTestBase::InitializeNetworkProcess() {
if (initialized_network_process_)
return;
initialized_network_process_ = true;
if (host_resolver()) {
host_resolver()->DisableModifications();
}
if (IsInProcessNetworkService()) {
if (replace_system_dns_config_ || test_doh_config_) {
base::RunLoop run_loop;
content::GetNetworkTaskRunner()->PostTaskAndReply(
FROM_HERE, base::BindLambdaForTesting([&] {
network::NetworkService* network_service =
network::NetworkService::GetNetworkServiceForTesting();
ASSERT_TRUE(network_service);
if (replace_system_dns_config_) {
base::RunLoop run_loop_dns_config_service(
base::RunLoop::Type::kNestableTasksAllowed);
network_service->ReplaceSystemDnsConfigForTesting(
run_loop_dns_config_service.QuitClosure());
run_loop_dns_config_service.Run();
}
if (test_doh_config_) {
network_service->SetTestDohConfigForTesting(
test_doh_config_->first, test_doh_config_->second);
}
}),
run_loop.QuitClosure());
run_loop.Run();
}
return;
}
network_service_test_.reset();
content::GetNetworkService()->BindTestInterfaceForTesting(
network_service_test_.BindNewPipeAndPassReceiver());
if (allow_network_access_to_host_resolutions_) {
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
network_service_test_->SetAllowNetworkAccessToHostResolutions();
return;
}
if (replace_system_dns_config_) {
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
network_service_test_->ReplaceSystemDnsConfig();
}
if (test_doh_config_.has_value()) {
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
network_service_test_->SetTestDohConfig(test_doh_config_->first,
test_doh_config_->second);
}
std::vector<network::mojom::RulePtr> mojo_rules;
if (host_resolver()) {
net::RuleBasedHostResolverProc::RuleList rules =
host_resolver()->GetRules();
for (const auto& rule : rules) {
if (rule.resolver_type ==
net::RuleBasedHostResolverProc::Rule::kResolverTypeFail ||
rule.resolver_type ==
net::RuleBasedHostResolverProc::Rule::kResolverTypeFailTimeout) {
if (rule.host_pattern != "wpad") {
network::mojom::RulePtr mojo_rule = network::mojom::Rule::New();
mojo_rule->resolver_type =
(rule.resolver_type ==
net::RuleBasedHostResolverProc::Rule::kResolverTypeFail)
? network::mojom::ResolverType::kResolverTypeFail
: network::mojom::ResolverType::kResolverTypeFailTimeout;
mojo_rule->host_pattern = rule.host_pattern;
mojo_rules.push_back(std::move(mojo_rule));
}
continue;
}
if ((rule.resolver_type !=
net::RuleBasedHostResolverProc::Rule::kResolverTypeSystem &&
rule.resolver_type !=
net::RuleBasedHostResolverProc::Rule::kResolverTypeIPLiteral) ||
rule.address_family !=
net::AddressFamily::ADDRESS_FAMILY_UNSPECIFIED ||
!!rule.latency_ms) {
continue;
}
network::mojom::RulePtr mojo_rule = network::mojom::Rule::New();
if (rule.resolver_type ==
net::RuleBasedHostResolverProc::Rule::kResolverTypeSystem) {
mojo_rule->resolver_type =
rule.replacement.empty()
? network::mojom::ResolverType::kResolverTypeDirectLookup
: network::mojom::ResolverType::kResolverTypeSystem;
} else {
mojo_rule->resolver_type =
network::mojom::ResolverType::kResolverTypeIPLiteral;
}
mojo_rule->host_pattern = rule.host_pattern;
mojo_rule->replacement = rule.replacement;
mojo_rule->host_resolver_flags = rule.host_resolver_flags;
mojo_rule->dns_aliases = rule.dns_aliases;
mojo_rules.push_back(std::move(mojo_rule));
}
}
if (mojo_rules.empty()) {
return;
}
base::RunLoop loop{base::RunLoop::Type::kNestableTasksAllowed};
network_service_test_->AddRules(std::move(mojo_rules), loop.QuitClosure());
loop.Run();
}
void BrowserTestBase::CreatedBrowserMainPartsImpl(
BrowserMainParts* browser_main_parts) {
browser_main_parts_ = browser_main_parts;
GetCurrentTestLauncherDelegate()->CreatedBrowserMainParts(browser_main_parts);
CreatedBrowserMainParts(browser_main_parts);
}
ContentMainDelegate* BrowserTestBase::GetOptionalContentMainDelegateOverride() {
return nullptr;
}
}