blob: 39e742ab431452ec3d5f152df42c9433f619df02 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/performance_manager/public/performance_manager.h"
#include <utility>
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/performance_manager_tab_helper.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/render_frame_host_proxy.h"
#include "components/performance_manager/public/web_contents_proxy.h"
#include "components/performance_manager/test_support/performance_manager_browsertest_harness.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/shell/browser/shell.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
using PerformanceManagerBrowserTest = PerformanceManagerBrowserTestHarness;
// A full browser test is required for this because we need RenderFrameHosts
// to be created.
IN_PROC_BROWSER_TEST_F(PerformanceManagerBrowserTest,
GetFrameNodeForRenderFrameHost) {
// NavigateToURL blocks until the load has completed. We assert that the
// contents has been reused as we don't have general WebContents creation
// hooks in our BrowserTest fixture, and if a new contents was created it
// would be missing the PM tab helper.
auto* old_contents = shell()->web_contents();
static const char kUrl[] = "about:blank";
ASSERT_TRUE(NavigateToURL(shell(), GURL(kUrl)));
content::WebContents* contents = shell()->web_contents();
ASSERT_EQ(contents, old_contents);
ASSERT_EQ(contents->GetLastCommittedURL().possibly_invalid_spec(), kUrl);
content::RenderFrameHost* rfh = contents->GetMainFrame();
ASSERT_TRUE(rfh->IsRenderFrameCreated());
base::WeakPtr<FrameNode> frame_node =
PerformanceManager::GetFrameNodeForRenderFrameHost(rfh);
// Post a task to the Graph and make it call a function on the UI thread that
// will ensure that |frame_node| is really associated with |rfh|.
base::RunLoop run_loop;
auto check_rfh_on_main_thread =
base::BindLambdaForTesting([&](const RenderFrameHostProxy& rfh_proxy) {
EXPECT_EQ(rfh, rfh_proxy.Get());
run_loop.Quit();
});
auto call_on_graph_cb = base::BindLambdaForTesting([&]() {
EXPECT_TRUE(frame_node.get());
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(std::move(check_rfh_on_main_thread),
frame_node->GetRenderFrameHostProxy()));
});
PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb);
// Wait for |check_rfh_on_main_thread| to be called.
run_loop.Run();
// This closes the window, and destroys the underlying WebContents.
shell()->Close();
contents = nullptr;
// After deleting |contents| the corresponding FrameNode WeakPtr should be
// invalid.
base::RunLoop run_loop_after_contents_reset;
auto quit_closure = run_loop_after_contents_reset.QuitClosure();
auto call_on_graph_cb_2 = base::BindLambdaForTesting([&]() {
EXPECT_FALSE(frame_node.get());
std::move(quit_closure).Run();
});
PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb_2);
run_loop_after_contents_reset.Run();
}
IN_PROC_BROWSER_TEST_F(PerformanceManagerBrowserTest, OpenerTrackingWorks) {
// Load a page that will load a popup.
GURL url(embedded_test_server()->GetURL("a.com", "/a_popup_a.html"));
content::ShellAddedObserver shell_added_observer;
ASSERT_TRUE(NavigateToURL(shell(), url));
// Wait for the popup window to appear, and then wait for it to load.
auto* popup = shell_added_observer.GetShell();
ASSERT_TRUE(popup);
WaitForLoad(popup->web_contents());
auto* contents = shell()->web_contents();
auto page = PerformanceManager::GetPrimaryPageNodeForWebContents(contents);
// Jump into the graph and make sure everything is connected as expected.
base::RunLoop run_loop;
PerformanceManager::CallOnGraph(
FROM_HERE, base::BindLambdaForTesting([&page, &run_loop]() {
EXPECT_TRUE(page);
auto* frame = page->GetMainFrameNode();
EXPECT_EQ(1u, frame->GetOpenedPageNodes().size());
auto* embedded_page = *(frame->GetOpenedPageNodes().begin());
EXPECT_EQ(frame, embedded_page->GetOpenerFrameNode());
run_loop.Quit();
}));
run_loop.Run();
}
class PerformanceManagerFencedFrameBrowserTest
: public PerformanceManagerBrowserTest {
public:
PerformanceManagerFencedFrameBrowserTest() = default;
~PerformanceManagerFencedFrameBrowserTest() override = default;
PerformanceManagerFencedFrameBrowserTest(
const PerformanceManagerFencedFrameBrowserTest&) = delete;
PerformanceManagerFencedFrameBrowserTest& operator=(
const PerformanceManagerFencedFrameBrowserTest&) = delete;
content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
return fenced_frame_helper_;
}
content::WebContents* GetWebContents() { return shell()->web_contents(); }
private:
content::test::FencedFrameTestHelper fenced_frame_helper_;
};
IN_PROC_BROWSER_TEST_F(PerformanceManagerFencedFrameBrowserTest,
FencedFrameDoesNotHaveParentFrameNode) {
auto initial_url = embedded_test_server()->GetURL("/empty.html");
ASSERT_TRUE(NavigateToURL(shell(), initial_url));
PerformanceManagerTabHelper* tab_helper =
PerformanceManagerTabHelper::FromWebContents(GetWebContents());
DCHECK(tab_helper);
EXPECT_EQ(tab_helper->frames_.size(), 1U);
// Load a fenced frame.
GURL fenced_frame_url =
embedded_test_server()->GetURL("/fenced_frames/title1.html");
content::RenderFrameHost* fenced_frame_host =
fenced_frame_test_helper().CreateFencedFrame(
GetWebContents()->GetMainFrame(), fenced_frame_url);
// Jump into the graph and make sure |fenced_frame_host| does not have a
// parent frame node.
base::RunLoop run_loop;
PerformanceManager::CallOnGraph(
FROM_HERE,
base::BindLambdaForTesting([tab_helper, fenced_frame_host, &run_loop]() {
// Fenced frame and Portals have an embedder frame node instead of a
// parent frame node. So, the fenced frame should not have a parent
// frame node.
ASSERT_EQ(tab_helper->frames_[fenced_frame_host]->parent_frame_node(),
nullptr);
// TODO(crbug.com/1260363): Check that the embedder relationship exists.
// See also crbug.com/1261454 because the check of
// tab_helper->frames_.size() caused a flaky test failure.
run_loop.Quit();
}));
run_loop.Run();
}
} // namespace performance_manager