| // Copyright 2019 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 <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/containers/flat_set.h" |
| #include "base/run_loop.h" |
| #include "base/strings/strcat.h" |
| #include "base/task/post_task.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/browser_process.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/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" |
| #include "components/google/core/common/google_util.h" |
| #include "components/metrics/content/subprocess_metrics_provider.h" |
| #include "components/optimization_guide/core/hints_component_info.h" |
| #include "components/optimization_guide/core/hints_component_util.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_store.h" |
| #include "components/optimization_guide/core/optimization_guide_switches.h" |
| #include "components/optimization_guide/core/optimization_hints_component_update_listener.h" |
| #include "components/optimization_guide/core/test_hints_component_creator.h" |
| #include "components/optimization_guide/core/top_host_provider.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_task_traits.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 "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_quality_tracker.h" |
| #include "third_party/blink/public/common/features.h" |
| |
| namespace { |
| |
| // Fetch and calculate the total number of samples from all the bins for |
| // |histogram_name|. Note: from some browertests run (such as chromeos) there |
| // might be two profiles created, and this will return the total sample count |
| // across profiles. |
| int GetTotalHistogramSamples(const base::HistogramTester* histogram_tester, |
| const std::string& histogram_name) { |
| std::vector<base::Bucket> buckets = |
| histogram_tester->GetAllSamples(histogram_name); |
| int total = 0; |
| for (const auto& bucket : buckets) |
| total += bucket.count; |
| |
| return total; |
| } |
| |
| // Retries fetching |histogram_name| until it contains at least |count| samples. |
| int RetryForHistogramUntilCountReached( |
| const base::HistogramTester* histogram_tester, |
| const std::string& histogram_name, |
| int count) { |
| int total = 0; |
| while (true) { |
| base::ThreadPoolInstance::Get()->FlushForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| |
| total = GetTotalHistogramSamples(histogram_tester, histogram_name); |
| if (total >= count) |
| return total; |
| |
| content::FetchHistogramsFromChildProcesses(); |
| metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| } |
| |
| enum class HintsFetcherRemoteResponseType { |
| kSuccessful = 0, |
| kUnsuccessful = 1, |
| kMalformed = 2, |
| kHung = 3, |
| }; |
| |
| constexpr char kGoogleHost[] = "www.google.com"; |
| |
| // 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); |
| } |
| |
| } // 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() 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); |
| 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(), "/search_results_page.html"); |
| ASSERT_TRUE(search_results_page_url_.is_valid() && |
| search_results_page_url_.SchemeIs(url::kHttpsScheme) && |
| google_util::IsGoogleHostname(search_results_page_url_.host(), |
| google_util::DISALLOW_SUBDOMAIN)); |
| |
| hints_server_ = std::make_unique<net::EmbeddedTestServer>( |
| net::EmbeddedTestServer::TYPE_HTTPS); |
| 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"; |
| param_feature_list_.InitAndEnableFeatureWithParameters( |
| blink::features::kNavigationPredictor, params); |
| |
| InProcessBrowserTest::SetUp(); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* cmd) override { |
| cmd->AppendSwitch("ignore-certificate-errors"); |
| |
| 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("host-rules", "MAP * 127.0.0.1"); |
| cmd->AppendSwitchASCII("force-variation-ids", "4"); |
| |
| cmd->AppendSwitchASCII(optimization_guide::switches::kFetchHintsOverride, |
| "example1.com, example2.com"); |
| |
| cmd->AppendSwitch(optimization_guide::switches::kFetchHintsOverrideTimer); |
| } |
| |
| // 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) { |
| 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); |
| |
| RetryForHistogramUntilCountReached( |
| &histogram_tester, |
| optimization_guide::kComponentHintsUpdatedResultHistogramString, 1); |
| } |
| |
| void SetNetworkConnectionOffline() { |
| content::NetworkConnectionChangeSimulator().SetConnectionType( |
| network::mojom::ConnectionType::CONNECTION_NONE); |
| } |
| |
| void SetResponseType(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. |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| 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 WaitUntilHintsFetcherRequestReceived() { |
| while (true) { |
| { |
| // 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().RunUntilIdle(); |
| } |
| } |
| |
| void ResetCountHintsRequestsReceived() { |
| base::AutoLock lock(lock_); |
| count_hints_requests_received_ = 0; |
| } |
| |
| protected: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| std::unique_ptr<net::EmbeddedTestServer> origin_server_; |
| std::unique_ptr<net::EmbeddedTestServer> hints_server_; |
| HintsFetcherRemoteResponseType response_type_ = |
| 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) { |
| base::AutoLock lock(lock_); |
| |
| ++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")); |
| |
| 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::features:: |
| MaxHostsForOptimizationGuideServiceHintsFetch(), |
| 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_ == 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(https_url_.host()); |
| 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_ == |
| HintsFetcherRemoteResponseType::kUnsuccessful) { |
| response->set_code(net::HTTP_NOT_FOUND); |
| |
| } else if (response_type_ == HintsFetcherRemoteResponseType::kMalformed) { |
| response->set_code(net::HTTP_OK); |
| |
| std::string serialized_request = "Not a proto"; |
| response->set_content(serialized_request); |
| } else if (response_type_ == 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/1051365): 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()); |
| |
| // We only expect 1 field trial to be allowed and sent up. |
| EXPECT_EQ(1, hints_request.active_field_trials_size()); |
| EXPECT_EQ(variations::HashName( |
| "scoped_feature_list_trial_for_OptimizationHintsFetching"), |
| hints_request.active_field_trials(0).name_hash()); |
| } |
| |
| 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; |
| |
| // 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. |
| absl::optional<base::flat_set<std::string>> |
| expect_hints_request_for_hosts_and_urls_; |
| |
| std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_; |
| |
| DISALLOW_COPY_AND_ASSIGN(HintsFetcherDisabledBrowserTest); |
| }; |
| |
| // This test class enables OnePlatform Hints. |
| class HintsFetcherBrowserTest : public HintsFetcherDisabledBrowserTest { |
| public: |
| HintsFetcherBrowserTest() = default; |
| |
| ~HintsFetcherBrowserTest() override = default; |
| |
| void SetUp() override { |
| // Enable OptimizationHintsFetching with |kRemoteOptimizationGuideFetching|. |
| scoped_feature_list_.InitWithFeaturesAndParameters( |
| { |
| {optimization_guide::features::kOptimizationHints, {}}, |
| {optimization_guide::features::kRemoteOptimizationGuideFetching, |
| {{"max_concurrent_page_navigation_fetches", "2"}, |
| {"onload_delay_for_hints_fetching_ms", "200"}}}, |
| {optimization_guide::features::kOptimizationHintsFieldTrials, |
| {{"allowed_field_trial_names", |
| "scoped_feature_list_trial_for_OptimizationHintsFetching"}}}, |
| }, |
| {}); |
| // 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( |
| Profile::FromBrowserContext(browser() |
| ->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetBrowserContext())) |
| ->RegisterOptimizationTypes({optimization_guide::proto::NOSCRIPT}); |
| |
| HintsFetcherDisabledBrowserTest::SetUpOnMainThread(); |
| } |
| |
| optimization_guide::TopHostProvider* top_host_provider() { |
| OptimizationGuideKeyedService* keyed_service = |
| OptimizationGuideKeyedServiceFactory::GetForProfile( |
| browser()->profile()); |
| return keyed_service->GetTopHostProvider(); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(HintsFetcherBrowserTest); |
| }; |
| |
| // 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(); |
| |
| // Whitelist 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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(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); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, |
| HintsFetcherFetchedHintsLoaded) { |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| GURL url = https_url(); |
| |
| // Whitelist 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1), |
| 1); |
| EXPECT_GE(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1), |
| 1); |
| |
| LoadHintsForUrl(https_url()); |
| |
| 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(HintsFetcherRemoteResponseType::kSuccessful); |
| |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| |
| // Whitelist 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(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(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(HintsFetcherRemoteResponseType::kUnsuccessful); |
| |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| |
| // Whitelist 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(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(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(HintsFetcherRemoteResponseType::kMalformed); |
| |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| |
| // Whitelist 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(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(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(HintsFetcherRemoteResponseType::kUnsuccessful); |
| |
| // Set the ECT to force a fetch at navigation time. |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| |
| ui_test_utils::NavigateToURL(browser(), GURL("https://unsuccessful.com/")); |
| |
| // We expect that we requested hints for 1 URL. |
| EXPECT_GE(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.UrlCount", 1), |
| 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| HintsFetcherBrowserTest, |
| HintsFetcherWithResponsesHungShouldRecordWhenActiveRequestCanceled) { |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| |
| SetResponseType(HintsFetcherRemoteResponseType::kHung); |
| |
| // Set the ECT to force a fetch at navigation time. |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| |
| ui_test_utils::NavigateToURL(browser(), GURL("https://hung.com/1")); |
| ui_test_utils::NavigateToURL(browser(), GURL("https://hung.com/2")); |
| ui_test_utils::NavigateToURL(browser(), GURL("https://hung.com/3")); |
| |
| // We expect that one request was canceled. |
| histogram_tester->ExpectUniqueSample( |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.ActiveRequestCanceled." |
| "PageNavigation", |
| 1, 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, HintsFetcherClearFetchedHints) { |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| GURL url = https_url(); |
| |
| // Whitelist 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.Status", 1), |
| 1); |
| EXPECT_GE(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HintCount", 1), |
| 1); |
| |
| LoadHintsForUrl(https_url()); |
| |
| 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()); |
| |
| 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); |
| |
| // Whitelist 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(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(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()); |
| |
| 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); |
| } |
| |
| // TODO(crbug.com/1177122) Re-enable test |
| IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, |
| DISABLED_HintsFetcherNetworkOffline) { |
| 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); |
| |
| // Set the network to be offline. |
| SetNetworkConnectionOffline(); |
| |
| // Whitelist NoScript for https_url()'s' host. |
| SetUpComponentUpdateHints(https_url()); |
| |
| // No HintsFetch should occur because the connection is offline. |
| histogram_tester->ExpectTotalCount( |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, HintsFetcherFetches) { |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| |
| // Whitelist 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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); |
| } |
| |
| // Test that the hints are fetched at the time of the navigation. |
| IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest, |
| HintsFetcher_NavigationFetch_ECT) { |
| { |
| base::HistogramTester histogram_tester; |
| |
| // Whitelist NoScript for https_url()'s' host. |
| SetUpComponentUpdateHints(https_url()); |
| |
| 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( |
| RetryForHistogramUntilCountReached( |
| &histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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()); |
| } |
| |
| // Change ECT to a low value. Hints should be fetched at the time of |
| // navigation. |
| { |
| base::HistogramTester histogram_tester; |
| ukm::TestAutoSetUkmRecorder ukm_recorder; |
| ResetCountHintsRequestsReceived(); |
| |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| |
| // Navigate to a host not in the seeded site engagement service; it |
| // should be recorded as covered by the hints fetcher due to the race. |
| base::flat_set<std::string> expected_request_2g; |
| std::string host_2g("https://unseenhost_2g.com/"); |
| expected_request_2g.insert(GURL(host_2g).host()); |
| expected_request_2g.insert(GURL(host_2g).spec()); |
| SetExpectedHintsRequestForHostsAndUrls(expected_request_2g); |
| ui_test_utils::NavigateToURL(browser(), GURL(host_2g)); |
| |
| EXPECT_EQ(1u, count_hints_requests_received()); |
| RetryForHistogramUntilCountReached( |
| &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString, |
| 1); |
| // Navigate away so metrics are recorded. |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN); |
| ui_test_utils::NavigateToURL(browser(), GURL("http://nohints.com/")); |
| auto entries = ukm_recorder.GetEntriesByName( |
| ukm::builders::OptimizationGuide::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| auto* entry = entries[0]; |
| EXPECT_TRUE(ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchRequestLatencyName)); |
| EXPECT_TRUE(ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName)); |
| ukm_recorder.ExpectEntryMetric( |
| entry, |
| ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName, |
| static_cast<int>(optimization_guide::RaceNavigationFetchAttemptStatus:: |
| kRaceNavigationFetchHostAndURL)); |
| } |
| |
| // Change ECT to unknown. Hints should not be fetched at the time of |
| // navigation as the ECT is unknown so the fetcher should not race. |
| { |
| base::HistogramTester histogram_tester; |
| ResetCountHintsRequestsReceived(); |
| |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN); |
| |
| base::flat_set<std::string> expected_request_unknown; |
| std::string host_unknown_ect("https://unseenhost_unknown_ect.com/"); |
| expected_request_unknown.insert((GURL(host_unknown_ect).host())); |
| expected_request_unknown.insert((GURL(host_unknown_ect).spec())); |
| SetExpectedHintsRequestForHostsAndUrls(expected_request_unknown); |
| ui_test_utils::NavigateToURL(browser(), GURL(host_unknown_ect)); |
| |
| EXPECT_EQ(0u, count_hints_requests_received()); |
| RetryForHistogramUntilCountReached( |
| &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString, |
| 1); |
| |
| // Navigate away so metrics are recorded. |
| base::HistogramTester prev_nav_histogram_tester; |
| ukm::TestAutoSetUkmRecorder prev_nav_ukm_recorder; |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN); |
| ui_test_utils::NavigateToURL(browser(), GURL("http://nohints.com/")); |
| auto entries = prev_nav_ukm_recorder.GetEntriesByName( |
| ukm::builders::OptimizationGuide::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| auto* entry = entries[0]; |
| EXPECT_FALSE(prev_nav_ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchRequestLatencyName)); |
| EXPECT_FALSE(prev_nav_ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName)); |
| } |
| |
| // Change ECT back to a low value. Hints should be fetched at the time of |
| // navigation. |
| { |
| base::HistogramTester histogram_tester; |
| ResetCountHintsRequestsReceived(); |
| |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_3G); |
| |
| // Navigate to a host not in the seeded site engagement service; it |
| // should be recorded as not covered by the hints fetcher. |
| base::flat_set<std::string> expected_request_3g; |
| std::string host_3g("https://unseenhost_3g.com/"); |
| expected_request_3g.insert(GURL(host_3g).host()); |
| expected_request_3g.insert(GURL(host_3g).spec()); |
| SetExpectedHintsRequestForHostsAndUrls(expected_request_3g); |
| ui_test_utils::NavigateToURL(browser(), GURL(host_3g)); |
| |
| EXPECT_EQ(1u, count_hints_requests_received()); |
| RetryForHistogramUntilCountReached( |
| &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString, |
| 1); |
| |
| // Navigate away so metrics are recorded. |
| base::HistogramTester prev_nav_histogram_tester; |
| ukm::TestAutoSetUkmRecorder prev_nav_ukm_recorder; |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN); |
| ui_test_utils::NavigateToURL(browser(), GURL("http://nohints.com/")); |
| auto entries = prev_nav_ukm_recorder.GetEntriesByName( |
| ukm::builders::OptimizationGuide::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| auto* entry = entries[0]; |
| EXPECT_TRUE(prev_nav_ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchRequestLatencyName)); |
| EXPECT_TRUE(prev_nav_ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName)); |
| prev_nav_ukm_recorder.ExpectEntryMetric( |
| entry, |
| ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName, |
| static_cast<int>(optimization_guide::RaceNavigationFetchAttemptStatus:: |
| kRaceNavigationFetchHostAndURL)); |
| } |
| |
| // Navigate again to a webpage with the |
| // same host. Hints should be available at the time of |
| // navigation. |
| { |
| base::HistogramTester histogram_tester; |
| ResetCountHintsRequestsReceived(); |
| |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_3G); |
| |
| // 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_3g; |
| std::string host_3g("https://unseenhost_3g.com"); |
| expected_request_3g.insert(GURL(host_3g).host()); |
| expected_request_3g.insert(GURL(host_3g).spec()); |
| SetExpectedHintsRequestForHostsAndUrls(expected_request_3g); |
| ui_test_utils::NavigateToURL(browser(), |
| GURL("https://unseenhost_3g.com/test1.html")); |
| |
| // With URL-keyed Hints, every unique URL navigated to will result in a |
| // hints fetch if racing is enabled and allowed. |
| EXPECT_EQ(1u, count_hints_requests_received()); |
| RetryForHistogramUntilCountReached( |
| &histogram_tester, optimization_guide::kLoadedHintLocalHistogramString, |
| 1); |
| // Navigate away so metrics are recorded. |
| base::HistogramTester prev_nav_histogram_tester; |
| ukm::TestAutoSetUkmRecorder prev_nav_ukm_recorder; |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN); |
| ui_test_utils::NavigateToURL(browser(), GURL("http://nohints.com/")); |
| auto entries = prev_nav_ukm_recorder.GetEntriesByName( |
| ukm::builders::OptimizationGuide::kEntryName); |
| EXPECT_EQ(1u, entries.size()); |
| auto* entry = entries[0]; |
| EXPECT_TRUE(prev_nav_ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchRequestLatencyName)); |
| EXPECT_TRUE(prev_nav_ukm_recorder.EntryHasMetric( |
| entry, ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName)); |
| prev_nav_ukm_recorder.ExpectEntryMetric( |
| entry, |
| ukm::builders::OptimizationGuide:: |
| kNavigationHintsFetchAttemptStatusName, |
| static_cast<int>(optimization_guide::RaceNavigationFetchAttemptStatus:: |
| kRaceNavigationFetchHostAndURL)); |
| } |
| } |
| |
| // 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(); |
| |
| // Whitelist NoScript for https_url()'s' host. |
| SetUpComponentUpdateHints(https_url()); |
| |
| 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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()); |
| |
| // Setting the connection type to be slow so the page navigation race fetch |
| // is initiated. |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| 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); |
| ui_test_utils::NavigateToURL(browser(), GURL(full_url)); |
| |
| EXPECT_EQ(2u, count_hints_requests_received()); |
| 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); |
| 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()); |
| 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()); |
| ui_test_utils::NavigateToURL(otr_browser, GURL(full_url)); |
| |
| // Make sure no additional hints requests were received. |
| 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(); |
| |
| // Whitelist NoScript for https_url()'s' host. |
| SetUpComponentUpdateHints(https_url()); |
| |
| 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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()); |
| |
| // Setting the connection type to be slow so the page navigation race fetch |
| // is initiated. |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| 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); |
| ui_test_utils::NavigateToURL(browser(), GURL(full_url)); |
| |
| EXPECT_EQ(2u, count_hints_requests_received()); |
| 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); |
| 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()); |
| 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(); |
| |
| // Whitelist NoScript for https_url()'s' host. |
| SetUpComponentUpdateHints(https_url()); |
| |
| 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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()); |
| |
| // Setting the connection type to be slow so the page navigation race fetch |
| // is initiated. |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| 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); |
| ui_test_utils::NavigateToURL(browser(), GURL(full_url)); |
| |
| EXPECT_EQ(2u, count_hints_requests_received()); |
| 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); |
| 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()); |
| 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 HintsFetcherSearchPageBrowserTest : public HintsFetcherBrowserTest { |
| void SetUpCommandLine(base::CommandLine* cmd) override { |
| cmd->AppendSwitch(optimization_guide::switches:: |
| kDisableFetchingHintsAtNavigationStartForTesting); |
| cmd->AppendSwitch("ignore-certificate-errors"); |
| HintsFetcherBrowserTest::SetUpCommandLine(cmd); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(HintsFetcherSearchPageBrowserTest, |
| HintsFetcher_SRP_Slow_Connection) { |
| g_browser_process->network_quality_tracker() |
| ->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| |
| const base::HistogramTester* histogram_tester = GetHistogramTester(); |
| |
| // Whitelist 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(RetryForHistogramUntilCountReached( |
| histogram_tester, |
| "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 1), |
| 1); |
| |
| EXPECT_GE(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(); |
| 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); |
| } |