#include "chrome/test/base/in_process_browser_test.h"
#include <map>
#include <string_view>
#include <utility>
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/path_service.h"
#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/test_file_util.h"
#include "base/test/test_switches.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/after_startup_task_utils.h"
#include "chrome/browser/browser_features.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/lifetime/application_lifetime_desktop.h"
#include "chrome/browser/lifetime/termination_notification.h"
#include "chrome/browser/navigation_predictor/search_engine_preconnector.h"
#include "chrome/browser/net/chrome_network_delegate.h"
#include "chrome/browser/net/net_error_tab_helper.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/predictors/loading_predictor_config.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar_controller_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/chrome_content_renderer_client.h"
#include "chrome/test/base/chrome_test_suite.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/captive_portal/core/buildflags.h"
#include "components/custom_handlers/test_protocol_handler_registry_delegate.h"
#include "components/embedder_support/switches.h"
#include "components/feature_engagement/public/feature_list.h"
#include "components/google/core/common/google_util.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/os_crypt/async/browser/key_provider.h"
#include "components/os_crypt/sync/os_crypt_mocker.h"
#include "components/search_engines/search_engine_choice/search_engine_choice_utils.h"
#include "content/public/browser/browser_main_parts.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_launcher.h"
#include "content/public/test/test_navigation_observer.h"
#include "extensions/buildflags/buildflags.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/device/public/cpp/device_features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/base/test/ui_controls.h"
#include "ui/base/ui_base_features.h"
#if BUILDFLAG(IS_MAC)
#include "base/apple/scoped_nsautorelease_pool.h"
#include "chrome/test/base/scoped_bundle_swizzler_mac.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "chrome/browser/os_crypt/app_bound_encryption_win.h"
#include "components/version_info/version_info.h"
#include "ui/base/win/atl_module.h"
#endif
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#include "services/device/public/cpp/test/fake_geolocation_system_permission_manager.h"
#endif
#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
#include "components/captive_portal/content/captive_portal_service.h"
#endif
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service.h"
#include "chrome/browser/ui/webui/whats_new/whats_new_util.h"
#include "components/storage_monitor/test_storage_monitor.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "ash/shell.h"
#include "base/system/sys_info.h"
#include "chrome/browser/ash/app_restore/full_restore_app_launch_handler.h"
#include "chrome/browser/ash/input_method/input_method_configuration.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
#include "chromeos/ash/services/device_sync/device_sync_impl.h"
#include "chromeos/ash/services/device_sync/fake_device_sync.h"
#include "components/user_manager/user_names.h"
#include "ui/display/display_switches.h"
#include "ui/events/test/event_generator.h"
#endif
#if BUILDFLAG(IS_OZONE)
#include "ui/views/test/test_desktop_screen_ozone.h"
#endif
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/test/views/accessibility_checker.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "base/base_switches.h"
#include "base/environment.h"
#include "base/files/file_path_watcher.h"
#include "base/process/launch.h"
#include "base/threading/thread_restrictions.h"
#include "base/uuid.h"
#include "base/version.h"
#include "chrome/browser/lacros/browser_test_util.h"
#include "chrome/browser/lacros/cert/cert_db_initializer_factory.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/crosapi/mojom/test_controller.mojom-test-utils.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/startup/browser_params_proxy.h"
#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
#include "components/account_manager_core/chromeos/fake_account_manager_ui.h"
#include "components/variations/variations_switches.h"
#include "content/public/test/network_connection_change_simulator.h"
#endif
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
class FakeDeviceSyncImplFactory
: public ash::device_sync::DeviceSyncImpl::Factory {
public:
FakeDeviceSyncImplFactory() = default;
~FakeDeviceSyncImplFactory() override = default;
std::unique_ptr<ash::device_sync::DeviceSyncBase> CreateInstance(
signin::IdentityManager* identity_manager,
instance_id::InstanceIDDriver* instance_id_driver,
PrefService* profile_prefs,
const ash::device_sync::GcmDeviceInfoProvider* gcm_device_info_provider,
ash::device_sync::ClientAppMetadataProvider* client_app_metadata_provider,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<base::OneShotTimer> timer,
ash::device_sync::AttestationCertificatesSyncer::
GetAttestationCertificatesFunction
get_attestation_certificates_function) override {
return std::make_unique<ash::device_sync::FakeDeviceSync>();
}
};
FakeDeviceSyncImplFactory* GetFakeDeviceSyncImplFactory() {
static base::NoDestructor<FakeDeviceSyncImplFactory> factory;
return factory.get();
}
#endif
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
class ChromeBrowserMainExtraPartsBrowserProcessInjection
: public ChromeBrowserMainExtraParts {
public:
ChromeBrowserMainExtraPartsBrowserProcessInjection() = default;
void PreCreateMainMessageLoop() override {
if (features::IsOsLevelGeolocationPermissionSupportEnabled()) {
auto fake_geolocation_system_permission_manager =
std::make_unique<device::FakeGeolocationSystemPermissionManager>();
fake_geolocation_system_permission_manager->SetSystemPermission(
device::LocationSystemPermissionStatus::kAllowed);
device::GeolocationSystemPermissionManager::SetInstance(
std::move(fake_geolocation_system_permission_manager));
}
}
ChromeBrowserMainExtraPartsBrowserProcessInjection(
const ChromeBrowserMainExtraPartsBrowserProcessInjection&) = delete;
ChromeBrowserMainExtraPartsBrowserProcessInjection& operator=(
const ChromeBrowserMainExtraPartsBrowserProcessInjection&) = delete;
};
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
class IdentityExtraSetUp : public ChromeBrowserMainExtraParts {
public:
void PreProfileInit() override {
scoped_ash_account_manager_ =
std::make_unique<ScopedAshAccountManagerForTests>(
std::make_unique<FakeAccountManagerUI>());
auto* account_manager = MaybeGetAshAccountManagerForTests();
CHECK(account_manager);
account_manager->InitializeInEphemeralMode(
g_browser_process->system_network_context_manager()
->GetSharedURLLoaderFactory());
ProfileAttributesStorage* storage =
&g_browser_process->profile_manager()->GetProfileAttributesStorage();
for (const ProfileAttributesEntry* entry :
storage->GetAllProfilesAttributes()) {
const std::string& gaia_id = entry->GetGAIAId();
if (!gaia_id.empty()) {
account_manager->UpsertAccount(
{gaia_id, account_manager::AccountType::kGaia},
base::UTF16ToUTF8(entry->GetUserName()),
"identity_extra_setup_test_token");
}
}
}
private:
std::unique_ptr<ScopedAshAccountManagerForTests> scoped_ash_account_manager_;
};
bool IsTestControllerAvailable() {
auto* lacros_service = chromeos::LacrosService::Get();
return lacros_service &&
lacros_service->IsAvailable<crosapi::mojom::TestController>();
}
#endif
class OSCryptAsyncExtraSetUp : public ChromeBrowserMainExtraParts { … };
void EnsureBrowserContextKeyedServiceFactoriesForTestingBuilt() { … }
bool WaitForWindowCreation(Browser* browser) { … }
InProcessBrowserTest* g_current_test;
}
InProcessBrowserTest::SetUpBrowserFunction*
InProcessBrowserTest::global_browser_set_up_function_ = …;
InProcessBrowserTest::InProcessBrowserTest() { … }
#if defined(TOOLKIT_VIEWS)
InProcessBrowserTest::InProcessBrowserTest(
std::unique_ptr<views::ViewsDelegate> views_delegate) { … }
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
void InProcessBrowserTest::set_launch_browser_for_testing(
std::unique_ptr<ash::full_restore::ScopedLaunchBrowserForTesting>
launch_browser_for_testing) {
launch_browser_for_testing_ = std::move(launch_browser_for_testing);
}
#endif
void InProcessBrowserTest::RunScheduledLayouts() { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
FakeAccountManagerUI* InProcessBrowserTest::GetFakeAccountManagerUI() const {
return static_cast<FakeAccountManagerUI*>(
MaybeGetAshAccountManagerUIForTests());
}
base::Version InProcessBrowserTest::GetAshChromeVersion() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::FilePath ash_chrome_path =
command_line->GetSwitchValuePath("ash-chrome-path");
CHECK(!ash_chrome_path.empty());
base::CommandLine invoker(ash_chrome_path);
invoker.AppendSwitch(switches::kVersion);
std::string output;
base::ScopedAllowBlockingForTesting blocking;
CHECK(base::GetAppOutput(invoker, &output));
std::vector<std::string> tokens = base::SplitString(
output, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
CHECK_GT(tokens.size(), 1U);
base::Version version(tokens[tokens.size() - 2]);
CHECK(version.IsValid()) << "Can not find "
<< "chrome version in string: " << output;
return version;
}
void InProcessBrowserTest::VerifyNoAshBrowserWindowOpenRightNow() {
CHECK(IsTestControllerAvailable());
crosapi::mojom::TestControllerAsyncWaiter waiter(
chromeos::LacrosService::Get()
->GetRemote<crosapi::mojom::TestController>()
.get());
uint32_t number = 1;
waiter.GetOpenAshBrowserWindows(&number);
EXPECT_EQ(0u, number)
<< "There should not be any ash browser window open at this point.";
}
void InProcessBrowserTest::CloseAllAshBrowserWindows() {
CHECK(IsTestControllerAvailable());
crosapi::mojom::TestControllerAsyncWaiter waiter(
chromeos::LacrosService::Get()
->GetRemote<crosapi::mojom::TestController>()
.get());
bool success;
waiter.CloseAllAshBrowserWindowsAndConfirm(&success);
EXPECT_TRUE(success) << "Failed to close all ash browser windows";
}
void InProcessBrowserTest::WaitUntilAtLeastOneAshBrowserWindowOpen() {
CHECK(IsTestControllerAvailable());
crosapi::mojom::TestControllerAsyncWaiter waiter(
chromeos::LacrosService::Get()
->GetRemote<crosapi::mojom::TestController>()
.get());
bool has_open_window;
waiter.CheckAtLeastOneAshBrowserWindowOpen(&has_open_window);
EXPECT_TRUE(has_open_window);
}
#endif
void InProcessBrowserTest::Initialize() { … }
InProcessBrowserTest::~InProcessBrowserTest() { … }
InProcessBrowserTest* InProcessBrowserTest::GetCurrent() { … }
void InProcessBrowserTest::SetUp() { … }
void InProcessBrowserTest::SetUpDefaultCommandLine(
base::CommandLine* command_line) { … }
void InProcessBrowserTest::TearDown() { … }
size_t InProcessBrowserTest::GetTestPreCount() { … }
void InProcessBrowserTest::CreatedBrowserMainParts(
content::BrowserMainParts* parts) { … }
void InProcessBrowserTest::SelectFirstBrowser() { … }
void InProcessBrowserTest::RecordPropertyFromMap(
const std::map<std::string, std::string>& tags) { … }
void InProcessBrowserTest::SetUpLocalStatePrefService(
PrefService* local_state) { … }
void InProcessBrowserTest::CloseBrowserSynchronously(Browser* browser) { … }
void InProcessBrowserTest::CloseBrowserAsynchronously(Browser* browser) { … }
void InProcessBrowserTest::CloseAllBrowsers() { … }
void InProcessBrowserTest::RunUntilBrowserProcessQuits() { … }
bool InProcessBrowserTest::AddTabAtIndexToBrowser(
Browser* browser,
int index,
const GURL& url,
ui::PageTransition transition,
bool check_navigation_success) { … }
bool InProcessBrowserTest::AddTabAtIndexToBrowser(
Browser* browser,
int index,
const GURL& url,
ui::PageTransition transition) { … }
bool InProcessBrowserTest::AddTabAtIndex(int index,
const GURL& url,
ui::PageTransition transition) { … }
bool InProcessBrowserTest::SetUpUserDataDirectory() { … }
void InProcessBrowserTest::SetScreenInstance() { … }
#if !BUILDFLAG(IS_MAC)
void InProcessBrowserTest::OpenDevToolsWindow(
content::WebContents* web_contents) { … }
Browser* InProcessBrowserTest::OpenURLOffTheRecord(Profile* profile,
const GURL& url) { … }
Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) { … }
Browser* InProcessBrowserTest::CreateIncognitoBrowser(Profile* profile) { … }
Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) { … }
Browser* InProcessBrowserTest::CreateBrowserForApp(const std::string& app_name,
Profile* profile) { … }
#endif
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
Browser* InProcessBrowserTest::CreateGuestBrowser() { … }
#endif
void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) { … }
#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_CHROMEOS_LACROS)
base::CommandLine InProcessBrowserTest::GetCommandLineForRelaunch() { … }
#endif
base::FilePath InProcessBrowserTest::GetChromeTestDataDir() const { … }
void InProcessBrowserTest::PreRunTestOnMainThread() { … }
void InProcessBrowserTest::PostRunTestOnMainThread() { … }
void InProcessBrowserTest::QuitBrowsers() { … }
void InProcessBrowserTest::SetupProtocolHandlerTestFactories(
content::BrowserContext* context) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
void InProcessBrowserTest::StartUniqueAshChrome(
const std::vector<std::string>& enabled_features,
const std::vector<std::string>& disabled_features,
const std::vector<std::string>& additional_cmdline_switches,
const std::string& bug_number_and_reason) {
DCHECK(!bug_number_and_reason.empty());
CHECK(!chromeos::BrowserParamsProxy::IsCrosapiDisabledForTesting())
<< "You can only start unique ash chrome when crosapi is enabled. "
<< "It should not be necessary otherwise.";
base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
base::FilePath ash_dir_holder = cmdline->GetSwitchValuePath("unique-ash-dir");
CHECK(!ash_dir_holder.empty());
CHECK(unique_ash_user_data_dir_.CreateUniqueTempDirUnderPath(ash_dir_holder));
base::FilePath socket_file =
unique_ash_user_data_dir_.GetPath().Append("lacros.sock");
cmdline->RemoveSwitch("lacros-mojo-socket-for-testing");
cmdline->AppendSwitchPath("lacros-mojo-socket-for-testing", socket_file);
base::Environment::Create()->SetVar(
"WAYLAND_DISPLAY",
base::JoinString({"unique_wayland",
base::Uuid::GenerateRandomV4().AsLowercaseString()},
"_"));
base::FilePath ash_chrome_path =
cmdline->GetSwitchValuePath("ash-chrome-path");
CHECK(!ash_chrome_path.empty());
base::CommandLine ash_cmdline(ash_chrome_path);
ash_cmdline.AppendSwitchPath(switches::kUserDataDir,
unique_ash_user_data_dir_.GetPath());
ash_cmdline.AppendSwitch("enable-wayland-server");
ash_cmdline.AppendSwitch(switches::kNoStartupWindow);
ash_cmdline.AppendSwitch("disable-lacros-keep-alive");
ash_cmdline.AppendSwitch("disable-login-lacros-opening");
ash_cmdline.AppendSwitch(
variations::switches::kEnableFieldTrialTestingConfig);
for (const std::string& cmdline_switch : additional_cmdline_switches) {
size_t pos = cmdline_switch.find("=");
if (pos == std::string::npos) {
ash_cmdline.AppendSwitch(cmdline_switch);
} else {
CHECK_GT(pos, 0u);
ash_cmdline.AppendSwitchASCII(cmdline_switch.substr(0, pos),
cmdline_switch.substr(pos + 1));
}
}
std::vector<std::string> all_enabled_features = {
"LacrosSupport", "LacrosPrimary", "LacrosOnly"};
all_enabled_features.insert(all_enabled_features.end(),
enabled_features.begin(),
enabled_features.end());
ash_cmdline.AppendSwitch("enable-lacros-for-testing");
ash_cmdline.AppendSwitchASCII(switches::kEnableFeatures,
base::JoinString(all_enabled_features, ","));
ash_cmdline.AppendSwitchASCII(switches::kDisableFeatures,
base::JoinString(disabled_features, ","));
ash_cmdline.AppendSwitchPath("lacros-mojo-socket-for-testing", socket_file);
std::string wayland_socket;
CHECK(
base::Environment::Create()->GetVar("WAYLAND_DISPLAY", &wayland_socket));
DCHECK(!wayland_socket.empty());
ash_cmdline.AppendSwitchASCII("wayland-server-socket", wayland_socket);
const base::FilePath ash_ready_file =
unique_ash_user_data_dir_.GetPath().AppendASCII("ash_ready.txt");
ash_cmdline.AppendSwitchPath("ash-ready-file-path", ash_ready_file);
base::test::SingleThreadTaskEnvironment task_environment;
base::FilePathWatcher watcher;
base::RunLoop run_loop;
CHECK(watcher.Watch(base::FilePath(ash_ready_file),
base::FilePathWatcher::Type::kNonRecursive,
base::BindLambdaForTesting(
[&](const base::FilePath& filepath, bool error) {
CHECK(!error);
run_loop.Quit();
})));
base::LaunchOptions option;
ash_process_ = base::LaunchProcess(ash_cmdline, option);
CHECK(ash_process_.IsValid());
run_loop.Run();
CHECK(base::PathExists(socket_file));
LOG(INFO) << "Successfully started a unique ash chrome.";
}
#endif