chromium/chrome/browser/predictors/loading_predictor_browsertest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/browser/predictors/loading_predictor.h"

#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "base/base64.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/escape.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.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 "chrome/browser/browser_features.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/navigation_predictor/navigation_predictor_features.h"
#include "chrome/browser/navigation_predictor/navigation_predictor_preconnect_client.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/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h"
#include "chrome/browser/predictors/loading_predictor_factory.h"
#include "chrome/browser/predictors/loading_test_util.h"
#include "chrome/browser/predictors/preconnect_manager.h"
#include "chrome/browser/predictors/predictors_enums.h"
#include "chrome/browser/predictors/predictors_features.h"
#include "chrome/browser/predictors/predictors_switches.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.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/optimization_guide_features.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/referrer.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/simple_url_loader_test_helper.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "net/base/features.h"
#include "net/base/network_anonymization_key.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/connection_tracker.h"
#include "net/test/embedded_test_server/controllable_http_response.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_quality_tracker.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/clear_data_filter.mojom.h"
#include "services/network/public/mojom/cors.mojom.h"
#include "services/network/public/mojom/ip_address_space.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "url/gurl.h"
#include "url/origin.h"

BrowserThread;
Optional;
SizeIs;

namespace predictors {

const char kChromiumUrl[] =;

const char kHtmlSubresourcesPath[] =;
// The embedded test server runs on test.com.
// kHtmlSubresourcesPath contains high priority resources from baz.com and
// foo.com. kHtmlSubresourcesPath also contains a low priority resource from
// bar.com.
const char* const kHtmlSubresourcesHosts[] =;

std::string GetPathWithPortReplacement(const std::string& path, uint16_t port) {}

GURL GetDataURLWithContent(const std::string& content) {}

// Helper class to track and allow waiting for ResourcePrefetchPredictor
// initialization. WARNING: OnPredictorInitialized event will not be fired if
// ResourcePrefetchPredictor is initialized before the observer creation.
class PredictorInitializer : public TestObserver {};

class LcpElementLearnWaiter : public TestObserver {};

class TestPreconnectManagerObserver : public PreconnectManager::Observer {};

struct PrefetchResult {};

class TestPrefetchManagerObserver : public PrefetchManager::Observer {};

class LoadingPredictorBrowserTest : public InProcessBrowserTest {};

// Tests that a navigation triggers the LoadingPredictor.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, SimpleNavigation) {}

// Tests that two concurrenct navigations are recorded correctly by the
// predictor.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, TwoConcurrentNavigations) {}

// Tests that two navigations to the same URL are deduplicated.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
                       TwoNavigationsToTheSameURL) {}

// Tests that the LoadingPredictor doesn't record non-http(s) navigations.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, NonHttpNavigation) {}

// Tests that the LoadingPredictor doesn't preconnect to non-http(s) urls.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
                       PrepareForPageLoadNonHttpScheme) {}

namespace {
class TestPrerenderStopObserver
    : public prerender::NoStatePrefetchHandle::Observer {};
}  // namespace

// Tests that the LoadingPredictor preconnects to the main frame origin even if
// it doesn't have any prediction for this origin.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
                       PrepareForPageLoadWithoutPrediction) {}

// Tests that the LoadingPredictor has a prediction for a host after navigating
// to it.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, LearnFromNavigation) {}

class LoadingPredictorBrowserTestLearnAllResources
    : public LoadingPredictorBrowserTest {};

// Tests that the LoadingPredictor has a prediction for a host after navigating
// to it. Disables kLoadingOnlyLearnHighPriorityResources.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTestLearnAllResources,
                       LearnFromNavigation) {}

// Tests that the LoadingPredictor correctly learns from navigations with
// redirect.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
                       LearnFromNavigationWithRedirect) {}

// Tests that the LoadingPredictor performs preresolving/preconnecting for a
// navigation which it has a prediction for.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
                       PrepareForPageLoadWithPrediction) {}

// Tests that a host requested by <link rel="dns-prefetch"> is looked up.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, DnsPrefetch) {}

// Tests that preconnect warms up a socket connection to a test server.
// Note: This test uses a data URI to serve the preconnect hint, to make sure
// that the network stack doesn't just re-use its connection to the test server.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, PreconnectNonCors) {}

// TODO(crbug.com/40063266): isolate test per feature.  Currently, it has
// test for script observer and fonts.
class LCPCriticalPathPredictorBrowserTest : public LoadingPredictorBrowserTest {};

