| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stddef.h> |
| |
| #include <string_view> |
| #include <vector> |
| |
| #include "base/files/file_path.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/path_service.h" |
| #include "base/run_loop.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/devtools/devtools_window_testing.h" |
| #include "chrome/browser/extensions/extension_browsertest.h" |
| #include "chrome/browser/notifications/notification_test_util.h" |
| #include "chrome/browser/predictors/autocomplete_action_predictor.h" |
| #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/task_manager/common/task_manager_features.h" |
| #include "chrome/browser/task_manager/task_manager_browsertest_util.h" |
| #include "chrome/browser/task_manager/task_manager_interface.h" |
| #include "chrome/browser/task_manager/task_manager_tester.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tabs/tab_enums.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/task_manager/task_manager_table_model.h" |
| #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/grit/generated_resources.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/confirm_infobar_delegate.h" |
| #include "components/infobars/core/infobar.h" |
| #include "components/url_formatter/url_formatter.h" |
| #include "content/public/browser/child_process_security_policy.h" |
| #include "content/public/browser/page_navigator.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/site_isolation_policy.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/isolated_world_ids.h" |
| #include "content/public/test/back_forward_cache_util.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/fenced_frame_test_util.h" |
| #include "content/public/test/no_renderer_crashes_assertion.h" |
| #include "content/public/test/prerender_test_util.h" |
| #include "content/public/test/render_frame_host_test_support.h" |
| #include "content/public/test/test_navigation_observer.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/common/extension.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "services/strings/grit/services_strings.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/page_transition_types.h" |
| #include "url/gurl.h" |
| #include "url/url_constants.h" |
| |
| using content::WebContents; |
| using task_manager::DisplayCategory; |
| using task_manager::browsertest_util::ColumnSpecifier; |
| using task_manager::browsertest_util::MatchAboutBlankTab; |
| using task_manager::browsertest_util::MatchAnyApp; |
| using task_manager::browsertest_util::MatchAnyBFCache; |
| using task_manager::browsertest_util::MatchAnyExtension; |
| using task_manager::browsertest_util::MatchAnyFencedFrame; |
| using task_manager::browsertest_util::MatchAnyIncognitoFencedFrame; |
| using task_manager::browsertest_util::MatchAnyIncognitoTab; |
| using task_manager::browsertest_util::MatchAnyPrerender; |
| using task_manager::browsertest_util::MatchAnySubframe; |
| using task_manager::browsertest_util::MatchAnyTab; |
| using task_manager::browsertest_util::MatchAnyUtility; |
| using task_manager::browsertest_util::MatchApp; |
| using task_manager::browsertest_util::MatchBFCache; |
| using task_manager::browsertest_util::MatchExtension; |
| using task_manager::browsertest_util::MatchFencedFrame; |
| using task_manager::browsertest_util::MatchIncognitoFencedFrame; |
| using task_manager::browsertest_util::MatchIncognitoTab; |
| using task_manager::browsertest_util::MatchPrerender; |
| using task_manager::browsertest_util::MatchSubframe; |
| using task_manager::browsertest_util::MatchTab; |
| using task_manager::browsertest_util::MatchUtility; |
| using task_manager::browsertest_util::WaitForTaskManagerRows; |
| using task_manager::browsertest_util::WaitForTaskManagerStatToExceed; |
| |
| namespace { |
| |
| const base::FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html"); |
| |
| } // namespace |
| |
| class TaskManagerBrowserTest : public extensions::ExtensionBrowserTest { |
| public: |
| TaskManagerBrowserTest() = default; |
| TaskManagerBrowserTest(const TaskManagerBrowserTest&) = delete; |
| TaskManagerBrowserTest& operator=(const TaskManagerBrowserTest&) = delete; |
| ~TaskManagerBrowserTest() override = default; |
| |
| task_manager::TaskManagerTester* model() { return model_.get(); } |
| |
| void ShowTaskManager() { |
| // Show the task manager. This populates the model, and helps with debugging |
| // (you see the task manager). |
| chrome::ShowTaskManager(browser()); |
| model_ = task_manager::TaskManagerTester::Create(base::BindRepeating( |
| &TaskManagerBrowserTest::TaskManagerTableModelSanityCheck, |
| base::Unretained(this))); |
| } |
| |
| void HideTaskManager() { |
| model_.reset(); |
| |
| // Hide the task manager, and wait for it to go. |
| chrome::HideTaskManager(); |
| base::RunLoop().RunUntilIdle(); // OnWindowClosed happens asynchronously. |
| } |
| |
| GURL GetTestURL() { |
| return ui_test_utils::GetTestUrl( |
| base::FilePath(base::FilePath::kCurrentDirectory), |
| base::FilePath(kTitle1File)); |
| } |
| |
| std::optional<size_t> FindResourceIndex(const std::u16string& title) { |
| for (size_t i = 0; i < model_->GetRowCount(); ++i) { |
| if (title == model_->GetRowTitle(i)) |
| return i; |
| } |
| return std::nullopt; |
| } |
| |
| protected: |
| void TearDownOnMainThread() override { |
| model_.reset(); |
| extensions::ExtensionBrowserTest::TearDownOnMainThread(); |
| } |
| |
| void SetUpOnMainThread() override { |
| extensions::ExtensionBrowserTest::SetUpOnMainThread(); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| |
| // Add content/test/data so we can use cross_site_iframe_factory.html |
| base::FilePath test_data_dir; |
| ASSERT_TRUE( |
| base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &test_data_dir)); |
| embedded_test_server()->ServeFilesFromDirectory( |
| test_data_dir.AppendASCII("content/test/data/")); |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| content::SetupCrossSiteRedirector(embedded_test_server()); |
| embedded_test_server()->StartAcceptingConnections(); |
| } |
| |
| private: |
| void TaskManagerTableModelSanityCheck() { |
| // Ensure the groups are self-consistent. |
| for (size_t i = 0; i < model()->GetRowCount(); ++i) { |
| size_t start, length; |
| model()->GetRowsGroupRange(i, &start, &length); |
| for (size_t j = 0; j < length; ++j) { |
| size_t start2, length2; |
| model()->GetRowsGroupRange(start + j, &start2, &length2); |
| EXPECT_EQ(start, start2); |
| EXPECT_EQ(length, length2); |
| } |
| } |
| } |
| |
| std::unique_ptr<task_manager::TaskManagerTester> model_; |
| }; |
| |
| class TaskManagerUtilityProcessBrowserTest : public TaskManagerBrowserTest { |
| public: |
| TaskManagerUtilityProcessBrowserTest() = default; |
| TaskManagerUtilityProcessBrowserTest( |
| const TaskManagerUtilityProcessBrowserTest&) = delete; |
| TaskManagerUtilityProcessBrowserTest& operator=( |
| const TaskManagerUtilityProcessBrowserTest&) = delete; |
| |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| TaskManagerBrowserTest::SetUpCommandLine(command_line); |
| |
| // Use a trivial PAC script to ensure that some javascript is being |
| // executed. |
| command_line->AppendSwitchASCII( |
| switches::kProxyPacUrl, |
| "data:,function FindProxyForURL(url, host){return \"DIRECT;\";}"); |
| } |
| }; |
| |
| // Parameterized variant of TaskManagerBrowserTest which runs with/without |
| // --site-per-process, which enables out of process iframes (OOPIFs). |
| class TaskManagerOOPIFBrowserTest : public TaskManagerBrowserTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| TaskManagerOOPIFBrowserTest() = default; |
| TaskManagerOOPIFBrowserTest(const TaskManagerOOPIFBrowserTest&) = delete; |
| TaskManagerOOPIFBrowserTest& operator=(const TaskManagerOOPIFBrowserTest&) = |
| delete; |
| |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| TaskManagerBrowserTest::SetUpCommandLine(command_line); |
| if (GetParam()) |
| content::IsolateAllSitesForTesting(command_line); |
| } |
| |
| bool ShouldExpectSubframes() { |
| return content::AreAllSitesIsolatedForTesting(); |
| } |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(DefaultIsolation, |
| TaskManagerOOPIFBrowserTest, |
| ::testing::Values(false)); |
| INSTANTIATE_TEST_SUITE_P(SitePerProcess, |
| TaskManagerOOPIFBrowserTest, |
| ::testing::Values(true)); |
| |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| #define MAYBE_ShutdownWhileOpen DISABLED_ShutdownWhileOpen |
| #else |
| #define MAYBE_ShutdownWhileOpen ShutdownWhileOpen |
| #endif |
| |
| // Regression test for http://crbug.com/13361 |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_ShutdownWhileOpen) { |
| ShowTaskManager(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchTab("title1.html"))); |
| |
| // Open a new tab and make sure the task manager notices it. |
| ASSERT_TRUE(AddTabAtIndex(0, GetTestURL(), ui::PAGE_TRANSITION_TYPED)); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| |
| // Close the tab and verify that we notice. |
| browser()->tab_strip_model()->CloseWebContentsAt(0, |
| TabCloseTypes::CLOSE_NONE); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillTab) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchTab("title1.html"))); |
| |
| // Open a new tab and make sure the task manager notices it. |
| ASSERT_TRUE(AddTabAtIndex(0, GetTestURL(), ui::PAGE_TRANSITION_TYPED)); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| |
| // Killing the tab via task manager should remove the row. |
| std::optional<size_t> tab = FindResourceIndex(MatchTab("title1.html")); |
| ASSERT_TRUE(tab.has_value()); |
| ASSERT_TRUE(model()->GetTabId(tab.value()).is_valid()); |
| { |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| model()->Kill(tab.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| } |
| |
| // Tab should reappear in task manager upon reload. |
| chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| } |
| |
| // Regression test for http://crbug.com/444945. |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NavigateAwayFromHungRenderer) { |
| ShowTaskManager(); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| GURL url1(embedded_test_server()->GetURL("/title2.html")); |
| GURL url3(embedded_test_server()->GetURL("a.com", "/iframe.html")); |
| |
| // Open a new tab and make sure the task manager notices it. |
| ASSERT_TRUE(AddTabAtIndex(0, url1, ui::PAGE_TRANSITION_TYPED)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| WebContents* tab1 = browser()->tab_strip_model()->GetActiveWebContents(); |
| |
| // Initiate a navigation that will create a new WebContents in the same |
| // SiteInstance. Then immediately hang the renderer so that title3.html can't |
| // load in this process. |
| content::WebContentsAddedObserver web_contents_added_observer; |
| content::DOMMessageQueue message_queue; |
| content::ExecuteScriptAsync(tab1->GetPrimaryMainFrame(), |
| "window.open('title3.html', '_blank');\n" |
| "window.domAutomationController.send(false);\n" |
| "while(1);"); |
| std::string message; |
| EXPECT_TRUE(message_queue.WaitForMessage(&message)); |
| EXPECT_EQ("false", message); |
| |
| // Blocks until a new WebContents appears as a result of window.open(). |
| WebContents* tab2 = web_contents_added_observer.GetWebContents(); |
| |
| // Make sure the new WebContents is in tab1's hung renderer process. |
| ASSERT_NE(nullptr, tab2); |
| ASSERT_NE(tab1, tab2); |
| ASSERT_EQ(tab1->GetPrimaryMainFrame()->GetProcess(), |
| tab2->GetPrimaryMainFrame()->GetProcess()) |
| << "New WebContents must be in the same process as the old WebContents, " |
| << "so that the new tab doesn't finish loading (what this test is all " |
| << "about)"; |
| ASSERT_EQ(tab1->GetSiteInstance(), tab2->GetSiteInstance()) |
| << "New WebContents must initially be in the same site instance as the " |
| << "old WebContents"; |
| |
| // Now navigate this tab to a different site. This should wind up in a |
| // different renderer process, so it should complete and show up in the task |
| // manager. |
| tab2->OpenURL(content::OpenURLParams(url3, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionTabChanges) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| ASSERT_TRUE(LoadExtension( |
| test_data_dir_.AppendASCII("good").AppendASCII("Extensions") |
| .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") |
| .AppendASCII("1.0.0.0"))); |
| |
| // Browser, Extension background page, and the New Tab Page. |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("My extension 1"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| // Open a new tab to an extension URL. Afterwards, the third entry (background |
| // page) should be an extension resource whose title starts with "Extension:". |
| // The fourth entry (page.html) is also of type extension and has both a |
| // WebContents and an extension. The title should start with "Extension:". |
| GURL url("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html"); |
| ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_TYPED)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchExtension("Foobar"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("My extension 1"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| std::optional<size_t> extension_tab = |
| FindResourceIndex(MatchExtension("Foobar")); |
| ASSERT_TRUE(extension_tab.has_value()); |
| ASSERT_TRUE(model()->GetTabId(extension_tab.value()).is_valid()); |
| |
| std::optional<size_t> background_page = |
| FindResourceIndex(MatchExtension("My extension 1")); |
| ASSERT_TRUE(background_page.has_value()); |
| ASSERT_FALSE(model()->GetTabId(background_page.value()).is_valid()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionTab) { |
| // With the task manager closed, open a new tab to an extension URL. |
| // Afterwards, when we open the task manager, the third entry (background |
| // page) should be an extension resource whose title starts with "Extension:". |
| // The fourth entry (page.html) is also of type extension and has both a |
| // WebContents and an extension. The title should start with "Extension:". |
| ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("good") |
| .AppendASCII("Extensions") |
| .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") |
| .AppendASCII("1.0.0.0"))); |
| GURL url("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html"); |
| ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_TYPED)); |
| |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchExtension("Foobar"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("My extension 1"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| std::optional<size_t> extension_tab = |
| FindResourceIndex(MatchExtension("Foobar")); |
| ASSERT_TRUE(extension_tab.has_value()); |
| ASSERT_TRUE(model()->GetTabId(extension_tab.value()).is_valid()); |
| |
| std::optional<size_t> background_page = |
| FindResourceIndex(MatchExtension("My extension 1")); |
| ASSERT_TRUE(background_page.has_value()); |
| ASSERT_FALSE(model()->GetTabId(background_page.value()).is_valid()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeAppTabChanges) { |
| ShowTaskManager(); |
| |
| ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("packaged_app"))); |
| const extensions::Extension* extension = |
| extension_registry()->GetExtensionById( |
| last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyApp())); |
| |
| // Open a new tab to the app's launch URL and make sure we notice that. |
| GURL url(extension->GetResourceURL("main.html")); |
| ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_TYPED)); |
| |
| // There should be 1 "App: " tab and the original new tab page. |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchApp("Packaged App Test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyApp())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| |
| // Check that the third entry (main.html) is of type extension and has both |
| // a tab contents and an extension. |
| std::optional<size_t> app_tab = |
| FindResourceIndex(MatchApp("Packaged App Test")); |
| ASSERT_TRUE(app_tab.has_value()); |
| ASSERT_TRUE(model()->GetTabId(app_tab.value()).is_valid()); |
| ASSERT_EQ(2, browser()->tab_strip_model()->count()); |
| |
| // Unload extension to make sure the tab goes away. |
| UnloadExtension(last_loaded_extension_id()); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyApp())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_EQ(1, browser()->tab_strip_model()->count()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeAppTab) { |
| ASSERT_TRUE(LoadExtension( |
| test_data_dir_.AppendASCII("packaged_app"))); |
| const extensions::Extension* extension = |
| extension_registry()->GetExtensionById( |
| last_loaded_extension_id(), extensions::ExtensionRegistry::ENABLED); |
| |
| // Open a new tab to the app's launch URL and make sure we notice that. |
| GURL url(extension->GetResourceURL("main.html")); |
| ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_TYPED)); |
| |
| ShowTaskManager(); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchApp("Packaged App Test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyApp())); |
| |
| // Check that the third entry (main.html) is of type extension and has both |
| // a tab contents and an extension. |
| std::optional<size_t> app_tab = |
| FindResourceIndex(MatchApp("Packaged App Test")); |
| ASSERT_TRUE(app_tab.has_value()); |
| ASSERT_TRUE(model()->GetTabId(app_tab.value()).is_valid()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabChanges) { |
| ShowTaskManager(); |
| |
| // The app under test acts on URLs whose host is "localhost", |
| // so the URLs we navigate to must have host "localhost". |
| GURL::Replacements replace_host; |
| replace_host.SetHostStr("localhost"); |
| GURL base_url = embedded_test_server()->GetURL( |
| "/extensions/api_test/app_process/"); |
| base_url = base_url.ReplaceComponents(replace_host); |
| |
| // Open a new tab to an app URL before the app is loaded. |
| GURL url(base_url.Resolve("path1/empty.html")); |
| NavigateToURLWithDisposition(browser(), url, |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); |
| |
| // Check that the new entry's title starts with "Tab:". |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| |
| // Load the hosted app and make sure it still starts with "Tab:", |
| // since it hasn't changed to an app process yet. |
| ASSERT_TRUE(LoadExtension( |
| test_data_dir_.AppendASCII("api_test").AppendASCII("app_process"))); |
| // Force the TaskManager to query the title. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("Unmodified"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| |
| // Now reload and check that the last entry's title now starts with "App:". |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // Force the TaskManager to query the title. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyApp())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchApp("Unmodified"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| |
| // Disable extension and reload. |
| DisableExtension(last_loaded_extension_id()); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| // The hosted app should now show up as a normal "Tab: ". |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("Unmodified"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyApp())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabAfterReload) { |
| // The app under test acts on URLs whose host is "localhost", |
| // so the URLs we navigate to must have host "localhost". |
| GURL base_url = embedded_test_server()->GetURL( |
| "localhost", "/extensions/api_test/app_process/"); |
| |
| // Open a new tab to an app URL before the app is loaded. |
| GURL url(base_url.Resolve("path1/empty.html")); |
| NavigateToURLWithDisposition(browser(), url, |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); |
| |
| // Load the hosted app and make sure it still starts with "Tab:", |
| // since it hasn't changed to an app process yet. |
| ASSERT_TRUE(LoadExtension( |
| test_data_dir_.AppendASCII("api_test").AppendASCII("app_process"))); |
| |
| // Now reload, which should transition this tab to being an App. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| |
| ShowTaskManager(); |
| |
| // The TaskManager should show this as an "App: " |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyApp())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabBeforeReload) { |
| // The app under test acts on URLs whose host is "localhost", |
| // so the URLs we navigate to must have host "localhost". |
| GURL base_url = embedded_test_server()->GetURL( |
| "localhost", "/extensions/api_test/app_process/"); |
| |
| // Open a new tab to an app URL before the app is loaded. |
| GURL url(base_url.Resolve("path1/empty.html")); |
| NavigateToURLWithDisposition(browser(), url, |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); |
| |
| // Load the hosted app and make sure it still starts with "Tab:", |
| // since it hasn't changed to an app process yet. |
| ASSERT_TRUE(LoadExtension( |
| test_data_dir_.AppendASCII("api_test").AppendASCII("app_process"))); |
| |
| ShowTaskManager(); |
| |
| // The TaskManager should show this as a "Tab: " because the page hasn't been |
| // reloaded since the hosted app was installed. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyApp())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| } |
| |
| // Regression test for http://crbug.com/18693. |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ReloadExtension) { |
| ShowTaskManager(); |
| ASSERT_TRUE(LoadExtension( |
| test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); |
| |
| // Wait until we see the loaded extension in the task manager (the three |
| // resources are: the browser process, New Tab Page, and the extension). |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("background_page"))); |
| |
| // Reload the extension a few times and make sure our resource count doesn't |
| // increase. |
| std::string extension_id = last_loaded_extension_id(); |
| for (int i = 1; i <= 5; i++) { |
| SCOPED_TRACE(testing::Message() << "Reloading extension for the " << i |
| << "th time."); |
| ReloadExtension(extension_id); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("background_page"))); |
| } |
| } |
| |
| // Checks that task manager counts a worker thread JS heap size. |
| // http://crbug.com/241066 |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, WebWorkerJSHeapMemory) { |
| // Workers require a trustworthy (e.g. https) context. |
| net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server.ServeFilesFromSourceDirectory("chrome/test/data"); |
| ASSERT_TRUE(https_server.Start()); |
| GURL test_url = https_server.GetURL("/title1.html"); |
| |
| ShowTaskManager(); |
| model()->ToggleColumnVisibility(ColumnSpecifier::V8_MEMORY); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url)); |
| size_t minimal_heap_size = 4 * 1024 * 1024 * sizeof(void*); |
| std::string test_js = base::StringPrintf( |
| "var blob = new Blob([\n" |
| " 'mem = new Array(%lu);',\n" |
| " 'for (var i = 0; i < mem.length; i += 16)'," |
| " ' mem[i] = i;',\n" |
| " 'postMessage(\"okay\");']);\n" |
| "blobURL = window.URL.createObjectURL(blob);\n" |
| "var worker = new Worker(blobURL);\n" |
| "new Promise(resolve => {\n" |
| " worker.addEventListener('message', function(e) {\n" |
| " resolve(e.data);\n" // e.data == "okay" |
| " });\n" |
| " worker.postMessage('go');\n" |
| "});\n", |
| static_cast<unsigned long>(minimal_heap_size)); |
| ASSERT_EQ("okay", |
| content::EvalJs( |
| browser()->tab_strip_model()->GetActiveWebContents(), test_js)); |
| |
| // The worker has allocated objects of at least |minimal_heap_size| bytes. |
| // Wait for the heap stats to reflect this. |
| const char kTabWildcard[] = "127.0.0.1:*/title1.html"; |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab(kTabWildcard), ColumnSpecifier::V8_MEMORY, minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab(kTabWildcard), ColumnSpecifier::V8_MEMORY_USED, |
| minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab(kTabWildcard), ColumnSpecifier::MEMORY_FOOTPRINT, |
| minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab(kTabWildcard))); |
| } |
| |
| // Checks that task manager counts renderer JS heap size. |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, JSHeapMemory) { |
| ShowTaskManager(); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL())); |
| size_t minimal_heap_size = 4 * 1024 * 1024 * sizeof(void*); |
| std::string test_js = base::StringPrintf( |
| "mem = new Array(%lu);\n" |
| "for (var i = 0; i < mem.length; i += 16)\n" |
| " mem[i] = i;\n" |
| "\"okay\";\n", |
| static_cast<unsigned long>(minimal_heap_size)); |
| std::string ok; |
| ASSERT_EQ("okay", |
| content::EvalJs( |
| browser()->tab_strip_model()->GetActiveWebContents(), test_js)); |
| |
| model()->ToggleColumnVisibility(ColumnSpecifier::V8_MEMORY); |
| |
| // The page's js has allocated objects of at least |minimal_heap_size| bytes. |
| // Wait for the heap stats to reflect this. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("title1.html"), ColumnSpecifier::V8_MEMORY, minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("title1.html"), ColumnSpecifier::V8_MEMORY_USED, |
| minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| } |
| |
| #if defined(MEMORY_SANITIZER) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| // This tests times out when MSan is enabled. See https://crbug.com/890313. |
| // Failing on Linux CFI. See https://crbug.com/995132. |
| #define MAYBE_SentDataObserved DISABLED_SentDataObserved |
| #else |
| #define MAYBE_SentDataObserved SentDataObserved |
| #endif |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_SentDataObserved) { |
| // TODO(crbug.com/397484647): Migrate TaskManagerDesktopRefreshBrowserTest |
| // version of this test into this one. |
| ShowTaskManager(); |
| GURL test_gurl = embedded_test_server()->GetURL("/title1.html"); |
| |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_gurl)); |
| std::string test_js = R"( |
| document.title = 'network use'; |
| var mem = new Uint8Array(16 << 20); |
| for (var i = 0; i < mem.length; i += 16) { |
| mem[i] = i; |
| } |
| var formData = new FormData(); |
| formData.append('StringKey1', new Blob([mem])); |
| var request = |
| new Request(location.href, {method: 'POST', body: formData}); |
| fetch(request).then(response => response.text()); |
| )"; |
| |
| browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame() |
| ->ExecuteJavaScriptForTests(base::UTF8ToUTF16(test_js), |
| base::NullCallback(), |
| content::ISOLATED_WORLD_ID_GLOBAL); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("network use"), ColumnSpecifier::TOTAL_NETWORK_USE, 16000000)); |
| // There shouldn't be too much usage on the browser process. Note that it |
| // should be the first row since tasks are sorted by process ID then by task |
| // ID. |
| if (base::FeatureList::IsEnabled(features::kTaskManagerDesktopRefresh)) { |
| model()->UpdateModel(DisplayCategory::kSystem, u""); |
| } |
| EXPECT_GE(20000, |
| model()->GetColumnValue(ColumnSpecifier::TOTAL_NETWORK_USE, 0)); |
| } |
| |
| #if defined(MEMORY_SANITIZER) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| // This tests times out when MSan is enabled. See https://crbug.com/890313. |
| // Failing on Linux CFI. See https://crbug.com/995132. |
| #define MAYBE_TotalSentDataObserved DISABLED_TotalSentDataObserved |
| #else |
| #define MAYBE_TotalSentDataObserved TotalSentDataObserved |
| #endif |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_TotalSentDataObserved) { |
| // TODO(crbug.com/397484647): Migrate TaskManagerDesktopRefreshBrowserTest |
| // version of this test into this one. |
| ShowTaskManager(); |
| GURL test_gurl = embedded_test_server()->GetURL("/title1.html"); |
| |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_gurl)); |
| std::string test_js = R"( |
| document.title = 'network use'; |
| var mem = new Uint8Array(16 << 20); |
| for (var i = 0; i < mem.length; i += 16) { |
| mem[i] = i; |
| } |
| var formData = new FormData(); |
| formData.append('StringKey1', new Blob([mem])); |
| var request = |
| new Request(location.href, {method: 'POST', body: formData}); |
| fetch(request).then(response => response.text()); |
| )"; |
| |
| browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame() |
| ->ExecuteJavaScriptForTests(base::UTF8ToUTF16(test_js), |
| base::NullCallback(), |
| content::ISOLATED_WORLD_ID_GLOBAL); |
| |
| // This test uses |setTimeout| to exceed the Nyquist ratio to ensure that at |
| // least 1 refresh has happened of no traffic. |
| test_js = R"( |
| var request = |
| new Request(location.href, {method: 'POST', body: formData}); |
| setTimeout( |
| () => {fetch(request).then(response => response.text())}, 2000); |
| )"; |
| |
| browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame() |
| ->ExecuteJavaScriptForTests(base::UTF8ToUTF16(test_js), |
| base::NullCallback(), |
| content::ISOLATED_WORLD_ID_GLOBAL); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("network use"), ColumnSpecifier::TOTAL_NETWORK_USE, |
| 16000000 * 2)); |
| // There shouldn't be too much usage on the browser process. Note that it |
| // should be the first row since tasks are sorted by process ID then by task |
| // ID. |
| if (base::FeatureList::IsEnabled(features::kTaskManagerDesktopRefresh)) { |
| model()->UpdateModel(DisplayCategory::kSystem, u""); |
| } |
| EXPECT_GE(20000, |
| model()->GetColumnValue(ColumnSpecifier::TOTAL_NETWORK_USE, 0)); |
| } |
| |
| // Checks that task manager counts idle wakeups. Since this test relies on |
| // forcing actual system-level idle wakeups to happen, it is inherently |
| // dependent on the load of the rest of the system, details of the OS scheduler, |
| // and so on, which makes it very prone to flakes. |
| #if BUILDFLAG(IS_MAC) |
| // This test is too flaky to be useable on Mac, because of the reasons given |
| // above. |
| #define MAYBE_IdleWakeups DISABLED_IdleWakeups |
| #else |
| #define MAYBE_IdleWakeups IdleWakeups |
| #endif |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_IdleWakeups) { |
| ShowTaskManager(); |
| model()->ToggleColumnVisibility(ColumnSpecifier::IDLE_WAKEUPS); |
| |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL())); |
| |
| std::string test_js = |
| "function myWait() {\n" |
| " setTimeout(function() { myWait(); }, 1)\n" |
| "}\n" |
| "myWait();\n" |
| "\"okay\";\n"; |
| |
| ASSERT_EQ("okay", |
| content::EvalJs( |
| browser()->tab_strip_model()->GetActiveWebContents(), test_js)); |
| |
| // The script above should trigger a lot of idle wakeups - up to 1000 per |
| // second. Let's make sure we get at least 100 (in case the test runs slow). |
| const int kMinExpectedWakeCount = 100; |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("title1.html"), ColumnSpecifier::IDLE_WAKEUPS, |
| kMinExpectedWakeCount)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| } |
| |
| // Crashes on multiple builders. http://crbug.com/1025346 |
| // Checks that task manager counts utility process JS heap size. |
| IN_PROC_BROWSER_TEST_F(TaskManagerUtilityProcessBrowserTest, |
| DISABLED_UtilityJSHeapMemory) { |
| ShowTaskManager(); |
| model()->ToggleColumnVisibility(ColumnSpecifier::V8_MEMORY); |
| |
| auto proxy_resolver_name = |
| l10n_util::GetStringUTF16(IDS_PROXY_RESOLVER_DISPLAY_NAME); |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL())); |
| // The PAC script is trivial, so don't expect a large heap. |
| size_t minimal_heap_size = 1024; |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchUtility(proxy_resolver_name), ColumnSpecifier::V8_MEMORY, |
| minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchUtility(proxy_resolver_name), ColumnSpecifier::V8_MEMORY_USED, |
| minimal_heap_size)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchUtility(proxy_resolver_name))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsNewDockedWindow) { |
| ShowTaskManager(); // Task manager shown BEFORE dev tools window. |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| DevToolsWindow* devtools = |
| DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsNewUndockedWindow) { |
| ShowTaskManager(); // Task manager shown BEFORE dev tools window. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| DevToolsWindow* devtools = |
| DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), false); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnyTab())); |
| DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsOldDockedWindow) { |
| DevToolsWindow* devtools = |
| DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true); |
| ShowTaskManager(); // Task manager shown AFTER dev tools window. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DevToolsOldUndockedWindow) { |
| DevToolsWindow* devtools = |
| DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), false); |
| ShowTaskManager(); // Task manager shown AFTER dev tools window. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnyTab())); |
| DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, HistoryNavigationInNewTab) { |
| ShowTaskManager(); |
| |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestURL())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| ASSERT_TRUE( |
| ui_test_utils::NavigateToURL(browser(), GURL("chrome://version/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("About Version"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| chrome::GoBack(browser(), WindowOpenDisposition::NEW_BACKGROUND_TAB); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("About Version"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("title1.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyTab())); |
| |
| // In http://crbug.com/738169, the task_manager::Task for the background tab |
| // was created with process id 0, resulting in zero values for all process |
| // metrics. Ensure that this is not the case. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("title1.html"), ColumnSpecifier::PROCESS_ID, |
| base::kNullProcessId)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("title1.html"), ColumnSpecifier::MEMORY_FOOTPRINT, 1000)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchTab("About Version"), ColumnSpecifier::MEMORY_FOOTPRINT, 1000)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, SubframeHistoryNavigation) { |
| if (!ShouldExpectSubframes()) |
| return; // This test is lame without OOPIFs. |
| |
| ShowTaskManager(); |
| |
| // This URL will have two out-of-process iframe processes (for b.com and |
| // c.com) under --site-per-process: it's an a.com page containing a b.com |
| // <iframe> containing a b.com <iframe> containing a c.com <iframe>. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL( |
| "a.com", "/cross_site_iframe_factory.html?a(b(b(c)))"))); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Cross-site iframe factory"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| |
| content::WebContents* tab = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| |
| // Simulate a user gesture on the frame about to be navigated so that the |
| // corresponding navigation entry is not marked as skippable. |
| content::RenderFrameHost* child_frame = |
| ChildFrameAt(tab->GetPrimaryMainFrame(), 0); |
| content::RenderFrameHost* grandchild_frame = ChildFrameAt(child_frame, 0); |
| grandchild_frame->ExecuteJavaScriptWithUserGestureForTests( |
| u"a=5", base::NullCallback(), content::ISOLATED_WORLD_ID_GLOBAL); |
| |
| GURL d_url = embedded_test_server()->GetURL( |
| "d.com", "/cross_site_iframe_factory.html?d(e)"); |
| ASSERT_TRUE( |
| content::ExecJs(tab->GetPrimaryMainFrame(), |
| "frames[0][0].location.href = '" + d_url.spec() + "';")); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(0, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://d.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://e.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnySubframe())); |
| |
| ASSERT_TRUE(chrome::CanGoBack(browser())); |
| chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(0, MatchSubframe("http://d.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(0, MatchSubframe("http://e.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| |
| ASSERT_TRUE(chrome::CanGoForward(browser())); |
| chrome::GoForward(browser(), WindowOpenDisposition::CURRENT_TAB); |
| |
| // When the subframe appears in the cloned process, it must have a valid |
| // process ID. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchSubframe("http://d.com/"), ColumnSpecifier::PROCESS_ID, |
| base::kNullProcessId)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchSubframe("http://e.com/"), ColumnSpecifier::PROCESS_ID, |
| base::kNullProcessId)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(0, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://d.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://e.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnySubframe())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| // Subframe processes should report some amount of physical memory usage. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchSubframe("http://d.com/"), ColumnSpecifier::MEMORY_FOOTPRINT, 1000)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerStatToExceed( |
| MatchSubframe("http://e.com/"), ColumnSpecifier::MEMORY_FOOTPRINT, 1000)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, KillSubframe) { |
| ShowTaskManager(); |
| |
| // Navigate to a page A(B,C). |
| content::TestNavigationObserver navigation_observer( |
| browser()->tab_strip_model()->GetActiveWebContents()); |
| GURL main_url(embedded_test_server()->GetURL( |
| "/cross-site/a.com/iframe_cross_site.html")); |
| int expected_c_subframes = 1; |
| if (!content::AreAllSitesIsolatedForTesting()) { |
| // Isolate b.com so that it will be forced into a separate process. This |
| // will prevent the main frame and c.com subframe from being placed in the |
| // the process that gets killed by this test. |
| content::IsolateOriginsForTesting( |
| embedded_test_server(), |
| browser()->tab_strip_model()->GetActiveWebContents(), {"b.com"}); |
| |
| // Do not expect to see subframe information for c.com. This is because |
| // c.com will not require a dedicated process and will be placed in the same |
| // process as the main frame (a.com). |
| expected_c_subframes = 0; |
| } |
| |
| auto check_num_subframes = [](int expected_b_subframes, |
| int expected_c_subframes) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| expected_b_subframes, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| expected_c_subframes, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| expected_b_subframes + expected_c_subframes, MatchAnySubframe())); |
| }; |
| browser()->OpenURL(content::OpenURLParams(main_url, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| // Verify the expected number of b.com and c.com subframes. |
| ASSERT_NO_FATAL_FAILURE(check_num_subframes(1, expected_c_subframes)); |
| |
| // Remember |b_url| to be able to later renavigate to the same URL without |
| // doing any process swaps (we want to avoid redirects that would happen |
| // when going through /cross-site/foo.com/..., because |
| // https://crbug.com/642958 wouldn't repro in presence of process swaps). |
| navigation_observer.Wait(); |
| auto* b_frame = |
| ChildFrameAt(browser()->tab_strip_model()->GetActiveWebContents(), 0); |
| GURL b_url = b_frame->GetLastCommittedURL(); |
| ASSERT_EQ(b_url.host(), "b.com"); // Sanity check of test code / setup. |
| ASSERT_TRUE(b_frame->GetSiteInstance()->RequiresDedicatedProcess()); |
| { |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> subframe_b = |
| FindResourceIndex(MatchSubframe("http://b.com/")); |
| ASSERT_TRUE(subframe_b.has_value()); |
| ASSERT_TRUE(model()->GetTabId(subframe_b.value()).is_valid()); |
| model()->Kill(subframe_b.value()); |
| |
| // Verify the expected number of b.com and c.com subframes. |
| ASSERT_NO_FATAL_FAILURE(check_num_subframes(0, expected_c_subframes)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| } |
| |
| HideTaskManager(); |
| ShowTaskManager(); |
| |
| // Verify the expected number of b.com and c.com subframes. |
| ASSERT_NO_FATAL_FAILURE(check_num_subframes(0, expected_c_subframes)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| |
| // Reload the subframe and verify it has re-appeared in the task manager. |
| // This is a regression test for https://crbug.com/642958. |
| ASSERT_TRUE(content::ExecJs( |
| browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(), |
| "document.getElementById('frame1').src = '" + b_url.spec() + "';")); |
| |
| // Verify the expected number of b.com and c.com subframes. |
| ASSERT_NO_FATAL_FAILURE(check_num_subframes(1, expected_c_subframes)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| } |
| |
| // Tests what happens when a tab navigates to a site (a.com) that it previously |
| // has a cross-process subframe into (b.com). |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, NavigateToSubframeProcess) { |
| ShowTaskManager(); |
| |
| // Navigate the tab to a page on a.com with cross-process subframes to |
| // b.com and c.com. |
| GURL a_dotcom(embedded_test_server()->GetURL( |
| "/cross-site/a.com/iframe_cross_site.html")); |
| browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| } |
| |
| // Now navigate to a page on b.com with a simple (same-site) iframe. |
| // This should not show any subframe resources in the task manager. |
| GURL b_dotcom( |
| embedded_test_server()->GetURL("/cross-site/b.com/iframe.html")); |
| |
| browser()->OpenURL(content::OpenURLParams(b_dotcom, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| HideTaskManager(); |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, |
| NavigateToSiteWithSubframeToOriginalSite) { |
| ShowTaskManager(); |
| |
| // Navigate to a page on b.com with a simple (same-site) iframe. |
| // This should not show any subframe resources in the task manager. |
| GURL b_dotcom( |
| embedded_test_server()->GetURL("/cross-site/b.com/iframe.html")); |
| |
| browser()->OpenURL(content::OpenURLParams(b_dotcom, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| |
| // Now navigate the tab to a page on a.com with cross-process subframes to |
| // b.com and c.com. |
| GURL a_dotcom(embedded_test_server()->GetURL( |
| "/cross-site/a.com/iframe_cross_site.html")); |
| browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| } |
| |
| HideTaskManager(); |
| ShowTaskManager(); |
| |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| } |
| } |
| |
| // Tests what happens when a tab navigates a cross-frame iframe (to b.com) |
| // back to the site of the parent document (a.com). |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, |
| CrossSiteIframeBecomesSameSite) { |
| ShowTaskManager(); |
| |
| // Navigate the tab to a page on a.com with cross-process subframes to |
| // b.com and c.com. |
| content::TestNavigationObserver navigation_observer( |
| browser()->tab_strip_model()->GetActiveWebContents()); |
| GURL a_dotcom(embedded_test_server()->GetURL( |
| "/cross-site/a.com/iframe_cross_site.html")); |
| browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| } |
| |
| // Navigate the b.com frame back to a.com. It is no longer a cross-site iframe |
| navigation_observer.Wait(); |
| const std::string r_script = |
| R"( document.getElementById('frame1').src='/title1.html'; |
| document.title='aac'; )"; |
| ASSERT_TRUE(content::ExecJs(browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(), |
| r_script)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); |
| } |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| HideTaskManager(); |
| ShowTaskManager(); |
| |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); |
| } |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, |
| LeavePageWithCrossSiteIframes) { |
| ShowTaskManager(); |
| |
| // Navigate the tab to a page on a.com with cross-process subframes. |
| GURL a_dotcom_with_iframes(embedded_test_server()->GetURL( |
| "/cross-site/a.com/iframe_cross_site.html")); |
| browser()->OpenURL( |
| content::OpenURLParams(a_dotcom_with_iframes, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| |
| if (!ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); |
| } |
| |
| // Navigate the tab to a page on a.com without cross-process subframes, and |
| // the subframe processes should disappear. |
| GURL a_dotcom_simple( |
| embedded_test_server()->GetURL("/cross-site/a.com/title2.html")); |
| browser()->OpenURL( |
| content::OpenURLParams(a_dotcom_simple, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| |
| HideTaskManager(); |
| ShowTaskManager(); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } |
| |
| // TODO(crbug.com/40710551): disabled as test is flaky. |
| IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, |
| DISABLED_OrderingOfDependentRows) { |
| ShowTaskManager(); |
| |
| GURL a_with_frames(embedded_test_server()->GetURL( |
| "a.com", "/cross_site_iframe_factory.html?a(b,b,c(d,a,b,c))")); |
| browser()->OpenURL(content::OpenURLParams(a_with_frames, content::Referrer(), |
| WindowOpenDisposition::CURRENT_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| if (ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://d.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnySubframe())); |
| } |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Cross-site iframe factory"))); |
| |
| std::optional<size_t> index = |
| FindResourceIndex(MatchTab("Cross-site iframe factory")); |
| ASSERT_TRUE(index.has_value()); |
| std::vector<size_t> subframe_offsets; |
| if (ShouldExpectSubframes()) { |
| std::optional<size_t> index_b = |
| FindResourceIndex(MatchSubframe("http://b.com/")); |
| ASSERT_TRUE(index_b.has_value()); |
| std::optional<size_t> index_c = |
| FindResourceIndex(MatchSubframe("http://c.com/")); |
| ASSERT_TRUE(index_c.has_value()); |
| std::optional<size_t> index_d = |
| FindResourceIndex(MatchSubframe("http://d.com/")); |
| ASSERT_TRUE(index_d.has_value()); |
| subframe_offsets = {index_b.value() - index.value(), |
| index_c.value() - index.value(), |
| index_d.value() - index.value()}; |
| EXPECT_THAT(subframe_offsets, testing::UnorderedElementsAre(1u, 2u, 3u)); |
| } |
| |
| // Opening a new tab should appear below the existing tab. |
| GURL other_tab_url(embedded_test_server()->GetURL( |
| "d.com", "/cross_site_iframe_factory.html?d(a(c(b)))")); |
| browser()->OpenURL( |
| content::OpenURLParams(other_tab_url, content::Referrer(), |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_TYPED, false), |
| /*navigation_handle_callback=*/{}); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(2, MatchTab("Cross-site iframe factory"))); |
| if (ShouldExpectSubframes()) { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(6, MatchAnySubframe())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(2, MatchSubframe("http://b.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(2, MatchSubframe("http://c.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://d.com/"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://a.com/"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(6, MatchAnySubframe())); |
| } else { |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } |
| |
| // The first tab may have moved in absolute position in the list (due to |
| // random e.g. zygote or gpu activity). |
| index = FindResourceIndex(MatchTab("Cross-site iframe factory")); |
| ASSERT_TRUE(index.has_value()); |
| |
| // All of Tab 2's subframes will reuse Tab 1's existing processes for |
| // corresponding sites. Tab 2's d.com main frame row should then appear |
| // after all the subframe processes. |
| size_t tab2_subframe_count = ShouldExpectSubframes() ? 3 : 0; |
| size_t tab2_main_frame_index = |
| index.value() + subframe_offsets.size() + tab2_subframe_count + 1; |
| EXPECT_EQ("Tab: Cross-site iframe factory", |
| base::UTF16ToUTF8(model()->GetRowTitle(tab2_main_frame_index))); |
| |
| if (ShouldExpectSubframes()) { |
| // Tab 2's a.com subframe should share Tab 1's main frame process and go |
| // directly below it. |
| EXPECT_EQ(index.value() + 1, |
| FindResourceIndex(MatchSubframe("http://a.com/"))); |
| |
| // The other tab 2 subframes (b.com and c.com) should join existing |
| // subframe processes from tab 1. Check that the b.com and c.com subframe |
| // processes now have two rows each. |
| std::optional<size_t> subframe_b_index = |
| FindResourceIndex(MatchSubframe("http://b.com/")); |
| ASSERT_TRUE(subframe_b_index.has_value()); |
| std::optional<size_t> subframe_c_index = |
| FindResourceIndex(MatchSubframe("http://c.com/")); |
| ASSERT_TRUE(subframe_c_index.has_value()); |
| std::optional<size_t> subframe_d_index = |
| FindResourceIndex(MatchSubframe("http://d.com/")); |
| ASSERT_TRUE(subframe_d_index.has_value()); |
| EXPECT_EQ( |
| "Subframe: http://b.com/", |
| base::UTF16ToUTF8(model()->GetRowTitle(subframe_b_index.value() + 1))); |
| EXPECT_EQ( |
| "Subframe: http://c.com/", |
| base::UTF16ToUTF8(model()->GetRowTitle(subframe_c_index.value() + 1))); |
| |
| // The subframe processes should preserve their relative ordering. |
| EXPECT_EQ(subframe_offsets[0] < subframe_offsets[1], |
| subframe_b_index < subframe_c_index); |
| EXPECT_EQ(subframe_offsets[1] < subframe_offsets[2], |
| subframe_c_index < subframe_d_index); |
| EXPECT_EQ(subframe_offsets[0] < subframe_offsets[2], |
| subframe_b_index < subframe_d_index); |
| } |
| } |
| |
| //============================================================================== |
| // Prerender tasks test. |
| namespace { |
| // Prerender trigger page URL. |
| const char kMainPageUrl[] = "/title2.html"; |
| // The prerendered URL. |
| const char kPrerenderURL[] = "/title1.html"; |
| |
| class AutocompleteActionPredictorObserverImpl |
| : public predictors::AutocompleteActionPredictor::Observer { |
| public: |
| explicit AutocompleteActionPredictorObserverImpl( |
| predictors::AutocompleteActionPredictor* predictor) { |
| observation_.Observe(predictor); |
| } |
| |
| ~AutocompleteActionPredictorObserverImpl() override = default; |
| |
| void WaitForInitialization() { |
| base::RunLoop loop; |
| waiting_ = loop.QuitClosure(); |
| loop.Run(); |
| } |
| |
| // predictors::AutocompleteActionPredictor::Observer: |
| void OnInitialized() override { |
| DCHECK(waiting_); |
| std::move(waiting_).Run(); |
| } |
| |
| base::ScopedObservation<predictors::AutocompleteActionPredictor, |
| predictors::AutocompleteActionPredictor::Observer> |
| observation_{this}; |
| base::OnceClosure waiting_; |
| }; |
| |
| class PrerenderTaskBrowserTest : public TaskManagerBrowserTest { |
| public: |
| PrerenderTaskBrowserTest() { |
| // `blink::features::kPrerender2` and |
| // `blink::features::kPrerender2MemoryControls` are enabled in |
| // |prerender_helper_|. |
| prerender_helper_ = std::make_unique<content::test::PrerenderTestHelper>( |
| base::BindRepeating(&PrerenderTaskBrowserTest::GetActiveWebContents, |
| base::Unretained(this))); |
| feature_list_.InitWithFeaturesAndParameters( |
| content::GetDefaultEnabledBackForwardCacheFeaturesForTesting( |
| /*ignore_outstanding_network_request=*/false), |
| /*disabled_features=*/{}); |
| EXPECT_TRUE(content::BackForwardCache::IsBackForwardCacheFeatureEnabled()); |
| } |
| PrerenderTaskBrowserTest(const PrerenderTaskBrowserTest&) = delete; |
| PrerenderTaskBrowserTest& operator=(const PrerenderTaskBrowserTest&) = delete; |
| ~PrerenderTaskBrowserTest() override = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| content::IsolateAllSitesForTesting(command_line); |
| ASSERT_TRUE(content::AreAllSitesIsolatedForTesting()); |
| TaskManagerBrowserTest::SetUpCommandLine(command_line); |
| } |
| |
| void SetUpOnMainThread() override { |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| embedded_test_server()->ServeFilesFromDirectory( |
| base::PathService::CheckedGet(chrome::DIR_TEST_DATA)); |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| embedded_test_server()->StartAcceptingConnections(); |
| } |
| |
| void NavigateTo(std::string_view page_url) const { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL(page_url))); |
| } |
| |
| WebContents* GetActiveWebContents() { |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| predictors::AutocompleteActionPredictor* GetAutocompleteActionPredictor() { |
| return predictors::AutocompleteActionPredictorFactory::GetForProfile( |
| browser()->profile()); |
| } |
| |
| void WaitForAutocompleteActionPredictorInitialization() { |
| if (GetAutocompleteActionPredictor()->initialized()) { |
| return; |
| } |
| AutocompleteActionPredictorObserverImpl predictor_observer( |
| GetAutocompleteActionPredictor()); |
| predictor_observer.WaitForInitialization(); |
| } |
| |
| WebContents* NavigateToURLWithDispositionAndTransition( |
| const GURL& url, |
| WindowOpenDisposition disposition, |
| ui::PageTransition transition) { |
| return GetActiveWebContents()->OpenURL( |
| content::OpenURLParams(url, content::Referrer(), disposition, |
| transition, |
| /*is_renderer_initiated=*/false), |
| /*navigation_handle_callback=*/{}); |
| } |
| |
| content::test::PrerenderTestHelper* prerender_helper() { |
| return prerender_helper_.get(); |
| } |
| |
| // Prerender's task title is constructed from |RFH->GetLastCommittedURL|, |
| // which contains the port of the testing webserver. |
| std::string port() const { |
| return base::NumberToString(embedded_test_server()->port()); |
| } |
| |
| private: |
| std::unique_ptr<content::test::PrerenderTestHelper> prerender_helper_; |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| } // namespace |
| |
| // TODO(crbug.com/40232771): Flaky on Windows7. |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_ProperlyShowsTasks DISABLED_ProperlyShowsTasks |
| #else |
| #define MAYBE_ProperlyShowsTasks ProperlyShowsTasks |
| #endif |
| // Tests that the task manager properly: |
| // 1. shows the Prerender entry when the speculation rule is injected; |
| // 2. shows the Prerender entry when the manager is closed and reopened. |
| // 3. deletes the Prerender entry when the prerendered page is activated. |
| IN_PROC_BROWSER_TEST_F(PrerenderTaskBrowserTest, MAYBE_ProperlyShowsTasks) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(kMainPageUrl); |
| |
| const auto prerender_gurl = embedded_test_server()->GetURL(kPrerenderURL); |
| std::string server_port; |
| if (prerender_gurl.has_port()) { |
| server_port = prerender_gurl.port(); |
| } |
| |
| // Inject the speculation rule and wait for prerender to complete. |
| prerender_helper()->AddPrerender(prerender_gurl); |
| |
| // Must have one tab task, one prerender task. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(prerender_gurl.spec()))); |
| |
| // "Close" the task manager and "reopen" it. We should see the same tasks. |
| HideTaskManager(); |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(prerender_gurl.spec()))); |
| |
| // Activate the prerender page. The triggering page is placed in BFCache, |
| // and the prerendered page is activated. |
| content::test::PrerenderHostObserver obs(*GetActiveWebContents(), |
| prerender_gurl); |
| content::test::PrerenderTestHelper::NavigatePrimaryPage( |
| *GetActiveWebContents(), prerender_gurl); |
| ASSERT_TRUE(obs.was_activated()); |
| |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyBFCache())); |
| // Take out the "http://". |
| const auto tab_title = |
| url_formatter::FormatUrl(embedded_test_server()->GetURL(kPrerenderURL)); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab(base::UTF16ToUTF8(tab_title)))); |
| if (content::SiteIsolationPolicy::AreOriginKeyedProcessesEnabledByDefault() && |
| !server_port.empty()) { |
| // When kOriginKeyedProcessesByDefault is enabled, we need to include the |
| // port number as the SiteInstance's site_url will include it. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchBFCache("http://127.0.0.1:" + server_port + "/"))); |
| } else { |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchBFCache("http://127.0.0.1/"))); |
| } |
| } |
| |
| // TODO(crbug.com/40232771): Flaky on Windows7. |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_DeletesTaskAfterPrerenderKilled \ |
| DISABLED_DeletesTaskAfterPrerenderKilled |
| #else |
| #define MAYBE_DeletesTaskAfterPrerenderKilled DeletesTaskAfterPrerenderKilled |
| #endif |
| // Tests that the task manager properly deletes the prerender task once the |
| // prerender is cancelled. |
| IN_PROC_BROWSER_TEST_F(PrerenderTaskBrowserTest, |
| MAYBE_DeletesTaskAfterPrerenderKilled) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(kMainPageUrl); |
| |
| const auto prerender_gurl = embedded_test_server()->GetURL(kPrerenderURL); |
| prerender_helper()->AddPrerender(prerender_gurl); |
| |
| // Must have one tab task, one prerender task. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(prerender_gurl.spec()))); |
| |
| // Terminate the prerender task, which should signal the task manager to |
| // remove the prerender task entry. |
| { |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> prerender_row = |
| FindResourceIndex(MatchPrerender(prerender_gurl.spec())); |
| ASSERT_TRUE(prerender_row.has_value()); |
| ASSERT_TRUE(model()->GetTabId(prerender_row.value()).is_valid()); |
| model()->Kill(prerender_row.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| } |
| } |
| |
| // TODO(crbug.com/40232771): Flaky on Windows7. |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_DeletesTaskAfterTriggerPageKilled \ |
| DISABLED_DeletesTaskAfterTriggerPageKilled |
| #else |
| #define MAYBE_DeletesTaskAfterTriggerPageKilled \ |
| DeletesTaskAfterTriggerPageKilled |
| #endif |
| // Tests that the task manager properly deletes the task of the trigger tab and |
| // prerender when the trigger is terminated. |
| IN_PROC_BROWSER_TEST_F(PrerenderTaskBrowserTest, |
| MAYBE_DeletesTaskAfterTriggerPageKilled) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(kMainPageUrl); |
| |
| const auto prerender_gurl = embedded_test_server()->GetURL(kPrerenderURL); |
| prerender_helper()->AddPrerender(prerender_gurl); |
| |
| // Must have one tab task, one prerender task. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(prerender_gurl.spec()))); |
| |
| // Terminate the prerender task, which should signal the task manager to |
| // remove the prerender task entry. |
| { |
| base::HistogramTester histogram_tester; |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> trigger_row = |
| FindResourceIndex(MatchTab("Title Of Awesomeness")); |
| ASSERT_TRUE(trigger_row.has_value()); |
| ASSERT_TRUE(model()->GetTabId(trigger_row.value()).is_valid()); |
| model()->Kill(trigger_row.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyPrerender())); |
| histogram_tester.ExpectUniqueSample( |
| "Prerender.Experimental.PrerenderHostFinalStatus.SpeculationRule", |
| /*PrerenderFinalStatus::kPrimaryMainFrameRendererProcessKilled=*/57, 1); |
| } |
| } |
| |
| // TODO(crbug.com/40232771): Flaky on Windows7. |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_ProperlyShowsPrerenderTaskByAutocompletePredictor \ |
| DISABLED_ProperlyShowsPrerenderTaskByAutocompletePredictor |
| #else |
| #define MAYBE_ProperlyShowsPrerenderTaskByAutocompletePredictor \ |
| ProperlyShowsPrerenderTaskByAutocompletePredictor |
| #endif |
| // Test that the autocomplete action predictor trigger Prerender tasks are |
| // properly displayed. Such predictor is used to trigger Omnibox Prerender. |
| IN_PROC_BROWSER_TEST_F( |
| PrerenderTaskBrowserTest, |
| MAYBE_ProperlyShowsPrerenderTaskByAutocompletePredictor) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(kMainPageUrl); |
| |
| ASSERT_TRUE(GetAutocompleteActionPredictor()); |
| WaitForAutocompleteActionPredictorInitialization(); |
| const auto prerender_gurl = embedded_test_server()->GetURL(kPrerenderURL); |
| GetAutocompleteActionPredictor()->StartPrerendering( |
| prerender_gurl, *(browser()->tab_strip_model()->GetActiveWebContents())); |
| |
| // One task for main page and one for the prerendered page. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(prerender_gurl.spec()))); |
| // Main task stays after prerendered task is terminated. |
| { |
| base::HistogramTester histogram_tester; |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> prerender_row = |
| FindResourceIndex(MatchPrerender(prerender_gurl.spec())); |
| ASSERT_TRUE(prerender_row.has_value()); |
| ASSERT_TRUE(model()->GetTabId(prerender_row.value()).is_valid()); |
| model()->Kill(prerender_row.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyPrerender())); |
| histogram_tester.ExpectUniqueSample( |
| "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_" |
| "DirectURLInput", |
| /*PrerenderFinalStatus::kRendererProcessKilled=*/14, 1); |
| } |
| // Both tasks are deleted after main task is terminated. |
| { |
| // Use a different URL because re-using the same URL does not trigger new |
| // prerendering: |
| // https://crsrc.org/c/chrome/browser/predictors/autocomplete_action_predictor.cc;l=208;drc=a08a4e1c3f6862b3b1385b8a040a4fdb524e509d |
| base::HistogramTester histogram_tester; |
| const char kNewPrerenderURL[] = "/title3.html"; |
| const auto new_prerender_gurl = |
| embedded_test_server()->GetURL(kNewPrerenderURL); |
| GetAutocompleteActionPredictor()->StartPrerendering( |
| embedded_test_server()->GetURL(kNewPrerenderURL), |
| *GetActiveWebContents()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(new_prerender_gurl.spec()))); |
| |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> trigger_row = |
| FindResourceIndex(MatchTab("Title Of Awesomeness")); |
| ASSERT_TRUE(trigger_row.has_value()); |
| ASSERT_TRUE(model()->GetTabId(trigger_row.value()).is_valid()); |
| model()->Kill(trigger_row.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyPrerender())); |
| histogram_tester.ExpectUniqueSample( |
| "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_" |
| "DirectURLInput", |
| /*PrerenderFinalStatus::kPrimaryMainFrameRendererProcessKilled=*/57, 1); |
| } |
| } |
| |
| // TODO(crbug.com/40232771): Flaky on Windows7. |
| #if BUILDFLAG(IS_WIN) |
| #define MAYBE_OmniboxPrerenderActivationClearsTask \ |
| DISABLED_OmniboxPrerenderActivationClearsTask |
| #else |
| #define MAYBE_OmniboxPrerenderActivationClearsTask \ |
| OmniboxPrerenderActivationClearsTask |
| #endif |
| // Test that the Omnibox-triggered prerender activation clears the prerender |
| // entry in the task manager. |
| IN_PROC_BROWSER_TEST_F(PrerenderTaskBrowserTest, |
| MAYBE_OmniboxPrerenderActivationClearsTask) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(kMainPageUrl); |
| |
| ASSERT_TRUE(GetAutocompleteActionPredictor()); |
| WaitForAutocompleteActionPredictorInitialization(); |
| const auto prerender_gurl = embedded_test_server()->GetURL(kPrerenderURL); |
| GetAutocompleteActionPredictor()->StartPrerendering(prerender_gurl, |
| *GetActiveWebContents()); |
| |
| // One task for main page and one for the prerendered page. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyPrerender())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchPrerender(prerender_gurl.spec()))); |
| |
| // Activate the Omnibox prerender, after which the prerender task should |
| // disappear. |
| content::test::PrerenderHostObserver obs(*GetActiveWebContents(), |
| prerender_gurl); |
| // |ui::PAGE_TRANSITION_FROM_ADDRESS_BAR| augmentation is required for omnibox |
| // activation. |
| auto* web_contents = NavigateToURLWithDispositionAndTransition( |
| prerender_gurl, WindowOpenDisposition::CURRENT_TAB, |
| ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED | |
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)); |
| obs.WaitForActivation(); |
| ASSERT_TRUE(obs.was_activated()); |
| ASSERT_EQ(web_contents, GetActiveWebContents()); // Current tab. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyPrerender())); |
| // Take out the "http://". |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, |
| MatchTab(base::UTF16ToUTF8(url_formatter::FormatUrl(prerender_gurl))))); |
| } |
| |
| //============================================================================== |
| // FencedFrame tasks test. |
| namespace { |
| |
| class FencedFrameTaskBrowserTest : public TaskManagerBrowserTest { |
| public: |
| FencedFrameTaskBrowserTest() { |
| EXPECT_TRUE(blink::features::IsFencedFramesEnabled()); |
| } |
| FencedFrameTaskBrowserTest(const FencedFrameTaskBrowserTest&) = delete; |
| FencedFrameTaskBrowserTest& operator=(const FencedFrameTaskBrowserTest&) = |
| delete; |
| ~FencedFrameTaskBrowserTest() override = default; |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| content::IsolateAllSitesForTesting(command_line); |
| ASSERT_TRUE(content::AreAllSitesIsolatedForTesting()); |
| TaskManagerBrowserTest::SetUpCommandLine(command_line); |
| } |
| |
| void SetUpOnMainThread() override { |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| https_server()->ServeFilesFromDirectory( |
| base::PathService::CheckedGet(chrome::DIR_TEST_DATA)); |
| https_server()->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); |
| content::SetupCrossSiteRedirector(https_server()); |
| ASSERT_TRUE(https_server()->InitializeAndListen()); |
| https_server()->StartAcceptingConnections(); |
| } |
| |
| void NavigateTo(Browser* browser, |
| std::string_view host, |
| std::string_view rel_url) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser, https_server()->GetURL(host, rel_url))); |
| } |
| |
| std::string GetFencedFrameTitle(const GURL& url) const { |
| GURL::Replacements replacements; |
| replacements.ClearPath(); |
| replacements.ClearRef(); |
| if (!content::SiteIsolationPolicy:: |
| AreOriginKeyedProcessesEnabledByDefault()) { |
| // Only include the port for origin-isolated urls. |
| replacements.ClearPort(); |
| } |
| return url.ReplaceComponents(replacements).spec(); |
| } |
| |
| net::EmbeddedTestServer* https_server() { return &https_server_; } |
| |
| content::test::FencedFrameTestHelper* helper() { return helper_.get(); } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS}; |
| std::unique_ptr<content::test::FencedFrameTestHelper> helper_ = |
| std::make_unique<content::test::FencedFrameTestHelper>(); |
| }; |
| |
| // TODO(crbug.com/40285326): This fails with the field trial testing config. |
| class FencedFrameTaskBrowserTestNoTestingConfig |
| : public FencedFrameTaskBrowserTest { |
| public: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| FencedFrameTaskBrowserTest::SetUpCommandLine(command_line); |
| command_line->AppendSwitch("disable-field-trial-config"); |
| } |
| }; |
| |
| } // namespace |
| |
| // Testing that the task manager properly displays fenced frame tasks with |
| // re-opening task manager, and with fenced frame navigations. |
| IN_PROC_BROWSER_TEST_F(FencedFrameTaskBrowserTestNoTestingConfig, |
| ProperlyShowsTasks) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(browser(), "a.test", "/title2.html"); |
| // Create two fenced frames. |
| auto* main_frame = browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| const auto initial_gurl = |
| https_server()->GetURL("a.test", "/fenced_frames/title1.html"); |
| content::RenderFrameHostWrapper fenced_frame_rfh( |
| helper()->CreateFencedFrame(main_frame, initial_gurl)); |
| ASSERT_TRUE(fenced_frame_rfh); |
| |
| // One task for the embedder. Same origin fenced frame does not show up in the |
| // task manager. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| |
| // Navigate the same-site FF to a cross-site url. The changes should be |
| // reflected in the task manager. |
| const auto cross_site_gurl = |
| https_server()->GetURL("b.test", "/fenced_frames/title2.html"); |
| helper()->NavigateFrameInFencedFrameTree(fenced_frame_rfh.get(), |
| cross_site_gurl); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchFencedFrame(GetFencedFrameTitle(cross_site_gurl)))); |
| |
| // Close the task manager and re-open it, all tasks should be re-created. |
| HideTaskManager(); |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchFencedFrame(GetFencedFrameTitle(cross_site_gurl)))); |
| |
| // Terminate the fenced frame. The embedder frame remains intact. |
| { |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> fenced_frame_row = FindResourceIndex( |
| MatchFencedFrame(GetFencedFrameTitle(cross_site_gurl))); |
| ASSERT_TRUE(fenced_frame_row.has_value()); |
| ASSERT_TRUE(model()->GetTabId(fenced_frame_row.value()).is_valid()); |
| model()->Kill(fenced_frame_row.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| } |
| // Re-create the fenced frame and terminate the embedding frame. The |
| // embedder's task and the remaining fenced frame tasks are destroyed. |
| { |
| helper()->CreateFencedFrame(main_frame, initial_gurl); |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| std::optional<size_t> embedder_row = |
| FindResourceIndex(MatchTab("Title Of Awesomeness")); |
| ASSERT_TRUE(embedder_row.has_value()); |
| ASSERT_TRUE(model()->GetTabId(embedder_row.value()).is_valid()); |
| model()->Kill(embedder_row.value()); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyFencedFrame())); |
| } |
| } |
| |
| // Test that the empty fenced frame (one without a `src`) is not shown in the |
| // task manager. Not shown because we cannot observe any navigation events for |
| // fenced frame creation (only |RenderFrameCreated| is triggered). |
| IN_PROC_BROWSER_TEST_F(FencedFrameTaskBrowserTest, EmptyFencedFrameNotShown) { |
| const std::string kEmptyFencedFrameSnippet = R"( |
| const ff = document.createElement("fencedframe"); |
| document.body.appendChild(ff); |
| )"; |
| |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(browser(), "a.test", "/title2.html"); |
| |
| auto* main_frame = browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| ASSERT_TRUE(content::ExecJs(main_frame, kEmptyFencedFrameSnippet)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyFencedFrame())); |
| |
| // Navigation on the empty fenced frame should create an entry. |
| auto* fenced_frame_rfh = |
| content::test::FencedFrameTestHelper::GetMostRecentlyAddedFencedFrame( |
| main_frame); |
| ASSERT_NE(fenced_frame_rfh, nullptr); |
| const auto fenced_frame_gurl = |
| https_server()->GetURL("b.test", "/fenced_frames/title1.html"); |
| helper()->NavigateFrameInFencedFrameTree(fenced_frame_rfh, fenced_frame_gurl); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchFencedFrame(GetFencedFrameTitle(fenced_frame_gurl)))); |
| } |
| |
| // Tests that the task manager properly shows tasks in Incognito mode. |
| IN_PROC_BROWSER_TEST_F(FencedFrameTaskBrowserTest, ShowsIncognitoTask) { |
| auto* incognito_browser = CreateIncognitoBrowser(); |
| ASSERT_NE(incognito_browser, nullptr); |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(incognito_browser, "a.test", "/title2.html"); |
| auto* main_frame = incognito_browser->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| const auto fenced_frame_gurl = |
| https_server()->GetURL("b.test", "/fenced_frames/title1.html"); |
| content::RenderFrameHostWrapper ff_rfh( |
| helper()->CreateFencedFrame(main_frame, fenced_frame_gurl)); |
| ASSERT_TRUE(ff_rfh); |
| // Two tasks: one for the incognito main frame and another for the incognito |
| // fenced frames. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyIncognitoTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchAnyIncognitoFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchIncognitoTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchIncognitoFencedFrame(GetFencedFrameTitle(fenced_frame_gurl)))); |
| } |
| |
| // Test that clicking on the task manager fenced frame task row brings the focus |
| // to the embedder page. |
| IN_PROC_BROWSER_TEST_F(FencedFrameTaskBrowserTest, TaskActivationChangesFocus) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(browser(), "a.test", "/title2.html"); |
| // Create one fenced frame. |
| auto* main_frame = browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| const auto fenced_frame_gurl = |
| https_server()->GetURL("b.test", "/fenced_frames/title1.html"); |
| content::RenderFrameHostWrapper ff_rfh( |
| helper()->CreateFencedFrame(main_frame, fenced_frame_gurl)); |
| ASSERT_TRUE(ff_rfh); |
| |
| // One main tab task, one fenced frame task. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchFencedFrame(GetFencedFrameTitle(fenced_frame_gurl)))); |
| |
| // Open a new tab of "about:blank". This appends an active WebContents at |
| // index 1. |
| ui_test_utils::NavigateToURLWithDisposition( |
| browser(), GURL(url::kAboutBlankURL), |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); |
| |
| // The WebContents of "about:blank" is active. |
| ASSERT_EQ(browser()->tab_strip_model()->active_index(), 1); |
| |
| const std::optional<size_t> fenced_frame_task_row = FindResourceIndex( |
| MatchFencedFrame(GetFencedFrameTitle(fenced_frame_gurl))); |
| ASSERT_TRUE(fenced_frame_task_row.has_value()); |
| model()->Activate(fenced_frame_task_row.value()); |
| |
| // The WebContents of the embedder page is active. |
| ASSERT_EQ(browser()->tab_strip_model()->active_index(), 0); |
| } |
| |
| // Test that same-document navigation does not change the task's title. |
| IN_PROC_BROWSER_TEST_F(FencedFrameTaskBrowserTest, |
| NoTitleChangeForSameDocNavigation) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| NavigateTo(browser(), "a.test", "/title2.html"); |
| // Create one fenced frame. |
| auto* main_frame = browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| const auto fenced_frame_gurl = |
| https_server()->GetURL("b.test", "/fenced_frames/title1.html"); |
| content::RenderFrameHostWrapper ff_rfh( |
| helper()->CreateFencedFrame(main_frame, fenced_frame_gurl)); |
| ASSERT_TRUE(ff_rfh); |
| |
| // One main tab task, one fenced frame task. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchFencedFrame(GetFencedFrameTitle(fenced_frame_gurl)))); |
| |
| // Same-doc navigation of the fenced frame. |
| const auto same_doc_navi_gurl = https_server()->GetURL( |
| "b.test", base::StrCat({"/fenced_frames/title1.html", "#same_doc_navi"})); |
| helper()->NavigateFrameInFencedFrameTree(ff_rfh.get(), same_doc_navi_gurl); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyFencedFrame())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows( |
| 1, MatchFencedFrame(GetFencedFrameTitle(fenced_frame_gurl)))); |
| } |
| |
| // Asserts that the task manager does not attempt to create any task for a RFH |
| // in `kPendingCommit` or `kPendingDeletion` state. Creating tasks during these |
| // two states will trigger a `NOTREACHED()` in |
| // `WebContentsTaskProvider::WebContentsEntry::CreateTaskForFrame`. |
| IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, |
| NoCrashOnPendingCommitPendingDeletaionRFH) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("a.test", "/title2.html"))); |
| auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); |
| auto* main_frame = web_contents->GetPrimaryMainFrame(); |
| |
| const std::string kCreateAndNavigateIFrame = R"( |
| const iframe = document.createElement("iframe"); |
| iframe.src = $1; |
| document.body.appendChild(iframe); |
| )"; |
| |
| // Create a cross-origin iframe, because we don't show tasks for iframes of |
| // the same origin. |
| const GURL cross_origin_subframe_url = |
| embedded_test_server()->GetURL("b.test", "/title3.html"); |
| content::TestNavigationManager nav_obs(web_contents, |
| cross_origin_subframe_url); |
| ASSERT_TRUE(ExecJs( |
| main_frame, |
| content::JsReplace(kCreateAndNavigateIFrame, cross_origin_subframe_url))); |
| ASSERT_TRUE(nav_obs.WaitForRequestStart()); |
| |
| ShowTaskManager(); |
| // Main frame. The task manager does not create tasks for speculative RFHs. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| |
| nav_obs.ResumeNavigation(); |
| ASSERT_TRUE(nav_obs.WaitForNavigationFinished()); |
| |
| // Main frame + subframe after the navigation is resumed. |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchSubframe("http://b.test/"))); |
| |
| HideTaskManager(); |
| // Get hold of the subframe RFH, and stop it from being deleted. |
| content::RenderFrameHostWrapper subframe_rfh( |
| content::ChildFrameAt(main_frame, 0)); |
| content::LeaveInPendingDeletionState(subframe_rfh.get()); |
| |
| const std::string kRemoveIFrame = R"( |
| const iframe = document.querySelector('iframe'); |
| document.body.removeChild(iframe); |
| )"; |
| ASSERT_TRUE(ExecJs(main_frame, kRemoveIFrame)); |
| |
| // The `kPendingDeletion` subframe RFH is not destroyed, and reachable from |
| // the `WebContents`, so it's possible for |
| // `WebContentsTaskProvider::WebContentsEntry::CreateAllTasks()` to create a |
| // task for it. |
| ASSERT_FALSE(subframe_rfh.IsDestroyed()); |
| bool reached = false; |
| web_contents->ForEachRenderFrameHost([&](content::RenderFrameHost* rfh) { |
| if (rfh == subframe_rfh.get()) { |
| reached = true; |
| } |
| }); |
| ASSERT_TRUE(reached); |
| |
| // However we shouldn't create any tasks for a RFH to be deleted. |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); |
| } |
| |
| //============================================================================== |
| // Desktop refreshed task manager test. |
| class TaskManagerDesktopRefreshBrowserTest : public TaskManagerBrowserTest { |
| public: |
| TaskManagerDesktopRefreshBrowserTest() { |
| feature_list_.InitWithFeaturesAndParameters( |
| {{features::kTaskManagerDesktopRefresh, {}}}, |
| /*disabled_features=*/{}); |
| EXPECT_TRUE( |
| base::FeatureList::IsEnabled(features::kTaskManagerDesktopRefresh)); |
| } |
| TaskManagerDesktopRefreshBrowserTest( |
| const TaskManagerDesktopRefreshBrowserTest&) = delete; |
| TaskManagerDesktopRefreshBrowserTest& operator=( |
| const TaskManagerDesktopRefreshBrowserTest&) = delete; |
| ~TaskManagerDesktopRefreshBrowserTest() override = default; |
| |
| void UpdateModel(const DisplayCategory display_category, |
| std::u16string_view search_term) { |
| model()->UpdateModel(display_category, search_term); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Testing that the refreshed task manager properly displays tasks on different |
| // tabs. |
| IN_PROC_BROWSER_TEST_F(TaskManagerDesktopRefreshBrowserTest, |
| FilterTasksByCategoryAndSearchTerm) { |
| ShowTaskManager(); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAboutBlankTab())); |
| |
| // New tab should be shown on the default `Tabs` tab of the task manager. |
| ASSERT_TRUE(ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("a.test", "/title2.html"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyUtility())); |
| |
| // Load an extension which should be shown in the default `Tabs & Extensions` |
| // tab of the task manager. Current the task list is like below. The utility |
| // processes might be different for different systems. |
| // Utility: Network Service |
| // Utility: Video Capture |
| // Utility: Storage Service |
| // Tab: Title Of Awesomeness |
| // Extension: My extension 1 |
| // Extension: Foobar |
| ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("good") |
| .AppendASCII("Extensions") |
| .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") |
| .AppendASCII("1.0.0.0"))); |
| GURL url("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html"); |
| ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_TYPED)); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyUtility())); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchExtension("Foobar"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("My extension 1"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyUtility())); |
| |
| // Switch to `System` tab, the extension and tabs should not be shown. |
| UpdateModel(DisplayCategory::kSystem, u""); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyTab())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| |
| // Input search terms, all matched tasks would be shown no matter which tab |
| // they lie in. |
| UpdateModel(DisplayCategory::kAll, u"title"); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyUtility())); |
| |
| UpdateModel(DisplayCategory::kAll, u"EN"); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchTab("Title Of Awesomeness"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchExtension("Foobar"))); |
| ASSERT_NO_FATAL_FAILURE( |
| WaitForTaskManagerRows(1, MatchExtension("My extension 1"))); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnyExtension())); |
| ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); |
| } |