chromium/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc

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

#include <string>

#include "base/containers/contains.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/timer/elapsed_timer.h"
#include "build/build_config.h"
#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
#include "chrome/browser/browser_features.h"
#include "chrome/browser/preloading/chrome_preloading.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/cache_alias_search_prefetch_url_loader.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_request.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/search_preload_test_response_utils.h"
#include "chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h"
#include "chrome/browser/preloading/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/platform_browser_test.h"
#include "chrome/test/base/search_test_utils.h"
#include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_result.h"
#include "components/search_engines/template_url_data.h"
#include "components/search_engines/template_url_service.h"
#include "content/public/browser/preloading.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/preloading_test_util.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "net/base/net_errors.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/network/public/mojom/early_hints.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"

#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/omnibox/browser/autocomplete_controller.h"
#include "components/omnibox/browser/omnibox_controller.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/browser/omnibox_view.h"
#endif  // BUILDFLAG(IS_ANDROID)

namespace {

UkmEntry;
Preloading_Attempt;
Preloading_Prediction;
PrerenderPageLoad;
static const auto kMockElapsedTime =;

// Sets up testing context for the search preloading features: search prefetch
// and search prerender.
// These features are able to coordinate with the other: A prefetched result
// might be upgraded to prerender when needed (usually when service suggests
// clients to do so), and they share the prefetched response and other
// resources, so it is a unified test designed to test the interaction between
// these two features.
class SearchPreloadUnifiedBrowserTest : public PlatformBrowserTest,
                                        public SearchPreloadResponseController {};

// Tests that the SearchSuggestionService can trigger prerendering after the
// corresponding prefetch request succeeds.
// TODO(crbug.com/40943413): enable the flaky test.
#if BUILDFLAG(IS_LINUX)
#define MAYBE_PrerenderHintReceivedBeforeSucceed
#else
#define MAYBE_PrerenderHintReceivedBeforeSucceed
#endif
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       MAYBE_PrerenderHintReceivedBeforeSucceed) {}

// Tests that the SearchSuggestionService can trigger prerendering if it
// receives prerender hints after the previous prefetch request succeeds.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrerenderHintReceivedAfterSucceed) {}

// Tests that the SearchSuggestionService will not trigger prerender if the
// prefetch failed.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       FailedPrefetchCannotBeUpgraded) {}

// Tests that the SearchSuggestionService will not trigger prerender if the
// suggestions changes before SearchSuggestionService receives a servable
// response.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       SuggestionChangeBeforeStartPrerender) {}

// Tests the activated prerendered page records navigation timings correctly.
// Though the prerender happens before the activation navigation, the timings
// should not be a negative value, so that the activated page can measure the
// timing correctly.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       SetLoaderTimeCorrectly) {}

// Tests that prerender fails as well if the prefetch response that prerender
// uses fails.
// TODO(crbug.com/351753962): Fix flakiness and re-enable.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_NavigationFailsAfterPrefetchServedTheResponse
#else
#define MAYBE_NavigationFailsAfterPrefetchServedTheResponse
#endif
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       MAYBE_NavigationFailsAfterPrefetchServedTheResponse) {}

// Tests the prerender works well when running in the
// `StreamingSearchPrefetchURLLoader::serving_from_data_` mode, even if the
// server is slow.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, ChunkedResponseBody) {}

// Tests prerender is cancelled after SearchPrefetchService cancels prefetch
// requests.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, DoNotRefetchSameTerms) {}

class HoldbackSearchPreloadUnifiedBrowserTest
    : public SearchPreloadUnifiedBrowserTest {};

class DSEPrerenderHoldbackSearchPreloadUnifiedBrowserTest
    : public HoldbackSearchPreloadUnifiedBrowserTest {};

// Tests that we log correct metrics for Prerender holdback in case of Search
// Prerender.
IN_PROC_BROWSER_TEST_F(DSEPrerenderHoldbackSearchPreloadUnifiedBrowserTest,
                       PrerenderDSEHoldbackTest) {}