// Tests that the LoadingPredictor has a LCP critical path predictor
// (LCPP) prediction after navigating to it.
// LCPP:
// https://docs.google.com/document/d/18qTNRyv_9K2CtvVrl_ancLzPxiAnfAcbvrCNegU9IBM
// LCP: https://web.dev/lcp/
IN_PROC_BROWSER_TEST_F(LCPCriticalPathPredictorBrowserTest,
                       LearnLCPPFromNavigation) {}

IN_PROC_BROWSER_TEST_F(LCPCriticalPathPredictorBrowserTest, LearnLCPPFont) {}

class SuppressesLoadingPredictorOnSlowNetworkBrowserTest
    : public LoadingPredictorBrowserTest {};

// Tests that kSuppressesLoadingPredictorOnSlowNetwork feature suppresses
// LoadingPredictor on slow network.
IN_PROC_BROWSER_TEST_F(SuppressesLoadingPredictorOnSlowNetworkBrowserTest,
                       SuppressesOnSlowNetwork) {}

enum class NetworkIsolationKeyMode {};

class LoadingPredictorNetworkIsolationKeyBrowserTest
    : public LoadingPredictorBrowserTest,
      public testing::WithParamInterface<NetworkIsolationKeyMode> {};

INSTANTIATE_TEST_SUITE_P();

// Make sure that the right NetworkAnonymizationKey is used by the
// LoadingPredictor, both when the predictor is populated and when it isn't.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       LoadingPredictorNoRedirects) {}

// Make sure that the right NetworkAnonymizationKey is used by the
// LoadingPredictor, both when the predictor is populated and when it isn't.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       LoadingPredictorWithRedirects) {}

// Checks the opposite of the above test - tests that even when a redirect is
// predicted, preconnects are still made to the original origin using the
// correct NetworkAnonymizationKey.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       LoadingPredictorWithRedirects2) {}

IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       LinkRelPreconnectMainFrame) {}

IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       LinkRelPreconnectSubFrame) {}

// Tests that preconnect warms up a non-CORS connection to a test
// server, and that socket is used when fetching a non-CORS resource.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       PreconnectNonCorsAndFetchNonCors) {}

// Tests that preconnect warms up a non-CORS connection to a test
// server, but that socket is not used when fetching a CORS resource.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       PreconnectNonCorsAndFetchCors) {}

// Tests that preconnect warms up a CORS connection to a test server,
// but that socket is not used when fetching a non-CORS resource.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       PreconnectCorsAndFetchNonCors) {}

// Tests that preconnect warms up a CORS connection to a test server,
// that socket is used when fetching a CORS resource.
IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
                       PreconnectCorsAndFetchCors) {}

class LoadingPredictorBrowserTestWithProxy
    : public LoadingPredictorBrowserTest {};

IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTestWithProxy,
                       PrepareForPageLoadWithoutPrediction) {}

IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTestWithProxy,
                       PrepareForPageLoadWithPrediction) {}

class LoadingPredictorBrowserTestWithOptimizationGuide
    : public ::testing::WithParamInterface<
          std::tuple<bool, bool, bool, std::string>>,
      public LoadingPredictorBrowserTest {};

INSTANTIATE_TEST_SUITE_P();

IN_PROC_BROWSER_TEST_P(LoadingPredictorBrowserTestWithOptimizationGuide,
                       NavigationHasLocalPredictionNoOptimizationHint) {}

IN_PROC_BROWSER_TEST_P(LoadingPredictorBrowserTestWithOptimizationGuide,
                       NavigationWithBothLocalPredictionAndOptimizationHint) {}

IN_PROC_BROWSER_TEST_P(LoadingPredictorBrowserTestWithOptimizationGuide,
                       NavigationWithNoLocalPredictionsButHasOptimizationHint) {}

IN_PROC_BROWSER_TEST_P(
    LoadingPredictorBrowserTestWithOptimizationGuide,
    OptimizationGuidePredictionsNotAppliedForAlreadyCommittedNavigation) {}

IN_PROC_BROWSER_TEST_P(LoadingPredictorBrowserTestWithOptimizationGuide,
                       OptimizationGuidePredictionsNotAppliedForRedirect) {}

class LoadingPredictorBrowserTestWithNoLocalPredictions
    : public LoadingPredictorBrowserTest {};

IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTestWithNoLocalPredictions,
                       ShouldNotActOnLocalPrediction) {}

// A fixture for testing prefetching with optimization guide hints.
class LoadingPredictorPrefetchBrowserTest
    : public LoadingPredictorBrowserTestWithOptimizationGuide {};

