| // 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 "chrome/browser/ui/startup/startup_browser_creator.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| |
| #include "base/base_switches.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/json/json_writer.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/path_service.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/bind.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/mock_log.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/test_future.h" |
| #include "build/branding_buildflags.h" |
| #include "build/build_config.h" |
| #include "build/buildflag.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/browser_features.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/buildflags.h" |
| #include "chrome/browser/chrome_browser_main.h" |
| #include "chrome/browser/extensions/extension_browsertest.h" |
| #include "chrome/browser/extensions/launch_util.h" |
| #include "chrome/browser/first_run/first_run.h" |
| #include "chrome/browser/lifetime/application_lifetime.h" |
| #include "chrome/browser/prefs/chrome_pref_service_factory.h" |
| #include "chrome/browser/prefs/session_startup_pref.h" |
| #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h" |
| #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.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_impl.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/profiles/profile_test_util.h" |
| #include "chrome/browser/profiles/profile_window.h" |
| #include "chrome/browser/profiles/profiles_state.h" |
| #include "chrome/browser/search/search.h" |
| #include "chrome/browser/sessions/app_session_service.h" |
| #include "chrome/browser/sessions/app_session_service_factory.h" |
| #include "chrome/browser/sessions/exit_type_service.h" |
| #include "chrome/browser/sessions/session_restore.h" |
| #include "chrome/browser/sessions/session_restore_test_helper.h" |
| #include "chrome/browser/sessions/session_restore_test_utils.h" |
| #include "chrome/browser/sessions/session_service_factory.h" |
| #include "chrome/browser/signin/signin_features.h" |
| #include "chrome/browser/signin/signin_promo.h" |
| #include "chrome/browser/signin/signin_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_window.h" |
| #include "chrome/browser/ui/profiles/profile_ui_test_utils.h" |
| #include "chrome/browser/ui/search/ntp_test_utils.h" |
| #include "chrome/browser/ui/startup/launch_mode_recorder.h" |
| #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" |
| #include "chrome/browser/ui/startup/startup_tab_provider.h" |
| #include "chrome/browser/ui/startup/startup_types.h" |
| #include "chrome/browser/ui/startup/web_app_startup_utils.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/ui_features.h" |
| #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" |
| #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" |
| #include "chrome/browser/web_applications/test/fake_web_app_provider.h" |
| #include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" |
| #include "chrome/browser/web_applications/test/web_app_test_observers.h" |
| #include "chrome/browser/web_applications/web_app_command_scheduler.h" |
| #include "chrome/browser/web_applications/web_app_constants.h" |
| #include "chrome/browser/web_applications/web_app_install_info.h" |
| #include "chrome/browser/web_applications/web_app_install_manager.h" |
| #include "chrome/browser/web_applications/web_app_install_params.h" |
| #include "chrome/browser/web_applications/web_app_provider.h" |
| #include "chrome/common/buildflags.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/chrome_version.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/infobars/content/content_infobar_manager.h" |
| #include "components/infobars/core/infobar.h" |
| #include "components/infobars/core/infobar_delegate.h" |
| #include "components/keep_alive_registry/keep_alive_registry.h" |
| #include "components/keep_alive_registry/keep_alive_types.h" |
| #include "components/keep_alive_registry/scoped_keep_alive.h" |
| #include "components/metrics/metrics_pref_names.h" |
| #include "components/policy/core/browser/browser_policy_connector.h" |
| #include "components/policy/core/common/mock_configuration_policy_provider.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/public/base/signin_buildflags.h" |
| #include "components/webapps/browser/install_result_code.h" |
| #include "components/webapps/browser/installable/installable_metrics.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/browser_test.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 "content/public/test/test_utils.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/pref_names.h" |
| #include "extensions/browser/test_management_policy.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/strings/ascii.h" |
| #include "ui/views/controls/webview/webview.h" |
| #include "url/gurl.h" |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "base/functional/callback.h" |
| #include "base/json/values_util.h" |
| #include "base/run_loop.h" |
| #include "base/values.h" |
| #include "chrome/browser/first_run/scoped_relaunch_chrome_browser_override.h" |
| #include "chrome/browser/ui/profiles/profile_picker.h" |
| #include "chrome/browser/ui/webui/signin/profile_picker_handler.h" |
| #include "chrome/browser/ui/webui/signin/profile_picker_ui.h" |
| #include "components/policy/core/common/external_data_fetcher.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/core/common/policy_types.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| #include "chromeos/startup/browser_init_params.h" |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| #include "base/json/json_string_value_serializer.h" |
| #include "chrome/browser/ui/views/web_apps/protocol_handler_launch_dialog_view.h" |
| #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" |
| #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" |
| #include "chrome/browser/web_applications/web_app.h" |
| #include "chrome/browser/web_applications/web_app_registrar.h" |
| #include "chrome/browser/web_applications/web_app_registry_update.h" |
| #include "chrome/browser/web_applications/web_app_sync_bridge.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "ui/views/widget/any_widget_observer.h" |
| #include "ui/views/widget/widget.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| #include "chrome/browser/ui/webui/welcome/helpers.h" |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \ |
| (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS)) |
| #include "chrome/browser/ui/web_applications/app_browser_controller.h" |
| #endif |
| |
| using testing::Return; |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| #if BUILDFLAG(IS_MAC) |
| #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h" |
| #include "chrome/browser/chrome_browser_application_mac.h" |
| #include "chrome/browser/web_applications/app_shim_registry_mac.h" |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "base/base_paths_win.h" |
| #include "base/test/scoped_path_override.h" |
| #endif // BUILDFLAG(IS_WIN) |
| |
| using extensions::Extension; |
| using testing::_; |
| using web_app::WebAppProvider; |
| |
| namespace { |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| const char kAppId[] = "dofnemchnjfeendjmdhaldenaiabpiad"; |
| const char16_t kAppName[] = u"Test App"; |
| const char kStartUrl[] = "https://test.com"; |
| |
| // Check that there are two browsers. Find the one that is not |browser|. |
| Browser* FindOneOtherBrowser(Browser* browser) { |
| // There should only be one other browser. |
| EXPECT_EQ(2u, chrome::GetBrowserCount(browser->profile())); |
| |
| // Find the new browser. |
| Browser* other_browser = nullptr; |
| for (Browser* b : *BrowserList::GetInstance()) { |
| if (b != browser) |
| other_browser = b; |
| } |
| return other_browser; |
| } |
| |
| void DisableWelcomePages(const std::vector<Profile*>& profiles) { |
| for (Profile* profile : profiles) |
| profile->GetPrefs()->SetBoolean(prefs::kHasSeenWelcomePage, true); |
| |
| // Also disable What's New. |
| PrefService* pref_service = g_browser_process->local_state(); |
| pref_service->SetInteger(prefs::kLastWhatsNewVersion, CHROME_VERSION_MAJOR); |
| } |
| |
| Browser* OpenNewBrowser(Profile* profile) { |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreatorImpl creator(base::FilePath(), dummy, |
| chrome::startup::IsFirstRun::kYes); |
| ui_test_utils::BrowserChangeObserver new_browser_observer( |
| nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); |
| creator.Launch(profile, chrome::startup::IsProcessStartup::kNo, nullptr, |
| /*restore_tabbed_browser=*/true); |
| Browser* new_browser = new_browser_observer.Wait(); |
| ui_test_utils::WaitForBrowserSetLastActive(new_browser); |
| return new_browser; |
| } |
| |
| Browser* CloseBrowserAndOpenNew(Browser* browser, Profile* profile) { |
| browser->window()->Close(); |
| ui_test_utils::WaitForBrowserToClose(browser); |
| return OpenNewBrowser(profile); |
| } |
| |
| bool HasInfoBar(infobars::ContentInfoBarManager* infobar_manager, |
| const infobars::InfoBarDelegate::InfoBarIdentifier identifier) { |
| return base::Contains(infobar_manager->infobars(), identifier, |
| &infobars::InfoBar::GetIdentifier); |
| } |
| |
| struct StartupBrowserCreatorFlagTypeValue { |
| std::string flag; |
| infobars::InfoBarDelegate::InfoBarIdentifier infobar_identifier; |
| // True if the infobar is supposed to be shown in every tab, false if it is |
| // only supposed to be shown once. |
| bool is_global_infobar; |
| }; |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| typedef std::optional<policy::PolicyLevel> PolicyVariant; |
| |
| // This class waits until all browser windows are closed, and then runs |
| // a quit closure. |
| class AllBrowsersClosedWaiter : public BrowserListObserver { |
| public: |
| explicit AllBrowsersClosedWaiter(base::OnceClosure quit_closure); |
| AllBrowsersClosedWaiter(const AllBrowsersClosedWaiter&) = delete; |
| AllBrowsersClosedWaiter& operator=(const AllBrowsersClosedWaiter&) = delete; |
| ~AllBrowsersClosedWaiter() override; |
| |
| // BrowserListObserver: |
| void OnBrowserRemoved(Browser* browser) override; |
| |
| private: |
| base::OnceClosure quit_closure_; |
| }; |
| |
| AllBrowsersClosedWaiter::AllBrowsersClosedWaiter(base::OnceClosure quit_closure) |
| : quit_closure_(std::move(quit_closure)) { |
| BrowserList::AddObserver(this); |
| } |
| |
| AllBrowsersClosedWaiter::~AllBrowsersClosedWaiter() { |
| BrowserList::RemoveObserver(this); |
| } |
| |
| void AllBrowsersClosedWaiter::OnBrowserRemoved(Browser* browser) { |
| if (chrome::GetTotalBrowserCount() == 0) |
| std::move(quit_closure_).Run(); |
| } |
| |
| } // namespace |
| |
| class StartupBrowserCreatorTest : public extensions::ExtensionBrowserTest { |
| protected: |
| StartupBrowserCreatorTest() {} |
| |
| bool SetUpUserDataDirectory() override { |
| return extensions::ExtensionBrowserTest::SetUpUserDataDirectory(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| extensions::ExtensionBrowserTest::SetUpCommandLine(command_line); |
| command_line->AppendSwitchASCII(switches::kHomePage, url::kAboutBlankURL); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // TODO(nkostylev): Investigate if we can remove this switch. |
| command_line->AppendSwitch(switches::kCreateBrowserOnStartupForTests); |
| #endif |
| } |
| |
| // Helper functions return void so that we can ASSERT*(). |
| // Use ASSERT_NO_FATAL_FAILURE around calls to these functions to stop the |
| // test if an assert fails. |
| void LoadApp(const std::string& app_name, |
| const Extension** out_app_extension) { |
| ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(app_name.c_str()))); |
| |
| *out_app_extension = extension_registry()->GetExtensionById( |
| last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED); |
| ASSERT_TRUE(*out_app_extension); |
| |
| // Code that opens a new browser assumes we start with exactly one. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| void SetAppLaunchPref(const std::string& app_id, |
| extensions::LaunchType launch_type) { |
| extensions::SetLaunchType(browser()->profile(), app_id, launch_type); |
| } |
| |
| Browser* FindOneOtherBrowserForProfile(Profile* profile, |
| Browser* not_this_browser) { |
| for (Browser* browser : *BrowserList::GetInstance()) { |
| if (browser != not_this_browser && browser->profile() == profile) |
| return browser; |
| } |
| return nullptr; |
| } |
| |
| // A helper function that checks the session restore UI (infobar) is shown |
| // when Chrome starts up after crash. |
| void EnsureRestoreUIWasShown(content::WebContents* web_contents) { |
| #if BUILDFLAG(IS_MAC) |
| infobars::ContentInfoBarManager* infobar_manager = |
| infobars::ContentInfoBarManager::FromWebContents(web_contents); |
| EXPECT_EQ(1U, infobar_manager->infobars().size()); |
| #endif // BUILDFLAG(IS_MAC) |
| } |
| }; |
| |
| class OpenURLsPopupObserver : public BrowserListObserver { |
| public: |
| OpenURLsPopupObserver() = default; |
| |
| void OnBrowserAdded(Browser* browser) override { added_browser_ = browser; } |
| |
| void OnBrowserRemoved(Browser* browser) override {} |
| |
| raw_ptr<Browser> added_browser_ = nullptr; |
| }; |
| |
| // Test that when there is a popup as the active browser any requests to |
| // StartupBrowserCreatorImpl::OpenURLsInBrowser don't crash because there's no |
| // explicit profile given. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, OpenURLsPopup) { |
| std::vector<GURL> urls; |
| urls.push_back(GURL("http://localhost")); |
| |
| // Note that in our testing we do not ever query the BrowserList for the "last |
| // active" browser. That's because the browsers are set as "active" by |
| // platform UI toolkit messages, and those messages are not sent during unit |
| // testing sessions. |
| |
| OpenURLsPopupObserver observer; |
| BrowserList::AddObserver(&observer); |
| |
| Browser* popup = Browser::Create( |
| Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true)); |
| ASSERT_TRUE(popup->is_type_popup()); |
| ASSERT_EQ(popup, observer.added_browser_); |
| |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| chrome::startup::IsFirstRun first_run = |
| first_run::IsChromeFirstRun() ? chrome::startup::IsFirstRun::kYes |
| : chrome::startup::IsFirstRun::kNo; |
| StartupBrowserCreatorImpl launch(base::FilePath(), dummy, first_run); |
| // This should create a new window, but re-use the profile from |popup|. If |
| // it used a null or invalid profile, it would crash. |
| launch.OpenURLsInBrowser(popup, chrome::startup::IsProcessStartup::kNo, urls); |
| ASSERT_NE(popup, observer.added_browser_); |
| BrowserList::RemoveObserver(&observer); |
| } |
| |
| // We don't do non-process-startup browser launches on ChromeOS. |
| // Session restore for process-startup browser launches is tested |
| // in session_restore_uitest. |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| // Verify that startup URLs are honored when the process already exists but has |
| // no tabbed browser windows (eg. as if the process is running only due to a |
| // background application. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| StartupURLsOnNewWindowWithNoTabbedBrowsers) { |
| // Use a couple same-site HTTP URLs. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| std::vector<GURL> urls; |
| urls.push_back(embedded_test_server()->GetURL("/title1.html")); |
| urls.push_back(embedded_test_server()->GetURL("/title2.html")); |
| |
| Profile* profile = browser()->profile(); |
| |
| DisableWelcomePages({profile}); |
| |
| // Set the startup preference to open these URLs. |
| SessionStartupPref pref(SessionStartupPref::URLS); |
| pref.urls = urls; |
| SessionStartupPref::SetStartupPref(profile, pref); |
| |
| // Keep the browser process running while browsers are closed. |
| ScopedKeepAlive keep_alive(KeepAliveOrigin::BROWSER, |
| KeepAliveRestartOption::DISABLED); |
| ScopedProfileKeepAlive profile_keep_alive( |
| profile, ProfileKeepAliveOrigin::kBrowserWindow); |
| |
| // Close the browser. |
| CloseBrowserAsynchronously(browser()); |
| |
| Browser* new_browser = OpenNewBrowser(profile); |
| ASSERT_TRUE(new_browser); |
| |
| std::vector<GURL> expected_urls(urls); |
| |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(static_cast<int>(expected_urls.size()), tab_strip->count()); |
| for (size_t i = 0; i < expected_urls.size(); i++) |
| EXPECT_EQ(expected_urls[i], |
| tab_strip->GetWebContentsAt(i)->GetVisibleURL()); |
| |
| // The two test_server tabs, despite having the same site, should be in |
| // different SiteInstances. |
| EXPECT_NE( |
| tab_strip->GetWebContentsAt(tab_strip->count() - 2)->GetSiteInstance(), |
| tab_strip->GetWebContentsAt(tab_strip->count() - 1)->GetSiteInstance()); |
| } |
| |
| // Verify that startup URLs aren't used when the process already exists |
| // and has other tabbed browser windows. This is the common case of starting a |
| // new browser. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, StartupURLsOnNewWindow) { |
| // Use a couple arbitrary URLs. |
| std::vector<GURL> urls; |
| urls.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title1.html")))); |
| urls.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title2.html")))); |
| |
| // Set the startup preference to open these URLs. |
| SessionStartupPref pref(SessionStartupPref::URLS); |
| pref.urls = urls; |
| SessionStartupPref::SetStartupPref(browser()->profile(), pref); |
| |
| DisableWelcomePages({browser()->profile()}); |
| |
| Browser* new_browser = OpenNewBrowser(browser()->profile()); |
| ASSERT_TRUE(new_browser); |
| |
| // The new browser should have exactly one tab (not the startup URLs). |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ( |
| chrome::kChromeUINewTabURL, |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().possibly_invalid_spec()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, OpenAppUrlShortcut) { |
| // Add --app=<url> to the command line. Tests launching legacy apps which may |
| // have been created by "Add to Desktop" in old versions of Chrome. |
| // TODO(mgiuca): Delete this feature (https://crbug.com/751029). We are |
| // keeping it for now to avoid disrupting existing workflows. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| GURL url = ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title2.html"))); |
| command_line.AppendSwitchASCII(switches::kApp, url.spec()); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| Browser* new_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(new_browser); |
| |
| // The new window should be an app window. |
| EXPECT_TRUE(new_browser->is_type_app()); |
| |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| // At this stage, the web contents' URL should be the one passed in to --app |
| // (but it will not yet be committed into the navigation controller). |
| EXPECT_EQ("title2.html", web_contents->GetVisibleURL().ExtractFileName()); |
| |
| // Wait until the navigation is complete. Then the URL will be committed to |
| // the navigation controller. |
| content::TestNavigationObserver observer(web_contents, 1); |
| observer.Wait(); |
| EXPECT_EQ("title2.html", |
| web_contents->GetLastCommittedURL().ExtractFileName()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, OpenAppUrlIncognitoShortcut) { |
| // Add --app=<url> and --incognito to the command line. Tests launching |
| // legacy apps which may have been created by "Add to Desktop" in old versions |
| // of Chrome. Some existing workflows (especially testing scenarios) also |
| // use the --incognito command line. |
| // TODO(mgiuca): Delete this feature (https://crbug.com/751029). We are |
| // keeping it for now to avoid disrupting existing workflows. |
| // IMPORTANT NOTE: This is being committed because it is an easy fix, but |
| // this use case is not officially supported. If a future refactor or |
| // feature launch causes this to break again, we have no formal |
| // responsibility to make this continue working. If you rely on the |
| // combination of these two flags, you WILL be broken in the future. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| GURL url = ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title2.html"))); |
| command_line.AppendSwitchASCII(switches::kApp, url.spec()); |
| command_line.AppendSwitch(switches::kIncognito); |
| |
| Browser* incognito = CreateIncognitoBrowser(); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {incognito->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| Browser* new_browser = FindOneOtherBrowser(incognito); |
| ASSERT_TRUE(new_browser); |
| |
| // The new window should be an app window. |
| EXPECT_TRUE(new_browser->is_type_app()); |
| |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| // At this stage, the web contents' URL should be the one passed in to --app |
| // (but it will not yet be committed into the navigation controller). |
| EXPECT_EQ("title2.html", web_contents->GetVisibleURL().ExtractFileName()); |
| |
| // Wait until the navigation is complete. Then the URL will be committed to |
| // the navigation controller. |
| content::TestNavigationObserver observer(web_contents, 1); |
| observer.Wait(); |
| EXPECT_EQ("title2.html", |
| web_contents->GetLastCommittedURL().ExtractFileName()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| LaunchWebAppWhileKeepAliveRegistryIsShutdown) { |
| // Command line to simulate app launch. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, "app_id_1"); |
| |
| // Simulate keep alive registry shutdown and try to launch the app and verify |
| // that we don't crash. |
| KeepAliveRegistry::GetInstance()->SetIsShuttingDown(true); |
| web_app::startup::MaybeHandleWebAppLaunch( |
| command_line, base::FilePath(FILE_PATH_LITERAL("\\path")), |
| browser()->profile(), chrome::startup::IsFirstRun::kNo); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| namespace { |
| |
| enum class ChromeAppDeprecationFeatureValue { |
| kDefault, |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| kEnabledWithNoLaunch, |
| kDisabled, |
| #endif |
| }; |
| |
| std::string ChromeAppDeprecationFeatureValueToString( |
| const ::testing::TestParamInfo<ChromeAppDeprecationFeatureValue>& |
| param_info) { |
| std::string result; |
| switch (param_info.param) { |
| case ChromeAppDeprecationFeatureValue::kDefault: |
| result = "ChromeAppDeprecationFeatureDefault"; |
| break; |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| case ChromeAppDeprecationFeatureValue::kEnabledWithNoLaunch: |
| result = "ChromeAppDeprecationFeatureEnabledWithNoLaunch"; |
| break; |
| case ChromeAppDeprecationFeatureValue::kDisabled: |
| result = "ChromeAppDeprecationFeatureDisabled"; |
| break; |
| #endif |
| } |
| return result; |
| } |
| |
| } // namespace |
| |
| class StartupBrowserCreatorChromeAppShortcutTest |
| : public StartupBrowserCreatorTest, |
| public ::testing::WithParamInterface<ChromeAppDeprecationFeatureValue> { |
| protected: |
| StartupBrowserCreatorChromeAppShortcutTest() { |
| switch (GetParam()) { |
| case ChromeAppDeprecationFeatureValue::kDefault: |
| break; |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| case ChromeAppDeprecationFeatureValue::kEnabledWithNoLaunch: |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kChromeAppsDeprecation); |
| break; |
| case ChromeAppDeprecationFeatureValue::kDisabled: |
| scoped_feature_list_.InitAndDisableFeature( |
| features::kChromeAppsDeprecation); |
| break; |
| #endif |
| } |
| } |
| |
| void SetUpOnMainThread() override { |
| StartupBrowserCreatorTest::SetUpOnMainThread(); |
| } |
| |
| void ExpectBlockLaunch(const std::string& app_id, bool force_install_dialog) { |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| auto waiter = views::NamedWidgetShownWaiter( |
| views::test::AnyWidgetTestPasskey{}, |
| force_install_dialog ? "ForceInstalledDeprecatedAppsDialogView" |
| : "DeprecatedAppsDialogView"); |
| #endif |
| // Should have opened the requested homepage about:blank in 1st window. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| EXPECT_FALSE(browser()->is_type_app()); |
| EXPECT_TRUE(browser()->is_type_normal()); |
| EXPECT_EQ(GURL(url::kAboutBlankURL), |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL()); |
| // Should have opened the chrome://apps unsupported app flow in 2nd window. |
| Browser* other_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(other_browser); |
| TabStripModel* other_tab_strip = other_browser->tab_strip_model(); |
| EXPECT_EQ(1, other_tab_strip->count()); |
| EXPECT_FALSE(other_browser->is_type_app()); |
| EXPECT_TRUE(other_browser->is_type_normal()); |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| |
| GURL expected_url = |
| force_install_dialog |
| ? GURL(chrome::kChromeUIAppsWithForceInstalledDeprecationDialogURL + |
| app_id) |
| : GURL(chrome::kChromeUIAppsWithDeprecationDialogURL + app_id); |
| EXPECT_EQ(expected_url, |
| other_tab_strip->GetWebContentsAt(0)->GetVisibleURL()); |
| |
| // Verify that the Deprecated Apps Dialog View also shows up. |
| EXPECT_TRUE(waiter.WaitIfNeededAndGet() != nullptr); |
| #endif |
| } |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| |
| enum class ExpectedLaunchBehavior{kLaunchAnywaysInTab, kLaunchAnywaysInWindow, |
| kNoLaunch}; |
| void ExpectBlockLaunchWithLaunchBehavior(const std::string& app_id, |
| bool force_install_dialog) { |
| EXPECT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| auto waiter = views::NamedWidgetShownWaiter( |
| views::test::AnyWidgetTestPasskey{}, |
| force_install_dialog ? "ForceInstalledDeprecatedAppsDialogView" |
| : "DeprecatedAppsDialogView"); |
| // Should have opened the requested homepage about:blank in 1st window. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| EXPECT_FALSE(browser()->is_type_app()); |
| EXPECT_TRUE(browser()->is_type_normal()); |
| EXPECT_EQ(GURL(url::kAboutBlankURL), |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL()); |
| // Should have opened the chrome://apps unsupported app flow in 2nd window. |
| Browser* other_browser = FindOneOtherBrowser(browser()); |
| DCHECK(other_browser); |
| TabStripModel* other_tab_strip = other_browser->tab_strip_model(); |
| EXPECT_EQ(1, other_tab_strip->count()); |
| EXPECT_FALSE(other_browser->is_type_app()); |
| EXPECT_TRUE(other_browser->is_type_normal()); |
| |
| GURL expected_url = |
| force_install_dialog |
| ? GURL(chrome::kChromeUIAppsWithForceInstalledDeprecationDialogURL + |
| app_id) |
| : GURL(chrome::kChromeUIAppsWithDeprecationDialogURL + app_id); |
| EXPECT_EQ(expected_url, |
| other_tab_strip->GetWebContentsAt(0)->GetVisibleURL()); |
| |
| std::set<Browser*> initial_browsers; |
| for (Browser* initial_browser : *BrowserList::GetInstance()) { |
| initial_browsers.insert(initial_browser); |
| } |
| |
| content::TestNavigationObserver same_tab_observer( |
| other_tab_strip->GetActiveWebContents(), 1, |
| content::MessageLoopRunner::QuitMode::DEFERRED, |
| /*ignore_uncommitted_navigations=*/false); |
| |
| // Verify that the Deprecated Apps Dialog View also shows up. |
| auto* dialog = waiter.WaitIfNeededAndGet(); |
| EXPECT_TRUE(dialog != nullptr); |
| if (force_install_dialog) { |
| // The 'accept' option in the force-install dialog is "launch anyways". |
| dialog->widget_delegate()->AsDialogDelegate()->Accept(); |
| } else { |
| // The 'cancel' option in the deprecation dialog is "launch anyways". |
| dialog->widget_delegate()->AsDialogDelegate()->Cancel(); |
| } |
| |
| // To ensure that no launch happens, run the run loop until idle. |
| base::RunLoop().RunUntilIdle(); |
| Browser* app_browser = ui_test_utils::GetBrowserNotInSet(initial_browsers); |
| EXPECT_EQ(app_browser, nullptr); |
| } |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| |
| bool IsExpectedToAllowLaunch() { |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_FUCHSIA) |
| return false; |
| #else |
| return true; |
| #endif |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTest, |
| OpenAppShortcutNoPref) { |
| // Load an app with launch.container = 'tab'. |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // When we start, the browser should already have an open tab. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| ui_test_utils::TabAddedWaiter tab_waiter(browser()); |
| |
| // Add --app-id=<extension->id()> to the command line. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| if (IsExpectedToAllowLaunch()) { |
| // No pref was set, so the app should have opened in a tab in the existing |
| // window. |
| tab_waiter.Wait(); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| EXPECT_EQ(2, tab_strip->count()); |
| EXPECT_EQ(tab_strip->GetActiveWebContents(), |
| tab_strip->GetWebContentsAt(1)); |
| |
| // It should be a standard tabbed window, not an app window. |
| EXPECT_FALSE(browser()->is_type_app()); |
| EXPECT_TRUE(browser()->is_type_normal()); |
| |
| // It should have loaded the requested app. |
| const std::u16string expected_title( |
| u"app_with_tab_container/empty.html title"); |
| content::TitleWatcher title_watcher(tab_strip->GetActiveWebContents(), |
| expected_title); |
| EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| } else { |
| ExpectBlockLaunch(extension_app->id(), /*force_install_dialog=*/false); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTest, |
| OpenAppShortcutWindowPref) { |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // Set a pref indicating that the user wants to open this app in a window. |
| SetAppLaunchPref(extension_app->id(), extensions::LAUNCH_TYPE_WINDOW); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| |
| ui_test_utils::BrowserChangeObserver browser_waiter( |
| nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| if (IsExpectedToAllowLaunch()) { |
| // Pref was set to open in a window, so the app should have opened in a |
| // window. The launch should have created a new browser. Find the new |
| // browser. |
| Browser* new_browser = browser_waiter.Wait(); |
| ASSERT_TRUE(new_browser); |
| |
| // Expect an app window. |
| EXPECT_TRUE(new_browser->is_type_app()); |
| |
| // The browser's app_name should include the app's ID. |
| EXPECT_NE(new_browser->app_name().find(extension_app->id()), |
| std::string::npos) |
| << new_browser->app_name(); |
| } else { |
| ExpectBlockLaunch(extension_app->id(), /*force_install_dialog=*/false); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTest, |
| OpenAppShortcutTabPref) { |
| // When we start, the browser should already have an open tab. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| ui_test_utils::TabAddedWaiter tab_waiter(browser()); |
| |
| // Load an app with launch.container = 'tab'. |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // Set a pref indicating that the user wants to open this app in a tab. |
| SetAppLaunchPref(extension_app->id(), extensions::LAUNCH_TYPE_REGULAR); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| if (IsExpectedToAllowLaunch()) { |
| // When an app shortcut is open and the pref indicates a tab should open, |
| // the tab is open in the existing browser window. |
| tab_waiter.Wait(); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| EXPECT_EQ(2, tab_strip->count()); |
| EXPECT_EQ(tab_strip->GetActiveWebContents(), |
| tab_strip->GetWebContentsAt(1)); |
| |
| // The browser's app_name should not include the app's ID: it is in a normal |
| // tabbed browser. |
| EXPECT_EQ(browser()->app_name().find(extension_app->id()), |
| std::string::npos) |
| << browser()->app_name(); |
| |
| // It should have loaded the requested app. |
| const std::u16string expected_title( |
| u"app_with_tab_container/empty.html title"); |
| content::TitleWatcher title_watcher(tab_strip->GetActiveWebContents(), |
| expected_title); |
| EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| } else { |
| ExpectBlockLaunch(extension_app->id(), /*force_install_dialog=*/false); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTest, |
| OpenPolicyForcedAppShortcut) { |
| // Load an app with launch.container = 'tab'. |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // Install a test policy provider which will mark the app as force-installed. |
| extensions::TestManagementPolicyProvider policy_provider( |
| extensions::TestManagementPolicyProvider::MUST_REMAIN_INSTALLED); |
| extensions::ExtensionSystem* extension_system = |
| extensions::ExtensionSystem::Get(browser()->profile()); |
| extension_system->management_policy()->RegisterProvider(&policy_provider); |
| |
| // When we start, the browser should already have an open tab. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| ui_test_utils::TabAddedWaiter tab_waiter(browser()); |
| |
| // Add --app-id=<extension->id()> to the command line. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| if (IsExpectedToAllowLaunch()) { |
| tab_waiter.Wait(); |
| |
| // Policy force-installed app should be allowed regardless of Chrome App |
| // Deprecation status. |
| // |
| // No app launch pref was set, so the app should have opened in a tab in the |
| // existing window. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| EXPECT_EQ(2, tab_strip->count()); |
| EXPECT_EQ(tab_strip->GetActiveWebContents(), |
| tab_strip->GetWebContentsAt(1)); |
| |
| // It should be a standard tabbed window, not an app window. |
| EXPECT_FALSE(browser()->is_type_app()); |
| EXPECT_TRUE(browser()->is_type_normal()); |
| |
| // It should have loaded the requested app. |
| const std::u16string expected_title( |
| u"app_with_tab_container/empty.html title"); |
| content::TitleWatcher title_watcher(tab_strip->GetActiveWebContents(), |
| expected_title); |
| EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| } else { |
| ExpectBlockLaunch(extension_app->id(), /*force_install_dialog=*/true); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| StartupBrowserCreatorChromeAppShortcutTest, |
| ::testing::Values( |
| ChromeAppDeprecationFeatureValue::kDefault |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| , |
| ChromeAppDeprecationFeatureValue::kEnabledWithNoLaunch, |
| ChromeAppDeprecationFeatureValue::kDisabled |
| #endif |
| ), |
| ChromeAppDeprecationFeatureValueToString); |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| |
| using StartupBrowserCreatorChromeAppShortcutTestWithLaunch = |
| StartupBrowserCreatorChromeAppShortcutTest; |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTestWithLaunch, |
| OpenAppShortcutNoPref) { |
| // Load an app with launch.container = 'tab'. |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // When we start, the browser should already have an open tab. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| ui_test_utils::TabAddedWaiter tab_waiter(browser()); |
| |
| // Add --app-id=<extension->id()> to the command line. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| ExpectBlockLaunchWithLaunchBehavior(extension_app->id(), |
| /*force_install_dialog=*/false); |
| |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTestWithLaunch, |
| OpenAppShortcutWindowPref) { |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // Set a pref indicating that the user wants to open this app in a window. |
| SetAppLaunchPref(extension_app->id(), extensions::LAUNCH_TYPE_WINDOW); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| |
| ui_test_utils::BrowserChangeObserver browser_waiter( |
| nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| ExpectBlockLaunchWithLaunchBehavior(extension_app->id(), |
| /*force_install_dialog=*/false); |
| |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTestWithLaunch, |
| OpenAppShortcutTabPref) { |
| // When we start, the browser should already have an open tab. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| ui_test_utils::TabAddedWaiter tab_waiter(browser()); |
| |
| // Load an app with launch.container = 'tab'. |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // Set a pref indicating that the user wants to open this app in a tab. |
| SetAppLaunchPref(extension_app->id(), extensions::LAUNCH_TYPE_REGULAR); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| ExpectBlockLaunchWithLaunchBehavior(extension_app->id(), |
| /*force_install_dialog=*/false); |
| |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorChromeAppShortcutTestWithLaunch, |
| OpenPolicyForcedAppShortcut) { |
| // Load an app with launch.container = 'tab'. |
| const Extension* extension_app = nullptr; |
| ASSERT_NO_FATAL_FAILURE(LoadApp("app_with_tab_container", &extension_app)); |
| |
| // Install a test policy provider which will mark the app as force-installed. |
| extensions::TestManagementPolicyProvider policy_provider( |
| extensions::TestManagementPolicyProvider::MUST_REMAIN_INSTALLED); |
| extensions::ExtensionSystem* extension_system = |
| extensions::ExtensionSystem::Get(browser()->profile()); |
| extension_system->management_policy()->RegisterProvider(&policy_provider); |
| |
| // When we start, the browser should already have an open tab. |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| EXPECT_EQ(1, tab_strip->count()); |
| ui_test_utils::TabAddedWaiter tab_waiter(browser()); |
| |
| // Add --app-id=<extension->id()> to the command line. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, extension_app->id()); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| ExpectBlockLaunchWithLaunchBehavior(extension_app->id(), |
| /*force_install_dialog=*/true); |
| |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| // These tests are specifically for testing what happens when the "Launch |
| // Anyways" button is pressed. |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| StartupBrowserCreatorChromeAppShortcutTestWithLaunch, |
| ::testing::Values( |
| ChromeAppDeprecationFeatureValue::kEnabledWithNoLaunch), |
| ChromeAppDeprecationFeatureValueToString); |
| |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| #if BUILDFLAG(IS_WIN) |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, ValidNotificationLaunchId) { |
| // Simulate a launch from the notification_helper process which appends the |
| // kNotificationLaunchId switch to the command line. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchNative( |
| switches::kNotificationLaunchId, |
| L"1|1|0|Default|aumi|0|https://example.com/|notification_id"); |
| |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| // The launch delegates to the notification system and doesn't open any new |
| // browser window. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, InvalidNotificationLaunchId) { |
| // Simulate a launch with invalid launch id, which will fail. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchNative(switches::kNotificationLaunchId, L""); |
| StartupBrowserCreator browser_creator; |
| ASSERT_FALSE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| // No new browser window is open. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| NotificationLaunchIdDisablesLastOpenProfiles) { |
| Profile* default_profile = browser()->profile(); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| // Create another profile. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| dest_path = dest_path.Append(FILE_PATH_LITERAL("New Profile 1")); |
| |
| Profile& other_profile = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path); |
| |
| // Close the browser. |
| CloseBrowserAsynchronously(browser()); |
| |
| // Simulate a launch. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchNative( |
| switches::kNotificationLaunchId, |
| L"1|1|0|Default|0|https://example.com/|notification_id"); |
| |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(&other_profile); |
| |
| StartupBrowserCreator browser_creator; |
| browser_creator.Start(command_line, profile_manager->user_data_dir(), |
| {default_profile, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| |
| // |browser()| is still around at this point, even though we've closed its |
| // window. Thus the browser count for default_profile is 1. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(default_profile)); |
| |
| // When the kNotificationLaunchId switch is present, any last opened profile |
| // is ignored. Thus there is no browser for other_profile. |
| ASSERT_EQ(0u, chrome::GetBrowserCount(&other_profile)); |
| } |
| |
| #endif // BUILDFLAG(IS_WIN) |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| ReadingWasRestartedAfterRestart) { |
| // Tests that StartupBrowserCreator::WasRestarted reads and resets the |
| // preference kWasRestarted correctly. |
| StartupBrowserCreator::was_restarted_read_ = false; |
| PrefService* pref_service = g_browser_process->local_state(); |
| pref_service->SetBoolean(prefs::kWasRestarted, true); |
| EXPECT_TRUE(StartupBrowserCreator::WasRestarted()); |
| EXPECT_FALSE(pref_service->GetBoolean(prefs::kWasRestarted)); |
| EXPECT_TRUE(StartupBrowserCreator::WasRestarted()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| ReadingWasRestartedAfterNormalStart) { |
| // Tests that StartupBrowserCreator::WasRestarted reads and resets the |
| // preference kWasRestarted correctly. |
| StartupBrowserCreator::was_restarted_read_ = false; |
| PrefService* pref_service = g_browser_process->local_state(); |
| pref_service->SetBoolean(prefs::kWasRestarted, false); |
| EXPECT_FALSE(StartupBrowserCreator::WasRestarted()); |
| EXPECT_FALSE(pref_service->GetBoolean(prefs::kWasRestarted)); |
| EXPECT_FALSE(StartupBrowserCreator::WasRestarted()); |
| } |
| |
| #if !BUILDFLAG(IS_CHROMEOS) |
| // If startup pref is set as LAST_AND_URLS, startup urls should be opened in a |
| // new browser window separated from the last-session-restored browser. This |
| // test does not apply to ChromeOS. Ash-chrome and lacros-chrome handle startup |
| // URLs in a different way. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, StartupPrefSetAsLastAndURLs) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Create a new profile. |
| base::FilePath dest_path = |
| profile_manager->user_data_dir().Append(FILE_PATH_LITERAL("New Profile")); |
| Profile& profile = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path); |
| |
| DisableWelcomePages({&profile}); |
| |
| const GURL t1_url = embedded_test_server()->GetURL("/title1.html"); |
| const GURL t2_url = embedded_test_server()->GetURL("/title2.html"); |
| const GURL t3_url = embedded_test_server()->GetURL("/title3.html"); |
| |
| // Set the profiles to open both urls and last visited pages. |
| SessionStartupPref startup_pref(SessionStartupPref::LAST_AND_URLS); |
| std::vector<GURL> urls_to_open; |
| urls_to_open.push_back(t1_url); |
| urls_to_open.push_back(t2_url); |
| startup_pref.urls = urls_to_open; |
| SessionStartupPref::SetStartupPref(&profile, startup_pref); |
| |
| // Open |t3_url| in a tab. |
| Browser* new_browser = Browser::Create( |
| Browser::CreateParams(Browser::TYPE_NORMAL, &profile, true)); |
| TabStripModel* tab_strip_model = new_browser->tab_strip_model(); |
| ui_test_utils::NavigateToURLWithDisposition( |
| new_browser, t3_url, WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); |
| ASSERT_EQ(1, tab_strip_model->count()); |
| EXPECT_EQ(t3_url, |
| tab_strip_model->GetWebContentsAt(0)->GetLastCommittedURL()); |
| |
| // Close the browser without deleting |profile|. |
| ScopedProfileKeepAlive profile_keep_alive( |
| &profile, ProfileKeepAliveOrigin::kBrowserWindow); |
| CloseBrowserSynchronously(new_browser); |
| |
| // Close the main browser. |
| CloseBrowserAsynchronously(browser()); |
| |
| // Do a simple non-process-startup browser launch. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| |
| StartupBrowserCreator browser_creator; |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(browser()->profile()); |
| last_opened_profiles.push_back(&profile); |
| |
| base::RunLoop run_loop; |
| browser_creator.Start( |
| dummy, profile_manager->user_data_dir(), |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| testing::SessionsRestoredWaiter restore_waiter(run_loop.QuitClosure(), 1); |
| run_loop.Run(); |
| |
| const auto wait_for_load_stop_for_browser = [](Browser* browser) { |
| TabStripModel* tab_strip_model = browser->tab_strip_model(); |
| for (int i = 0; i < tab_strip_model->count(); ++i) { |
| content::WebContents* contents = tab_strip_model->GetWebContentsAt(i); |
| EXPECT_TRUE(content::WaitForLoadStop(contents)); |
| } |
| }; |
| |
| // |profile| restored the last open pages and opened the urls in an active new |
| // window. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(&profile)); |
| Browser* pref_urls_opened_browser = |
| chrome::FindLastActiveWithProfile(&profile); |
| ASSERT_TRUE(pref_urls_opened_browser); |
| Browser* last_session_opened_browser = |
| FindOneOtherBrowserForProfile(&profile, pref_urls_opened_browser); |
| ASSERT_TRUE(last_session_opened_browser); |
| // Check the last-session-restored browser. |
| EXPECT_NO_FATAL_FAILURE( |
| wait_for_load_stop_for_browser(last_session_opened_browser)); |
| tab_strip_model = last_session_opened_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip_model->count()); |
| EXPECT_EQ(t3_url, tab_strip_model->GetWebContentsAt(0)->GetVisibleURL()); |
| // Check the pref-urls-opened browser. |
| EXPECT_NO_FATAL_FAILURE( |
| wait_for_load_stop_for_browser(pref_urls_opened_browser)); |
| tab_strip_model = pref_urls_opened_browser->tab_strip_model(); |
| EXPECT_EQ(2, tab_strip_model->GetTabCount()); |
| EXPECT_EQ(t1_url, tab_strip_model->GetWebContentsAt(0)->GetVisibleURL()); |
| EXPECT_EQ(t2_url, tab_strip_model->GetWebContentsAt(1)->GetVisibleURL()); |
| EXPECT_EQ(0, tab_strip_model->active_index()); |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS) |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, StartupURLsForTwoProfiles) { |
| Profile* default_profile = browser()->profile(); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| // Create another profile. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| dest_path = dest_path.Append(FILE_PATH_LITERAL("New Profile 1")); |
| Profile& other_profile = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path); |
| |
| // Use a couple arbitrary URLs. |
| std::vector<GURL> urls1; |
| urls1.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title1.html")))); |
| std::vector<GURL> urls2; |
| urls2.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title2.html")))); |
| |
| // Set different startup preferences for the 2 profiles. |
| SessionStartupPref pref1(SessionStartupPref::URLS); |
| pref1.urls = urls1; |
| SessionStartupPref::SetStartupPref(default_profile, pref1); |
| SessionStartupPref pref2(SessionStartupPref::URLS); |
| pref2.urls = urls2; |
| SessionStartupPref::SetStartupPref(&other_profile, pref2); |
| |
| DisableWelcomePages({default_profile, &other_profile}); |
| |
| // Close the browser. |
| CloseBrowserAsynchronously(browser()); |
| |
| // Do a simple non-process-startup browser launch. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| |
| StartupBrowserCreator browser_creator; |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(default_profile); |
| last_opened_profiles.push_back(&other_profile); |
| browser_creator.Start(dummy, profile_manager->user_data_dir(), |
| {default_profile, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| |
| // urls1 were opened in a browser for default_profile, and urls2 were opened |
| // in a browser for other_profile. |
| Browser* new_browser = nullptr; |
| // |browser()| is still around at this point, even though we've closed its |
| // window. Thus the browser count for default_profile is 2. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(default_profile)); |
| new_browser = FindOneOtherBrowserForProfile(default_profile, browser()); |
| ASSERT_TRUE(new_browser); |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| |
| // The new browser should have only the desired URL for the profile. |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ(urls1[0], tab_strip->GetWebContentsAt(0)->GetVisibleURL()); |
| |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&other_profile)); |
| new_browser = FindOneOtherBrowserForProfile(&other_profile, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ(urls2[0], tab_strip->GetWebContentsAt(0)->GetVisibleURL()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, PRE_UpdateWithTwoProfiles) { |
| // Simulate a browser restart by creating the profiles in the PRE_ part. |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Create two profiles. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 2"))); |
| DisableWelcomePages({&profile1, &profile2}); |
| |
| // Don't delete Profiles too early. |
| ScopedProfileKeepAlive profile1_keep_alive( |
| &profile1, ProfileKeepAliveOrigin::kBrowserWindow); |
| ScopedProfileKeepAlive profile2_keep_alive( |
| &profile2, ProfileKeepAliveOrigin::kBrowserWindow); |
| |
| // Open some urls with the browsers, and close them. |
| Browser* browser1 = Browser::Create( |
| Browser::CreateParams(Browser::TYPE_NORMAL, &profile1, true)); |
| chrome::NewTab(browser1); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser1, embedded_test_server()->GetURL("/empty.html"))); |
| CloseBrowserSynchronously(browser1); |
| |
| Browser* browser2 = Browser::Create( |
| Browser::CreateParams(Browser::TYPE_NORMAL, &profile2, true)); |
| chrome::NewTab(browser2); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser2, embedded_test_server()->GetURL("/form.html"))); |
| CloseBrowserSynchronously(browser2); |
| |
| // Set different startup preferences for the 2 profiles. |
| std::vector<GURL> urls1; |
| urls1.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title1.html")))); |
| std::vector<GURL> urls2; |
| urls2.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title2.html")))); |
| |
| // Set different startup preferences for the 2 profiles. |
| SessionStartupPref pref1(SessionStartupPref::URLS); |
| pref1.urls = urls1; |
| SessionStartupPref::SetStartupPref(&profile1, pref1); |
| SessionStartupPref pref2(SessionStartupPref::URLS); |
| pref2.urls = urls2; |
| SessionStartupPref::SetStartupPref(&profile2, pref2); |
| |
| profile1.GetPrefs()->CommitPendingWrite(); |
| profile2.GetPrefs()->CommitPendingWrite(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, UpdateWithTwoProfiles) { |
| // Make StartupBrowserCreator::WasRestarted() return true. |
| StartupBrowserCreator::was_restarted_read_ = false; |
| PrefService* pref_service = g_browser_process->local_state(); |
| pref_service->SetBoolean(prefs::kWasRestarted, true); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Open the two profiles. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 2"))); |
| |
| // Simulate a launch after a browser update. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreator browser_creator; |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(&profile1); |
| last_opened_profiles.push_back(&profile2); |
| |
| base::RunLoop run_loop; |
| testing::SessionsRestoredWaiter restore_waiter(run_loop.QuitClosure(), 2); |
| browser_creator.Start(dummy, profile_manager->user_data_dir(), |
| {&profile1, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| run_loop.Run(); |
| |
| // The startup URLs are ignored, and instead the last open sessions are |
| // restored. |
| EXPECT_TRUE(profile1.restored_last_session()); |
| EXPECT_TRUE(profile2.restored_last_session()); |
| |
| Browser* new_browser = nullptr; |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile1)); |
| new_browser = FindOneOtherBrowserForProfile(&profile1, nullptr); |
| ASSERT_TRUE(new_browser); |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("/empty.html", |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL().path()); |
| |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile2)); |
| new_browser = FindOneOtherBrowserForProfile(&profile2, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("/form.html", |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL().path()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| ProfilesWithoutPagesNotLaunched) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Create 4 more profiles. |
| base::FilePath dest_path1 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 1")); |
| base::FilePath dest_path2 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 2")); |
| base::FilePath dest_path3 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 3")); |
| base::FilePath dest_path4 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 4")); |
| |
| Profile& profile_home1 = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path1); |
| Profile& profile_home2 = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path2); |
| Profile& profile_last = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path3); |
| Profile& profile_urls = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path4); |
| |
| DisableWelcomePages( |
| {&profile_home1, &profile_home2, &profile_last, &profile_urls}); |
| |
| // Set the profiles to open urls, open last visited pages or display the home |
| // page. |
| SessionStartupPref pref_home(SessionStartupPref::DEFAULT); |
| SessionStartupPref::SetStartupPref(&profile_home1, pref_home); |
| SessionStartupPref::SetStartupPref(&profile_home2, pref_home); |
| |
| SessionStartupPref pref_last(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(&profile_last, pref_last); |
| |
| std::vector<GURL> urls; |
| urls.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title1.html")))); |
| |
| SessionStartupPref pref_urls(SessionStartupPref::URLS); |
| pref_urls.urls = urls; |
| SessionStartupPref::SetStartupPref(&profile_urls, pref_urls); |
| |
| // Open a page with profile_last. |
| Browser* browser_last = Browser::Create( |
| Browser::CreateParams(Browser::TYPE_NORMAL, &profile_last, true)); |
| chrome::NewTab(browser_last); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser_last, embedded_test_server()->GetURL("/empty.html"))); |
| |
| // Close the browser without deleting |profile_last|. |
| ScopedProfileKeepAlive profile_last_keep_alive( |
| &profile_last, ProfileKeepAliveOrigin::kBrowserWindow); |
| CloseBrowserSynchronously(browser_last); |
| |
| // Close the main browser. |
| CloseBrowserAsynchronously(browser()); |
| |
| // Do a simple non-process-startup browser launch. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| |
| StartupBrowserCreator browser_creator; |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(&profile_home1); |
| last_opened_profiles.push_back(&profile_home2); |
| last_opened_profiles.push_back(&profile_last); |
| last_opened_profiles.push_back(&profile_urls); |
| |
| base::RunLoop run_loop; |
| // Only profile_last should get its session restored. |
| testing::SessionsRestoredWaiter restore_waiter(run_loop.QuitClosure(), 1); |
| browser_creator.Start(dummy, profile_manager->user_data_dir(), |
| {&profile_home1, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| run_loop.Run(); |
| |
| Browser* new_browser = nullptr; |
| // The last open profile (the profile_home1 in this case) will always be |
| // launched, even if it will open just the NTP (and the welcome page on |
| // relevant platforms). |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile_home1)); |
| new_browser = FindOneOtherBrowserForProfile(&profile_home1, nullptr); |
| ASSERT_TRUE(new_browser); |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| |
| // The new browser should have only the NTP. |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ(ntp_test_utils::GetFinalNtpUrl(new_browser->profile()), |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL()); |
| |
| // profile_urls opened the urls. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile_urls)); |
| new_browser = FindOneOtherBrowserForProfile(&profile_urls, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ(urls[0], tab_strip->GetWebContentsAt(0)->GetVisibleURL()); |
| |
| // profile_last opened the last open pages. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile_last)); |
| new_browser = FindOneOtherBrowserForProfile(&profile_last, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("/empty.html", |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL().path()); |
| |
| // profile_home2 was not launched since it would've only opened the home page. |
| ASSERT_EQ(0u, chrome::GetBrowserCount(&profile_home2)); |
| } |
| |
| // This tests that opening multiple profiles with session restore enabled, |
| // shutting down, and then launching with kNoStartupWindow doesn't restore |
| // the previously opened profiles. |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| // TODO(crbug.com/40176564): enable this test on Lacros. |
| #define MAYBE_RestoreWithNoStartupWindow DISABLED_RestoreWithNoStartupWindow |
| #else |
| #define MAYBE_RestoreWithNoStartupWindow RestoreWithNoStartupWindow |
| #endif |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| MAYBE_RestoreWithNoStartupWindow) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Create 2 more profiles. |
| base::FilePath dest_path1 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 1")); |
| base::FilePath dest_path2 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 2")); |
| Profile& profile1 = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path1); |
| Profile& profile2 = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path2); |
| DisableWelcomePages({&profile1, &profile2}); |
| |
| // Set the profiles to open last visited pages. |
| SessionStartupPref pref_last(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(&profile1, pref_last); |
| SessionStartupPref::SetStartupPref(&profile2, pref_last); |
| |
| Profile* default_profile = browser()->profile(); |
| |
| // TODO(crbug.com/88586): Adapt this test for DestroyProfileOnBrowserClose if |
| // needed. |
| ScopedKeepAlive keep_alive(KeepAliveOrigin::SESSION_RESTORE, |
| KeepAliveRestartOption::DISABLED); |
| ScopedProfileKeepAlive default_profile_keep_alive( |
| default_profile, ProfileKeepAliveOrigin::kBrowserWindow); |
| ScopedProfileKeepAlive profile1_keep_alive( |
| &profile1, ProfileKeepAliveOrigin::kBrowserWindow); |
| ScopedProfileKeepAlive profile2_keep_alive( |
| &profile2, ProfileKeepAliveOrigin::kBrowserWindow); |
| |
| // Open a page with profile1 and profile2. |
| Browser* browser1 = Browser::Create({Browser::TYPE_NORMAL, &profile1, true}); |
| chrome::NewTab(browser1); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser1, embedded_test_server()->GetURL("/empty.html"))); |
| |
| Browser* browser2 = Browser::Create({Browser::TYPE_NORMAL, &profile2, true}); |
| chrome::NewTab(browser2); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser2, embedded_test_server()->GetURL("/empty.html"))); |
| // Exit the browser, saving the multi-profile session state. |
| chrome::ExecuteCommand(browser(), IDC_EXIT); |
| { |
| base::RunLoop run_loop; |
| AllBrowsersClosedWaiter waiter(run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| // While we closed all the browsers above, this doesn't quit the Mac app, |
| // leaving the app in a half-closed state. Cancel the termination to put the |
| // Mac app back into a known state. |
| chrome_browser_application_mac::CancelTerminate(); |
| #endif |
| |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| dummy.AppendSwitch(switches::kNoStartupWindow); |
| |
| StartupBrowserCreator browser_creator; |
| std::vector<Profile*> last_opened_profiles = {&profile1, &profile2}; |
| browser_creator.Start(dummy, profile_manager->user_data_dir(), |
| {default_profile, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| |
| // TODO(davidbienvenu): Waiting for some sort of browser is started |
| // notification would be better. But, we're not opening any browser |
| // windows, so we'd need to invent a new notification. |
| content::RunAllTasksUntilIdle(); |
| |
| // No browser windows should be opened. |
| EXPECT_EQ(chrome::GetBrowserCount(&profile1), 0u); |
| EXPECT_EQ(chrome::GetBrowserCount(&profile2), 0u); |
| |
| base::CommandLine empty(base::CommandLine::NO_PROGRAM); |
| base::RunLoop run_loop; |
| testing::SessionsRestoredWaiter restore_waiter(run_loop.QuitClosure(), 2); |
| |
| StartupBrowserCreator::ProcessCommandLineAlreadyRunning( |
| empty, {}, {dest_path1, StartupProfileModeReason::kWasRestarted}); |
| run_loop.Run(); |
| |
| // profile1 and profile2 browser windows should be opened. |
| EXPECT_EQ(chrome::GetBrowserCount(&profile1), 1u); |
| EXPECT_EQ(chrome::GetBrowserCount(&profile2), 1u); |
| } |
| |
| // Flaky. See https://crbug.com/819976. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| DISABLED_ProfilesLaunchedAfterCrash) { |
| // After an unclean exit, all profiles will be launched. However, they won't |
| // open any pages automatically. |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Create 3 profiles. |
| base::FilePath dest_path1 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 1")); |
| base::FilePath dest_path2 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 2")); |
| base::FilePath dest_path3 = profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 3")); |
| Profile& profile_home = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path1); |
| Profile& profile_last = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path2); |
| Profile& profile_urls = |
| profiles::testing::CreateProfileSync(profile_manager, dest_path3); |
| |
| // Set the profiles to open the home page, last visited pages or URLs. |
| SessionStartupPref pref_home(SessionStartupPref::DEFAULT); |
| SessionStartupPref::SetStartupPref(&profile_home, pref_home); |
| |
| SessionStartupPref pref_last(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(&profile_last, pref_last); |
| |
| std::vector<GURL> urls; |
| urls.push_back(ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title1.html")))); |
| |
| SessionStartupPref pref_urls(SessionStartupPref::URLS); |
| pref_urls.urls = urls; |
| SessionStartupPref::SetStartupPref(&profile_urls, pref_urls); |
| |
| // Simulate a launch after an unclear exit. |
| CloseBrowserAsynchronously(browser()); |
| ExitTypeService::GetInstanceForProfile(&profile_home) |
| ->SetLastSessionExitTypeForTest(ExitType::kCrashed); |
| ExitTypeService::GetInstanceForProfile(&profile_last) |
| ->SetLastSessionExitTypeForTest(ExitType::kCrashed); |
| ExitTypeService::GetInstanceForProfile(&profile_urls) |
| ->SetLastSessionExitTypeForTest(ExitType::kCrashed); |
| |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| dummy.AppendSwitchASCII(switches::kTestType, "browser"); |
| StartupBrowserCreator browser_creator; |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(&profile_home); |
| last_opened_profiles.push_back(&profile_last); |
| last_opened_profiles.push_back(&profile_urls); |
| browser_creator.Start(dummy, profile_manager->user_data_dir(), |
| {&profile_home, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| |
| // No profiles are getting restored, since they all display the crash info |
| // bar. |
| EXPECT_FALSE(SessionRestore::IsRestoring(&profile_home)); |
| EXPECT_FALSE(SessionRestore::IsRestoring(&profile_last)); |
| EXPECT_FALSE(SessionRestore::IsRestoring(&profile_urls)); |
| |
| // The profile which normally opens the home page displays the new tab page. |
| // The welcome page is also shown for relevant platforms. |
| Browser* new_browser = nullptr; |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile_home)); |
| new_browser = FindOneOtherBrowserForProfile(&profile_home, nullptr); |
| ASSERT_TRUE(new_browser); |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| |
| // The new browser should have only the NTP. |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0))); |
| |
| EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0)); |
| |
| // The profile which normally opens last open pages displays the new tab page. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile_last)); |
| new_browser = FindOneOtherBrowserForProfile(&profile_last, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0))); |
| EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0)); |
| |
| // The profile which normally opens URLs displays the new tab page. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile_urls)); |
| new_browser = FindOneOtherBrowserForProfile(&profile_urls, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0))); |
| EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, |
| LaunchMultipleLockedProfiles) { |
| signin_util::ScopedForceSigninSetterForTesting force_signin_setter(true); |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| base::FilePath user_data_dir = profile_manager->user_data_dir(); |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, |
| user_data_dir.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, |
| user_data_dir.Append(FILE_PATH_LITERAL("New Profile 2"))); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreator browser_creator; |
| std::vector<GURL> urls; |
| urls.push_back(embedded_test_server()->GetURL("/title1.html")); |
| std::vector<Profile*> last_opened_profiles; |
| last_opened_profiles.push_back(&profile1); |
| last_opened_profiles.push_back(&profile2); |
| SessionStartupPref pref(SessionStartupPref::URLS); |
| pref.urls = urls; |
| SessionStartupPref::SetStartupPref(&profile2, pref); |
| |
| ProfileAttributesEntry* entry1 = |
| profile_manager->GetProfileAttributesStorage() |
| .GetProfileAttributesWithPath(profile1.GetPath()); |
| ASSERT_NE(entry1, nullptr); |
| entry1->LockForceSigninProfile(true); |
| |
| ProfileAttributesEntry* entry2 = |
| profile_manager->GetProfileAttributesStorage() |
| .GetProfileAttributesWithPath(profile2.GetPath()); |
| ASSERT_NE(entry2, nullptr); |
| entry2->LockForceSigninProfile(false); |
| |
| browser_creator.Start(command_line, profile_manager->user_data_dir(), |
| {&profile1, StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| |
| ASSERT_EQ(0u, chrome::GetBrowserCount(&profile1)); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile2)); |
| } |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) |
| webapps::AppId InstallPWAWithName(Profile* profile, |
| const GURL& start_url, |
| const std::string& app_name) { |
| auto web_app_info = std::make_unique<web_app::WebAppInstallInfo>(); |
| web_app_info->start_url = start_url; |
| web_app_info->scope = start_url.GetWithoutFilename(); |
| web_app_info->user_display_mode = |
| web_app::mojom::UserDisplayMode::kStandalone; |
| web_app_info->title = base::UTF8ToUTF16(app_name); |
| return web_app::test::InstallWebApp(profile, std::move(web_app_info)); |
| } |
| |
| class StartupBrowserWithListAppsFeature : public StartupBrowserCreatorTest { |
| public: |
| StartupBrowserWithListAppsFeature() { |
| scoped_feature_list_.InitAndEnableFeature(features::kListWebAppsSwitch); |
| } |
| |
| private: |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithListAppsFeature, |
| ListAppsForAllProfiles) { |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| base::FilePath user_data_dir = profile_manager->user_data_dir(); |
| Profile* profile1 = browser()->profile(); |
| |
| // Create a new profile. |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, |
| user_data_dir.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| |
| // Install web apps for the two profiles. |
| auto example_url1 = GURL("http://www.example_one.com"); |
| std::string app_name1 = "A Test Web App1"; |
| webapps::AppId app_id1 = |
| InstallPWAWithName(profile1, example_url1, app_name1); |
| auto example_url2 = GURL("http://www.example_two.com"); |
| std::string app_name2 = "A Test Web App2"; |
| webapps::AppId app_id2 = |
| InstallPWAWithName(profile1, example_url2, app_name2); |
| auto example_url3 = GURL("http://www.example_three.com"); |
| std::string app_name3 = "A Test Web App3"; |
| webapps::AppId app_id3 = |
| InstallPWAWithName(&profile2, example_url3, app_name3); |
| auto example_url4 = GURL("http://www.example_four.com"); |
| std::string app_name4 = "A Test Web App4"; |
| webapps::AppId app_id4 = |
| InstallPWAWithName(&profile2, example_url4, app_name4); |
| |
| // Launch web apps for the two profiles. |
| Browser* app_browser1 = |
| web_app::LaunchWebAppBrowserAndWait(profile1, app_id1); |
| Browser* app_browser2 = |
| web_app::LaunchWebAppBrowserAndWait(&profile2, app_id3); |
| ASSERT_NE(app_browser1, nullptr); |
| ASSERT_NE(app_browser2, nullptr); |
| |
| // List web apps for all profiles. |
| std::vector<Profile*> expected_profiles = {&profile2, profile1}; |
| std::vector<webapps::AppId*> expected_installed_apps_id = { |
| &app_id4, &app_id3, &app_id2, &app_id1}; |
| std::vector<std::string*> expected_installed_apps_name = { |
| &app_name4, &app_name3, &app_name2, &app_name1}; |
| std::vector<webapps::AppId*> expected_open_apps_id = {&app_id1, &app_id3}; |
| std::vector<std::string*> expected_open_apps_name = {&app_name1, &app_name3}; |
| base::Value::Dict apps_for_all_profiles; |
| base::Value::List installed_apps_for_all_profile; |
| base::Value::List open_apps_for_all_profile; |
| for (int i = 0; i < 2; i++) { |
| // Get installed web apps. |
| base::Value::Dict installed_item_info; |
| installed_item_info.Set("profile_id", |
| expected_profiles[i]->GetBaseName().AsUTF8Unsafe()); |
| base::Value::List installed_apps_per_profile; |
| for (int j = 0; j < 2; j++) { |
| base::Value::Dict web_app_info; |
| web_app_info.Set("id", *expected_installed_apps_id[i * 2 + j]); |
| web_app_info.Set("name", *expected_installed_apps_name[i * 2 + j]); |
| installed_apps_per_profile.Append(std::move(web_app_info)); |
| } |
| installed_item_info.Set("web_apps", std::move(installed_apps_per_profile)); |
| installed_apps_for_all_profile.Append(std::move(installed_item_info)); |
| // Get open web apps. |
| base::Value::Dict open_item_info; |
| open_item_info.Set("profile_id", |
| expected_profiles[1 - i]->GetBaseName().AsUTF8Unsafe()); |
| base::Value::List open_apps_per_profile; |
| base::Value::Dict web_app_info; |
| web_app_info.Set("id", *expected_open_apps_id[i]); |
| web_app_info.Set("name", *expected_open_apps_name[i]); |
| open_apps_per_profile.Append(std::move(web_app_info)); |
| open_item_info.Set("web_apps", std::move(open_apps_per_profile)); |
| open_apps_for_all_profile.Append(std::move(open_item_info)); |
| } |
| apps_for_all_profiles.Set("installed_web_apps", |
| std::move(installed_apps_for_all_profile)); |
| apps_for_all_profiles.Set("open_web_apps", |
| std::move(open_apps_for_all_profile)); |
| |
| std::string expected_info; |
| JSONStringValueSerializer serializer(&expected_info); |
| serializer.set_pretty_print(true); |
| EXPECT_TRUE(serializer.Serialize(apps_for_all_profiles)); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| base::FilePath output_path = |
| user_data_dir.Append(FILE_PATH_LITERAL("AppsForAllProfiles.json")); |
| command_line.AppendSwitchPath(switches::kListApps, output_path); |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| CloseBrowserSynchronously(app_browser1); |
| CloseBrowserSynchronously(app_browser2); |
| CloseBrowserSynchronously(browser()); |
| |
| content::RunAllTasksUntilIdle(); |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| std::string file_contents; |
| ASSERT_TRUE(base::ReadFileToString(output_path, &file_contents)); |
| ASSERT_EQ(expected_info, file_contents); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithListAppsFeature, |
| ListAppsForGivenProfile) { |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| base::FilePath user_data_dir = profile_manager->user_data_dir(); |
| Profile* profile1 = browser()->profile(); |
| |
| // Create a new profile. |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, |
| user_data_dir.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| |
| // Install web apps for the two profiles. |
| auto example_url1 = GURL("http://www.example_one.com"); |
| std::string app_name1 = "A Test Web App1"; |
| webapps::AppId app_id1 = |
| InstallPWAWithName(profile1, example_url1, app_name1); |
| auto example_url2 = GURL("http://www.example_two.com"); |
| std::string app_name2 = "A Test Web App2"; |
| webapps::AppId app_id2 = |
| InstallPWAWithName(profile1, example_url2, app_name2); |
| auto example_url3 = GURL("http://www.example_three.com"); |
| std::string app_name3 = "A Test Web App3"; |
| webapps::AppId app_id3 = |
| InstallPWAWithName(&profile2, example_url3, app_name3); |
| auto example_url4 = GURL("http://www.example_four.com"); |
| std::string app_name4 = "A Test Web App4"; |
| webapps::AppId app_id4 = |
| InstallPWAWithName(&profile2, example_url4, app_name4); |
| |
| // Launch web apps for the two profiles. |
| Browser* app_browser1 = |
| web_app::LaunchWebAppBrowserAndWait(profile1, app_id1); |
| Browser* app_browser2 = |
| web_app::LaunchWebAppBrowserAndWait(&profile2, app_id3); |
| ASSERT_NE(app_browser1, nullptr); |
| ASSERT_NE(app_browser2, nullptr); |
| |
| // List web apps for the given profile. |
| |
| // Get installed web apps. |
| base::Value::List installed_apps_for_given_profile; |
| base::Value::Dict installed_item_info; |
| installed_item_info.Set("profile_id", profile2.GetBaseName().AsUTF8Unsafe()); |
| base::Value::List installed_apps_per_profile; |
| base::Value::Dict web_app_info1; |
| web_app_info1.Set("name", app_name4); |
| web_app_info1.Set("id", app_id4); |
| installed_apps_per_profile.Append(std::move(web_app_info1)); |
| base::Value::Dict web_app_info2; |
| web_app_info2.Set("name", app_name3); |
| web_app_info2.Set("id", app_id3); |
| installed_apps_per_profile.Append(std::move(web_app_info2)); |
| installed_item_info.Set("web_apps", std::move(installed_apps_per_profile)); |
| installed_apps_for_given_profile.Append(std::move(installed_item_info)); |
| |
| // Get open web apps. |
| base::Value::List open_apps_for_given_profile; |
| base::Value::Dict open_item_info; |
| open_item_info.Set("profile_id", profile2.GetBaseName().AsUTF8Unsafe()); |
| base::Value::List open_apps_per_profile; |
| base::Value::Dict web_app_info3; |
| web_app_info3.Set("name", app_name3); |
| web_app_info3.Set("id", app_id3); |
| open_apps_per_profile.Append(std::move(web_app_info3)); |
| open_item_info.Set("web_apps", std::move(open_apps_per_profile)); |
| open_apps_for_given_profile.Append(std::move(open_item_info)); |
| |
| base::Value::Dict apps_for_given_profiles; |
| apps_for_given_profiles.Set("installed_web_apps", |
| std::move(installed_apps_for_given_profile)); |
| apps_for_given_profiles.Set("open_web_apps", |
| std::move(open_apps_for_given_profile)); |
| std::string expected_info; |
| JSONStringValueSerializer serializer(&expected_info); |
| serializer.set_pretty_print(true); |
| EXPECT_TRUE(serializer.Serialize(apps_for_given_profiles)); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| base::FilePath output_path = |
| user_data_dir.Append(FILE_PATH_LITERAL("AppsForGivenProfile.json")); |
| command_line.AppendSwitchPath(switches::kListApps, output_path); |
| command_line.AppendSwitchASCII(switches::kProfileBaseName, "New Profile 1"); |
| ASSERT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| |
| CloseBrowserSynchronously(app_browser1); |
| CloseBrowserSynchronously(app_browser2); |
| CloseBrowserSynchronously(browser()); |
| |
| content::RunAllTasksUntilIdle(); |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| std::string file_contents; |
| ASSERT_TRUE(base::ReadFileToString(output_path, &file_contents)); |
| ASSERT_EQ(expected_info, file_contents); |
| } |
| } |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) |
| |
| #if !BUILDFLAG(IS_CHROMEOS) |
| webapps::AppId InstallPWA(Profile* profile, const GURL& start_url) { |
| auto web_app_info = std::make_unique<web_app::WebAppInstallInfo>(); |
| web_app_info->start_url = start_url; |
| web_app_info->scope = start_url.GetWithoutFilename(); |
| web_app_info->user_display_mode = |
| web_app::mojom::UserDisplayMode::kStandalone; |
| web_app_info->title = u"A Web App"; |
| return web_app::test::InstallWebApp(profile, std::move(web_app_info)); |
| } |
| |
| class StartupBrowserCreatorRestartTest : public StartupBrowserCreatorTest, |
| public BrowserListObserver { |
| protected: |
| StartupBrowserCreatorRestartTest() { BrowserList::AddObserver(this); } |
| ~StartupBrowserCreatorRestartTest() override { |
| // We might have already been removed but it's safe to call again. |
| BrowserList::RemoveObserver(this); |
| } |
| |
| void SetUpInProcessBrowserTestFixture() override { |
| base::StringPiece test_name = |
| ::testing::UnitTest::GetInstance()->current_test_info()->name(); |
| |
| if (base::StartsWith(test_name, "PRE_")) { |
| // The PRE_ test will call chrome::AttemptRestart(). |
| mock_relaunch_callback_ = std::make_unique<::testing::StrictMock< |
| base::MockCallback<upgrade_util::RelaunchChromeBrowserCallback>>>(); |
| EXPECT_CALL(*mock_relaunch_callback_, Run); |
| relaunch_chrome_override_ = |
| std::make_unique<upgrade_util::ScopedRelaunchChromeBrowserOverride>( |
| mock_relaunch_callback_->Get()); |
| } |
| } |
| |
| void OnBrowserAdded(Browser* browser) override { |
| base::StringPiece test_name = |
| ::testing::UnitTest::GetInstance()->current_test_info()->name(); |
| |
| // The non PRE_ test will start up as if it was restarted. |
| // Check that, then remove the observer. |
| if (!base::StartsWith(test_name, "PRE_")) { |
| EXPECT_TRUE(StartupBrowserCreator::WasRestarted()); |
| EXPECT_FALSE(browser_added_check_passed_); |
| browser_added_check_passed_ = true; |
| BrowserList::RemoveObserver(this); |
| } |
| } |
| |
| bool browser_added_check_passed_ = false; |
| |
| private: |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| std::unique_ptr< |
| base::MockCallback<upgrade_util::RelaunchChromeBrowserCallback>> |
| mock_relaunch_callback_; |
| std::unique_ptr<upgrade_util::ScopedRelaunchChromeBrowserOverride> |
| relaunch_chrome_override_; |
| }; |
| |
| // Open an App and restart in preparation for the real test. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorRestartTest, |
| PRE_ProfileRestartedAppRestore) { |
| // Ensure services are started. |
| Profile* test_profile = browser()->profile(); |
| |
| AppSessionServiceFactory::GetForProfileForSessionRestore(test_profile); |
| SessionStartupPref pref_last(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(test_profile, pref_last); |
| |
| // Install web app |
| auto example_url = GURL("http://www.example.com"); |
| webapps::AppId app_id = InstallPWA(test_profile, example_url); |
| Browser* app_browser = |
| web_app::LaunchWebAppBrowserAndWait(test_profile, app_id); |
| |
| ASSERT_NE(app_browser, nullptr); |
| ASSERT_EQ(app_browser->type(), Browser::Type::TYPE_APP); |
| ASSERT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id)); |
| |
| chrome::AttemptRestart(); |
| |
| PrefService* pref_service = g_browser_process->local_state(); |
| EXPECT_TRUE(pref_service->GetBoolean(prefs::kWasRestarted)); |
| } |
| |
| // This test tests a specific scenario where the browser is marked as restarted |
| // and a SessionBrowserCreatorImpl::MaybeAsyncRestore is triggered. |
| // ShouldRestoreApps will return true because the profile is marked as |
| // restarted which will trigger apps to restore. If apps are open at this point |
| // and an app restore occurs, apps will be duplicated. This test ensures that |
| // does not occur. This test doesn't build on non app_session_service |
| // platforms, hence the buildflag disablement. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorRestartTest, |
| ProfileRestartedAppRestore) { |
| Profile* test_profile = browser()->profile(); |
| |
| // StartupBrowserCreator() has already run in SetUp(), so it would already be |
| // reset by this point. |
| EXPECT_FALSE(StartupBrowserCreator::WasRestarted()); |
| EXPECT_TRUE(browser_added_check_passed_); |
| // Now close the original (and last alive) tabbed browser window |
| // note: there is still an app open |
| ASSERT_EQ(2u, BrowserList::GetInstance()->size()); |
| CloseBrowserSynchronously(browser()); |
| ASSERT_EQ(1U, BrowserList::GetInstance()->size()); |
| |
| // Now hit the codepath that would get hit if someone opened chrome |
| // from a desktop shortcut or similar. |
| SessionRestoreTestHelper restore_waiter; |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreatorImpl creator(base::FilePath(), dummy, |
| chrome::startup::IsFirstRun::kNo); |
| creator.Launch(test_profile, chrome::startup::IsProcessStartup::kNo, nullptr, |
| /*restore_tabbed_browser=*/true); |
| restore_waiter.Wait(); |
| |
| // We expect a browser to open, but we should NOT get a duplicate app. |
| // Note at this point, the profile IsRestarted() is still true. |
| ASSERT_EQ(2u, BrowserList::GetInstance()->size()); |
| bool app_found = false; |
| bool browser_found = false; |
| for (Browser* browser : *(BrowserList::GetInstance())) { |
| if (browser->type() == Browser::Type::TYPE_APP) { |
| ASSERT_FALSE(app_found); |
| app_found = true; |
| } else if (browser->type() == Browser::Type::TYPE_NORMAL) { |
| ASSERT_FALSE(browser_found); |
| browser_found = true; |
| } |
| } |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS) |
| |
| // An observer that returns back to test code after a new browser is added to |
| // the BrowserList. |
| class BrowserAddedObserver : public BrowserListObserver { |
| public: |
| BrowserAddedObserver() { BrowserList::AddObserver(this); } |
| |
| ~BrowserAddedObserver() override { BrowserList::RemoveObserver(this); } |
| |
| Browser* Wait() { |
| run_loop_.Run(); |
| return browser_; |
| } |
| |
| protected: |
| // BrowserListObserver: |
| void OnBrowserAdded(Browser* browser) override { |
| browser_ = browser; |
| run_loop_.Quit(); |
| } |
| |
| private: |
| raw_ptr<Browser> browser_ = nullptr; |
| base::RunLoop run_loop_; |
| }; |
| |
| class StartupBrowserWithWebAppTest : public StartupBrowserCreatorTest { |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| StartupBrowserCreatorTest::SetUpCommandLine(command_line); |
| if (GetTestPreCount() == 1) { |
| // Load an app with launch.container = 'window'. |
| |
| #if BUILDFLAG(IS_MAC) |
| // While the non-mac version of this test would pass on macOS, it isn't |
| // testing a code path that would actually be used on macOS, and thus not |
| // very useful as a test. Instead test the way an app shim would launch |
| // Chrome in the background to launch an app. |
| command_line->AppendSwitch(switches::kNoStartupWindow); |
| #else |
| command_line->AppendSwitchASCII(switches::kAppId, kAppId); |
| command_line->AppendSwitchASCII(switches::kProfileDirectory, "Default"); |
| #endif |
| } |
| } |
| WebAppProvider& provider() { return *WebAppProvider::GetForTest(profile()); } |
| |
| base::test::ScopedFeatureList scoped_feature_list_; |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithWebAppTest, |
| PRE_PRE_LastUsedProfilesWithWebApp) { |
| // Simulate a browser restart by creating the profiles in the PRE_PRE part. |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Create two profiles. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 2"))); |
| DisableWelcomePages({&profile1, &profile2}); |
| |
| // Open some urls with the browsers, and close them. |
| Browser* browser1 = Browser::Create({Browser::TYPE_NORMAL, &profile1, true}); |
| chrome::NewTab(browser1); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser1, embedded_test_server()->GetURL("/title1.html"))); |
| |
| Browser* browser2 = Browser::Create({Browser::TYPE_NORMAL, &profile2, true}); |
| chrome::NewTab(browser2); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser2, embedded_test_server()->GetURL("/title2.html"))); |
| |
| // Set startup preferences for the 2 profiles to restore last session. |
| SessionStartupPref pref1(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(&profile1, pref1); |
| SessionStartupPref pref2(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(&profile2, pref2); |
| |
| profile1.GetPrefs()->CommitPendingWrite(); |
| profile2.GetPrefs()->CommitPendingWrite(); |
| |
| // Install a web app that we will launch from the command line in |
| // the PRE test. |
| WebAppProvider* const provider = |
| WebAppProvider::GetForTest(browser()->profile()); |
| |
| // Install web app set to open as a standalone window. |
| { |
| std::unique_ptr<web_app::WebAppInstallInfo> info = |
| std::make_unique<web_app::WebAppInstallInfo>(); |
| info->start_url = GURL(kStartUrl); |
| info->title = kAppName; |
| info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; |
| base::test::TestFuture<const webapps::AppId&, webapps::InstallResultCode> |
| result; |
| provider->scheduler().InstallFromInfoWithParams( |
| std::move(info), /*overwrite_existing_manifest_fields=*/true, |
| webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, |
| result.GetCallback(), web_app::WebAppInstallParams()); |
| |
| EXPECT_EQ(result.Get<webapps::AppId>(), kAppId); |
| EXPECT_EQ(result.Get<webapps::InstallResultCode>(), |
| webapps::InstallResultCode::kSuccessNewInstall); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppUserDisplayMode(kAppId), |
| web_app::mojom::UserDisplayMode::kStandalone); |
| |
| #if BUILDFLAG(IS_MAC) |
| AppShimRegistry::Get()->OnAppInstalledForProfile( |
| kAppId, browser()->profile()->GetPath()); |
| #endif |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithWebAppTest, |
| PRE_LastUsedProfilesWithWebApp) { |
| { |
| BrowserAddedObserver added_observer; |
| |
| #if BUILDFLAG(IS_MAC) |
| // Simulate an app shim connecting and launching an app. |
| apps::AppShimManager::Get()->LoadAndLaunchAppForTesting(kAppId); |
| #endif |
| |
| content::RunAllTasksUntilIdle(); |
| // Launching with an app opens the app window via a task, so the test |
| // might start before SelectFirstBrowser is called. |
| if (!browser()) { |
| added_observer.Wait(); |
| SelectFirstBrowser(); |
| } |
| } |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| |
| // An app window should have been launched. |
| EXPECT_TRUE(browser()->is_type_app()); |
| CloseBrowserSynchronously(browser()); |
| } |
| |
| // TODO(crbug.com/327256043): Flaky on win |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_LastUsedProfilesWithWebApp DISABLED_LastUsedProfilesWithWebApp |
| #else |
| #define MAYBE_LastUsedProfilesWithWebApp LastUsedProfilesWithWebApp |
| #endif |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithWebAppTest, |
| MAYBE_LastUsedProfilesWithWebApp) { |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| Profile& profile2 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 2"))); |
| |
| while (SessionRestore::IsRestoring(&profile1) || |
| SessionRestore::IsRestoring(&profile2)) { |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| // The last open sessions should be restored. |
| EXPECT_TRUE(profile1.restored_last_session()); |
| EXPECT_TRUE(profile2.restored_last_session()); |
| |
| Browser* new_browser = nullptr; |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile1)); |
| new_browser = FindOneOtherBrowserForProfile(&profile1, nullptr); |
| ASSERT_TRUE(new_browser); |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| EXPECT_EQ("/title1.html", |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL().path()); |
| |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile2)); |
| new_browser = FindOneOtherBrowserForProfile(&profile2, nullptr); |
| ASSERT_TRUE(new_browser); |
| tab_strip = new_browser->tab_strip_model(); |
| EXPECT_EQ("/title2.html", |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL().path()); |
| } |
| |
| #if !BUILDFLAG(IS_CHROMEOS_LACROS) |
| class StartupBrowserCreatorTestWithGuestParam |
| : public StartupBrowserCreatorTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| bool IsGuest() const { return GetParam(); } |
| |
| GURL GetTestURL() const { return GURL("https://www.youtube.com"); } |
| |
| // Creates a browser for a new profile (which may be Guest, based on |
| // `IsGuest()`). |
| Browser* CreateBrowser() { |
| if (IsGuest()) { |
| profiles::SwitchToGuestProfile(); |
| } else { |
| base::FilePath profile_path = g_browser_process->profile_manager() |
| ->GenerateNextProfileDirectoryPath(); |
| profiles::SwitchToProfile(profile_path, /*always_create=*/true); |
| } |
| Browser* test_browser = ui_test_utils::WaitForBrowserToOpen(); |
| profiles::SetLastUsedProfile(test_browser->profile()->GetBaseName()); |
| return test_browser; |
| } |
| |
| void OpenTabAlreadyRunning() { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendArg(GetTestURL().spec()); |
| ChromeBrowserMainParts::ProcessSingletonNotificationCallback( |
| command_line, /*current_directory=*/{}); |
| } |
| }; |
| |
| // Tests that receiving a launch notification while Chrome is already running |
| // opens the URL in the current browser window. |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorTestWithGuestParam, |
| ProcessCommandLineAlreadyRunning) { |
| ScopedKeepAlive keep_alive(KeepAliveOrigin::BACKGROUND_MODE_MANAGER, |
| KeepAliveRestartOption::DISABLED); |
| CloseBrowserSynchronously(browser()); |
| |
| // Create a browser for a new profile. |
| Browser* test_browser = CreateBrowser(); |
| ASSERT_TRUE(test_browser); |
| ASSERT_EQ(test_browser->profile()->IsGuestSession(), IsGuest()); |
| TabStripModel* tab_strip = test_browser->tab_strip_model(); |
| int initial_tab_count = tab_strip->count(); |
| |
| // Open a URL while a browser is already open. |
| ui_test_utils::AllBrowserTabAddedWaiter tab_waiter; |
| OpenTabAlreadyRunning(); |
| content::WebContents* contents = tab_waiter.Wait(); |
| |
| EXPECT_EQ(initial_tab_count + 1, tab_strip->count()); |
| EXPECT_EQ(contents, tab_strip->GetWebContentsAt(tab_strip->count() - 1)); |
| EXPECT_EQ(GetTestURL(), contents->GetVisibleURL()); |
| } |
| |
| // Tests that receiving a launch notification while Chrome is already running, |
| // but there was no browser window, reopens the last profile if it was regular, |
| // and opens the profile picker if it was guest. |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorTestWithGuestParam, |
| ProcessCommandLineAlreadyRunningAfterBrowserClose) { |
| ScopedKeepAlive keep_alive(KeepAliveOrigin::BACKGROUND_MODE_MANAGER, |
| KeepAliveRestartOption::DISABLED); |
| CloseBrowserSynchronously(browser()); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| // Create a browser for a new profile. |
| Browser* test_browser = CreateBrowser(); |
| Profile* last_profile = test_browser->profile(); |
| ASSERT_TRUE(test_browser); |
| ASSERT_EQ(last_profile->IsGuestSession(), IsGuest()); |
| |
| std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive; |
| if (!IsGuest()) { |
| // Keep the profile alive to avoid unloading and immediately reloading it, |
| // which causes some flakiness within the HistoryService. |
| // This is not done for the guest profile because: |
| // - the test scenario does not involve reloading the guest profile, |
| // - it is not allowed to take a keep alive on a OTR profile. |
| profile_keep_alive = std::make_unique<ScopedProfileKeepAlive>( |
| last_profile, ProfileKeepAliveOrigin::kBackgroundMode); |
| } |
| |
| CloseBrowserSynchronously(test_browser); |
| // Closing the browser did not change the last used profile. |
| EXPECT_EQ(profile_manager->GetLastUsedProfileDir(), last_profile->GetPath()); |
| ASSERT_FALSE(ProfilePicker::IsOpen()); |
| |
| // Open a URL after the last active browser was closed. |
| OpenTabAlreadyRunning(); |
| |
| if (IsGuest()) { |
| // The profile picker opens. There is no browser, the URL is not loaded. |
| profiles::testing::WaitForPickerWidgetCreated(); |
| EXPECT_EQ(0u, BrowserList::GetInstance()->size()); |
| } else { |
| // The last used profile is reopened and the URL is loaded. |
| Browser* browser = ui_test_utils::WaitForBrowserToOpen(); |
| Profile* profile = browser->profile(); |
| EXPECT_FALSE(profile->IsGuestSession()); |
| TabStripModel* tab_strip = browser->tab_strip_model(); |
| EXPECT_EQ( |
| tab_strip->GetWebContentsAt(tab_strip->count() - 1)->GetVisibleURL(), |
| GetTestURL()); |
| EXPECT_FALSE(ProfilePicker::IsOpen()); |
| EXPECT_EQ(1u, BrowserList::GetInstance()->size()); |
| EXPECT_EQ(last_profile, profile); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(, |
| StartupBrowserCreatorTestWithGuestParam, |
| testing::Bool()); |
| |
| class StartupBrowserWithRealWebAppTest : public StartupBrowserCreatorTest { |
| protected: |
| StartupBrowserWithRealWebAppTest() = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override {} |
| |
| WebAppProvider& provider() { return *WebAppProvider::GetForTest(profile()); } |
| |
| private: |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithRealWebAppTest, |
| PRE_PRE_LastUsedProfilesWithRealWebApp) { |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| // Simulate a browser restart by creating the profiles in the PRE_PRE part. |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Create a profile. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| DisableWelcomePages({&profile1}); |
| |
| // Open some urls with the browsers, and close them. |
| SessionServiceFactory::GetForProfileForSessionRestore(&profile1); |
| Browser* browser1 = Browser::Create({Browser::TYPE_NORMAL, &profile1, true}); |
| chrome::NewTab(browser1); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser1, embedded_test_server()->GetURL("/title1.html"))); |
| browser1->window()->Show(); |
| browser1->window()->Maximize(); |
| |
| // Set startup preferences to restore last session. |
| SessionStartupPref pref1(SessionStartupPref::LAST); |
| SessionStartupPref::SetStartupPref(&profile1, pref1); |
| profile1.GetPrefs()->CommitPendingWrite(); |
| |
| SessionStartupPref::SetStartupPref(browser()->profile(), pref1); |
| browser()->profile()->GetPrefs()->CommitPendingWrite(); |
| |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&profile1)); |
| ASSERT_EQ(2u, BrowserList::GetInstance()->size()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithRealWebAppTest, |
| PRE_LastUsedProfilesWithRealWebApp) { |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| |
| auto example_url = GURL("http://www.example.com"); |
| webapps::AppId new_app_id = InstallPWA(&profile1, example_url); |
| Browser* app = web_app::LaunchWebAppBrowserAndWait(&profile1, new_app_id); |
| ASSERT_TRUE(app); |
| |
| // destroy session services so we don't record this closure. |
| // This simulates a user choosing ... -> Exit Chromium. |
| for (auto* profile : profile_manager->GetLoadedProfiles()) { |
| // Don't construct SessionServices for every type just to |
| // shut them down. If they were never created, just skip. |
| if (SessionServiceFactory::GetForProfileIfExisting(profile)) |
| SessionServiceFactory::ShutdownForProfile(profile); |
| |
| if (AppSessionServiceFactory::GetForProfileIfExisting(profile)) |
| AppSessionServiceFactory::ShutdownForProfile(profile); |
| } |
| |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| ASSERT_EQ(2u, chrome::GetBrowserCount(&profile1)); |
| |
| // On ozone-linux, for some reason, these profile 1 windows come back in |
| // the next test. To reliably ensure they don't, but don't destroy the |
| // session restore state, close them while the session services are shutdown. |
| |
| Browser* close_this = FindOneOtherBrowserForProfile(&profile1, app); |
| CloseBrowserSynchronously(close_this); |
| CloseBrowserSynchronously(app); |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| #define MAYBE_LastUsedProfilesWithRealWebApp \ |
| DISABLED_LastUsedProfilesWithRealWebApp |
| #else |
| #define MAYBE_LastUsedProfilesWithRealWebApp LastUsedProfilesWithRealWebApp |
| #endif |
| // TODO(stahon@microsoft.com) App restores are disabled on mac. |
| // see http://crbug.com/1194201 |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWithRealWebAppTest, |
| MAYBE_LastUsedProfilesWithRealWebApp) { |
| // Make StartupBrowserCreator::WasRestarted() return true. |
| StartupBrowserCreator::was_restarted_read_ = false; |
| PrefService* pref_service = g_browser_process->local_state(); |
| pref_service->SetBoolean(prefs::kWasRestarted, true); |
| |
| ASSERT_TRUE(StartupBrowserCreator::WasRestarted()); |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| |
| Profile& profile1 = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("New Profile 1"))); |
| Profile& default_profile = profiles::testing::CreateProfileSync( |
| profile_manager, dest_path.Append(FILE_PATH_LITERAL("Default"))); |
| |
| // At this point, nothing is open except the basic browser. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| ASSERT_EQ(1u, BrowserList::GetInstance()->size()); |
| |
| // Trigger the restore via StartupBrowserCreator. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreatorImpl launch(base::FilePath(), dummy, |
| chrome::startup::IsFirstRun::kNo); |
| // Fake |process_startup| true. |
| launch.Launch(&profile1, chrome::startup::IsProcessStartup::kYes, nullptr, |
| /*restore_tabbed_browser=*/true); |
| |
| // We should get two windows from profile1. |
| ASSERT_EQ(3u, BrowserList::GetInstance()->size()); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&default_profile)); |
| ASSERT_EQ(2u, chrome::GetBrowserCount(&profile1)); |
| |
| while (SessionRestore::IsRestoring(&profile1)) { |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| // Since there's one app being restored, ensure the provider is ready. |
| WebAppProvider* provider = WebAppProvider::GetForTest(&profile1); |
| ASSERT_TRUE(provider->on_registry_ready().is_signaled()); |
| |
| // The last open sessions should be restored. |
| EXPECT_TRUE(profile1.restored_last_session()); |
| |
| Browser* new_browser = nullptr; |
| |
| // 2x profile1, 1x default profile here. |
| ASSERT_EQ(3u, BrowserList::GetInstance()->size()); |
| ASSERT_EQ(2u, chrome::GetBrowserCount(&profile1)); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(&default_profile)); |
| new_browser = FindOneOtherBrowserForProfile(&profile1, nullptr); |
| if (new_browser->type() != Browser::Type::TYPE_NORMAL) { |
| new_browser = FindOneOtherBrowserForProfile(&profile1, new_browser); |
| } |
| ASSERT_TRUE(new_browser); |
| EXPECT_EQ(new_browser->type(), Browser::Type::TYPE_NORMAL); |
| |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| EXPECT_EQ("/title1.html", |
| tab_strip->GetWebContentsAt(0)->GetLastCommittedURL().path()); |
| |
| // Now get the app, it should just be the other browser from this profile. |
| new_browser = FindOneOtherBrowserForProfile(&profile1, new_browser); |
| ASSERT_EQ(new_browser->type(), Browser::Type::TYPE_APP); |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS_LACROS) |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| |
| class StartupBrowserWebAppProtocolHandlingTest : public InProcessBrowserTest { |
| protected: |
| StartupBrowserWebAppProtocolHandlingTest() = default; |
| |
| void SetUpOnMainThread() override { |
| InProcessBrowserTest::SetUpOnMainThread(); |
| } |
| |
| WebAppProvider* provider() { |
| return WebAppProvider::GetForTest(browser()->profile()); |
| } |
| |
| // Install a web app with `protocol_handlers` (and optionally `file_handlers`) |
| // then register it with the ProtocolHandlerRegistry. This is sufficient for |
| // testing URL translation and launch at startup. |
| webapps::AppId InstallWebAppWithProtocolHandlers( |
| const std::vector<apps::ProtocolHandlerInfo>& protocol_handlers, |
| const std::vector<apps::FileHandler>& file_handlers = {}) { |
| std::unique_ptr<web_app::WebAppInstallInfo> info = |
| std::make_unique<web_app::WebAppInstallInfo>(); |
| info->start_url = GURL(kStartUrl); |
| info->title = kAppName; |
| info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; |
| info->protocol_handlers = protocol_handlers; |
| info->file_handlers = file_handlers; |
| webapps::AppId app_id = |
| web_app::test::InstallWebApp(browser()->profile(), std::move(info)); |
| |
| auto& protocol_handler_manager = |
| provider() |
| ->os_integration_manager() |
| .protocol_handler_manager_for_testing(); |
| |
| base::RunLoop run_loop; |
| protocol_handler_manager.RegisterOsProtocolHandlers( |
| app_id, base::BindLambdaForTesting([&](web_app::Result result) { |
| EXPECT_EQ(web_app::Result::kOk, result); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| return app_id; |
| } |
| |
| void SetUpCommandlineAndStart(const std::string& url, |
| const webapps::AppId& app_id) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendArg(url); |
| command_line.AppendSwitchASCII(switches::kAppId, app_id); |
| |
| std::vector<Profile*> last_opened_profiles; |
| StartupBrowserCreator browser_creator; |
| browser_creator.Start( |
| command_line, g_browser_process->profile_manager()->user_data_dir(), |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, |
| last_opened_profiles); |
| } |
| |
| private: |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| #if BUILDFLAG(IS_WIN) |
| // This is needed to stop StartupBrowserWebAppProtocolHandlingTests creating a |
| // shortcut in the Windows start menu. The override needs to last until the |
| // test is destroyed, because Windows shortcut tasks which create the shortcut |
| // can run after the test body returns. |
| base::ScopedPathOverride override_start_dir{base::DIR_START_MENU}; |
| #endif // BUILDFLAG(IS_WIN) |
| }; |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsNotLaunchedWithProtocolUrlAndDialogCancel) { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Register web app as a protocol handler that should handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and close it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kEscKeyPressed); |
| |
| // Check that no extra window is launched. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsLaunchedWithProtocolUrlAndDialogAccept) { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Register web app as a protocol handler that should handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| bool allowed_protocols_notified = false; |
| web_app::WebAppTestRegistryObserverAdapter observer(browser()->profile()); |
| observer.SetWebAppProtocolSettingsChangedDelegate( |
| base::BindLambdaForTesting([&]() { allowed_protocols_notified = true; })); |
| |
| web_app::ProtocolHandlerLaunchDialogView:: |
| SetDefaultRememberSelectionForTesting(true); |
| |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and accepts it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kAcceptButtonClicked); |
| |
| web_app::ProtocolHandlerLaunchDialogView:: |
| SetDefaultRememberSelectionForTesting(false); |
| // Wait for app launch task to complete. |
| content::RunAllTasksUntilIdle(); |
| |
| // Check that we added this protocol to web app's allowed_launch_protocols |
| // on accept. |
| web_app::WebAppRegistrar& registrar = provider()->registrar_unsafe(); |
| EXPECT_TRUE(registrar.IsAllowedLaunchProtocol(app_id, "web+test")); |
| EXPECT_TRUE(allowed_protocols_notified); |
| |
| // Check for new app window. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| Browser* app_browser; |
| app_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(app_browser); |
| EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id)); |
| |
| // Check the app is launched with the correctly translated URL. |
| TabStripModel* tab_strip = app_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| EXPECT_EQ("https://test.com/testing=web%2Btest%3A%2F%2FparameterString", |
| web_contents->GetVisibleURL()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsNotTranslatedWithUnhandledProtocolUrl) { |
| // Register web app as a protocol handler that should *not* handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| |
| // Launch the browser via a command line with an unhandled protocol URL param. |
| SetUpCommandlineAndStart("web+unhandled://parameterString", app_id); |
| |
| // Wait for app launch task to complete. |
| content::RunAllTasksUntilIdle(); |
| |
| // Check an app window is launched. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| Browser* app_browser; |
| app_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(app_browser); |
| EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id)); |
| |
| // Check the app is launched to the home page and not the translated URL. |
| TabStripModel* tab_strip = app_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| EXPECT_EQ(GURL(kStartUrl), web_contents->GetVisibleURL()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsLaunchedWithAllowedProtocolUrlPref) { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Register web app as a protocol handler that should handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| |
| web_app::ProtocolHandlerLaunchDialogView:: |
| SetDefaultRememberSelectionForTesting(true); |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and accepts it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kAcceptButtonClicked); |
| |
| web_app::ProtocolHandlerLaunchDialogView:: |
| SetDefaultRememberSelectionForTesting(false); |
| |
| // Wait for app launch task to complete and launches a new browser. |
| ui_test_utils::WaitForBrowserToOpen(); |
| |
| // Check that we added this protocol to web app's allowed_launch_protocols |
| // on accept. |
| web_app::WebAppRegistrar& registrar = provider()->registrar_unsafe(); |
| EXPECT_TRUE(registrar.IsAllowedLaunchProtocol(app_id, "web+test")); |
| |
| // Check the first app window is created. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| Browser* app_browser1; |
| app_browser1 = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(app_browser1); |
| |
| // Launch the browser via a command line with an handled protocol URL |
| // param, but this time we expect the permission dialog to not show up. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // Wait for app launch task to complete and launches a new browser. |
| ui_test_utils::WaitForBrowserToOpen(); |
| |
| // Check the second app window is launched directly this time. The dialog |
| // is skipped because we have the allowed protocol scheme for the same |
| // app launch. |
| Browser* app_browser2; |
| // There should be 3 browser windows opened at the moment. |
| ASSERT_EQ(3u, chrome::GetBrowserCount(browser()->profile())); |
| for (Browser* b : *BrowserList::GetInstance()) { |
| if (b != browser() && b != app_browser1) |
| app_browser2 = b; |
| } |
| ASSERT_TRUE(app_browser2); |
| EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser2, app_id)); |
| |
| // Check the app is launched with the correctly translated URL. |
| TabStripModel* tab_strip = app_browser2->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| EXPECT_EQ("https://test.com/testing=web%2Btest%3A%2F%2FparameterString", |
| web_contents->GetVisibleURL()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsLaunchedWithAllowedProtocol) { |
| // Register web app as a protocol handler that should handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| |
| { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and accepts it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kAcceptButtonClicked); |
| } |
| |
| // Wait for app launch task to complete and launches a new browser. |
| ui_test_utils::WaitForBrowserToOpen(); |
| |
| // Check that we did not add this protocol to web app's |
| // allowed_launch_protocols on accept. |
| web_app::WebAppRegistrar& registrar = provider()->registrar_unsafe(); |
| EXPECT_FALSE(registrar.IsAllowedLaunchProtocol(app_id, "web+test")); |
| |
| // Check the first app window is created. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| Browser* app_browser1; |
| app_browser1 = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(app_browser1); |
| |
| { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and accepts it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kAcceptButtonClicked); |
| } |
| |
| // Wait for app launch task to complete and launches a new browser. |
| ui_test_utils::WaitForBrowserToOpen(); |
| |
| Browser* app_browser2; |
| // There should be 3 browser windows opened at the moment. |
| ASSERT_EQ(3u, chrome::GetBrowserCount(browser()->profile())); |
| for (Browser* b : *BrowserList::GetInstance()) { |
| if (b != browser() && b != app_browser1) |
| app_browser2 = b; |
| } |
| ASSERT_TRUE(app_browser2); |
| EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser2, app_id)); |
| |
| // Check the app is launched with the correctly translated URL. |
| TabStripModel* tab_strip = app_browser2->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| EXPECT_EQ("https://test.com/testing=web%2Btest%3A%2F%2FparameterString", |
| web_contents->GetVisibleURL()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsLaunchedWithDiallowedProtocolUrlPref) { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Register web app as a protocol handler that should handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| |
| web_app::ProtocolHandlerLaunchDialogView:: |
| SetDefaultRememberSelectionForTesting(true); |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and accepts it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kCancelButtonClicked); |
| base::RunLoop().RunUntilIdle(); |
| |
| web_app::ProtocolHandlerLaunchDialogView:: |
| SetDefaultRememberSelectionForTesting(false); |
| |
| // Check that we added this protocol to web app's allowed_launch_protocols |
| // on accept. |
| web_app::WebAppRegistrar& registrar = provider()->registrar_unsafe(); |
| EXPECT_TRUE(registrar.IsDisallowedLaunchProtocol(app_id, "web+test")); |
| |
| // Check the no app window is created. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserWebAppProtocolHandlingTest, |
| WebAppLaunch_WebAppIsLaunchedWithDisallowedOnceProtocol) { |
| // Register web app as a protocol handler that should handle the launch. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/testing=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| webapps::AppId app_id = InstallWebAppWithProtocolHandlers({protocol_handler}); |
| |
| { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and cancels it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kCancelButtonClicked); |
| } |
| |
| // Check that we did not add this protocol to web app's |
| // allowed_launch_protocols on accept. |
| web_app::WebAppRegistrar& registrar = provider()->registrar_unsafe(); |
| EXPECT_FALSE(registrar.IsDisallowedLaunchProtocol(app_id, "web+test")); |
| |
| // Check the no app window is created. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| |
| { |
| views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, |
| "ProtocolHandlerLaunchDialogView"); |
| |
| // Launch the browser via a command line with a handled protocol URL param. |
| SetUpCommandlineAndStart("web+test://parameterString", app_id); |
| |
| // The waiter will get the dialog when it shows up and accepts it. |
| waiter.WaitIfNeededAndGet()->CloseWithReason( |
| views::Widget::ClosedReason::kCancelButtonClicked); |
| } |
| // There should be only 1 browser window opened at the moment. |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| class StartupBrowserWebAppProtocolAndFileHandlingTest |
| : public StartupBrowserWebAppProtocolHandlingTest { |
| base::test::ScopedFeatureList feature_list_{ |
| blink::features::kFileHandlingAPI}; |
| }; |
| |
| // Verifies that a "file://" URL on the command line is treated as a file |
| // handling launch, not a protocol handling or URL launch. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserWebAppProtocolAndFileHandlingTest, |
| WebAppLaunch_FileProtocol) { |
| // Install an app with protocol handlers and a handler for plain text files. |
| apps::ProtocolHandlerInfo protocol_handler; |
| const std::string handler_url = std::string(kStartUrl) + "/protocol=%s"; |
| protocol_handler.url = GURL(handler_url); |
| protocol_handler.protocol = "web+test"; |
| apps::FileHandler file_handler; |
| file_handler.action = GURL(std::string(kStartUrl) + "/file_handler"); |
| file_handler.accept.push_back({}); |
| file_handler.accept.back().mime_type = "text/plain"; |
| file_handler.accept.back().file_extensions = {".txt"}; |
| webapps::AppId app_id = |
| InstallWebAppWithProtocolHandlers({protocol_handler}, {file_handler}); |
| |
| // Skip the file handler dialog by simulating prior user approval of the API. |
| provider()->sync_bridge_unsafe().SetAppFileHandlerApprovalState( |
| app_id, web_app::ApiApprovalState::kAllowed); |
| |
| // Pass a file:// url on the command line. |
| SetUpCommandlineAndStart("file:///C:/test.txt", app_id); |
| |
| // Wait for app launch task to complete. |
| content::RunAllTasksUntilIdle(); |
| |
| // Check an app window is launched. |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| Browser* app_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(app_browser); |
| EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id)); |
| |
| // Check the app is launched to the file handler URL and not the protocol URL. |
| TabStripModel* tab_strip = app_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| content::WebContents* web_contents = tab_strip->GetWebContentsAt(0); |
| EXPECT_EQ(file_handler.action, web_contents->GetVisibleURL()); |
| |
| app_browser->window()->Close(); |
| ui_test_utils::WaitForBrowserToClose(app_browser); |
| } |
| |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) |
| |
| // These tests are not applicable to Chrome OS as neither initial preferences |
| // nor the onboarding promos exist there. |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| enum class ForYouFreStateParam { |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| // On Lacros we are waterfalling the feature, follow whatever the hardcoded |
| // default is. |
| kDefault, |
| #else |
| kEnabled, |
| kDisabled, |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| }; |
| |
| class StartupBrowserCreatorFirstRunTest |
| : public InProcessBrowserTest, |
| public testing::WithParamInterface<ForYouFreStateParam> { |
| public: |
| StartupBrowserCreatorFirstRunTest() { |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| if (UsesForYouFre()) { |
| scoped_feature_list_.InitWithFeatures( |
| {welcome::kForceEnabled, kForYouFre}, {}); |
| } else { |
| scoped_feature_list_.InitWithFeatures({welcome::kForceEnabled}, |
| {kForYouFre}); |
| } |
| #endif |
| } |
| StartupBrowserCreatorFirstRunTest(const StartupBrowserCreatorFirstRunTest&) = |
| delete; |
| StartupBrowserCreatorFirstRunTest& operator=( |
| const StartupBrowserCreatorFirstRunTest&) = delete; |
| |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override; |
| void SetUpInProcessBrowserTestFixture() override; |
| |
| // Returns `true` when the "ForYouFre" feature is enabled, which does not use |
| // chrome://welcome, but instead runs the first run experience in a dedicated |
| // window. |
| bool UsesForYouFre() const { |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| return base::FeatureList::IsEnabled(kForYouFre); |
| #else |
| return GetParam() == ForYouFreStateParam::kEnabled; |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| } |
| |
| testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_; |
| policy::PolicyMap policy_map_; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| void StartupBrowserCreatorFirstRunTest::SetUpCommandLine( |
| base::CommandLine* command_line) { |
| command_line->AppendSwitch(switches::kForceFirstRun); |
| } |
| |
| void StartupBrowserCreatorFirstRunTest::SetUpInProcessBrowserTestFixture() { |
| #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \ |
| BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| // Set a policy that prevents the first-run dialog from being shown. |
| policy_map_.Set( |
| #if BUILDFLAG(IS_CHROMEOS) |
| policy::key::kDeviceMetricsReportingEnabled, |
| #else |
| policy::key::kMetricsReportingEnabled, |
| #endif |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, |
| policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr); |
| provider_.UpdateChromePolicy(policy_map_); |
| #endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && |
| // BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| |
| provider_.SetDefaultReturns(/*is_initialization_complete_return=*/true, |
| /*is_first_policy_load_complete_return=*/true); |
| policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorFirstRunTest, AddFirstRunTabs) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| StartupBrowserCreator browser_creator; |
| browser_creator.AddFirstRunTabs( |
| {embedded_test_server()->GetURL("/title1.html"), |
| embedded_test_server()->GetURL("/title2.html")}); |
| |
| // Do a simple non-process-startup browser launch. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| |
| StartupBrowserCreatorImpl launch(base::FilePath(), dummy, &browser_creator, |
| chrome::startup::IsFirstRun::kYes); |
| launch.Launch(browser()->profile(), chrome::startup::IsProcessStartup::kNo, |
| nullptr, /*restore_tabbed_browser=*/true); |
| |
| // This should have created a new browser window. |
| Browser* new_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(new_browser); |
| |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| |
| EXPECT_EQ(2, tab_strip->count()); |
| |
| EXPECT_EQ("title1.html", |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().ExtractFileName()); |
| EXPECT_EQ("title2.html", |
| tab_strip->GetWebContentsAt(1)->GetVisibleURL().ExtractFileName()); |
| } |
| |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_MAC) |
| // http://crbug.com/314819 |
| #define MAYBE_RestoreOnStartupURLsPolicySpecified \ |
| DISABLED_RestoreOnStartupURLsPolicySpecified |
| #else |
| #define MAYBE_RestoreOnStartupURLsPolicySpecified \ |
| RestoreOnStartupURLsPolicySpecified |
| #endif |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorFirstRunTest, |
| MAYBE_RestoreOnStartupURLsPolicySpecified) { |
| #if BUILDFLAG(IS_WIN) |
| return; |
| #endif // BUILDFLAG(IS_WIN) |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| StartupBrowserCreator browser_creator; |
| |
| DisableWelcomePages({browser()->profile()}); |
| |
| // Set the following user policies: |
| // * RestoreOnStartup = RestoreOnStartupIsURLs |
| // * RestoreOnStartupURLs = [ "/title1.html" ] |
| policy_map_.Set(policy::key::kRestoreOnStartup, |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, |
| policy::POLICY_SOURCE_CLOUD, |
| base::Value(SessionStartupPref::kPrefValueURLs), nullptr); |
| base::Value::List startup_urls; |
| startup_urls.Append(embedded_test_server()->GetURL("/title1.html").spec()); |
| policy_map_.Set(policy::key::kRestoreOnStartupURLs, |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, |
| policy::POLICY_SOURCE_CLOUD, |
| base::Value(std::move(startup_urls)), nullptr); |
| provider_.UpdateChromePolicy(policy_map_); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Close the browser. |
| CloseBrowserAsynchronously(browser()); |
| |
| // Do a process-startup browser launch. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreatorImpl launch(base::FilePath(), dummy, &browser_creator, |
| chrome::startup::IsFirstRun::kYes); |
| launch.Launch(browser()->profile(), chrome::startup::IsProcessStartup::kYes, |
| nullptr, /*restore_tabbed_browser=*/true); |
| |
| // This should have created a new browser window. |
| Browser* new_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(new_browser); |
| |
| // Verify that the URL specified through policy is shown and no sync promo has |
| // been added. |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("title1.html", |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().ExtractFileName()); |
| } |
| |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_MAC) |
| // http://crbug.com/314819 |
| #define MAYBE_FirstRunTabsWithRestoreSession \ |
| DISABLED_FirstRunTabsWithRestoreSession |
| #else |
| #define MAYBE_FirstRunTabsWithRestoreSession FirstRunTabsWithRestoreSession |
| #endif |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorFirstRunTest, |
| MAYBE_FirstRunTabsWithRestoreSession) { |
| // Simulate the following initial preferences: |
| // { |
| // "first_run_tabs" : [ |
| // "/title1.html" |
| // ], |
| // "session" : { |
| // "restore_on_startup" : 1 |
| // }, |
| // "sync_promo" : { |
| // "user_skipped" : true |
| // } |
| // } |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| StartupBrowserCreator browser_creator; |
| browser_creator.AddFirstRunTabs( |
| {embedded_test_server()->GetURL("/title1.html")}); |
| browser()->profile()->GetPrefs()->SetInteger(prefs::kRestoreOnStartup, 1); |
| |
| // Do a process-startup browser launch. |
| base::CommandLine dummy(base::CommandLine::NO_PROGRAM); |
| StartupBrowserCreatorImpl launch(base::FilePath(), dummy, &browser_creator, |
| chrome::startup::IsFirstRun::kYes); |
| launch.Launch(browser()->profile(), chrome::startup::IsProcessStartup::kYes, |
| nullptr, /*restore_tabbed_browser=*/true); |
| |
| // This should have created a new browser window. |
| Browser* new_browser = FindOneOtherBrowser(browser()); |
| ASSERT_TRUE(new_browser); |
| |
| // Verify that the first-run tab is shown and no other pages are present. |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("title1.html", |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().ExtractFileName()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorFirstRunTest, WelcomePages) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| // Welcome page should not be shown on Lacros. |
| // (about:blank or new tab page will be shown instead) |
| TabStripModel* tab_strip = browser()->tab_strip_model(); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_NE(chrome::kChromeUIWelcomeURL, tab_strip->GetWebContentsAt(0) |
| ->GetLastCommittedURL() |
| .possibly_invalid_spec()); |
| #endif |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Open the two profiles. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| |
| std::unique_ptr<Profile> profile1; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| profile1 = Profile::CreateProfile( |
| dest_path.Append(FILE_PATH_LITERAL("New Profile 1")), nullptr, |
| Profile::CreateMode::CREATE_MODE_SYNCHRONOUS); |
| } |
| Profile* profile1_ptr = profile1.get(); |
| ASSERT_TRUE(profile1_ptr); |
| profile_manager->RegisterTestingProfile(std::move(profile1), true); |
| |
| Browser* browser = OpenNewBrowser(profile1_ptr); |
| ASSERT_TRUE(browser); |
| |
| TabStripModel* tab_strip1 = browser->tab_strip_model(); |
| |
| // Ensure that the standard Welcome page appears on second run on Win 10, and |
| // on first run on all other platforms. |
| ASSERT_EQ(1, tab_strip1->count()); |
| bool should_show_welcome = !UsesForYouFre(); |
| std::string new_tab_url1 = |
| tab_strip1->GetWebContentsAt(0)->GetVisibleURL().possibly_invalid_spec(); |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| // Welcome page should not be shown on Lacros. |
| // (about:blank or new tab page will be shown instead) |
| should_show_welcome = false; |
| #endif |
| if (should_show_welcome) |
| EXPECT_EQ(chrome::kChromeUIWelcomeURL, new_tab_url1); |
| else |
| EXPECT_NE(chrome::kChromeUIWelcomeURL, new_tab_url1); |
| |
| // TODO(crbug.com/88586): Adapt this test for DestroyProfileOnBrowserClose. |
| ScopedProfileKeepAlive profile1_keep_alive( |
| profile1_ptr, ProfileKeepAliveOrigin::kBrowserWindow); |
| |
| browser = CloseBrowserAndOpenNew(browser, profile1_ptr); |
| ASSERT_TRUE(browser); |
| tab_strip1 = browser->tab_strip_model(); |
| |
| // Ensure that the new tab page appears on subsequent runs. |
| ASSERT_EQ(1, tab_strip1->count()); |
| EXPECT_EQ( |
| chrome::kChromeUINewTabURL, |
| tab_strip1->GetWebContentsAt(0)->GetVisibleURL().possibly_invalid_spec()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorFirstRunTest, |
| WelcomePagesWithPolicy) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Set the following user policies: |
| // * RestoreOnStartup = RestoreOnStartupIsURLs |
| // * RestoreOnStartupURLs = [ "/title1.html" ] |
| policy_map_.Set(policy::key::kRestoreOnStartup, |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, |
| policy::POLICY_SOURCE_CLOUD, base::Value(4), nullptr); |
| base::Value::List url_list; |
| url_list.Append(embedded_test_server()->GetURL("/title1.html").spec()); |
| policy_map_.Set(policy::key::kRestoreOnStartupURLs, |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, |
| policy::POLICY_SOURCE_CLOUD, base::Value(std::move(url_list)), |
| nullptr); |
| provider_.UpdateChromePolicy(policy_map_); |
| base::RunLoop().RunUntilIdle(); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| |
| // Open the two profiles. |
| base::FilePath dest_path = profile_manager->user_data_dir(); |
| |
| std::unique_ptr<Profile> profile1; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| profile1 = Profile::CreateProfile( |
| dest_path.Append(FILE_PATH_LITERAL("New Profile 1")), nullptr, |
| Profile::CreateMode::CREATE_MODE_SYNCHRONOUS); |
| } |
| Profile* profile1_ptr = profile1.get(); |
| ASSERT_TRUE(profile1_ptr); |
| profile_manager->RegisterTestingProfile(std::move(profile1), true); |
| |
| Browser* browser = OpenNewBrowser(profile1_ptr); |
| ASSERT_TRUE(browser); |
| |
| TabStripModel* tab_strip = browser->tab_strip_model(); |
| |
| // TODO(crbug.com/88586): Adapt this test for DestroyProfileOnBrowserClose. |
| ScopedProfileKeepAlive profile1_keep_alive( |
| profile1_ptr, ProfileKeepAliveOrigin::kBrowserWindow); |
| |
| #if BUILDFLAG(IS_WIN) |
| // Windows has its own Welcome page but even that should not show up when |
| // the policy is set. |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("title1.html", |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().ExtractFileName()); |
| |
| browser = CloseBrowserAndOpenNew(browser, profile1_ptr); |
| ASSERT_TRUE(browser); |
| tab_strip = browser->tab_strip_model(); |
| #endif // BUILDFLAG(IS_WIN) |
| |
| // Ensure that the policy page page appears on second run on Win 10, and |
| // on first run on all other platforms. |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("title1.html", |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().ExtractFileName()); |
| |
| browser = CloseBrowserAndOpenNew(browser, profile1_ptr); |
| ASSERT_TRUE(browser); |
| tab_strip = browser->tab_strip_model(); |
| |
| // Ensure that the policy page page appears on subsequent runs. |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ("title1.html", |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().ExtractFileName()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(, |
| StartupBrowserCreatorFirstRunTest, |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| testing::Values(ForYouFreStateParam::kDefault) |
| #else |
| testing::Values(ForYouFreStateParam::kEnabled, |
| ForYouFreStateParam::kDisabled) |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| ); |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // Validates that prefs::kWasRestarted is automatically reset after next browser |
| // start. |
| class StartupBrowserCreatorWasRestartedFlag : public InProcessBrowserTest, |
| public BrowserListObserver { |
| public: |
| StartupBrowserCreatorWasRestartedFlag() { BrowserList::AddObserver(this); } |
| ~StartupBrowserCreatorWasRestartedFlag() override { |
| BrowserList::RemoveObserver(this); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| command_line->AppendSwitchPath(switches::kUserDataDir, temp_dir_.GetPath()); |
| std::string json; |
| base::Value::Dict local_state; |
| local_state.SetByDottedPath(prefs::kWasRestarted, true); |
| base::JSONWriter::Write(local_state, &json); |
| ASSERT_TRUE(base::WriteFile( |
| temp_dir_.GetPath().Append(chrome::kLocalStateFilename), json)); |
| } |
| |
| protected: |
| // SetUpCommandLine is setting kWasRestarted, so these tests all start up |
| // with WasRestarted() true. |
| void OnBrowserAdded(Browser* browser) override { |
| EXPECT_TRUE(StartupBrowserCreator::WasRestarted()); |
| EXPECT_FALSE( |
| g_browser_process->local_state()->GetBoolean(prefs::kWasRestarted)); |
| on_browser_added_hit_ = true; |
| } |
| |
| bool on_browser_added_hit_ = false; |
| |
| private: |
| base::ScopedTempDir temp_dir_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorWasRestartedFlag, Test) { |
| // OnBrowserAdded() should have been hit before the test body began. |
| EXPECT_TRUE(on_browser_added_hit_); |
| // This is a bit strange but what occurs is that StartupBrowserCreator runs |
| // before this test body is hit and ~StartupBrowserCreator() will reset the |
| // restarted state, so here when we read WasRestarted() it should already be |
| // reset to false. |
| EXPECT_FALSE(StartupBrowserCreator::WasRestarted()); |
| EXPECT_FALSE( |
| g_browser_process->local_state()->GetBoolean(prefs::kWasRestarted)); |
| } |
| |
| // The kCommandLineFlagSecurityWarningsEnabled policy doesn't exist on ChromeOS. |
| #if !BUILDFLAG(IS_CHROMEOS) |
| enum class CommandLineFlagSecurityWarningsPolicy { |
| kNoPolicy, |
| kEnabled, |
| kDisabled, |
| }; |
| |
| // Verifies that infobars are displayed (or not) depending on enterprise policy. |
| class StartupBrowserCreatorInfobarsTest |
| : public InProcessBrowserTest, |
| public ::testing::WithParamInterface< |
| std::tuple<StartupBrowserCreatorFlagTypeValue, |
| CommandLineFlagSecurityWarningsPolicy>> { |
| public: |
| StartupBrowserCreatorInfobarsTest() |
| : flag_type_(std::get<0>(GetParam())), policy_(std::get<1>(GetParam())) {} |
| |
| protected: |
| std::pair<Browser*, infobars::ContentInfoBarManager*> |
| LaunchBrowserAndGetCreatedInfoBarManager( |
| const base::CommandLine& command_line) { |
| BrowserAddedObserver added_observer; |
| |
| base::test::TestFuture<void> app_launch_done; |
| if (command_line.HasSwitch(switches::kAppId)) { |
| web_app::startup::SetStartupDoneCallbackForTesting( |
| app_launch_done.GetCallback()); |
| } else { |
| std::move(app_launch_done.GetCallback()).Run(); |
| } |
| EXPECT_TRUE(StartupBrowserCreator().ProcessCmdLineImpl( |
| command_line, base::FilePath(), chrome::startup::IsProcessStartup::kNo, |
| {browser()->profile(), StartupProfileMode::kBrowserWindow}, {})); |
| EXPECT_TRUE(app_launch_done.Wait()); |
| |
| // Wait until the new browser window has been created. Using |
| // `FindOneOtherBrowser` is not sufficient here, because the window may be |
| // created asynchronously. |
| Browser* new_browser = added_observer.Wait(); |
| EXPECT_TRUE(new_browser); |
| |
| infobars::ContentInfoBarManager* infobar_manager = |
| infobars::ContentInfoBarManager::FromWebContents( |
| new_browser->tab_strip_model()->GetWebContentsAt(0)); |
| EXPECT_TRUE(infobar_manager); |
| |
| return std::make_pair(new_browser, infobar_manager); |
| } |
| |
| const StartupBrowserCreatorFlagTypeValue flag_type_; |
| const CommandLineFlagSecurityWarningsPolicy policy_; |
| |
| private: |
| void SetUpInProcessBrowserTestFixture() override { |
| policy_provider_.SetDefaultReturns( |
| /*is_initialization_complete_return=*/true, |
| /*is_first_policy_load_complete_return=*/true); |
| policy::BrowserPolicyConnector::SetPolicyProviderForTesting( |
| &policy_provider_); |
| |
| if (policy_ != CommandLineFlagSecurityWarningsPolicy::kNoPolicy) { |
| bool is_enabled = |
| policy_ == CommandLineFlagSecurityWarningsPolicy::kEnabled; |
| policy::PolicyMap policies; |
| policies.Set(policy::key::kCommandLineFlagSecurityWarningsEnabled, |
| policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, |
| policy::POLICY_SOURCE_PLATFORM, base::Value(is_enabled), |
| nullptr); |
| policy_provider_.UpdateChromePolicy(policies); |
| } |
| } |
| web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_; |
| testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorInfobarsTest, CheckInfobar) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| // We deliberately set the flag on the process command line instead of on the |
| // command_line passed to the StartupBrowserCreator, because these flags are |
| // all read from CommandLine::ForCurrentProcess and ignore the command line |
| // passed to StartupBrowserCreator. In browser tests, this references the |
| // browser test's instead of the new process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(flag_type_.flag); |
| auto [browser, infobar_manager] = |
| LaunchBrowserAndGetCreatedInfoBarManager(command_line); |
| EXPECT_TRUE(browser->is_type_normal()); |
| |
| EXPECT_EQ(HasInfoBar(infobar_manager, flag_type_.infobar_identifier), |
| policy_ != CommandLineFlagSecurityWarningsPolicy::kDisabled); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorInfobarsTest, |
| CheckInfobarIsShownForWebApps) { |
| // We deliberately set the flag on the process command line instead of on the |
| // command_line passed to the StartupBrowserCreator, because these flags are |
| // all read from CommandLine::ForCurrentProcess and ignore the command line |
| // passed to StartupBrowserCreator. In browser tests, this references the |
| // browser test's instead of the new process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(flag_type_.flag); |
| |
| Profile* test_profile = browser()->profile(); |
| // Install web app |
| GURL example_url("http://www.example.com"); |
| webapps::AppId app_id = InstallPWA(test_profile, example_url); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(switches::kAppId, app_id); |
| |
| auto [browser, infobar_manager] = |
| LaunchBrowserAndGetCreatedInfoBarManager(command_line); |
| EXPECT_TRUE(browser->is_type_app()); |
| |
| EXPECT_EQ(HasInfoBar(infobar_manager, flag_type_.infobar_identifier), |
| policy_ != CommandLineFlagSecurityWarningsPolicy::kDisabled); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorInfobarsTest, |
| CheckInfobarIsShownForAppUrlShortcuts) { |
| // We deliberately set the flag on the process command line instead of on the |
| // command_line passed to the StartupBrowserCreator, because these flags are |
| // all read from CommandLine::ForCurrentProcess and ignore the command line |
| // passed to StartupBrowserCreator. In browser tests, this references the |
| // browser test's instead of the new process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(flag_type_.flag); |
| |
| // Add --app=<url> to the command line. Tests launching legacy apps which may |
| // have been created by "Add to Desktop" in old versions of Chrome. |
| // TODO(mgiuca): Delete this feature (https://crbug.com/751029). We are |
| // keeping it for now to avoid disrupting existing workflows. |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| GURL url = ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(FILE_PATH_LITERAL("title2.html"))); |
| command_line.AppendSwitchASCII(switches::kApp, url.spec()); |
| |
| auto [browser, infobar_manager] = |
| LaunchBrowserAndGetCreatedInfoBarManager(command_line); |
| EXPECT_TRUE(browser->is_type_app()); |
| |
| EXPECT_EQ(HasInfoBar(infobar_manager, flag_type_.infobar_identifier), |
| policy_ != CommandLineFlagSecurityWarningsPolicy::kDisabled); |
| } |
| |
| // The trybots set the kNoSandbox flag when running browser tests with the |
| // address sanitizer enabled, which contradicts with the assumption of this test |
| // that there is no bad flag on the process command line. |
| #if defined(ADDRESS_SANITIZER) |
| #define MAYBE_CheckInfobarOnlyUsesProcessCommandLine \ |
| DISABLED_CheckInfobarOnlyUsesProcessCommandLine |
| #else |
| #define MAYBE_CheckInfobarOnlyUsesProcessCommandLine \ |
| CheckInfobarOnlyUsesProcessCommandLine |
| #endif |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorInfobarsTest, |
| MAYBE_CheckInfobarOnlyUsesProcessCommandLine) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| // The flag should not result in an infobar when not set on the process |
| // command line via CommandLine::ForCurrentProcess. |
| command_line.AppendSwitch(flag_type_.flag); |
| auto [browser, infobar_manager] = |
| LaunchBrowserAndGetCreatedInfoBarManager(command_line); |
| EXPECT_TRUE(browser->is_type_normal()); |
| |
| EXPECT_FALSE(HasInfoBar(infobar_manager, flag_type_.infobar_identifier)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| PolicyControl, |
| StartupBrowserCreatorInfobarsTest, |
| ::testing::Combine( |
| ::testing::Values( |
| StartupBrowserCreatorFlagTypeValue{ |
| switches::kEnableAutomation, |
| infobars::InfoBarDelegate::AUTOMATION_INFOBAR_DELEGATE}, |
| // Test one of the flags from |bad_flags_prompt.cc|. Any of the |
| // flags should have the same behavior. |
| StartupBrowserCreatorFlagTypeValue{ |
| switches::kDisableWebSecurity, |
| infobars::InfoBarDelegate::BAD_FLAGS_INFOBAR_DELEGATE}), |
| ::testing::Values(CommandLineFlagSecurityWarningsPolicy::kNoPolicy, |
| CommandLineFlagSecurityWarningsPolicy::kEnabled, |
| CommandLineFlagSecurityWarningsPolicy::kDisabled)), |
| [](const testing::TestParamInfo< |
| StartupBrowserCreatorInfobarsTest::ParamType>& info) { |
| std::string policyState; |
| switch (std::get<1>(info.param)) { |
| case CommandLineFlagSecurityWarningsPolicy::kNoPolicy: |
| policyState = "no policy"; |
| break; |
| case CommandLineFlagSecurityWarningsPolicy::kEnabled: |
| policyState = "policy enabled"; |
| break; |
| case CommandLineFlagSecurityWarningsPolicy::kDisabled: |
| policyState = "policy disabled"; |
| break; |
| } |
| |
| std::string name = std::get<0>(info.param).flag + " " + policyState; |
| std::replace_if( |
| name.begin(), name.end(), |
| [](unsigned char c) { return !absl::ascii_isalnum(c); }, '_'); |
| return name; |
| }); |
| |
| // Verifies that infobars are displayed in the first browser window, even when |
| // the browser is started without an initial browser window by passing the |
| // `switches::kNoStartupWindow` command line switch. |
| class StartupBrowserCreatorInfobarsWithoutStartupWindowTest |
| : public InProcessBrowserTest, |
| public ::testing::WithParamInterface<StartupBrowserCreatorFlagTypeValue> { |
| public: |
| StartupBrowserCreatorInfobarsWithoutStartupWindowTest() |
| : flag_type_(GetParam()) {} |
| |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| InProcessBrowserTest::SetUpCommandLine(command_line); |
| command_line->AppendSwitch(switches::kNoStartupWindow); |
| command_line->AppendSwitch(switches::kKeepAliveForTest); |
| } |
| |
| infobars::ContentInfoBarManager* LaunchBrowserAndGetCreatedInfoBarManager() { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| Profile* profile = ProfileManager::GetLastUsedProfileIfLoaded(); |
| |
| StartupBrowserCreatorImpl launch(base::FilePath(), command_line, |
| chrome::startup::IsFirstRun::kNo); |
| launch.Launch(profile, chrome::startup::IsProcessStartup::kNo, nullptr, |
| /*restore_tabbed_browser=*/true); |
| Browser* new_browser = BrowserList::GetInstance()->GetLastActive(); |
| |
| return infobars::ContentInfoBarManager::FromWebContents( |
| new_browser->tab_strip_model()->GetWebContentsAt(0)); |
| } |
| |
| const StartupBrowserCreatorFlagTypeValue flag_type_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorInfobarsWithoutStartupWindowTest, |
| CheckInfobar) { |
| // We deliberately set the flag on the process command line instead of on the |
| // command_line passed to the StartupBrowserCreator, because these flags are |
| // all read from `CommandLine::ForCurrentProcess` and ignore the command line |
| // passed to `StartupBrowserCreator`. In browser tests, this references the |
| // browser test's instead of the new process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(flag_type_.flag); |
| |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| infobars::ContentInfoBarManager* infobar_manager = |
| LaunchBrowserAndGetCreatedInfoBarManager(); |
| ASSERT_TRUE(infobar_manager); |
| EXPECT_TRUE(HasInfoBar(infobar_manager, flag_type_.infobar_identifier)); |
| |
| // Now close and reopen the browser again - and re-check if the infobar is |
| // there. |
| CloseBrowserSynchronously(BrowserList::GetInstance()->GetLastActive()); |
| |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| infobar_manager = LaunchBrowserAndGetCreatedInfoBarManager(); |
| ASSERT_TRUE(infobar_manager); |
| EXPECT_EQ(flag_type_.is_global_infobar, |
| HasInfoBar(infobar_manager, flag_type_.infobar_identifier)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| StartupBrowserCreatorInfobarsWithoutStartupWindowTest, |
| ::testing::Values( |
| StartupBrowserCreatorFlagTypeValue{ |
| switches::kEnableAutomation, |
| infobars::InfoBarDelegate::AUTOMATION_INFOBAR_DELEGATE, true}, |
| // Test one of the flags from |bad_flags_prompt.cc|. Any of the |
| // flags should have the same behavior. |
| StartupBrowserCreatorFlagTypeValue{ |
| switches::kDisableWebSecurity, |
| infobars::InfoBarDelegate::BAD_FLAGS_INFOBAR_DELEGATE, false}), |
| [](const testing::TestParamInfo< |
| StartupBrowserCreatorInfobarsWithoutStartupWindowTest::ParamType>& |
| info) { |
| std::string name = info.param.flag; |
| std::replace_if( |
| name.begin(), name.end(), |
| [](unsigned char c) { return !absl::ascii_isalnum(c); }, '_'); |
| return name; |
| }); |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS) |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // Verifies that infobars are not displayed in Kiosk mode. |
| class StartupBrowserCreatorInfobarsKioskTest : public InProcessBrowserTest { |
| public: |
| StartupBrowserCreatorInfobarsKioskTest() = default; |
| |
| protected: |
| infobars::ContentInfoBarManager* |
| LaunchKioskBrowserAndGetCreatedInfoBarManager( |
| const std::string& extra_switch) { |
| Profile* profile = browser()->profile(); |
| |
| // CommandLine::ForCurrentProcess is used to determine whether kiosk mode is |
| // enabled instead of the command-line passed to StartupBrowserCreator. In |
| // browser tests, this references the browser test's instead of the new |
| // process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kKioskMode); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitch(extra_switch); |
| StartupBrowserCreatorImpl launch(base::FilePath(), command_line, |
| chrome::startup::IsFirstRun::kNo); |
| launch.Launch(profile, chrome::startup::IsProcessStartup::kYes, nullptr, |
| /*restore_tabbed_browser=*/true); |
| |
| // This should have created a new browser window. |
| Browser* new_browser = FindOneOtherBrowser(browser()); |
| EXPECT_TRUE(new_browser); |
| if (!new_browser) |
| return nullptr; |
| |
| return infobars::ContentInfoBarManager::FromWebContents( |
| new_browser->tab_strip_model()->GetActiveWebContents()); |
| } |
| }; |
| |
| // Verify that the Automation Enabled infobar is still shown in Kiosk mode. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorInfobarsKioskTest, |
| CheckInfobarForEnableAutomation) { |
| // CommandLine::ForCurrentProcess is used to determine whether automation is |
| // enabled instead of the command-line passed to StartupBrowserCreator. In |
| // browser tests, this references the browser test's instead of the new |
| // process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kEnableAutomation); |
| |
| // Passing the kEnableAutomation argument here presently does not do |
| // anything because of the aforementioned limitation. |
| infobars::ContentInfoBarManager* infobar_manager = |
| LaunchKioskBrowserAndGetCreatedInfoBarManager( |
| switches::kEnableAutomation); |
| ASSERT_TRUE(infobar_manager); |
| |
| EXPECT_TRUE(HasInfoBar( |
| infobar_manager, infobars::InfoBarDelegate::AUTOMATION_INFOBAR_DELEGATE)); |
| } |
| |
| // Verify that the Bad Flags infobar is not shown in kiosk mode. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorInfobarsKioskTest, |
| CheckInfobarForBadFlag) { |
| // BadFlagsPrompt::ShowBadFlagsPrompt uses CommandLine::ForCurrentProcess |
| // instead of the command-line passed to StartupBrowserCreator. In browser |
| // tests, this references the browser test's instead of the new process. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kDisableWebSecurity); |
| |
| // Passing the kDisableWebSecurity argument here presently does not do |
| // anything because of the aforementioned limitation. |
| // https://crbug.com/1060293 |
| infobars::ContentInfoBarManager* infobar_manager = |
| LaunchKioskBrowserAndGetCreatedInfoBarManager( |
| switches::kDisableWebSecurity); |
| ASSERT_TRUE(infobar_manager); |
| |
| EXPECT_FALSE(HasInfoBar( |
| infobar_manager, infobars::InfoBarDelegate::BAD_FLAGS_INFOBAR_DELEGATE)); |
| } |
| |
| // Checks the correct behavior of the profile picker on startup. |
| class StartupBrowserCreatorPickerTestBase : public InProcessBrowserTest { |
| public: |
| StartupBrowserCreatorPickerTestBase() { |
| // This test configures command line params carefully. Make sure |
| // InProcessBrowserTest does _not_ add about:blank as a startup URL to the |
| // command line. |
| set_open_about_blank_on_browser_launch(false); |
| } |
| StartupBrowserCreatorPickerTestBase( |
| const StartupBrowserCreatorPickerTestBase&) = delete; |
| StartupBrowserCreatorPickerTestBase& operator=( |
| const StartupBrowserCreatorPickerTestBase&) = delete; |
| ~StartupBrowserCreatorPickerTestBase() override = default; |
| |
| void CreateMultipleProfiles() { |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| // Create two additional profiles because the main test profile is created |
| // later in the startup process and so we need to have at least 2 fake |
| // profiles. |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| std::vector<base::FilePath> profile_paths = { |
| profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 1")), |
| profile_manager->user_data_dir().Append( |
| FILE_PATH_LITERAL("New Profile 2"))}; |
| for (int i = 0; i < 2; ++i) { |
| const base::FilePath& profile_path = profile_paths[i]; |
| profiles::testing::CreateProfileSync(profile_manager, profile_path); |
| // Mark newly created profiles as active. |
| ProfileAttributesEntry* entry = |
| profile_manager->GetProfileAttributesStorage() |
| .GetProfileAttributesWithPath(profile_path); |
| ASSERT_NE(entry, nullptr); |
| entry->SetActiveTimeToNow(); |
| entry->SetAuthInfo( |
| base::StringPrintf("gaia_id_%i", i), |
| base::UTF8ToUTF16(base::StringPrintf("user%i@gmail.com", i)), |
| /*is_consented_primary_account=*/false); |
| } |
| } |
| }; |
| |
| struct ProfilePickerSetup { |
| enum class ShutdownType { |
| kNormal, // Normal shutdown (e.g. by closing the browser window). |
| kExit, // Exit through the application menu. |
| kRestart // Restart (e.g. after an update). |
| }; |
| |
| bool expected_to_show; |
| std::optional<std::string> switch_name; |
| std::optional<std::string> switch_value_ascii; |
| std::optional<GURL> url_arg; |
| ShutdownType shutdown_type = ShutdownType::kNormal; |
| }; |
| |
| // Checks the correct behavior of the profile picker on startup. This feature is |
| // not available on ChromeOS. |
| class StartupBrowserCreatorPickerTest |
| : public StartupBrowserCreatorPickerTestBase, |
| public ::testing::WithParamInterface<ProfilePickerSetup> { |
| public: |
| StartupBrowserCreatorPickerTest() |
| : relaunch_chrome_override_(base::BindRepeating( |
| [](const base::CommandLine&) { return true; })) {} |
| StartupBrowserCreatorPickerTest(const StartupBrowserCreatorPickerTest&) = |
| delete; |
| StartupBrowserCreatorPickerTest& operator=( |
| const StartupBrowserCreatorPickerTest&) = delete; |
| ~StartupBrowserCreatorPickerTest() override = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| StartupBrowserCreatorPickerTestBase::SetUpCommandLine(command_line); |
| |
| if (content::IsPreTest()) |
| return; // Don't apply the test parameters to the PRE test. |
| |
| if (GetParam().url_arg) { |
| command_line->AppendArg(GetParam().url_arg->spec()); |
| } else if (GetParam().switch_value_ascii) { |
| DCHECK(GetParam().switch_name); |
| command_line->AppendSwitchASCII(*GetParam().switch_name, |
| *GetParam().switch_value_ascii); |
| } else if (GetParam().switch_name) { |
| command_line->AppendSwitch(*GetParam().switch_name); |
| } |
| } |
| |
| private: |
| // Prevent the browser from automatically relaunching in the PRE_ test. The |
| // browser will be relaunched by the main test. |
| upgrade_util::ScopedRelaunchChromeBrowserOverride relaunch_chrome_override_; |
| }; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorPickerTest, PRE_TestSetup) { |
| CreateMultipleProfiles(); |
| |
| switch (GetParam().shutdown_type) { |
| case ProfilePickerSetup::ShutdownType::kNormal: |
| // Need to close the browser window manually so that the real test does |
| // not treat it as session restore. |
| CloseAllBrowsers(); |
| break; |
| case ProfilePickerSetup::ShutdownType::kExit: |
| chrome::AttemptExit(); |
| break; |
| case ProfilePickerSetup::ShutdownType::kRestart: |
| chrome::AttemptRestart(); |
| break; |
| } |
| |
| ASSERT_EQ( |
| g_browser_process->local_state()->GetBoolean(prefs::kWasRestarted), |
| GetParam().shutdown_type == ProfilePickerSetup::ShutdownType::kRestart); |
| } |
| |
| // Checks that either the ProfilePicker or a browser window is open at startup. |
| // Except with switches::kNoStartupWindow, for which neither the picker nor a |
| // browser is open. |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorPickerTest, TestSetup) { |
| ProfilePickerSetup setup_param = GetParam(); |
| |
| // Check the ProfilePicker. |
| if (setup_param.expected_to_show) { |
| if (!ProfilePicker::IsOpen()) { |
| base::RunLoop run_loop; |
| ProfilePicker::AddOnProfilePickerOpenedCallbackForTesting( |
| run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| EXPECT_TRUE(ProfilePicker::IsOpen()); |
| } else { |
| EXPECT_FALSE(ProfilePicker::IsOpen()); |
| } |
| |
| // Check the browser window. |
| if (setup_param.expected_to_show || |
| setup_param.switch_name == switches::kNoStartupWindow) { |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| } else { |
| EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); |
| } |
| |
| // No Guest profile was created. |
| for (const Profile* profile : |
| g_browser_process->profile_manager()->GetLoadedProfiles()) { |
| EXPECT_FALSE(profile->IsGuestSession()); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| StartupBrowserCreatorPickerTest, |
| ::testing::Values( |
| // Flaky: https://crbug.com/1126886 |
| #if !BUILDFLAG(IS_OZONE) && !BUILDFLAG(IS_WIN) |
| // Picker should be shown in normal multi-profile startup situation. |
| ProfilePickerSetup{/*expected_to_show=*/true}, |
| #endif |
| // Skip the picker for various command-line params and use the last used |
| // profile, instead. |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/switches::kIncognito}, |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/switches::kApp}, |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/switches::kAppId}, |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/switches::kNoStartupWindow}, |
| // Skip the picker when a specific profile is requested (used e.g. by |
| // profile specific desktop shortcuts on Win). |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/switches::kProfileDirectory, |
| /*switch_value_ascii=*/"Default"}, |
| // Skip the picker when a specific profile is requested by email. |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/switches::kProfileEmail, |
| /*switch_value_ascii=*/"user0@gmail.com"}, |
| // Show the picker if the profile email is not found. |
| ProfilePickerSetup{/*expected_to_show=*/true, |
| /*switch_name=*/switches::kProfileEmail, |
| /*switch_value_ascii=*/"unknown@gmail.com"}, |
| // Skip the picker when a URL is provided on command-line (used by the |
| // OS when Chrome is the default web browser) and use the last used |
| // profile, instead. |
| ProfilePickerSetup{/*expected_to_show=*/false, |
| /*switch_name=*/std::nullopt, |
| /*switch_value_ascii=*/std::nullopt, |
| /*url_arg=*/GURL("https://www.foo.com/")}, |
| // Regression test for http://crbug.com/1166192 |
| // Picker should be shown after exit. |
| ProfilePickerSetup{ |
| /*expected_to_show=*/true, |
| /*switch_name=*/std::nullopt, |
| /*switch_value_ascii=*/std::nullopt, |
| /*url_arg=*/std::nullopt, |
| /*shutdown_type=*/ProfilePickerSetup::ShutdownType::kExit}, |
| // Regression test for http://crbug.com/1245374 |
| // Picker should not be shown after restart. |
| ProfilePickerSetup{ |
| /*expected_to_show=*/false, |
| /*switch_name=*/std::nullopt, |
| /*switch_value_ascii=*/std::nullopt, |
| /*url_arg=*/std::nullopt, |
| /*shutdown_type=*/ProfilePickerSetup::ShutdownType::kRestart})); |
| |
| class GuestStartupBrowserCreatorPickerTest |
| : public StartupBrowserCreatorPickerTestBase { |
| public: |
| GuestStartupBrowserCreatorPickerTest() = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| command_line->AppendSwitch(switches::kGuest); |
| } |
| }; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_F(GuestStartupBrowserCreatorPickerTest, |
| PRE_SkipsPickerWithGuest) { |
| CreateMultipleProfiles(); |
| // Need to close the browser window manually so that the real test does not |
| // treat it as session restore. |
| CloseAllBrowsers(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(GuestStartupBrowserCreatorPickerTest, |
| SkipsPickerWithGuest) { |
| // The picker is skipped which means a browser window is opened on startup. |
| EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); |
| EXPECT_TRUE(browser()->profile()->IsGuestSession()); |
| } |
| |
| class StartupBrowserCreatorPickerNoParamsTest |
| : public StartupBrowserCreatorPickerTestBase {}; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorPickerNoParamsTest, |
| PRE_ShowPickerWhenAlreadyLaunched) { |
| CreateMultipleProfiles(); |
| // Need to close the browser window manually so that the real test does not |
| // treat it as session restore. |
| CloseAllBrowsers(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorPickerNoParamsTest, |
| ShowPickerWhenAlreadyLaunched) { |
| // Preprequisite: The picker is shown on the first start-up |
| profiles::testing::WaitForPickerWidgetCreated(); |
| ASSERT_EQ(0u, chrome::GetTotalBrowserCount()); |
| |
| // Close the picker. |
| ScopedKeepAlive keep_alive(KeepAliveOrigin::BROWSER, |
| KeepAliveRestartOption::DISABLED); |
| ProfilePicker::Hide(); |
| profiles::testing::WaitForPickerClosed(); |
| EXPECT_FALSE(ProfilePicker::IsOpen()); |
| |
| // Simulate a second start when the browser is already running. |
| base::FilePath current_dir = base::FilePath(); |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| StartupProfilePathInfo startup_profile_path_info = |
| GetStartupProfilePath(current_dir, command_line, |
| /*ignore_profile_picker=*/false); |
| EXPECT_EQ(startup_profile_path_info.reason, |
| StartupProfileModeReason::kMultipleProfiles); |
| StartupBrowserCreator::ProcessCommandLineAlreadyRunning( |
| command_line, current_dir, startup_profile_path_info); |
| |
| // The picker is shown again if no profile was previously opened. |
| profiles::testing::WaitForPickerWidgetCreated(); |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| } |
| |
| class SearchQueryStartupBrowserCreatorPickerTest |
| : public StartupBrowserCreatorPickerTestBase { |
| public: |
| SearchQueryStartupBrowserCreatorPickerTest() = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| command_line->AppendArg("? Foo"); |
| } |
| }; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_F(SearchQueryStartupBrowserCreatorPickerTest, |
| PRE_SkipsPickerWithCommandLineSearchQuery) { |
| CreateMultipleProfiles(); |
| // Need to close the browser window manually so that the real test does not |
| // treat it as session restore. |
| CloseAllBrowsers(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(SearchQueryStartupBrowserCreatorPickerTest, |
| SkipsPickerWithCommandLineSearchQuery) { |
| // A browser window is shown on start-up because the command line contains a |
| // search query. |
| EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); |
| |
| // Check the return value of `GetStartupProfilePath()` explicitly. |
| base::FilePath current_dir = base::FilePath(); |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendArg("? Foo"); |
| StartupProfilePathInfo startup_profile_path_info = |
| GetStartupProfilePath(current_dir, command_line, |
| /*ignore_profile_picker=*/false); |
| EXPECT_EQ(startup_profile_path_info.reason, |
| StartupProfileModeReason::kCommandLineTabs); |
| } |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| #if !BUILDFLAG(IS_CHROMEOS) |
| |
| class StartupBrowserCreatorPickerInfobarTest |
| : public StartupBrowserCreatorPickerTestBase, |
| public ::testing::WithParamInterface<StartupBrowserCreatorFlagTypeValue> { |
| public: |
| StartupBrowserCreatorPickerInfobarTest() : flag_type_(GetParam()) {} |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override {} |
| |
| protected: |
| // Simulates a click on a profile card. The profile picker must be already |
| // opened. |
| void OpenProfileFromPicker(const base::FilePath& profile_path, |
| bool open_settings) { |
| base::Value::List args; |
| args.Append(base::FilePathToValue(profile_path)); |
| profile_picker_handler()->HandleLaunchSelectedProfile(open_settings, args); |
| } |
| |
| // Returns the profile picker webUI handler. The profile picker must be opened |
| // before calling this function. |
| ProfilePickerHandler* profile_picker_handler() { |
| DCHECK(ProfilePicker::IsOpen()); |
| |
| views::WebView* web_view = ProfilePicker::GetWebViewForTesting(); |
| if (web_view == nullptr) { |
| return nullptr; |
| } |
| |
| return web_view->GetWebContents() |
| ->GetWebUI() |
| ->GetController() |
| ->GetAs<ProfilePickerUI>() |
| ->GetProfilePickerHandlerForTesting(); |
| } |
| |
| const StartupBrowserCreatorFlagTypeValue flag_type_; |
| }; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorPickerInfobarTest, |
| PRE_ShowsEnableAutomationInfobar) { |
| CreateMultipleProfiles(); |
| // Need to close the browser window manually so that the real test does not |
| // treat it as session restore. |
| CloseAllBrowsers(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorPickerInfobarTest, |
| ShowsEnableAutomationInfobar) { |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| |
| // We deliberately set the flag on the process command line instead of on the |
| // command_line passed to the StartupBrowserCreator, because these flags are |
| // always read from the command line of the current process |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(flag_type_.flag); |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| Profile* profile = nullptr; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| profile = profile_manager->GetLastUsedProfile(); |
| } |
| |
| OpenProfileFromPicker(profile->GetPath(), false); |
| Browser* new_browser = BrowserList::GetInstance()->GetLastActive(); |
| |
| infobars::ContentInfoBarManager* infobar_manager = |
| infobars::ContentInfoBarManager::FromWebContents( |
| new_browser->tab_strip_model()->GetWebContentsAt(0)); |
| |
| EXPECT_TRUE(HasInfoBar(infobar_manager, flag_type_.infobar_identifier)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| StartupBrowserCreatorPickerInfobarTest, |
| ::testing::Values( |
| StartupBrowserCreatorFlagTypeValue{ |
| switches::kEnableAutomation, |
| infobars::InfoBarDelegate::AUTOMATION_INFOBAR_DELEGATE}, |
| // Test one of the flags from |bad_flags_prompt.cc|. Any of the |
| // flags should have the same behavior. |
| StartupBrowserCreatorFlagTypeValue{ |
| switches::kDisableWebSecurity, |
| infobars::InfoBarDelegate::BAD_FLAGS_INFOBAR_DELEGATE}), |
| [](const testing::TestParamInfo< |
| StartupBrowserCreatorPickerInfobarTest::ParamType>& info) { |
| std::string name = info.param.flag; |
| std::replace_if( |
| name.begin(), name.end(), |
| [](unsigned char c) { return !absl::ascii_isalnum(c); }, '_'); |
| return name; |
| }); |
| |
| // TODO(crbug.com/40265712): Mocking the logger appears to not work correctly on |
| // Windows. Investigate why it is not working and enable the test on Windows. |
| #if !BUILDFLAG(IS_WIN) |
| class StartupBrowserCreatorIwaCommandLineInstallProfilePickerErrorTest |
| : public StartupBrowserCreatorPickerTestBase { |
| protected: |
| void SetUp() override { |
| if (!content::IsPreTest()) { |
| EXPECT_CALL(mock_log_, Log(testing::_, testing::_, testing::_, testing::_, |
| testing::_)) |
| .Times(testing::AnyNumber()); |
| EXPECT_CALL( |
| mock_log_, |
| Log(::logging::LOGGING_ERROR, testing::_, testing::_, testing::_, |
| testing::HasSubstr("Command line switches to install IWAs are " |
| "incompatible with the Profile Picker"))); |
| mock_log_.StartCapturingLogs(); |
| } |
| |
| StartupBrowserCreatorPickerTestBase::SetUp(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| if (!content::IsPreTest()) { |
| command_line->AppendSwitchASCII("install-isolated-web-app-from-url", |
| "http://localhost"); |
| } |
| |
| StartupBrowserCreatorPickerTestBase::SetUpCommandLine(command_line); |
| } |
| |
| base::test::MockLog mock_log_; |
| }; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserCreatorIwaCommandLineInstallProfilePickerErrorTest, |
| PRE_DoesNotInstallIwaIfProfilePickerOpens) { |
| CreateMultipleProfiles(); |
| // Need to close the browser window manually so that the real test does not |
| // treat it as session restore. |
| CloseAllBrowsers(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| StartupBrowserCreatorIwaCommandLineInstallProfilePickerErrorTest, |
| DoesNotInstallIwaIfProfilePickerOpens) { |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| // The `EXPECT_CALL` call in `SetUp()` will check that an error message about |
| // the IWA not being installable is logged. |
| } |
| #endif // !BUILDFLAG(IS_WIN) |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| class StartupBrowserCreatorLacrosNoWindowTest |
| : public StartupBrowserCreatorPickerTestBase { |
| public: |
| StartupBrowserCreatorLacrosNoWindowTest() = default; |
| |
| void CreatedBrowserMainParts( |
| content::BrowserMainParts* browser_main_parts) override { |
| if (!content::IsPreTest()) { |
| crosapi::mojom::BrowserInitParamsPtr init_params = |
| crosapi::mojom::BrowserInitParams::New(); |
| init_params->initial_browser_action = |
| crosapi::mojom::InitialBrowserAction::kDoNotOpenWindow; |
| chromeos::BrowserInitParams::SetInitParamsForTests( |
| std::move(init_params)); |
| } |
| |
| StartupBrowserCreatorPickerTestBase::CreatedBrowserMainParts( |
| browser_main_parts); |
| } |
| |
| base::FilePath GetDefaultProfileDir() const { |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| return profile_manager->user_data_dir().Append( |
| profile_manager->GetInitialProfileDir()); |
| } |
| }; |
| |
| // Create a secondary profile in a separate PRE run because the existence of |
| // profiles is checked during startup in the actual test. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorLacrosNoWindowTest, |
| PRE_MultiProfile) { |
| CreateMultipleProfiles(); |
| // Need to close the browser window manually so that the real test does not |
| // treat it as session restore. |
| CloseAllBrowsers(); |
| } |
| |
| // Checks that no picker and no browser window are open when there are multiple |
| // profiles. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorLacrosNoWindowTest, MultiProfile) { |
| EXPECT_FALSE(ProfilePicker::IsOpen()); |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| } |
| |
| // Checks that no picker and no browser window are open when there is a single |
| // profile. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorLacrosNoWindowTest, SingleProfile) { |
| EXPECT_FALSE(ProfilePicker::IsOpen()); |
| EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); |
| |
| // Checks that it's possible to open a profile after startup. |
| // Regression test for https://crbug.com/1278549 |
| base::test::TestFuture<Browser*> future; |
| profiles::SwitchToProfile(GetDefaultProfileDir(), |
| /*always_create=*/false, future.GetCallback()); |
| Profile* profile = future.Get()->profile(); |
| EXPECT_NE(profile, nullptr); |
| EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); |
| |
| // Checks that it's possible to open the profile picker. |
| EXPECT_FALSE(ProfilePicker::IsOpen()); |
| ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( |
| ProfilePicker::EntryPoint::kProfileMenuManageProfiles)); |
| profiles::testing::WaitForPickerWidgetCreated(); |
| } |
| |
| class StartupBrowserCreatorLacrosGuestSessionTest |
| : public InProcessBrowserTest { |
| public: |
| StartupBrowserCreatorLacrosGuestSessionTest() = default; |
| |
| void CreatedBrowserMainParts( |
| content::BrowserMainParts* browser_main_parts) override { |
| crosapi::mojom::BrowserInitParamsPtr init_params = |
| crosapi::mojom::BrowserInitParams::New(); |
| init_params->session_type = crosapi::mojom::SessionType::kGuestSession; |
| chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params)); |
| |
| InProcessBrowserTest::CreatedBrowserMainParts(browser_main_parts); |
| } |
| }; |
| |
| // Checks that a browser window with new tab is open in Guest session. |
| IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorLacrosGuestSessionTest, Startup) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitch(::switches::kIncognito); |
| StartupBrowserCreatorImpl launch(base::FilePath(), command_line, |
| chrome::startup::IsFirstRun::kNo); |
| launch.Launch(browser()->profile(), chrome::startup::IsProcessStartup::kYes, |
| nullptr, /*restore_tabbed_browser=*/true); |
| |
| // A new browser window should be open. |
| Browser* new_browser = FindOneOtherBrowser(browser()); |
| EXPECT_TRUE(new_browser); |
| EXPECT_TRUE(new_browser->profile()->IsGuestSession()); |
| |
| // The new browser should have exactly one tab (new tab url). |
| TabStripModel* tab_strip = new_browser->tab_strip_model(); |
| EXPECT_TRUE(tab_strip); |
| ASSERT_EQ(1, tab_strip->count()); |
| EXPECT_EQ( |
| chrome::kChromeUINewTabURL, |
| tab_strip->GetWebContentsAt(0)->GetVisibleURL().possibly_invalid_spec()); |
| } |
| |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |