|  | // 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.GetHost(), "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.GetPort(); | 
|  | } | 
|  |  | 
|  | // 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())); | 
|  | } |