// Tests that the LoadingPredictor performs prefetching
// for a navigation which it has a prediction for and there isn't a local
// prediction available.
IN_PROC_BROWSER_TEST_P(
    LoadingPredictorPrefetchBrowserTest,
    DISABLED_PrepareForPageLoadWithPredictionForPrefetchNoLocalHint) {}

// Tests that the LoadingPredictor performs prefetching
// for a navigation which it has a prediction for and there is a local
// prediction available.
IN_PROC_BROWSER_TEST_P(
    LoadingPredictorPrefetchBrowserTest,
    PrepareForPageLoadWithPredictionForPrefetchHasLocalHint) {}

// A fixture for testing prefetching with the local resource check not bypassed.
// The normal fixture bypasses the check so that the embedded test server can be
// used.
class LoadingPredictorPrefetchBrowserTestWithBlockedLocalRequest
    : public LoadingPredictorPrefetchBrowserTest {};

// Test that prefetches to local resources are blocked.
// Disabled for being flaky. crbug.com/1116599
IN_PROC_BROWSER_TEST_P(
    LoadingPredictorPrefetchBrowserTestWithBlockedLocalRequest,
    DISABLED_PrepareForPageLoadWithPredictionForPrefetch) {}

// This fixture is for disabling prefetching via test suite instantiation to
// test the counterfactual arm (|always_retrieve_predictions| is
// true but using the predictions is disabled).
class LoadingPredictorPrefetchCounterfactualBrowserTest
    : public LoadingPredictorPrefetchBrowserTest {};

IN_PROC_BROWSER_TEST_P(
    LoadingPredictorPrefetchCounterfactualBrowserTest,
    PrepareForPageLoadWithPredictionForPrefetchHasLocalHint) {}

INSTANTIATE_TEST_SUITE_P();

// For the "BlockedLocalRequest" test, the params largely don't matter. We just
// need to enable prefetching and test one configuration, since the test passes
// if the prefetch is blocked.
INSTANTIATE_TEST_SUITE_P();

// For the "prefetch counterfactual" test, we want to retrieve the optimization
// guide hints but not use them, so set ShouldUseOptimizationGuidePredictions()
// to false. It doesn't matter if IsPrefetchEnabled() is true or not, since
// prefetching only uses optimization guide predictions.
INSTANTIATE_TEST_SUITE_P();

// Tests that LoadingPredictorTabHelper ignores prerender navigations and
// page activations.
class LoadingPredictorMultiplePageBrowserTest
    : public LoadingPredictorBrowserTest {};

IN_PROC_BROWSER_TEST_F(LoadingPredictorMultiplePageBrowserTest,
                       PrerenderNavigationNotObserved) {}

IN_PROC_BROWSER_TEST_F(LoadingPredictorMultiplePageBrowserTest,
                       PrerenderActivationNotObserved) {}

// TODO(crbug.com/325336071): Re-enable this test
#if BUILDFLAG(IS_LINUX)
#define MAYBE_BackForwardCacheNavigationNotObserved
#else
#define MAYBE_BackForwardCacheNavigationNotObserved
#endif
IN_PROC_BROWSER_TEST_F(LoadingPredictorMultiplePageBrowserTest,
                       MAYBE_BackForwardCacheNavigationNotObserved) {}

// Test interaction with fenced frame `window.fence.disableUntrustedNetwork()`
// API. See:
// https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frames_with_local_unpartitioned_data_access.md#revoking-network-access
class FencedFrameLoadingPredictorBrowserTest
    : public LoadingPredictorBrowserTest {};

// Verify DNS prefetch is working in fenced frame.
IN_PROC_BROWSER_TEST_F(FencedFrameLoadingPredictorBrowserTest, DnsPrefetch) {}

// Verify DNS prefetch is disabled after fenced frame untrusted network cutoff.
IN_PROC_BROWSER_TEST_F(FencedFrameLoadingPredictorBrowserTest,
                       NetworkCutoffDisablesDnsPrefetch) {}

// Verify DNS prefetch triggered by link response header is working in fenced
// frame.
IN_PROC_BROWSER_TEST_F(FencedFrameLoadingPredictorBrowserTest,
                       DnsPrefetchFromLinkHeader) {}

// Verify DNS prefetch triggered by link response header is disabled after
// fenced frame untrusted network cutoff.
IN_PROC_BROWSER_TEST_F(FencedFrameLoadingPredictorBrowserTest,
                       NetworkCutoffDisablesDnsPrefetchFromLinkHeader) {}

}  // namespace predictors