|  | // Copyright 2021 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/headless/headless_mode_browsertest.h" | 
|  |  | 
|  | #include "build/build_config.h" | 
|  |  | 
|  | // Native headless is currently available on Linux, Windows and Mac platforms. | 
|  | // More platforms will be added later, so avoid function level clutter by | 
|  | // providing a compile time condition over the entire file. | 
|  | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  |  | 
|  | #include "base/command_line.h" | 
|  | #include "base/files/file.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/test/multiprocess_test.h" | 
|  | #include "base/test/task_environment.h" | 
|  | #include "base/test/test_timeouts.h" | 
|  | #include "chrome/browser/chrome_process_singleton.h" | 
|  | #include "chrome/browser/headless/headless_mode_util.h" | 
|  | #include "chrome/browser/process_singleton.h" | 
|  | #include "chrome/browser/ui/browser.h" | 
|  | #include "chrome/browser/ui/browser_commands.h" | 
|  | #include "chrome/browser/ui/exclusive_access/exclusive_access_test.h" | 
|  | #include "chrome/common/chrome_switches.h" | 
|  | #include "content/public/common/content_switches.h" | 
|  | #include "content/public/test/browser_task_environment.h" | 
|  | #include "content/public/test/browser_test_utils.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/multiprocess_func_list.h" | 
|  | #include "ui/gfx/switches.h" | 
|  |  | 
|  | namespace { | 
|  | const int kErrorResultCode = -1; | 
|  | }  // namespace | 
|  |  | 
|  | void HeadlessModeBrowserTest::SetUpCommandLine( | 
|  | base::CommandLine* command_line) { | 
|  | InProcessBrowserTest::SetUpCommandLine(command_line); | 
|  |  | 
|  | command_line->AppendSwitchASCII(switches::kHeadless, kHeadlessSwitchValue); | 
|  | headless::SetUpCommandLine(command_line); | 
|  | } | 
|  |  | 
|  | void HeadlessModeBrowserTest::SetUpOnMainThread() { | 
|  | InProcessBrowserTest::SetUpOnMainThread(); | 
|  |  | 
|  | ASSERT_TRUE(headless::IsHeadlessMode()); | 
|  | } | 
|  |  | 
|  | void HeadlessModeBrowserTestWithStartWindowMode::SetUpCommandLine( | 
|  | base::CommandLine* command_line) { | 
|  | HeadlessModeBrowserTest::SetUpCommandLine(command_line); | 
|  |  | 
|  | switch (start_window_mode()) { | 
|  | case kStartWindowNormal: | 
|  | break; | 
|  | case kStartWindowMaximized: | 
|  | command_line->AppendSwitch(switches::kStartMaximized); | 
|  | break; | 
|  | case kStartWindowFullscreen: | 
|  | command_line->AppendSwitch(switches::kStartFullscreen); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ToggleFullscreenModeSync(Browser* browser) { | 
|  | FullscreenNotificationObserver observer(browser); | 
|  | chrome::ToggleFullscreenMode(browser); | 
|  | observer.Wait(); | 
|  | } | 
|  |  | 
|  | class HeadlessModeBrowserTestWithUserDataDir : public HeadlessModeBrowserTest { | 
|  | public: | 
|  | HeadlessModeBrowserTestWithUserDataDir() = default; | 
|  |  | 
|  | HeadlessModeBrowserTestWithUserDataDir( | 
|  | const HeadlessModeBrowserTestWithUserDataDir&) = delete; | 
|  | HeadlessModeBrowserTestWithUserDataDir& operator=( | 
|  | const HeadlessModeBrowserTestWithUserDataDir&) = delete; | 
|  |  | 
|  | ~HeadlessModeBrowserTestWithUserDataDir() override = default; | 
|  |  | 
|  | void SetUpCommandLine(base::CommandLine* command_line) override { | 
|  | HeadlessModeBrowserTest::SetUpCommandLine(command_line); | 
|  |  | 
|  | ASSERT_TRUE(user_data_dir_.CreateUniqueTempDir()); | 
|  | ASSERT_TRUE(base::IsDirectoryEmpty(user_data_dir())); | 
|  |  | 
|  | command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir()); | 
|  | } | 
|  |  | 
|  | const base::FilePath& user_data_dir() const { | 
|  | return user_data_dir_.GetPath(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | base::ScopedTempDir user_data_dir_; | 
|  | }; | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTestWithUserDataDir, | 
|  | ChromeProcessSingletonExists) { | 
|  | // Pass the user data dir to the child process which will try | 
|  | // to create a mock ChromeProcessSingleton in it that is | 
|  | // expected to fail. | 
|  | base::CommandLine command_line( | 
|  | base::GetMultiProcessTestChildBaseCommandLine()); | 
|  | command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir()); | 
|  |  | 
|  | base::Process child_process = | 
|  | base::SpawnMultiProcessTestChild("ChromeProcessSingletonChildProcessMain", | 
|  | command_line, base::LaunchOptions()); | 
|  |  | 
|  | int result = kErrorResultCode; | 
|  | ASSERT_TRUE(base::WaitForMultiprocessTestChildExit( | 
|  | child_process, TestTimeouts::action_timeout(), &result)); | 
|  |  | 
|  | EXPECT_EQ(static_cast<ProcessSingleton::NotifyResult>(result), | 
|  | ProcessSingleton::PROFILE_IN_USE); | 
|  | } | 
|  |  | 
|  | MULTIPROCESS_TEST_MAIN(ChromeProcessSingletonChildProcessMain) { | 
|  | content::BrowserTaskEnvironment task_environment; | 
|  |  | 
|  | base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 
|  | const base::FilePath user_data_dir = | 
|  | command_line->GetSwitchValuePath(switches::kUserDataDir); | 
|  | if (user_data_dir.empty()) | 
|  | return kErrorResultCode; | 
|  |  | 
|  | ChromeProcessSingleton chrome_process_singleton(user_data_dir); | 
|  | ProcessSingleton::NotifyResult notify_result = | 
|  | chrome_process_singleton.NotifyOtherProcessOrCreate(); | 
|  |  | 
|  | return static_cast<int>(notify_result); | 
|  | } | 
|  |  | 
|  | #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) |