blob: 4ab0a9a62a35ff6b01475f49891b383169488191 [file] [log] [blame]
// Copyright 2021 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.
#ifndef CONTENT_PUBLIC_TEST_PRERENDER_TEST_UTIL_H_
#define CONTENT_PUBLIC_TEST_PRERENDER_TEST_UTIL_H_
#include "base/callback.h"
#include "base/test/scoped_feature_list.h"
#include "content/public/browser/prerender_trigger_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
class WebContents;
namespace test {
class PrerenderHostRegistryObserverImpl;
// The PrerenderHostRegistryObserver permits waiting for a host to be created
// for a given URL.
class PrerenderHostRegistryObserver {
public:
explicit PrerenderHostRegistryObserver(WebContents& web_contents);
~PrerenderHostRegistryObserver();
PrerenderHostRegistryObserver(const PrerenderHostRegistryObserver&) = delete;
PrerenderHostRegistryObserver& operator=(
const PrerenderHostRegistryObserver&) = delete;
// Returns immediately if |gurl| was ever triggered before. Otherwise blocks
// on a RunLoop until a prerender of |gurl| is triggered.
void WaitForTrigger(const GURL& gurl);
// Invokes |callback| immediately if |gurl| was ever triggered before.
// Otherwise invokes |callback| when a prerender for |gurl| is triggered.
void NotifyOnTrigger(const GURL& gurl, base::OnceClosure callback);
private:
std::unique_ptr<PrerenderHostRegistryObserverImpl> impl_;
};
class PrerenderHostObserverImpl;
// The PrerenderHostObserver permits listening for host activation and
// destruction
class PrerenderHostObserver {
public:
// Begins observing the given PrerenderHost immediately. DCHECKs if |host_id|
// does not identify a live PrerenderHost.
PrerenderHostObserver(WebContents& web_contents, int host_id);
// Will start observing a PrerenderHost for |gurl| as soon as it is
// triggered.
PrerenderHostObserver(WebContents& web_contents, const GURL& gurl);
~PrerenderHostObserver();
PrerenderHostObserver(const PrerenderHostObserver&) = delete;
PrerenderHostObserver& operator=(const PrerenderHostObserver&) = delete;
// Returns immediately if the PrerenderHost was already activated, otherwise
// spins a RunLoop until the observed host is activated.
void WaitForActivation();
// Returns immediately if the PrerenderHost was already destroyed, otherwise
// spins a RunLoop until the observed host is destroyed.
void WaitForDestroyed();
// True if the PrerenderHost was activated to be the primary page.
bool was_activated() const;
private:
std::unique_ptr<PrerenderHostObserverImpl> impl_;
};
// Browser tests can use this class to more conveniently leverage prerendering.
class PrerenderTestHelper {
public:
explicit PrerenderTestHelper(const WebContents::Getter& fn);
~PrerenderTestHelper();
PrerenderTestHelper(const PrerenderTestHelper&) = delete;
PrerenderTestHelper& operator=(const PrerenderTestHelper&) = delete;
// This installs a network monitor on the http server. Be sure to call this
// before starting the server. This is typically done from SetUp, but it is
// fine to call from SetUpOnMainThread if ordering constraints make that
// impossible (eg, if the test helper is created later to avoid problematic
// creation/destruction relative to other ScopedFeatureLists or if the fixture
// creates test server after SetUp).
void SetUp(net::test_server::EmbeddedTestServer* http_server);
// Attempts to lookup the host for the given |gurl|. Returns
// RenderFrameHost::kNoFrameTreeNodeId upon failure.
int GetHostForUrl(const GURL& gurl);
// Waits until a prerender has finished loading. Note: this may not be called
// when the load fails (e.g. because it was blocked by a NavigationThrottle,
// or the WebContents is destroyed). If the prerender doesn't yet exist, this
// will wait until it is triggered.
static void WaitForPrerenderLoadCompletion(WebContents& web_contents,
const GURL& gurl);
void WaitForPrerenderLoadCompletion(const GURL& gurl);
void WaitForPrerenderLoadCompletion(int host_id);
// Adds <script type="speculationrules"> in the current main frame and waits
// until the completion of prerendering. Returns the id of the resulting
// prerendering host.
//
// AddPrerenderAsync() is the same as AddPrerender(), but does not wait until
// the completion of prerendering.
int AddPrerender(const GURL& prerendering_url);
void AddPrerenderAsync(const GURL& prerendering_url);
// Starts prerendering and returns a PrerenderHandle that should be kept alive
// until prerender activation. Note that it returns before the completion of
// the prerendering navigation.
std::unique_ptr<PrerenderHandle> AddEmbedderTriggeredPrerenderAsync(
const GURL& prerendering_url,
PrerenderTriggerType trigger_type,
const std::string& embedder_histogram_suffix,
ui::PageTransition page_transition);
// This navigates, but does not activate, the prerendered page.
void NavigatePrerenderedPage(int host_id, const GURL& gurl);
// Navigates the primary page to the URL and waits until the completion of
// the navigation.
//
// Navigations that could activate a prerendered page on the multiple
// WebContents architecture (not multiple-pages architecture known as
// MPArch) should use this function instead of the NavigateToURL() test
// helper. This is because the test helper accesses the predecessor
// WebContents to be destroyed during activation and results in crashes.
// See https://crbug.com/1154501 for the MPArch migration.
// TODO(crbug.com/1198960): remove this once the migration is complete.
static void NavigatePrimaryPage(WebContents& web_contents, const GURL& gurl);
void NavigatePrimaryPage(const GURL& gurl);
// Confirms that, internally, appropriate subframes report that they are
// prerendering (and that each frame tree type is kPrerender).
[[nodiscard]] ::testing::AssertionResult VerifyPrerenderingState(
const GURL& gurl);
RenderFrameHost* GetPrerenderedMainFrameHost(int host_id);
int GetRequestCount(const GURL& url);
net::test_server::HttpRequest::HeaderMap GetRequestHeaders(const GURL& url);
// Waits until the request count for `url` reaches `count`.
void WaitForRequest(const GURL& gurl, int count);
// Generates the histogram name by appending the trigger type and the embedder
// suffix to the base name.
std::string GenerateHistogramName(const std::string& histogram_base_name,
content::PrerenderTriggerType trigger_type,
const std::string& embedder_suffix);
private:
void MonitorResourceRequest(const net::test_server::HttpRequest& request);
WebContents* GetWebContents();
// Counts of requests sent to the server. Keyed by path (not by full URL)
// because the host part of the requests is translated ("a.test" to
// "127.0.0.1") before the server handles them.
// This is accessed from the UI thread and `EmbeddedTestServer::io_thread_`.
std::map<std::string, int> request_count_by_path_ GUARDED_BY(lock_);
std::map<std::string, net::test_server::HttpRequest::HeaderMap>
request_headers_by_path_ GUARDED_BY(lock_);
base::test::ScopedFeatureList feature_list_;
base::OnceClosure monitor_callback_ GUARDED_BY(lock_);
base::Lock lock_;
WebContents::Getter get_web_contents_fn_;
};
} // namespace test
} // namespace content
#endif // CONTENT_PUBLIC_TEST_PRERENDER_TEST_UTIL_H_