blob: 6d6854b739bc00c72f2b0ac882f18a1c2e53cebe [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/optimization_guide/core/hints/hints_fetcher.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/optimization_guide/browser_test_util.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h"
#include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_test_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/content_settings/core/common/features.h"
#include "components/google/core/common/google_switches.h"
#include "components/google/core/common/google_util.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_handle.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
#include "components/optimization_guide/core/filters/hints_component_info.h"
#include "components/optimization_guide/core/filters/hints_component_util.h"
#include "components/optimization_guide/core/filters/optimization_hints_component_update_listener.h"
#include "components/optimization_guide/core/filters/test_hints_component_creator.h"
#include "components/optimization_guide/core/hints/fake_hints_fetcher.h"
#include "components/optimization_guide/core/hints/hints_manager.h"
#include "components/optimization_guide/core/hints/optimization_guide_store.h"
#include "components/optimization_guide/core/hints/top_host_provider.h"
#include "components/optimization_guide/core/optimization_guide_constants.h"
#include "components/optimization_guide/core/optimization_guide_enums.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_prefs.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "components/prefs/pref_service.h"
#include "components/site_engagement/content/site_engagement_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/variations/hashing.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_base.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/network_connection_change_simulator.h"
#include "content/public/test/prerender_test_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/test/test_network_connection_tracker.h"
#include "third_party/blink/public/common/features.h"
namespace {
constexpr char kGoogleHost[] = "www.google.com";
constexpr char kGoogleSearchUrlPath[] = "/search?q=search_results_page.html";
// Modifies |relative_url|:
// Scheme of the returned URL matches the scheme of the |server|.
// Host of the returned URL matches kGoogleHost.
// Port number of the returned URL matches the port at which |server| is
// listening.
// Path of the returned URL is set to |relative_url|.
GURL GetURLWithGoogleHost(net::EmbeddedTestServer* server,
const std::string& relative_url) {
GURL server_base_url = server->base_url();
GURL base_url =
GURL(base::StrCat({server_base_url.scheme(), "://", kGoogleHost, ":",
server_base_url.port()}));
EXPECT_TRUE(base_url.is_valid()) << base_url.possibly_invalid_spec();
return base_url.Resolve(relative_url);
}
// Handles the server request to Google search URL.
std::unique_ptr<net::test_server::HttpResponse> HandleGoogleSearchUrlRequest(
const net::test_server::HttpRequest& request) {
if (base::EqualsCaseInsensitiveASCII(request.relative_url,
kGoogleSearchUrlPath)) {
// Serve the SRP file.
std::unique_ptr<net::test_server::BasicHttpResponse> response =
std::make_unique<net::test_server::BasicHttpResponse>();
std::string file_contents;
base::FilePath test_data_directory;
base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory);
if (base::ReadFileToString(test_data_directory.AppendASCII(
"previews/search_results_page.html"),
&file_contents)) {
response->set_content(file_contents);
response->set_code(net::HTTP_OK);
return std::move(response);
}
}
return nullptr;
}
} // namespace
// This test class sets up everything but does not enable any
// HintsFetcher-related features. The parameter selects whether the
// OptimizationGuideKeyedService is enabled (tests should pass in the same way
// for both cases).
class HintsFetcherDisabledBrowserTest : public InProcessBrowserTest {
public:
HintsFetcherDisabledBrowserTest() = default;
HintsFetcherDisabledBrowserTest(const HintsFetcherDisabledBrowserTest&) =
delete;
HintsFetcherDisabledBrowserTest& operator=(
const HintsFetcherDisabledBrowserTest&) = delete;
~HintsFetcherDisabledBrowserTest() override = default;
void SetUpOnMainThread() override {
content::NetworkConnectionChangeSimulator().SetConnectionType(
network::mojom::ConnectionType::CONNECTION_2G);
// Ensure that kGoogleHost resolves to the localhost where the embedded test
// server is listening.
host_resolver()->AddRule("*", "127.0.0.1");
ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
InProcessBrowserTest::SetUpOnMainThread();
}
void SetUp() override {
origin_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
net::EmbeddedTestServer::ServerCertificateConfig origin_server_cert_config;
origin_server_cert_config.dns_names = {kGoogleHost};
origin_server_cert_config.ip_addresses = {net::IPAddress::IPv4Localhost()};
origin_server_->SetSSLConfig(origin_server_cert_config);
origin_server_->RegisterRequestHandler(
base::BindRepeating(&HandleGoogleSearchUrlRequest));
origin_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews");
ASSERT_TRUE(origin_server_->Start());
https_url_ = origin_server_->GetURL("/hint_setup.html");
ASSERT_TRUE(https_url().SchemeIs(url::kHttpsScheme));
search_results_page_url_ =
GetURLWithGoogleHost(origin_server_.get(), kGoogleSearchUrlPath);
hints_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
net::EmbeddedTestServer::ServerCertificateConfig hints_server_cert_config;
hints_server_cert_config.dns_names = {
GURL(optimization_guide::kOptimizationGuideServiceGetHintsDefaultURL)
.host()};
hints_server_->SetSSLConfig(hints_server_cert_config);
hints_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews");
hints_server_->RegisterRequestHandler(base::BindRepeating(
&HintsFetcherDisabledBrowserTest::HandleGetHintsRequest,
base::Unretained(this)));
ASSERT_TRUE(hints_server_->Start());
std::map<std::string, std::string> params;
params["random_anchor_sampling_period"] = "1";
params["traffic_client_enabled_percent"] = "100";
param_feature_list_.InitAndEnableFeatureWithParameters(
blink::features::kNavigationPredictor, params);
InProcessBrowserTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitch("purge_hint_cache_store");
cmd->AppendSwitch(optimization_guide::switches::
kDisableCheckingUserPermissionsForTesting);
// Set up OptimizationGuideServiceURL, this does not enable HintsFetching,
// only provides the URL.
cmd->AppendSwitchASCII(
optimization_guide::switches::kOptimizationGuideServiceGetHintsURL,
hints_server_
->GetURL(GURL(optimization_guide::
kOptimizationGuideServiceGetHintsDefaultURL)
.host(),
"/")
.spec());
cmd->AppendSwitchASCII("force-variation-ids", "4");
cmd->AppendSwitchASCII(optimization_guide::switches::kFetchHintsOverride,
"example1.com, example2.com");
cmd->AppendSwitch(optimization_guide::switches::kFetchHintsOverrideTimer);
// Ignore the port numbers for the Google Search URL check.
cmd->AppendSwitch(switches::kIgnoreGooglePortNumbers);
}
// Creates hint data for the |hint_setup_url|'s so that the fetching of the
// hints is triggered.
void SetUpComponentUpdateHints(const GURL& hint_setup_url) {
optimization_guide::RetryForHistogramUntilCountReached(
GetHistogramTester(),
"OptimizationGuide.HintsManager.HintCacheInitialized", 1);
const optimization_guide::HintsComponentInfo& component_info =
test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
optimization_guide::proto::NOSCRIPT, {hint_setup_url.host()}, "*");
base::HistogramTester histogram_tester;
optimization_guide::OptimizationHintsComponentUpdateListener::GetInstance()
->MaybeUpdateHintsComponent(component_info);
optimization_guide::RetryForHistogramUntilCountReached(
&histogram_tester,
optimization_guide::kComponentHintsUpdatedResultHistogramString, 1);
}
void SetNetworkConnectionOffline() {
content::NetworkConnectionChangeSimulator().SetConnectionType(
network::mojom::ConnectionType::CONNECTION_NONE);
}
void SetNetworkConnectionOnline() {
content::NetworkConnectionChangeSimulator().SetConnectionType(
network::mojom::ConnectionType::CONNECTION_2G);
}
void SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType response_type) {
response_type_ = response_type;
}
void LoadHintsForUrl(const GURL& url) {
base::HistogramTester histogram_tester;
// Navigate to |url| to prime the OptimizationGuide hints for the
// url's host and ensure that they have been loaded from the store (via
// histogram) prior to the navigation that tests functionality.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
optimization_guide::RetryForHistogramUntilCountReached(
&histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
1);
}
const GURL& https_url() const { return https_url_; }
const base::HistogramTester* GetHistogramTester() {
return &histogram_tester_;
}
const GURL& search_results_page_url() const {
return search_results_page_url_;
}
void SetExpectedHintsRequestForHostsAndUrls(
const base::flat_set<std::string>& hosts_or_urls) {
base::AutoLock lock(lock_);
expect_hints_request_for_hosts_and_urls_ = hosts_or_urls;
}
size_t count_hints_requests_received() {
base::AutoLock lock(lock_);
return count_hints_requests_received_;
}
void increase_count_hints_requests_received() {
{
base::AutoLock lock(lock_);
++count_hints_requests_received_;
}
if (quit_closure_) {
content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
std::move(quit_closure_));
}
}
void SetExpectedBearerAccessToken(
const std::string& expected_bearer_access_token) {
expected_bearer_access_token_ = expected_bearer_access_token;
}
void WaitUntilHintsFetcherRequestReceived() {
{
// Acquire the |lock_| inside to avoid starving other consumers of the
// lock.
base::AutoLock lock(lock_);
if (count_hints_requests_received_ > 0) {
return;
}
}
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
void ResetCountHintsRequestsReceived() {
base::AutoLock lock(lock_);
count_hints_requests_received_ = 0;
}
// Triggers nostate prefetch of |url|.
void TriggerNoStatePrefetch(const GURL& url) {
prerender::NoStatePrefetchManager* no_state_prefetch_manager =
prerender::NoStatePrefetchManagerFactory::GetForBrowserContext(
browser()->profile());
ASSERT_TRUE(no_state_prefetch_manager);
prerender::test_utils::TestNoStatePrefetchContentsFactory*
no_state_prefetch_contents_factory =
new prerender::test_utils::TestNoStatePrefetchContentsFactory();
no_state_prefetch_manager->SetNoStatePrefetchContentsFactoryForTest(
no_state_prefetch_contents_factory);
content::SessionStorageNamespace* storage_namespace =
browser()
->tab_strip_model()
->GetActiveWebContents()
->GetController()
.GetDefaultSessionStorageNamespace();
ASSERT_TRUE(storage_namespace);
std::unique_ptr<prerender::test_utils::TestPrerender> test_prerender =
no_state_prefetch_contents_factory->ExpectNoStatePrefetchContents(
prerender::FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
std::unique_ptr<prerender::NoStatePrefetchHandle> no_state_prefetch_handle =
no_state_prefetch_manager->AddSameOriginSpeculation(
url, storage_namespace, gfx::Size(640, 480),
url::Origin::Create(url));
ASSERT_EQ(no_state_prefetch_handle->contents(), test_prerender->contents());
// The final status may be either FINAL_STATUS_NOSTATE_PREFETCH_FINISHED or
// FINAL_STATUS_RECENTLY_VISITED.
test_prerender->contents()->set_skip_final_checks(true);
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<net::EmbeddedTestServer> origin_server_;
std::unique_ptr<net::EmbeddedTestServer> hints_server_;
optimization_guide::HintsFetcherRemoteResponseType response_type_ =
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful;
private:
std::unique_ptr<net::test_server::HttpResponse> HandleOriginRequest(
const net::test_server::HttpRequest& request) {
EXPECT_EQ(request.method, net::test_server::METHOD_GET);
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
response->set_code(net::HTTP_OK);
return std::move(response);
}
std::unique_ptr<net::test_server::HttpResponse> HandleGetHintsRequest(
const net::test_server::HttpRequest& request) {
increase_count_hints_requests_received();
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
// If the request is a GET, it corresponds to a navigation so return a
// normal response.
EXPECT_EQ(request.method, net::test_server::METHOD_POST);
EXPECT_NE(request.headers.end(), request.headers.find("X-Client-Data"));
EXPECT_EQ(expected_bearer_access_token_.empty(),
!base::Contains(request.headers,
net::HttpRequestHeaders::kAuthorization));
if (!expected_bearer_access_token_.empty()) {
EXPECT_EQ(expected_bearer_access_token_,
request.headers.at(net::HttpRequestHeaders::kAuthorization));
}
// Make sure only one of API key or access token is sent.
EXPECT_EQ(base::Contains(request.headers, "X-Goog-Api-Key"),
expected_bearer_access_token_.empty());
optimization_guide::proto::GetHintsRequest hints_request;
EXPECT_TRUE(hints_request.ParseFromString(request.content));
EXPECT_FALSE(hints_request.hosts().empty() && hints_request.urls().empty());
EXPECT_GE(optimization_guide::HintsFetcher::kMaxHosts,
static_cast<size_t>(hints_request.hosts().size()));
// Only verify the hints if there are hosts in the request.
if (!hints_request.hosts().empty()) {
VerifyHintsMatchExpectedHostsAndUrls(hints_request);
}
if (response_type_ ==
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful) {
response->set_code(net::HTTP_OK);
optimization_guide::proto::GetHintsResponse get_hints_response;
optimization_guide::proto::Hint* hint = get_hints_response.add_hints();
hint->set_key_representation(optimization_guide::proto::HOST);
hint->set_key(search_results_page_url_.host());
hint->add_allowlisted_optimizations()->set_optimization_type(
optimization_guide::proto::OptimizationType::NOSCRIPT);
optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
page_hint->set_page_pattern("page pattern");
std::string serialized_request;
get_hints_response.SerializeToString(&serialized_request);
response->set_content(serialized_request);
} else if (response_type_ ==
optimization_guide::HintsFetcherRemoteResponseType::
kUnsuccessful) {
response->set_code(net::HTTP_NOT_FOUND);
} else if (response_type_ ==
optimization_guide::HintsFetcherRemoteResponseType::kMalformed) {
response->set_code(net::HTTP_OK);
std::string serialized_request = "Not a proto";
response->set_content(serialized_request);
} else if (response_type_ ==
optimization_guide::HintsFetcherRemoteResponseType::kHung) {
return std::make_unique<net::test_server::HungResponse>();
} else {
NOTREACHED();
}
return std::move(response);
}
// Verifies that the hosts present in |hints_request| match the expected set
// of hosts present in |expect_hints_request_for_hosts_|. The ordering of the
// hosts in not matched.
void VerifyHintsMatchExpectedHostsAndUrls(
const optimization_guide::proto::GetHintsRequest& hints_request) const {
if (!expect_hints_request_for_hosts_and_urls_) {
return;
}
base::flat_set<std::string> hosts_and_urls_requested;
for (const auto& host : hints_request.hosts()) {
hosts_and_urls_requested.insert(host.host());
}
for (const auto& url : hints_request.urls()) {
// TODO(crbug.com/40118423): Remove normalization step once nav predictor
// provides predictable URLs.
hosts_and_urls_requested.insert(GURL(url.url()).GetAsReferrer().spec());
}
EXPECT_EQ(expect_hints_request_for_hosts_and_urls_.value().size(),
hosts_and_urls_requested.size());
for (const auto& host_or_url :
expect_hints_request_for_hosts_and_urls_.value()) {
hosts_and_urls_requested.erase(host_or_url);
}
EXPECT_EQ(0u, hosts_and_urls_requested.size());
}
void TearDownOnMainThread() override {
EXPECT_TRUE(origin_server_->ShutdownAndWaitUntilComplete());
EXPECT_TRUE(hints_server_->ShutdownAndWaitUntilComplete());
InProcessBrowserTest::TearDownOnMainThread();
}
base::test::ScopedFeatureList param_feature_list_;
GURL https_url_;
GURL search_results_page_url_;
base::HistogramTester histogram_tester_;
optimization_guide::testing::TestHintsComponentCreator
test_hints_component_creator_;
base::Lock lock_;
// Guarded by |lock_|.
// Count of hints requests received so far by |hints_server_|.
size_t count_hints_requests_received_ = 0;
base::OnceClosure quit_closure_;
// Guarded by |lock_|. Set of hosts and URLs for which a hints request is
// expected to arrive. This set is verified to match with the set of hosts and
// URLs present in the hints request. If null, then the verification is not
// done.
std::optional<base::flat_set<std::string>>
expect_hints_request_for_hosts_and_urls_;
// The expected authorization header holding the bearer access token.
std::string expected_bearer_access_token_;
std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
};
IN_PROC_BROWSER_TEST_F(HintsFetcherDisabledBrowserTest, HintsFetcherDisabled) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Expect that the histogram for HintsFetcher to be 0 because the OnePlatform
// is not enabled.
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0);
}
// This test class enables OnePlatform Hints.
class HintsFetcherBrowserTest : public HintsFetcherDisabledBrowserTest {
public:
HintsFetcherBrowserTest() = default;
HintsFetcherBrowserTest(const HintsFetcherBrowserTest&) = delete;
HintsFetcherBrowserTest& operator=(const HintsFetcherBrowserTest&) = delete;
~HintsFetcherBrowserTest() override = default;
void SetUp() override {
std::vector<base::test::FeatureRefAndParams> enabled_features = {
{optimization_guide::features::kOptimizationHints, {}},
{*optimization_guide::kHintsMaxConcurrentNavigationFetches.feature,
{{optimization_guide::kHintsMaxConcurrentNavigationFetches.name,
"2"}}},
{optimization_guide::kHintsBatchUpdateForActiveTabsAndTopHosts, {}},
};
PopulateEnabledFeatures(&enabled_features);
scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features,
disabled_features_);
// Call to inherited class to match same set up with feature flags added.
HintsFetcherDisabledBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
// Register an optimization type, so hints will be fetched at page
// navigation.
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
HintsFetcherDisabledBrowserTest::SetUpOnMainThread();
}
// Allows subclasses to expand on the features to enable.
virtual void PopulateEnabledFeatures(
std::vector<base::test::FeatureRefAndParams>* enabled_features) {}
optimization_guide::TopHostProvider* top_host_provider() {
OptimizationGuideKeyedService* keyed_service =
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile());
return keyed_service->GetTopHostProvider();
}
void CanApplyOptimizationOnDemand(
const std::vector<GURL>& urls,
const std::vector<optimization_guide::proto::OptimizationType>&
optimization_types,
optimization_guide::OnDemandOptimizationGuideDecisionRepeatingCallback
callback) {
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->CanApplyOptimizationOnDemand(
urls, optimization_types,
optimization_guide::proto::CONTEXT_BOOKMARKS, callback);
}
protected:
std::vector<base::test::FeatureRef> disabled_features_;
};
// This test creates new browser with no profile and loads a random page with
// the feature flags for OptimizationHintsFetching. We confirm that the
// TopHostProvider is called and does not crash by checking UMA
// histograms for the total number of TopEngagementSites and
// the total number of sites returned controlled by the experiments flag
// |max_oneplatform_update_hosts|.
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, HintsFetcherEnabled) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
HintsFetcherFetchedHintsLoaded) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
GURL url = https_url();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1),
1);
LoadHintsForUrl(https_url());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), https_url()));
// Verifies that the fetched hint is just used in memory and nothing is
// loaded.
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintCache.HintType.Loaded", 0);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
HintsFetcherWithResponsesSuccessful) {
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
// Wait until histograms have been updated before performing checks for
// correct behavior based on the response.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
HintsFetcherWithResponsesUnsuccessful) {
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kUnsuccessful);
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
// Wait until histograms have been updated before performing checks for
// correct behavior based on the response.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status",
net::HTTP_NOT_FOUND, 1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 0);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
HintsFetcherWithResponsesMalformed) {
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kMalformed);
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
// Wait until histograms have been updated before performing checks for
// correct behavior based on the response.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 0);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
HintsFetcherWithResponsesUnsuccessfulAtNavigationTime) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kUnsuccessful);
// Set the connection online to force a fetch at navigation time.
SetNetworkConnectionOnline();
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
GURL("https://unsuccessful.com/")));
// We expect that we requested hints for 1 URL.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 1),
1);
}
IN_PROC_BROWSER_TEST_F(
HintsFetcherBrowserTest,
HintsFetcherWithResponsesHungShouldRecordWhenActiveRequestCanceled) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
SetResponseType(optimization_guide::HintsFetcherRemoteResponseType::kHung);
// Set the connection online to force a fetch at navigation time.
SetNetworkConnectionOnline();
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL("https://hung.com/1")));
WaitUntilHintsFetcherRequestReceived();
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL("https://hung.com/2")));
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL("https://hung.com/3")));
// We expect that one request was canceled.
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"PageNavigation",
optimization_guide::FetcherRequestStatus::kRequestCanceled, 1);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
DISABLED_HintsFetcherClearFetchedHints) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
GURL url = https_url();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as OnePlatform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1),
1);
LoadHintsForUrl(https_url());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), https_url()));
// Verifies that the fetched hint is used in-memory and no hint is loaded
// from store.
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintCache.HintType.Loaded", 0);
// Wipe the browser history - clear all the fetched hints.
browser()->profile()->Wipe();
// Wait until hint cache stabilizes and clears all the fetched hints.
base::ThreadPoolInstance::Get()->FlushForTesting();
base::RunLoop().RunUntilIdle();
// Try to load the same hint to confirm fetched hints are no longer there.
LoadHintsForUrl(https_url());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), https_url()));
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintCache.HintType.Loaded",
static_cast<int>(optimization_guide::OptimizationGuideStore::
StoreEntryType::kComponentHint),
1);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, HintsFetcherOverrideTimer) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
GURL url = https_url();
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
optimization_guide::switches::kFetchHintsOverride, "whatever.com");
base::CommandLine::ForCurrentProcess()->AppendSwitch(
optimization_guide::switches::kFetchHintsOverrideTimer);
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as OnePlatform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
// There should be 2 sites in the engagement service.
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 2, 1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
// There should have been 1 hint returned in the response.
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
LoadHintsForUrl(https_url());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), https_url()));
// Verifies that the fetched hint is used from memory and no hints are loaded.
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintCache.HintType.Loaded", 0);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, HintsFetcherFetches) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as hints fetching is enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
}
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
OnDemandFetchRepeatedlyNoCache) {
SetNetworkConnectionOnline();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
OptimizationGuideKeyedService* ogks =
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile());
ogks->RegisterOptimizationTypes(
{optimization_guide::proto::OptimizationType::NOSCRIPT});
GURL url_with_no_hints("https://urlwithnohints.com/notcached");
{
base::HistogramTester histogram_tester;
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
CanApplyOptimizationOnDemand(
{url_with_no_hints},
{optimization_guide::proto::OptimizationType::NOSCRIPT},
base::BindRepeating(
[](base::RunLoop* run_loop, const GURL& url,
const base::flat_map<
optimization_guide::proto::OptimizationType,
optimization_guide::OptimizationGuideDecisionWithMetadata>&
decisions) {
// Expect one decision per requested type.
EXPECT_EQ(decisions.size(), 1u);
auto it = decisions.find(
optimization_guide::proto::OptimizationType::NOSCRIPT);
EXPECT_NE(it, decisions.end());
EXPECT_EQ(it->second.decision,
optimization_guide::OptimizationGuideDecision::kFalse);
run_loop->Quit();
},
run_loop.get()));
run_loop->Run();
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"Bookmarks",
optimization_guide::FetcherRequestStatus::kSuccess, 1);
}
{
base::HistogramTester histogram_tester;
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
CanApplyOptimizationOnDemand(
{url_with_no_hints},
{optimization_guide::proto::OptimizationType::NOSCRIPT},
base::BindRepeating(
[](base::RunLoop* run_loop, const GURL& url,
const base::flat_map<
optimization_guide::proto::OptimizationType,
optimization_guide::OptimizationGuideDecisionWithMetadata>&
decisions) {
// Expect one decision per requested type.
EXPECT_EQ(decisions.size(), 1u);
auto it = decisions.find(
optimization_guide::proto::OptimizationType::NOSCRIPT);
EXPECT_NE(it, decisions.end());
EXPECT_EQ(it->second.decision,
optimization_guide::OptimizationGuideDecision::kFalse);
run_loop->Quit();
},
run_loop.get()));
run_loop->Run();
// Second time should refetch since on-demand always fetches.
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"Bookmarks",
optimization_guide::FetcherRequestStatus::kSuccess, 1);
}
}
// Test that the hints are fetched at the time of the navigation.
IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
HintsFetcher_NavigationFetch_URLKeyedNotRefetched) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
optimization_guide::kComponentHintsUpdatedResultHistogramString, 1);
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
EXPECT_EQ(1u, count_hints_requests_received());
// Enable the connection so the page navigation race fetch is initiated.
SetNetworkConnectionOnline();
std::string full_url("https://foo.com/test/");
{
// Navigate to a host not in the seeded site engagement service; it
// should be recorded as a race for both the host and the URL.
base::flat_set<std::string> expected_request;
expected_request.insert(GURL(full_url).host());
expected_request.insert(GURL(full_url).spec());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
EXPECT_EQ(2u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus",
optimization_guide::RaceNavigationFetchAttemptStatus::
kRaceNavigationFetchHostAndURL,
1);
}
// Navigate again to the same webpage, no race should occur.
{
// Navigate to a host that was recently fetched. It
// should be recorded as covered by the hints fetcher.
base::flat_set<std::string> expected_request;
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
// With URL-keyed Hints, every unique URL navigated to will result in a
// hints fetch if racing is enabled and allowed.
EXPECT_EQ(2u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
2);
// Only the host will be attempted to race, the fetcher should block the
// host from being fetched.
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus",
optimization_guide::RaceNavigationFetchAttemptStatus::
kRaceNavigationFetchNotAttempted,
1);
}
// Incognito page loads should not initiate any fetches.
{
base::HistogramTester incognito_histogram_tester;
// Instantiate off the record Optimization Guide Service.
OptimizationGuideKeyedServiceFactory::GetForProfile(
browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true))
->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
ASSERT_TRUE(ui_test_utils::NavigateToURL(otr_browser, GURL(full_url)));
// Make sure no additional hints requests were received.
optimization_guide::RetryForHistogramUntilCountReached(
&incognito_histogram_tester,
optimization_guide::kLoadedHintLocalHistogramString, 1);
EXPECT_EQ(2u, count_hints_requests_received());
incognito_histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus", 0);
}
}
// Test that the hints are fetched at the time of the navigation.
IN_PROC_BROWSER_TEST_F(
HintsFetcherBrowserTest,
HintsFetcher_NavigationFetch_FetchWithNewlyRegisteredOptType) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
optimization_guide::kComponentHintsUpdatedResultHistogramString, 1);
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
EXPECT_EQ(1u, count_hints_requests_received());
// Enable the network connection so the page navigation race fetch is
// initiated.
SetNetworkConnectionOnline();
std::string full_url("https://foo.com/test/");
{
// Navigate to a host not in the seeded site engagement service; it
// should be recorded as a race for both the host and the URL.
base::flat_set<std::string> expected_request;
expected_request.insert(GURL(full_url).host());
expected_request.insert(GURL(full_url).spec());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
EXPECT_EQ(2u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus",
optimization_guide::RaceNavigationFetchAttemptStatus::
kRaceNavigationFetchHostAndURL,
1);
}
OptimizationGuideKeyedServiceFactory::GetForProfile(
Profile::FromBrowserContext(browser()
->tab_strip_model()
->GetActiveWebContents()
->GetBrowserContext()))
->RegisterOptimizationTypes(
{optimization_guide::proto::COMPRESS_PUBLIC_IMAGES});
// Navigate again to the same webpage, the race should occur because the
// hints have been cleared.
{
// Navigate to a host that was recently fetched. It
// should be recorded as covered by the hints fetcher.
base::flat_set<std::string> expected_request;
expected_request.insert(GURL(full_url).host());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
// With URL-keyed Hints, every unique URL navigated to will result in a
// hints fetch if racing is enabled and allowed.
EXPECT_EQ(3u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
2);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus",
optimization_guide::RaceNavigationFetchAttemptStatus::
kRaceNavigationFetchHost,
1);
}
}
// Test that the hints are fetched at the time of the navigation.
IN_PROC_BROWSER_TEST_F(
HintsFetcherBrowserTest,
HintsFetcher_NavigationFetch_CacheNotClearedOnLaunchedOptTypes) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
optimization_guide::kComponentHintsUpdatedResultHistogramString, 1);
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
EXPECT_EQ(1u, count_hints_requests_received());
// Enable the network connection so the page navigation race fetch is
// initiated.
std::string full_url("https://foo.com/test/");
{
// Navigate to a host not in the seeded site engagement service; it
// should be recorded as a race for both the host and the URL.
base::flat_set<std::string> expected_request;
expected_request.insert(GURL(full_url).host());
expected_request.insert(GURL(full_url).spec());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
EXPECT_EQ(2u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus",
optimization_guide::RaceNavigationFetchAttemptStatus::
kRaceNavigationFetchHostAndURL,
1);
}
OptimizationGuideKeyedServiceFactory::GetForProfile(
Profile::FromBrowserContext(browser()
->tab_strip_model()
->GetActiveWebContents()
->GetBrowserContext()))
->RegisterOptimizationTypes(
{optimization_guide::proto::DEFER_ALL_SCRIPT});
// Navigate again to the same webpage, no race should occur.
{
// Navigate to a host that was recently fetched. It
// should be recorded as covered by the hints fetcher.
base::flat_set<std::string> expected_request;
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
// With URL-keyed Hints, every unique URL navigated to will result in a
// hints fetch if racing is enabled and allowed.
EXPECT_EQ(2u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString,
2);
// Only the host will be attempted to race, the fetcher should block the
// host from being fetched.
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus",
optimization_guide::RaceNavigationFetchAttemptStatus::
kRaceNavigationFetchNotAttempted,
1);
}
}
class HintsFetcherPre3pcdBrowserTest : public HintsFetcherBrowserTest {
public:
HintsFetcherPre3pcdBrowserTest() {
disabled_features_.push_back(
content_settings::features::kTrackingProtection3pcd);
}
};
IN_PROC_BROWSER_TEST_F(HintsFetcherPre3pcdBrowserTest,
HintsFetcherDoesntFetchOnNSP) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as hints fetching is enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
// Initiate a NSP.
SetNetworkConnectionOnline();
ResetCountHintsRequestsReceived();
TriggerNoStatePrefetch(GURL("https://someotherurl.com/"));
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsManager.RaceNavigationFetchAttemptStatus", 0);
}
class HintsFetcherSearchPageBrowserTest : public HintsFetcherBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitch(optimization_guide::switches::
kDisableFetchingHintsAtNavigationStartForTesting);
HintsFetcherBrowserTest::SetUpCommandLine(cmd);
}
};
// TODO(crbug.com/40919396): De-leakify and re-enable.
#if BUILDFLAG(IS_LINUX) && defined(LEAK_SANITIZER)
#define MAYBE_HintsFetcher_SRP_Slow_Connection \
DISABLED_HintsFetcher_SRP_Slow_Connection
#else
#define MAYBE_HintsFetcher_SRP_Slow_Connection HintsFetcher_SRP_Slow_Connection
#endif
IN_PROC_BROWSER_TEST_F(HintsFetcherSearchPageBrowserTest,
MAYBE_HintsFetcher_SRP_Slow_Connection) {
SetNetworkConnectionOnline();
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
// Populate expected hosts with hosts contained in the html response of
// search_results_page_url(). example2.com is contained in the HTML
// response, but hints for example2.com must not be fetched since they
// were pushed via kFetchHintsOverride switch above.
base::flat_set<std::string> expected_hosts_and_urls;
// Unique hosts.
expected_hosts_and_urls.insert(GURL("https://foo.com").host());
expected_hosts_and_urls.insert(GURL("https://example.com").host());
expected_hosts_and_urls.insert(GURL("https://example3.com").host());
// Unique URLs.
expected_hosts_and_urls.insert("https://foo.com/");
expected_hosts_and_urls.insert(
"https://foo.com/simple_page_with_anchors.html");
expected_hosts_and_urls.insert("https://example.com/foo.html");
expected_hosts_and_urls.insert("https://example.com/bar.html");
expected_hosts_and_urls.insert("https://example.com/baz.html");
expected_hosts_and_urls.insert("https://example2.com/foo.html");
expected_hosts_and_urls.insert("https://example3.com/foo.html");
SetExpectedHintsRequestForHostsAndUrls(expected_hosts_and_urls);
histogram_tester->ExpectTotalCount(
optimization_guide::kLoadedHintLocalHistogramString, 0);
// Navigate to a host not in the seeded site engagement service; it
// should be recorded as not covered by the hints fetcher.
ResetCountHintsRequestsReceived();
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), search_results_page_url()));
WaitUntilHintsFetcherRequestReceived();
EXPECT_EQ(1u, count_hints_requests_received());
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 3, 1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 7, 1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
1),
1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
1);
}
class HintsFetcherSearchPagePrerenderingBrowserTest
: public HintsFetcherSearchPageBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
HintsFetcherSearchPageBrowserTest::SetUpCommandLine(command_line);
// |prerender_helper_| has a ScopedFeatureList so we needed to delay its
// creation until now because HintsFetcherDisabledBrowserTest also uses a
// ScopedFeatureList and initialization order matters.
prerender_helper_ = std::make_unique<content::test::PrerenderTestHelper>(
base::BindRepeating(
&HintsFetcherSearchPagePrerenderingBrowserTest::web_contents,
base::Unretained(this)));
}
protected:
content::test::PrerenderTestHelper* prerender_helper() {
return prerender_helper_.get();
}
content::WebContents* web_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
private:
std::unique_ptr<content::test::PrerenderTestHelper> prerender_helper_;
};
// Tests that fetching the hints for a prerendered page is deferred until the
// page gets activated.
IN_PROC_BROWSER_TEST_F(HintsFetcherSearchPagePrerenderingBrowserTest,
HintsFetcherFetchedHintsLoadedAfterActivate) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Allowlist NoScript for https_url()'s' host.
SetUpComponentUpdateHints(https_url());
// Expect that the browser initialization will record at least one sample
// in each of the following histograms as One Platform Hints are enabled.
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1),
1);
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1),
1);
GURL initial_url =
GetURLWithGoogleHost(origin_server_.get(), "/iframe_blank.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url));
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.Status", net::HTTP_OK, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.NetErrorCode", net::OK,
1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
histogram_tester->ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1, 1);
histogram_tester->ExpectTotalCount(
optimization_guide::kLoadedHintLocalHistogramString, 1);
// Load a page in the prerender.
GURL prerender_url = search_results_page_url();
ResetCountHintsRequestsReceived();
content::FrameTreeNodeId host_id =
prerender_helper()->AddPrerender(prerender_url);
EXPECT_EQ(0u, count_hints_requests_received());
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0, 0);
histogram_tester->ExpectTotalCount(
optimization_guide::kLoadedHintLocalHistogramString, 1);
// Activate the page from the prerendering.
content::test::PrerenderHostObserver host_observer(*web_contents(), host_id);
prerender_helper()->NavigatePrimaryPage(prerender_url);
EXPECT_TRUE(host_observer.was_activated());
WaitUntilHintsFetcherRequestReceived();
EXPECT_EQ(1u, count_hints_requests_received());
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString, 2);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 3, 1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 7, 1);
}
class HintsFetcherSearchPageDisabledBrowserTest
: public HintsFetcherDisabledBrowserTest {
public:
HintsFetcherSearchPageDisabledBrowserTest() = default;
void SetUp() override {
std::vector<base::test::FeatureRefAndParams> enabled_features = {
{optimization_guide::features::kOptimizationHints, {}},
{blink::features::kNavigationPredictor,
{{"random_anchor_sampling_period", "1"},
{"traffic_client_enabled_percent", "100"}}},
{*optimization_guide::kHintsMaxConcurrentNavigationFetches.feature,
{{optimization_guide::kHintsMaxConcurrentNavigationFetches.name,
"2"}}},
{optimization_guide::kHintsBatchUpdateForActiveTabsAndTopHosts, {}},
};
scoped_feature_list_.InitWithFeaturesAndParameters(
enabled_features,
// Disabled.
{optimization_guide::features::kOptimizationGuideFetchingForSRP});
HintsFetcherDisabledBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
// Register an optimization type, so hints will be fetched at page
// navigation.
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
HintsFetcherDisabledBrowserTest::SetUpOnMainThread();
}
};
IN_PROC_BROWSER_TEST_F(HintsFetcherSearchPageDisabledBrowserTest,
HintsFetcherStillFetchesNavigations) {
SetNetworkConnectionOnline();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Navigate to a search results page - should not result in a request with
// more than 1 url.
ResetCountHintsRequestsReceived();
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), search_results_page_url()));
// Technically the results page counts as a navigation URL.
base::flat_set<std::string> srp_request;
srp_request.insert(GURL(search_results_page_url()).host());
srp_request.insert(GURL(search_results_page_url()).spec());
SetExpectedHintsRequestForHostsAndUrls(srp_request);
EXPECT_EQ(1u, count_hints_requests_received());
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1, 1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 1, 1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"PageNavigation",
1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
0);
// Now go to a regular URL.
ResetCountHintsRequestsReceived();
std::string full_url = "https://foo.com/test/";
base::flat_set<std::string> expected_request;
expected_request.insert(GURL(full_url).host());
expected_request.insert(GURL(full_url).spec());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(full_url)));
optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester, optimization_guide::kLoadedHintLocalHistogramString, 1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"PageNavigation",
2);
EXPECT_EQ(1u, count_hints_requests_received());
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1, 2);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 1, 2);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"PageNavigation",
2);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
0);
}
// Tests that OptimizationGuideWebContentsObserver limits the results for SRP.
//
// Note that `OptimizationGuideWebContentsObserver::FetchHintsUsingManager`
// limits the urls to `optimization_guide::features::MaxResultsForSRPFetch()`.
// In this test, this method is called with the following URLs but the order
// varies:
//
// - https://example.com/bar.html
// - https://example.com/baz.html
// - https://example.com/foo.html
// - https://example2.com/foo.html
// - https://example3.com/foo.html
// - https://foo.com/
// - https://foo.com/simple_page_with_anchors.html
//
// If we use `max_urls_for_srp_fetch > 1`, the result of
// `OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount` varies. So, we use
// `max_urls_for_srp_fetch = 1`.
class HintsFetcherSearchPageLimitedURLsBrowserTest
: public HintsFetcherDisabledBrowserTest {
public:
HintsFetcherSearchPageLimitedURLsBrowserTest() = default;
void SetUp() override {
std::vector<base::test::FeatureRefAndParams> enabled_features = {
{optimization_guide::features::kOptimizationHints, {}},
{
optimization_guide::features::kOptimizationGuideFetchingForSRP,
{{"max_urls_for_srp_fetch", "1"}},
},
{*optimization_guide::kHintsMaxConcurrentNavigationFetches.feature,
{{optimization_guide::kHintsMaxConcurrentNavigationFetches.name,
"2"}}},
{optimization_guide::kHintsBatchUpdateForActiveTabsAndTopHosts, {}},
};
scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features, {});
HintsFetcherDisabledBrowserTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitch(optimization_guide::switches::
kDisableFetchingHintsAtNavigationStartForTesting);
HintsFetcherDisabledBrowserTest::SetUpCommandLine(cmd);
}
void SetUpOnMainThread() override {
// Register an optimization type, so hints will be fetched at page
// navigation.
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT});
HintsFetcherDisabledBrowserTest::SetUpOnMainThread();
}
};
// TODO(crbug.com/40067071): Disable limited SRP test on Windows/CrOS for now.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
#define MAYBE_HintsFetcherLimitedResults DISABLED_HintsFetcherLimitedResults
#else
#define MAYBE_HintsFetcherLimitedResults HintsFetcherLimitedResults
#endif
IN_PROC_BROWSER_TEST_F(HintsFetcherSearchPageLimitedURLsBrowserTest,
MAYBE_HintsFetcherLimitedResults) {
SetNetworkConnectionOnline();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
const base::HistogramTester* histogram_tester = GetHistogramTester();
// Navigate to a search results page - should result a batch request with up
// to 2 urls.
ResetCountHintsRequestsReceived();
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), search_results_page_url()));
WaitUntilHintsFetcherRequestReceived();
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
1),
1);
EXPECT_EQ(1u, count_hints_requests_received());
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1, 1);
histogram_tester->ExpectBucketCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 1, 1);
histogram_tester->ExpectTotalCount(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
1);
}
class PersonalizedHintsFetcherBrowserTest : public HintsFetcherBrowserTest {
public:
PersonalizedHintsFetcherBrowserTest() = default;
PersonalizedHintsFetcherBrowserTest(
const PersonalizedHintsFetcherBrowserTest&) = delete;
PersonalizedHintsFetcherBrowserTest& operator=(
const HintsFetcherBrowserTest&) = delete;
~PersonalizedHintsFetcherBrowserTest() override = default;
void SetUpBrowserContextKeyedServices(
content::BrowserContext* context) override {
HintsFetcherBrowserTest::SetUpBrowserContextKeyedServices(context);
IdentityTestEnvironmentProfileAdaptor::
SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
}
void SetUpOnMainThread() override {
HintsFetcherBrowserTest::SetUpOnMainThread();
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
browser()->profile());
}
void PopulateEnabledFeatures(
std::vector<base::test::FeatureRefAndParams>* enabled_features) override {
base::FieldTrialParams personalized_fetching_params = {
{"allowed_contexts", "CONTEXT_BOOKMARKS"},
};
enabled_features->emplace_back(
optimization_guide::features::kOptimizationGuidePersonalizedFetching,
personalized_fetching_params);
}
void EnableSignin() {
identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable("user@gmail.com",
signin::ConsentLevel::kSignin);
identity_test_env_adaptor_->identity_test_env()
->SetAutomaticIssueOfAccessTokens(true);
}
void CanApplyOptimizationOnDemand(
optimization_guide::proto::OptimizationType optimization_type,
optimization_guide::proto::RequestContext request_context) {
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
->CanApplyOptimizationOnDemand(
{GURL("https://example.com")}, {optimization_type}, request_context,
base::BindRepeating(
[](optimization_guide::proto::OptimizationType
optimization_type,
base::RunLoop* run_loop, const GURL& url,
const base::flat_map<
optimization_guide::proto::OptimizationType,
optimization_guide::
OptimizationGuideDecisionWithMetadata>& decisions) {
// Expect one decision per requested type.
EXPECT_EQ(decisions.size(), 1u);
auto it = decisions.find(optimization_type);
EXPECT_NE(it, decisions.end());
EXPECT_EQ(
it->second.decision,
optimization_guide::OptimizationGuideDecision::kFalse);
run_loop->Quit();
},
optimization_type, run_loop.get()));
run_loop->Run();
}
private:
// Identity test support.
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
};
IN_PROC_BROWSER_TEST_F(PersonalizedHintsFetcherBrowserTest, NoUserSignIn) {
base::HistogramTester histogram_tester;
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
// No access token set when user is not signed in.
SetExpectedBearerAccessToken(std::string());
CanApplyOptimizationOnDemand(
optimization_guide::proto::OptimizationType::NOSCRIPT,
optimization_guide::proto::CONTEXT_BOOKMARKS);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus.Bookmarks",
optimization_guide::FetcherRequestStatus::kSuccess, 1);
}
IN_PROC_BROWSER_TEST_F(PersonalizedHintsFetcherBrowserTest, UserSignedIn) {
base::HistogramTester histogram_tester;
EnableSignin();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
SetExpectedBearerAccessToken("Bearer access_token");
CanApplyOptimizationOnDemand(
optimization_guide::proto::OptimizationType::NOSCRIPT,
optimization_guide::proto::CONTEXT_BOOKMARKS);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus.Bookmarks",
optimization_guide::FetcherRequestStatus::kSuccess, 1);
// Only the enabled RequestContext will have access token enabled.
SetExpectedBearerAccessToken(std::string());
CanApplyOptimizationOnDemand(
optimization_guide::proto::OptimizationType::NOSCRIPT,
optimization_guide::proto::CONTEXT_JOURNEYS);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus.Journeys",
optimization_guide::FetcherRequestStatus::kSuccess, 1);
}
// TODO(crbug.com/425936619): Add checks for url, hint counts, context.
class ProactivePersonalizationHintsFetcherBrowserTest
: public HintsFetcherBrowserTest {
public:
ProactivePersonalizationHintsFetcherBrowserTest() = default;
ProactivePersonalizationHintsFetcherBrowserTest(
const ProactivePersonalizationHintsFetcherBrowserTest&) = delete;
ProactivePersonalizationHintsFetcherBrowserTest& operator=(
const ProactivePersonalizationHintsFetcherBrowserTest&) = delete;
~ProactivePersonalizationHintsFetcherBrowserTest() override = default;
void SetUpBrowserContextKeyedServices(
content::BrowserContext* context) override {
HintsFetcherBrowserTest::SetUpBrowserContextKeyedServices(context);
IdentityTestEnvironmentProfileAdaptor::
SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
}
void SetUpOnMainThread() override {
HintsFetcherBrowserTest::SetUpOnMainThread();
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
browser()->profile());
}
void PopulateEnabledFeatures(
std::vector<base::test::FeatureRefAndParams>* enabled_features) override {
base::FieldTrialParams personalized_fetching_params = GetFieldTrialParams();
enabled_features->emplace_back(
optimization_guide::features::
kOptimizationGuideProactivePersonalizedHintsFetching,
personalized_fetching_params);
}
virtual base::FieldTrialParams GetFieldTrialParams() {
return {
{"allowed_optimization_types", "NOSCRIPT"},
};
}
void EnableSignin() {
identity_test_env_adaptor_->identity_test_env()
->MakePrimaryAccountAvailable("user@gmail.com",
signin::ConsentLevel::kSignin);
identity_test_env_adaptor_->identity_test_env()
->SetAutomaticIssueOfAccessTokens(true);
}
private:
// Identity test support.
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
};
// Verify access token is attached during navigation fetching if a
// personalizable optimization type is requested.
IN_PROC_BROWSER_TEST_F(ProactivePersonalizationHintsFetcherBrowserTest,
OnNavigationFetchesWithAccessToken) {
SetNetworkConnectionOnline();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
ResetCountHintsRequestsReceived();
EnableSignin();
SetExpectedBearerAccessToken("Bearer access_token");
GURL full_url = GURL("https://foo.com/test/");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), full_url));
base::flat_set<std::string> expected_request;
expected_request.insert(full_url.host());
expected_request.insert(full_url.spec());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
EXPECT_EQ(1u, count_hints_requests_received());
}
// Verify access token is attached during active tab fetching if a
// personalizable optimization type is requested.
IN_PROC_BROWSER_TEST_F(ProactivePersonalizationHintsFetcherBrowserTest,
ActiveTabFetchesWithAccessToken) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
EnableSignin();
SetExpectedBearerAccessToken("Bearer access_token");
SetUpComponentUpdateHints(https_url());
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateActiveTabs",
1),
1);
}
// Verify access token is attached during url fetching if a
// personalizable optimization type is requested.
// TODO(crbug.com/40919396): De-leakify and re-enable.
#if BUILDFLAG(IS_LINUX) && defined(LEAK_SANITIZER)
#define MAYBE_FetchingUrlFetchesWithAccessToken \
DISABLED_FetchingUrlFetchesWithAccessToken
#else
#define MAYBE_FetchingUrlFetchesWithAccessToken \
FetchingUrlFetchesWithAccessToken
#endif
IN_PROC_BROWSER_TEST_F(ProactivePersonalizationHintsFetcherBrowserTest,
MAYBE_FetchingUrlFetchesWithAccessToken) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
EnableSignin();
SetExpectedBearerAccessToken("Bearer access_token");
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), search_results_page_url()));
WaitUntilHintsFetcherRequestReceived();
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
1),
1);
}
class ProactivePersonalizationNoAllowedTypesHintsFetcherBrowserTest
: public ProactivePersonalizationHintsFetcherBrowserTest {
public:
base::FieldTrialParams GetFieldTrialParams() override {
return {
{"allowed_optimization_types", "PERFORMANCE_HINTS"},
};
}
};
// Verify access token is not attached during navigation fetching if no
// personalizable optimization type is requested.
IN_PROC_BROWSER_TEST_F(
ProactivePersonalizationNoAllowedTypesHintsFetcherBrowserTest,
OnNavigationDoesNotFetchAccessToken) {
SetNetworkConnectionOnline();
SetResponseType(
optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
ResetCountHintsRequestsReceived();
EnableSignin();
SetExpectedBearerAccessToken(std::string());
GURL full_url = GURL("https://foo.com/test/");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), full_url));
base::flat_set<std::string> expected_request;
expected_request.insert(full_url.host());
expected_request.insert(full_url.spec());
SetExpectedHintsRequestForHostsAndUrls(expected_request);
EXPECT_EQ(1u, count_hints_requests_received());
}
// Verify access token is not attached during active tab fetching if no
// personalizable optimization type is requested.
IN_PROC_BROWSER_TEST_F(
ProactivePersonalizationNoAllowedTypesHintsFetcherBrowserTest,
ActiveTabDoesNotFetchWithAccessToken) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
EnableSignin();
SetExpectedBearerAccessToken(std::string());
SetUpComponentUpdateHints(https_url());
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateActiveTabs",
1),
1);
}
// Verify access token is not attached during url fetching if no personalizable
// optimization type is requested.
// TODO(crbug.com/40919396): De-leakify and re-enable.
#if BUILDFLAG(IS_LINUX) && defined(LEAK_SANITIZER)
#define MAYBE_FetchingUrlDoesNotFetchWithAccessToken \
DISABLED_FetchingUrlDoesNotFetchWithAccessToken
#else
#define MAYBE_FetchingUrlDoesNotFetchWithAccessToken \
FetchingUrlDoesNotFetchWithAccessToken
#endif
IN_PROC_BROWSER_TEST_F(
ProactivePersonalizationNoAllowedTypesHintsFetcherBrowserTest,
MAYBE_FetchingUrlDoesNotFetchWithAccessToken) {
const base::HistogramTester* histogram_tester = GetHistogramTester();
EnableSignin();
SetExpectedBearerAccessToken(std::string());
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), search_results_page_url()));
WaitUntilHintsFetcherRequestReceived();
EXPECT_GE(optimization_guide::RetryForHistogramUntilCountReached(
histogram_tester,
"OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
"BatchUpdateGoogleSRP",
1),
1);
}