class PreloadingConfigHoldbackSearchPreloadUnifiedBrowserTest
    : public HoldbackSearchPreloadUnifiedBrowserTest {};

// Tests that we log correct metrics for Prerender holdback in case of Search
// Prerender.
IN_PROC_BROWSER_TEST_F(PreloadingConfigHoldbackSearchPreloadUnifiedBrowserTest,
                       PrerenderDSEHoldbackTest) {}

// Disables BFCache for testing back forward navigation can reuse the HTTP
// Cache.
class HTTPCacheSearchPreloadUnifiedBrowserTest
    : public SearchPreloadUnifiedBrowserTest {};

// Test back or forward navigations can use the HTTP Cache.
IN_PROC_BROWSER_TEST_F(HTTPCacheSearchPreloadUnifiedBrowserTest,
                       BackwardHitHttpCache) {}

// Tests the started prerender is destroyed after prefetch request expired.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrerenderGetDestroyedAfterPrefetchExpired) {}

// TODO(https://cubug.com/1282624): This test should run on Android after we're
// able to interact with Android UI.
// TODO(crbug.com/40231021): On LacrOS, the window's bound changes
// unexpectedly, and it stops auto completing.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest, TriggerAndActivate) {}

// Tests the metrics for analyzing the unideal scenario that prerender fails
// after taking response away. Without prerender, these prefetches could have
// helped improve the performance of loading SRPs, so it is necessary to
// understand the percentage of failing ones.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrerenderFailAfterResponseServed) {}
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)

// Tests prerender is not cancelled after SearchPrefetchService cancels prefetch
// requests.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       SuggestionChangeAfterStartPrerender) {}

// Used by SearchPreloadUnifiedFallbackBrowserTest and
// NoCancelSearchPreloadUnifiedFallbackBrowserTest to check the streaming
// loader's status. Since the result can be set upon Mojo disconnection, we have
// to wait until it to be reported.
void CheckCorrectForwardingResultMetric(
    base::HistogramTester& histogram_tester,
    StreamingSearchPrefetchURLLoader::ForwardingResult result,
    int count) {}

// Tests cancelling prerenders should not delete the prefetched responses.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrefetchSucceedAfterPrerenderFailed) {}

// Tests that prefetched response can be served to prerender client
// successfully.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       FetchPrerenderActivated) {}

// Tests that the SearchSuggestionService can trigger prerendering if it
// receives prerender hints after the previous prefetch request succeeds.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrerenderHintReceivedAfterCompletion) {}

// Tests that once prefetch encountered error, prerender would be canceled as
// well.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrefetchErrorCancelsPrerender) {}

// Tests that if prerender is canceled by itself before the loader receives
// response body from the internet, the correct result can be recorded.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrerenderDiscardedBeforeServingData) {}

// Edge case: when the prerendering navigation is still reading from the cache,
// the loader would not be deleted until finishing reading.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       ServingToPrerenderingUntilCompletion) {}

// It is possible that one prefetched response is served to multiple prerender
// in the current design.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       ServingToPrerenderNavigationTwice) {}

// Fake URLLoader that reads the prefetched response from memory cache.
class SearchPreloadServingTestURLLoader
    : public network::mojom::URLLoaderClient,
      public mojo::DataPipeDrainer::Client {};

// Regression test for https://crbug.com/1493229.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       PrerenderHandlerExecutedAfterPrefetchHandler) {}

// We cannot open the result in another tab on Android.
#if !BUILDFLAG(IS_ANDROID)

// Tests that even when prerendering is not failed, users can open the
// prefetched result in another tab and activate the prefetched response
// successfully.
#if (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)) && \
    defined(ADDRESS_SANITIZER)
#define MAYBE_OpenPrefetchedResponseInBackgroundedTab
#else
#define MAYBE_OpenPrefetchedResponseInBackgroundedTab
#endif
// TODO(crbug.com/40272425): Flaky on chromiumos ASAN LSAN and Linux
// ASAN.
IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedBrowserTest,
                       MAYBE_OpenPrefetchedResponseInBackgroundedTab) {}
#endif  // !BUILDFLAG(IS_ANDROID)

}  // namespace