0
Files
src/components/performance_manager/prerendering_browsertest.cc
Patrick Monette 908a725e17 [PM] Migrate uses of CallOnGraph/RunInGraph
The performance manager now lives on the UI thread, making
these functions obsolete.

The graph can be directly accessed through the
PerformanceManager::GetGraph() function.

This CL was uploaded by git cl split.

R=joenotcharles@google.com

Bug: 40755583
Change-Id: Id00ef39f891380c54eca6227456923956d565a6b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6284745
Reviewed-by: Joe Mason <joenotcharles@google.com>
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Auto-Submit: Patrick Monette <pmonette@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1422663}
2025-02-20 10:26:27 -08:00

217 lines
9.0 KiB
C++

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/performance_manager.h"
#include "components/performance_manager/test_support/performance_manager_browsertest_harness.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.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/prerender_test_util.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace performance_manager {
class Graph;
// Tests that the PerformanceManager node states are updated correctly during
// prerendering.
//
// TODO(crbug.com/40182881): These tests assume prerendering frames are added as
// extra FrameNodes on the existing PageNode. Update this logic once
// prerendering frame trees have their own PageNode.
class PerformanceManagerPrerenderingBrowserTest
: public PerformanceManagerBrowserTestHarness {
public:
using Super = PerformanceManagerBrowserTestHarness;
PerformanceManagerPrerenderingBrowserTest()
: prerender_helper_(base::BindRepeating(
&PerformanceManagerPrerenderingBrowserTest::web_contents,
base::Unretained(this))) {
prerender_helper_.RegisterServerRequestMonitor(&ssl_server_);
}
void SetUpOnMainThread() override {
Super::SetUpOnMainThread();
ssl_server_.AddDefaultHandlers(GetTestDataFilePath());
ssl_server_.SetSSLConfig(
net::test_server::EmbeddedTestServer::CERT_TEST_NAMES);
ASSERT_TRUE(ssl_server_.Start());
// TODO(crbug.com/40172688): PrerenderHost is not deleted when the
// page enters BackForwardCache, though it should be. While this
// functionality is not implemented, disable BackForwardCache for testing
// and wait for the old RenderFrameHost to be deleted after we navigate away
// from it.
content::DisableBackForwardCacheForTesting(
web_contents(), content::BackForwardCache::TEST_REQUIRES_NO_CACHING);
}
void TearDownOnMainThread() override {
EXPECT_TRUE(ssl_server_.ShutdownAndWaitUntilComplete());
Super::TearDownOnMainThread();
}
content::WebContents* web_contents() { return shell()->web_contents(); }
GURL GetUrl(const std::string& path) {
return ssl_server_.GetURL("a.test", path);
}
protected:
net::test_server::EmbeddedTestServer ssl_server_{
net::test_server::EmbeddedTestServer::TYPE_HTTPS};
content::test::PrerenderTestHelper prerender_helper_;
};
IN_PROC_BROWSER_TEST_F(PerformanceManagerPrerenderingBrowserTest,
PrerenderingFinishes) {
const GURL kInitialUrl = GetUrl("/empty.html");
const GURL kPrerenderingUrl = GetUrl("/empty.html?prerender");
// Navigate to an initial page. Test that PM has a PageNode for it, and
// GetMainFrameNode returns its main frame.
ASSERT_TRUE(content::NavigateToURL(web_contents(), kInitialUrl));
base::WeakPtr<PageNode> page_node =
PerformanceManager::GetPrimaryPageNodeForWebContents(web_contents());
ASSERT_TRUE(page_node);
EXPECT_EQ(page_node->GetMainFrameNodes().size(), 1U);
const FrameNode* initial_main_frame_node = page_node->GetMainFrameNode();
int64_t initial_navigation_id = page_node->GetNavigationID();
EXPECT_EQ(page_node->GetMainFrameUrl(), kInitialUrl);
EXPECT_TRUE(initial_main_frame_node->IsCurrent());
// Start prerendering a document. Test that the prerendering frame tree is
// added as additional frame nodes, but GetMainFrameNode is unchanged.
prerender_helper_.AddPrerender(kPrerenderingUrl);
base::WeakPtr<PageNode> page_node2 =
PerformanceManager::GetPrimaryPageNodeForWebContents(web_contents());
ASSERT_TRUE(page_node);
ASSERT_EQ(page_node.get(), page_node2.get());
EXPECT_EQ(page_node->GetMainFrameNodes().size(), 2U);
EXPECT_EQ(page_node->GetMainFrameNode(), initial_main_frame_node);
EXPECT_TRUE(initial_main_frame_node->IsCurrent());
// Find the prerendering MainFrameNode.
const FrameNode* prerender_main_frame_node = nullptr;
for (const FrameNode* frame_node : page_node->GetMainFrameNodes()) {
if (frame_node != initial_main_frame_node) {
prerender_main_frame_node = frame_node;
break;
}
}
ASSERT_TRUE(prerender_main_frame_node);
EXPECT_EQ(prerender_main_frame_node->GetURL(), kPrerenderingUrl);
EXPECT_FALSE(prerender_main_frame_node->IsCurrent());
// The prerendering navigation should not be reflected in the PageNode.
EXPECT_EQ(page_node->GetNavigationID(), initial_navigation_id);
EXPECT_EQ(page_node->GetMainFrameUrl(), kInitialUrl);
// Activate the prerendered document. Test that GetMainFrameNode now returns
// its main frame, and the original frame tree is gone.
content::RenderFrameDeletedObserver deleted_observer(
web_contents()->GetPrimaryMainFrame());
content::test::PrerenderHostObserver prerender_observer(*web_contents(),
kPrerenderingUrl);
prerender_helper_.NavigatePrimaryPage(kPrerenderingUrl);
ASSERT_TRUE(prerender_observer.was_activated());
deleted_observer.WaitUntilDeleted();
ASSERT_TRUE(page_node);
EXPECT_EQ(page_node->GetMainFrameNodes().size(), 1U);
EXPECT_EQ(page_node->GetMainFrameNode(), prerender_main_frame_node);
EXPECT_TRUE(prerender_main_frame_node->IsCurrent());
// Now the PageNode should reflect the prerendering navigation.
EXPECT_NE(page_node->GetNavigationID(), initial_navigation_id);
EXPECT_EQ(page_node->GetMainFrameUrl(), kPrerenderingUrl);
}
IN_PROC_BROWSER_TEST_F(PerformanceManagerPrerenderingBrowserTest,
PrerenderingCancelled) {
const GURL kInitialUrl = GetUrl("/empty.html");
const GURL kPrerenderingUrl = GetUrl("/empty.html?prerender");
const GURL kFinalUrl = GetUrl("/empty.html?elsewhere");
// Navigate to an initial page. Test that PM has a PageNode for it, and
// GetMainFrameNode returns its main frame.
ASSERT_TRUE(content::NavigateToURL(web_contents(), kInitialUrl));
base::WeakPtr<PageNode> page_node =
PerformanceManager::GetPrimaryPageNodeForWebContents(web_contents());
ASSERT_TRUE(page_node);
EXPECT_EQ(page_node->GetMainFrameNodes().size(), 1U);
const FrameNode* initial_main_frame_node = page_node->GetMainFrameNode();
int64_t initial_navigation_id = page_node->GetNavigationID();
EXPECT_EQ(page_node->GetMainFrameUrl(), kInitialUrl);
EXPECT_TRUE(initial_main_frame_node->IsCurrent());
// Start prerendering a document. Test that the prerendering frame tree is
// added as additional frame nodes, but GetMainFrameNode is unchanged.
content::FrameTreeNodeId prerender_host =
prerender_helper_.AddPrerender(kPrerenderingUrl);
base::WeakPtr<PageNode> page_node2 =
PerformanceManager::GetPrimaryPageNodeForWebContents(web_contents());
ASSERT_TRUE(page_node);
ASSERT_EQ(page_node.get(), page_node2.get());
EXPECT_EQ(page_node->GetMainFrameNodes().size(), 2U);
EXPECT_EQ(page_node->GetMainFrameNode(), initial_main_frame_node);
EXPECT_TRUE(initial_main_frame_node->IsCurrent());
// Find the prerendering MainFrameNode.
const FrameNode* prerender_main_frame_node = nullptr;
for (const FrameNode* frame_node : page_node->GetMainFrameNodes()) {
if (frame_node != initial_main_frame_node) {
prerender_main_frame_node = frame_node;
break;
}
}
ASSERT_TRUE(prerender_main_frame_node);
EXPECT_EQ(prerender_main_frame_node->GetURL(), kPrerenderingUrl);
EXPECT_FALSE(prerender_main_frame_node->IsCurrent());
// The prerendering navigation should not be reflected in the PageNode.
EXPECT_EQ(page_node->GetNavigationID(), initial_navigation_id);
EXPECT_EQ(page_node->GetMainFrameUrl(), kInitialUrl);
// Navigate the main frame to another page. Test that the prerendering frame
// tree is removed from PerformanceManager.
content::RenderFrameDeletedObserver deleted_observer(
prerender_helper_.GetPrerenderedMainFrameHost(prerender_host));
bool rfh_should_change =
web_contents()
->GetPrimaryMainFrame()
->ShouldChangeRenderFrameHostOnSameSiteNavigation();
ASSERT_TRUE(content::NavigateToURL(web_contents(), kFinalUrl));
deleted_observer.WaitUntilDeleted();
ASSERT_TRUE(page_node);
EXPECT_EQ(page_node->GetMainFrameNodes().size(), 1U);
// The RenderFrameHost might change after the navigation if RenderDocument
// is enabled.
EXPECT_EQ(rfh_should_change,
page_node->GetMainFrameNode() != initial_main_frame_node);
EXPECT_EQ(page_node->GetMainFrameUrl(), kFinalUrl);
EXPECT_TRUE(page_node->GetMainFrameNode()->IsCurrent());
}
} // namespace performance_manager