Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 5 | #include "content/browser/preloading/prefetch/prefetch_service.h" |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 6 | |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 7 | #include <algorithm> |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 8 | #include <memory> |
| 9 | #include <optional> |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 10 | #include <string_view> |
Andrew Rayskiy | dae52e9 | 2024-03-05 17:53:36 | [diff] [blame] | 11 | #include <vector> |
| 12 | |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 13 | #include "base/functional/callback_helpers.h" |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 14 | #include "base/memory/weak_ptr.h" |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 15 | #include "base/notreached.h" |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 16 | #include "base/run_loop.h" |
Lei Zhang | 0a85e65a | 2025-05-23 19:22:06 | [diff] [blame] | 17 | #include "base/strings/string_number_conversions.h" |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 18 | #include "base/strings/string_util.h" |
Lei Zhang | ab09dd84 | 2025-05-17 08:06:48 | [diff] [blame] | 19 | #include "base/strings/stringprintf.h" |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 20 | #include "base/test/bind.h" |
Adithya Srinivasan | d1c68ba | 2023-05-30 19:54:25 | [diff] [blame] | 21 | #include "base/test/mock_callback.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 22 | #include "base/test/scoped_feature_list.h" |
Hiroshige Hayashizaki | 6e9a189 | 2023-04-17 06:47:38 | [diff] [blame] | 23 | #include "base/test/test_future.h" |
William Liu | 60e005f | 2023-01-18 16:17:22 | [diff] [blame] | 24 | #include "base/time/time.h" |
| 25 | #include "base/timer/elapsed_timer.h" |
Liviu Tinta | 2e1ffe2 | 2024-06-21 21:01:33 | [diff] [blame] | 26 | #include "components/variations/scoped_variations_ids_provider.h" |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 27 | #include "content/browser/browser_context_impl.h" |
Jeremy Roman | e561b41 | 2024-02-15 18:31:34 | [diff] [blame] | 28 | #include "content/browser/preloading/prefetch/mock_prefetch_service_delegate.h" |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 29 | #include "content/browser/preloading/prefetch/prefetch_container.h" |
| 30 | #include "content/browser/preloading/prefetch/prefetch_document_manager.h" |
| 31 | #include "content/browser/preloading/prefetch/prefetch_features.h" |
Liviu Tinta | 4eaa53c2 | 2023-08-02 21:01:06 | [diff] [blame] | 32 | #include "content/browser/preloading/prefetch/prefetch_match_resolver.h" |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 33 | #include "content/browser/preloading/prefetch/prefetch_params.h" |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 34 | #include "content/browser/preloading/prefetch/prefetch_scheduler.h" |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 35 | #include "content/browser/preloading/prefetch/prefetch_servable_state.h" |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 36 | #include "content/browser/preloading/prefetch/prefetch_serving_handle.h" |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 37 | #include "content/browser/preloading/prefetch/prefetch_serving_page_metrics_container.h" |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 38 | #include "content/browser/preloading/prefetch/prefetch_streaming_url_loader.h" |
Hiroshige Hayashizaki | b2a4d78 | 2025-01-15 11:25:15 | [diff] [blame] | 39 | #include "content/browser/preloading/prefetch/prefetch_test_util_internal.h" |
Taiyo Mizuhashi | 6b0a495 | 2024-03-18 22:40:37 | [diff] [blame] | 40 | #include "content/browser/preloading/prefetch/prefetch_type.h" |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 41 | #include "content/browser/preloading/preloading.h" |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 42 | #include "content/browser/preloading/preloading_attempt_impl.h" |
Dave Tapuska | ab31ccf | 2023-04-12 19:27:27 | [diff] [blame] | 43 | #include "content/browser/preloading/preloading_config.h" |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 44 | #include "content/browser/preloading/preloading_data_impl.h" |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 45 | #include "content/browser/preloading/prerender/prerender_features.h" |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 46 | #include "content/browser/preloading/speculation_rules/speculation_rules_tags.h" |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 47 | #include "content/browser/renderer_host/frame_tree_node.h" |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 48 | #include "content/browser/renderer_host/render_frame_host_impl.h" |
Arthur Sonzogni | bdeca8e | 2023-09-11 08:32:12 | [diff] [blame] | 49 | #include "content/common/features.h" |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 50 | #include "content/public/browser/browser_context.h" |
Max Curran | 3df677bf | 2022-09-12 19:47:07 | [diff] [blame] | 51 | #include "content/public/browser/frame_accept_header.h" |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 52 | #include "content/public/browser/prefetch_request_status_listener.h" |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 53 | #include "content/public/browser/prefetch_service_delegate.h" |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 54 | #include "content/public/browser/preload_pipeline_info.h" |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 55 | #include "content/public/browser/preloading.h" |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 56 | #include "content/public/browser/storage_partition.h" |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 57 | #include "content/public/common/content_client.h" |
Simon Pelchat | efb7e7f | 2023-04-04 01:20:48 | [diff] [blame] | 58 | #include "content/public/common/content_features.h" |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 59 | #include "content/public/test/fake_service_worker_context.h" |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 60 | #include "content/public/test/mock_client_hints_controller_delegate.h" |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 61 | #include "content/public/test/mock_navigation_handle.h" |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 62 | #include "content/public/test/navigation_simulator.h" |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 63 | #include "content/public/test/preloading_test_util.h" |
| 64 | #include "content/public/test/test_browser_context.h" |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 65 | #include "content/test/test_content_browser_client.h" |
Dmitrii Kuragin | 8045a83 | 2022-07-18 17:44:32 | [diff] [blame] | 66 | #include "net/base/load_flags.h" |
Andrew Williams | 8a9e242 | 2023-11-06 20:32:57 | [diff] [blame] | 67 | #include "net/base/proxy_chain.h" |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 68 | #include "net/base/proxy_server.h" |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 69 | #include "net/base/request_priority.h" |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 70 | #include "net/http/http_no_vary_search_data.h" |
| 71 | #include "net/http/http_request_headers.h" |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 72 | #include "services/metrics/public/cpp/metrics_utils.h" |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 73 | #include "services/network/public/cpp/parsed_headers.h" |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 74 | #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 75 | #include "services/network/public/mojom/cookie_manager.mojom.h" |
| 76 | #include "services/network/public/mojom/network_context.mojom.h" |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 77 | #include "services/network/public/mojom/proxy_lookup_client.mojom.h" |
| 78 | #include "services/network/test/test_network_context.h" |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 79 | #include "services/network/test/test_url_loader_factory.h" |
| 80 | #include "services/network/test/test_utils.h" |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 81 | #include "testing/gmock/include/gmock/gmock.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 82 | #include "testing/gtest/include/gtest/gtest.h" |
David Risney | a1dd2bf | 2025-03-06 03:40:42 | [diff] [blame] | 83 | #include "third_party/blink/public/common/navigation/preloading_headers.h" |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 84 | #include "third_party/blink/public/common/web_preferences/web_preferences.h" |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 85 | #include "url/gurl.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 86 | |
| 87 | namespace content { |
| 88 | namespace { |
| 89 | |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 90 | #if BUILDFLAG(IS_CHROMEOS) |
| 91 | #define DISABLED_CHROMEOS(x) DISABLED_##x |
| 92 | #else |
| 93 | #define DISABLED_CHROMEOS(x) x |
| 94 | #endif |
| 95 | |
| 96 | #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_CASTOS) |
| 97 | #define DISABLED_CHROMEOS_AND_CASTOS(x) DISABLED_##x |
| 98 | #else |
| 99 | #define DISABLED_CHROMEOS_AND_CASTOS(x) x |
| 100 | #endif |
| 101 | |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 102 | // Represents the duration between prefetch is added and its URLRequest is |
| 103 | // started (`URLResponseHead.LoadTimingInfo.request_start`). |
| 104 | constexpr int kAddedToURLRequestStartLatency = 123; |
| 105 | // Represents the duration between the URLRequest is started |
| 106 | // (`URLResponseHead.LoadTimingInfo.request_start`) and the header is received |
| 107 | // (`URLResponseHead.LoadTimingInfo.receive_headers_end`). |
| 108 | constexpr int kHeaderLatency = 456; |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 109 | |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 110 | // TODO(taiyo): Convert const to constexper. |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 111 | const char kHTMLMimeType[] = "text/html"; |
| 112 | |
| 113 | const char kHTMLBody[] = R"( |
| 114 | <!DOCTYPE HTML> |
| 115 | <html> |
| 116 | <head></head> |
| 117 | <body></body> |
| 118 | </html>)"; |
| 119 | |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 120 | const char kHTMLBodyServerError[] = R"( |
| 121 | <!DOCTYPE HTML> |
| 122 | <html lang="en"> |
| 123 | <head> |
| 124 | <title>500 Internal Server Error</title> |
| 125 | </head> |
| 126 | <body> |
| 127 | </body> |
| 128 | </html> |
| 129 | )"; |
| 130 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 131 | // Param for parametrized tests for rearchitecturing/refactoring of |
| 132 | // `PrefetchService`. |
| 133 | // |
| 134 | // Do not remove and keep it even if there is no param to make it easy to add |
| 135 | // another param in the future. |
| 136 | struct PrefetchServiceRearchParam { |
| 137 | public: |
| 138 | using Arg = int; |
| 139 | |
| 140 | static std::vector<PrefetchServiceRearchParam::Arg> Params(); |
| 141 | static PrefetchServiceRearchParam CreateFromIndex(int index); |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 142 | |
| 143 | bool prefetch_scheduler; |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 144 | bool prefetch_scheduler_progress_sync_best_effort; |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 145 | }; |
| 146 | |
| 147 | // static |
| 148 | std::vector<int> PrefetchServiceRearchParam::Params() { |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 149 | return {0, 1, 2}; |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 150 | } |
| 151 | |
| 152 | // static |
| 153 | PrefetchServiceRearchParam PrefetchServiceRearchParam::CreateFromIndex( |
| 154 | int index) { |
| 155 | std::vector<PrefetchServiceRearchParam> params = { |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 156 | PrefetchServiceRearchParam{ |
| 157 | .prefetch_scheduler = false, |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 158 | .prefetch_scheduler_progress_sync_best_effort = false, |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 159 | }, |
| 160 | PrefetchServiceRearchParam{ |
| 161 | .prefetch_scheduler = true, |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 162 | .prefetch_scheduler_progress_sync_best_effort = false, |
| 163 | }, |
| 164 | PrefetchServiceRearchParam{ |
| 165 | .prefetch_scheduler = true, |
| 166 | .prefetch_scheduler_progress_sync_best_effort = true, |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 167 | }, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 168 | }; |
| 169 | return params[index]; |
| 170 | } |
| 171 | |
| 172 | class WithPrefetchServiceRearchParam { |
| 173 | public: |
| 174 | explicit WithPrefetchServiceRearchParam(int index) |
| 175 | : param_(PrefetchServiceRearchParam::CreateFromIndex(index)) {} |
| 176 | virtual ~WithPrefetchServiceRearchParam() = default; |
| 177 | |
| 178 | void InitRearchFeatures(); |
| 179 | |
| 180 | const PrefetchServiceRearchParam& rearch_param() { return param_; } |
| 181 | |
| 182 | private: |
| 183 | PrefetchServiceRearchParam param_; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 184 | base::test::ScopedFeatureList feature_list_prefetch_scheduler_; |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 185 | }; |
| 186 | |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 187 | void WithPrefetchServiceRearchParam::InitRearchFeatures() { |
| 188 | if (param_.prefetch_scheduler) { |
| 189 | feature_list_prefetch_scheduler_.InitWithFeaturesAndParameters( |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 190 | {{ |
| 191 | features::kPrefetchScheduler, |
| 192 | { |
| 193 | {"kPrefetchSchedulerProgressSyncBestEffort", |
| 194 | param_.prefetch_scheduler_progress_sync_best_effort ? "true" |
| 195 | : "false"}, |
| 196 | }, |
| 197 | }}, |
| 198 | {}); |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 199 | } |
| 200 | } |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 201 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 202 | class ScopedPrefetchServiceContentBrowserClient |
| 203 | : public TestContentBrowserClient { |
| 204 | public: |
| 205 | explicit ScopedPrefetchServiceContentBrowserClient( |
| 206 | std::unique_ptr<MockPrefetchServiceDelegate> |
| 207 | mock_prefetch_service_delegate) |
| 208 | : mock_prefetch_service_delegate_( |
| 209 | std::move(mock_prefetch_service_delegate)) { |
| 210 | old_browser_client_ = SetBrowserClientForTesting(this); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 211 | off_the_record_context_ = std::make_unique<TestBrowserContext>(); |
| 212 | off_the_record_context_->set_is_off_the_record(true); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | ~ScopedPrefetchServiceContentBrowserClient() override { |
| 216 | EXPECT_EQ(this, SetBrowserClientForTesting(old_browser_client_)); |
| 217 | } |
| 218 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 219 | // ContentBrowserClient. |
| 220 | std::unique_ptr<PrefetchServiceDelegate> CreatePrefetchServiceDelegate( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 221 | BrowserContext*) override { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 222 | return std::move(mock_prefetch_service_delegate_); |
| 223 | } |
| 224 | |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 225 | void UseOffTheRecordContextForStoragePartition(bool use) { |
| 226 | use_off_the_record_context_for_storage_paritition_ = use; |
| 227 | } |
| 228 | // `BrowserContext::GetStoragePartitionForUrl` eventually calls this method |
| 229 | // on the browser client to get the config. Overwrite it so the prefetch can |
| 230 | // be rejected due to a non-default storage partition. |
| 231 | StoragePartitionConfig GetStoragePartitionConfigForSite( |
| 232 | BrowserContext* browser_context, |
| 233 | const GURL& site) override { |
| 234 | if (use_off_the_record_context_for_storage_paritition_) { |
| 235 | return StoragePartitionConfig::CreateDefault( |
| 236 | off_the_record_context_.get()); |
| 237 | } |
| 238 | return TestContentBrowserClient::GetStoragePartitionConfigForSite( |
| 239 | browser_context, site); |
| 240 | } |
| 241 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 242 | private: |
| 243 | raw_ptr<ContentBrowserClient> old_browser_client_; |
| 244 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate_; |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 245 | // This browser context is used to generate a different storage partition if |
| 246 | // `use_off_the_record_context_for_storage_paritition_` is set to true. |
| 247 | std::unique_ptr<TestBrowserContext> off_the_record_context_; |
| 248 | bool use_off_the_record_context_for_storage_paritition_{false}; |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 249 | }; |
| 250 | |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 251 | // This is only used to test the proxy lookup. |
| 252 | class TestNetworkContext : public network::TestNetworkContext { |
| 253 | public: |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 254 | explicit TestNetworkContext(std::optional<net::ProxyInfo> proxy_info) |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 255 | : proxy_info_(proxy_info) {} |
| 256 | |
Brianna Goldstein | d22b064 | 2022-10-11 16:30:50 | [diff] [blame] | 257 | void LookUpProxyForURL( |
| 258 | const GURL& url, |
Brianna Goldstein | 581e2af8 | 2022-10-20 13:56:30 | [diff] [blame] | 259 | const net::NetworkAnonymizationKey& network_anonymization_key, |
Brianna Goldstein | d22b064 | 2022-10-11 16:30:50 | [diff] [blame] | 260 | mojo::PendingRemote<network::mojom::ProxyLookupClient> |
| 261 | pending_proxy_lookup_client) override { |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 262 | mojo::Remote<network::mojom::ProxyLookupClient> proxy_lookup_client( |
| 263 | std::move(pending_proxy_lookup_client)); |
| 264 | proxy_lookup_client->OnProxyLookupComplete(net::OK, proxy_info_); |
| 265 | } |
| 266 | |
| 267 | private: |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 268 | std::optional<net::ProxyInfo> proxy_info_; |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 269 | }; |
| 270 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 271 | net::RequestPriority ExpectedPriorityForEagerness( |
| 272 | blink::mojom::SpeculationEagerness eagerness) { |
| 273 | switch (eagerness) { |
| 274 | case blink::mojom::SpeculationEagerness::kConservative: |
| 275 | return net::RequestPriority::MEDIUM; |
| 276 | case blink::mojom::SpeculationEagerness::kModerate: |
| 277 | return net::RequestPriority::LOW; |
| 278 | default: |
| 279 | return net::RequestPriority::IDLE; |
| 280 | } |
| 281 | } |
| 282 | |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 283 | class PrefetchFakeServiceWorkerContext : public FakeServiceWorkerContext { |
| 284 | public: |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 285 | explicit PrefetchFakeServiceWorkerContext( |
| 286 | BrowserTaskEnvironment& task_environment) |
| 287 | : task_environment_(task_environment) {} |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 288 | |
| 289 | PrefetchFakeServiceWorkerContext(const PrefetchFakeServiceWorkerContext&) = |
| 290 | delete; |
| 291 | PrefetchFakeServiceWorkerContext& operator=( |
| 292 | const PrefetchFakeServiceWorkerContext&) = delete; |
| 293 | |
| 294 | ~PrefetchFakeServiceWorkerContext() override = default; |
| 295 | |
| 296 | void CheckHasServiceWorker(const GURL& url, |
| 297 | const blink::StorageKey& key, |
| 298 | CheckHasServiceWorkerCallback callback) override { |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 299 | if (long_service_worker_check_duration_.is_positive()) { |
| 300 | task_environment()->FastForwardBy(long_service_worker_check_duration_); |
| 301 | } |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 302 | if (!MaybeHasRegistrationForStorageKey(key)) { |
| 303 | std::move(callback).Run(ServiceWorkerCapability::NO_SERVICE_WORKER); |
| 304 | return; |
| 305 | } |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 306 | auto service_worker_info = std::ranges::find_if( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 307 | service_worker_scopes_, |
| 308 | [url](const std::pair<GURL, ServiceWorkerCapability>& |
| 309 | service_worker_info) { |
| 310 | return base::StartsWith(url.spec(), service_worker_info.first.spec()); |
| 311 | }); |
| 312 | if (service_worker_info != service_worker_scopes_.end()) { |
| 313 | std::move(callback).Run(service_worker_info->second); |
| 314 | return; |
| 315 | } |
| 316 | std::move(callback).Run(ServiceWorkerCapability::NO_SERVICE_WORKER); |
| 317 | } |
| 318 | |
| 319 | void AddServiceWorkerScope(const GURL& scope, |
| 320 | ServiceWorkerCapability capability) { |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 321 | ASSERT_NE(capability, ServiceWorkerCapability::NO_SERVICE_WORKER); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 322 | service_worker_scopes_[scope] = capability; |
| 323 | } |
| 324 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 325 | void SetServiceWorkerCheckDuration(base::TimeDelta duration) { |
| 326 | long_service_worker_check_duration_ = duration; |
| 327 | } |
| 328 | |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 329 | private: |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 330 | BrowserTaskEnvironment* task_environment() { |
| 331 | return &task_environment_.get(); |
| 332 | } |
| 333 | |
| 334 | base::TimeDelta long_service_worker_check_duration_; |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 335 | std::map<GURL, ServiceWorkerCapability> service_worker_scopes_; |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 336 | const base::raw_ref<BrowserTaskEnvironment> task_environment_; |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 337 | }; |
| 338 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 339 | struct NavigationResult { |
| 340 | std::unique_ptr<testing::NiceMock<MockNavigationHandle>> navigation_handle; |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 341 | base::test::TestFuture<PrefetchServingHandle> serving_handle_future; |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 342 | }; |
| 343 | |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 344 | // A `content::PrefetchRequestStatusListener` that tracks when the callbacks |
| 345 | // have been called. |
| 346 | class ProbePrefetchRequestStatusListener |
| 347 | : public content::PrefetchRequestStatusListener { |
| 348 | public: |
| 349 | ~ProbePrefetchRequestStatusListener() override = default; |
| 350 | |
Wayne Jackson Jr. | 0118d2a | 2025-02-21 10:53:46 | [diff] [blame] | 351 | void OnPrefetchStartFailedGeneric() override { |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 352 | prefetch_start_failed_called_ = true; |
| 353 | } |
| 354 | |
Wayne Jackson Jr. | 0118d2a | 2025-02-21 10:53:46 | [diff] [blame] | 355 | void OnPrefetchStartFailedDuplicate() override { |
| 356 | prefetch_start_failed_duplicate_called_ = true; |
| 357 | } |
| 358 | |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 359 | void OnPrefetchResponseCompleted() override { |
| 360 | prefetch_response_completed_called_ = true; |
| 361 | } |
| 362 | |
| 363 | void OnPrefetchResponseError() override { |
| 364 | prefetch_response_error_called_ = true; |
| 365 | } |
| 366 | |
| 367 | void OnPrefetchResponseServerError(int response_code) override { |
| 368 | prefetch_response_server_error_called_ = true; |
| 369 | server_response_code_ = response_code; |
| 370 | } |
| 371 | |
| 372 | bool GetPrefetchStartFailedCalled() { return prefetch_start_failed_called_; } |
| 373 | |
| 374 | bool GetPrefetchResponseCompletedCalled() { |
| 375 | return prefetch_response_completed_called_; |
| 376 | } |
| 377 | |
| 378 | bool GetPrefetchResponseErrorCalled() { |
| 379 | return prefetch_response_error_called_; |
| 380 | } |
| 381 | |
| 382 | bool GetPrefetchResponseServerErrorCalled() { |
| 383 | return prefetch_response_server_error_called_; |
| 384 | } |
| 385 | |
| 386 | base::WeakPtr<ProbePrefetchRequestStatusListener> GetWeakPtr() { |
| 387 | return weak_factory_.GetWeakPtr(); |
| 388 | } |
| 389 | |
| 390 | private: |
| 391 | bool prefetch_start_failed_called_ = false; |
Wayne Jackson Jr. | 0118d2a | 2025-02-21 10:53:46 | [diff] [blame] | 392 | bool prefetch_start_failed_duplicate_called_ = false; |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 393 | bool prefetch_response_completed_called_ = false; |
| 394 | bool prefetch_response_error_called_ = false; |
| 395 | bool prefetch_response_server_error_called_ = false; |
| 396 | |
| 397 | std::optional<int> server_response_code_; |
| 398 | |
| 399 | base::WeakPtrFactory<ProbePrefetchRequestStatusListener> weak_factory_{this}; |
| 400 | }; |
| 401 | |
| 402 | // A |content::PrefetchRequestStatusListener| that forwards the callback |
| 403 | // resolution to a `ProbePrefetchRequestStatusListener` for testability. |
| 404 | // |
| 405 | // The `ProbePrefetchRequestStatusListener` is needed because the |
| 406 | // `TestablePrefetchRequestStatusListener` is eventually owned by the browser |
| 407 | // context, whereas the `ProbePrefetchRequestStatusListener` is owned by the |
| 408 | // test. |
| 409 | class TestablePrefetchRequestStatusListener |
| 410 | : public content::PrefetchRequestStatusListener { |
| 411 | public: |
| 412 | explicit TestablePrefetchRequestStatusListener( |
| 413 | base::WeakPtr<ProbePrefetchRequestStatusListener> probe_listener) |
| 414 | : probe_listener_(probe_listener) {} |
| 415 | |
| 416 | ~TestablePrefetchRequestStatusListener() override = default; |
| 417 | |
Wayne Jackson Jr. | 0118d2a | 2025-02-21 10:53:46 | [diff] [blame] | 418 | void OnPrefetchStartFailedGeneric() override { |
| 419 | probe_listener_->OnPrefetchStartFailedGeneric(); |
| 420 | } |
| 421 | |
| 422 | void OnPrefetchStartFailedDuplicate() override { |
| 423 | probe_listener_->OnPrefetchStartFailedDuplicate(); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 424 | } |
| 425 | |
| 426 | void OnPrefetchResponseCompleted() override { |
| 427 | probe_listener_->OnPrefetchResponseCompleted(); |
| 428 | } |
| 429 | |
| 430 | void OnPrefetchResponseError() override { |
| 431 | probe_listener_->OnPrefetchResponseError(); |
| 432 | } |
| 433 | |
| 434 | void OnPrefetchResponseServerError(int response_code) override { |
| 435 | probe_listener_->OnPrefetchResponseServerError(response_code); |
| 436 | } |
| 437 | |
| 438 | private: |
| 439 | base::WeakPtr<ProbePrefetchRequestStatusListener> probe_listener_ = nullptr; |
| 440 | }; |
| 441 | |
Hiroshige Hayashizaki | b2a4d78 | 2025-01-15 11:25:15 | [diff] [blame] | 442 | class PrefetchServiceTestBase : public PrefetchingMetricsTestBase { |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 443 | public: |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 444 | const int kServiceWorkerCheckDuration = 1000; |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 445 | PrefetchServiceTestBase() |
Hiroshige Hayashizaki | b2a4d78 | 2025-01-15 11:25:15 | [diff] [blame] | 446 | : test_url_loader_factory_(/*observe_loader_requests=*/true), |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 447 | test_shared_url_loader_factory_( |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 448 | base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 449 | &test_url_loader_factory_)) { |
| 450 | service_worker_context_ = |
| 451 | std::make_unique<PrefetchFakeServiceWorkerContext>(*task_environment()); |
| 452 | } |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 453 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 454 | void SetUp() override { |
Hiroshige Hayashizaki | b2a4d78 | 2025-01-15 11:25:15 | [diff] [blame] | 455 | PrefetchingMetricsTestBase::SetUp(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 456 | |
| 457 | browser_context() |
| 458 | ->GetDefaultStoragePartition() |
| 459 | ->GetNetworkContext() |
| 460 | ->GetCookieManager(cookie_manager_.BindNewPipeAndPassReceiver()); |
| 461 | |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 462 | InitScopedFeatureList(); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 463 | |
| 464 | PrefetchService::SetURLLoaderFactoryForTesting( |
| 465 | test_shared_url_loader_factory_.get()); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 466 | |
| 467 | PrefetchService::SetHostNonUniqueFilterForTesting( |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 468 | [](std::string_view) { return false; }); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 469 | PrefetchService::SetServiceWorkerContextForTesting( |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 470 | service_worker_context_.get()); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 471 | } |
| 472 | |
| 473 | void TearDown() override { |
Max Curran | e044494 | 2022-09-06 23:55:23 | [diff] [blame] | 474 | if (PrefetchDocumentManager::GetForCurrentDocument(main_rfh())) |
| 475 | PrefetchDocumentManager::DeleteForCurrentDocument(main_rfh()); |
| 476 | PrefetchDocumentManager::SetPrefetchServiceForTesting(nullptr); |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 477 | mock_navigation_handle_.reset(); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 478 | PrefetchService::SetURLLoaderFactoryForTesting(nullptr); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 479 | PrefetchService::SetHostNonUniqueFilterForTesting(nullptr); |
| 480 | PrefetchService::SetServiceWorkerContextForTesting(nullptr); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 481 | PrefetchService::SetURLLoaderFactoryForTesting(nullptr); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 482 | test_content_browser_client_.reset(); |
Hiroshige Hayashizaki | a580b33 | 2023-09-06 00:16:54 | [diff] [blame] | 483 | request_handler_keep_alive_.clear(); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 484 | service_worker_context_.reset(); |
Hiroshige Hayashizaki | b2a4d78 | 2025-01-15 11:25:15 | [diff] [blame] | 485 | PrefetchingMetricsTestBase::TearDown(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 486 | } |
| 487 | |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 488 | virtual void InitScopedFeatureList() = 0; |
| 489 | |
| 490 | void InitBaseParams() { |
| 491 | scoped_feature_list_base_params_.InitWithFeaturesAndParameters( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 492 | {{features::kPrefetchUseContentRefactor, |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 493 | {{"ineligible_decoy_request_probability", "0"}, |
| 494 | {"prefetch_container_lifetime_s", "-1"}}}}, |
Steven Wei | 012a48d | 2025-08-07 17:21:20 | [diff] [blame] | 495 | {blink::features::kRemovePurposeHeaderForPrefetch}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 496 | } |
| 497 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 498 | void MakePrefetchService(std::unique_ptr<MockPrefetchServiceDelegate> |
| 499 | mock_prefetch_service_delegate) { |
| 500 | test_content_browser_client_ = |
| 501 | std::make_unique<ScopedPrefetchServiceContentBrowserClient>( |
| 502 | std::move(mock_prefetch_service_delegate)); |
| 503 | |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 504 | std::unique_ptr<PrefetchService> prefetch_service = |
| 505 | std::make_unique<PrefetchService>(browser_context()); |
| 506 | BrowserContextImpl::From(browser_context()) |
| 507 | ->SetPrefetchServiceForTesting(std::move(prefetch_service)); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 508 | PrefetchDocumentManager::SetPrefetchServiceForTesting( |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 509 | BrowserContextImpl::From(browser_context())->GetPrefetchService()); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 510 | } |
| 511 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 512 | // Creates a prefetch request for |url| on the current main frame. |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 513 | void MakePrefetchOnMainFrame( |
| 514 | const GURL& prefetch_url, |
| 515 | const PrefetchType& prefetch_type, |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 516 | const blink::mojom::Referrer& referrer = blink::mojom::Referrer(), |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 517 | network::mojom::NoVarySearchPtr&& no_vary_search_hint = |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 518 | network::mojom::NoVarySearchPtr(), |
| 519 | PreloadingType planned_max_preloading_type = PreloadingType::kPrefetch) { |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 520 | CHECK(prefetch_type.IsRendererInitiated()); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 521 | PrefetchDocumentManager* prefetch_document_manager = |
| 522 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
Takashi Toyoshima | 9e3ca21 | 2023-04-28 05:57:59 | [diff] [blame] | 523 | prefetch_document_manager->PrefetchUrl( |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 524 | prefetch_url, prefetch_type, |
| 525 | GetPredictorForPreloadingTriggerType(prefetch_type.trigger_type()), |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 526 | referrer, SpeculationRulesTags(), no_vary_search_hint, |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 527 | PreloadPipelineInfo::Create(planned_max_preloading_type)); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 528 | } |
| 529 | |
Hiroshige Hayashizaki | 40a2532f | 2025-03-07 21:42:00 | [diff] [blame] | 530 | [[nodiscard]] std::unique_ptr<PrefetchHandle> MakePrefetchFromEmbedder( |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 531 | const GURL& prefetch_url, |
| 532 | const PrefetchType& prefetch_type, |
| 533 | const blink::mojom::Referrer& referrer = blink::mojom::Referrer(), |
| 534 | const std::optional<url::Origin> referring_origin = std::nullopt) { |
| 535 | CHECK(!prefetch_type.IsRendererInitiated()); |
| 536 | |
| 537 | auto prefetch_container = std::make_unique<PrefetchContainer>( |
Taiyo Mizuhashi | 49959d0 | 2025-04-22 16:07:54 | [diff] [blame] | 538 | *web_contents(), prefetch_url, prefetch_type, |
| 539 | test::kPreloadingEmbedderHistgramSuffixForTesting, referrer, |
| 540 | std::move(referring_origin), |
| 541 | /*no_vary_search_hint=*/std::nullopt, |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 542 | /*priority=*/std::nullopt, |
kenoss | a1af66f1 | 2025-03-07 06:10:55 | [diff] [blame] | 543 | PreloadPipelineInfo::Create( |
| 544 | /*planned_max_preloading_type=*/PreloadingType::kPrefetch), |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 545 | /*attempt=*/nullptr); |
Hiroshige Hayashizaki | 40a2532f | 2025-03-07 21:42:00 | [diff] [blame] | 546 | return BrowserContextImpl::From(browser_context()) |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 547 | ->GetPrefetchService() |
Hiroshige Hayashizaki | 40a2532f | 2025-03-07 21:42:00 | [diff] [blame] | 548 | ->AddPrefetchContainerWithHandle(std::move(prefetch_container)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 549 | } |
| 550 | |
Taiyo Mizuhashi | c79b535 | 2025-06-20 16:15:17 | [diff] [blame] | 551 | [[nodiscard]] std::unique_ptr<content::PrefetchHandle> |
| 552 | MakePrefetchFromBrowserContext( |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 553 | const GURL& url, |
| 554 | std::optional<net::HttpNoVarySearchData> no_vary_search_data, |
| 555 | const net::HttpRequestHeaders& additional_headers, |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 556 | std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 557 | base::TimeDelta ttl = base::Seconds(/* 10 minutes */ 60 * 10), |
| 558 | bool should_disable_block_until_head_timeout = false) { |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 559 | return browser_context()->StartBrowserPrefetchRequest( |
Taiyo Mizuhashi | 49959d0 | 2025-04-22 16:07:54 | [diff] [blame] | 560 | url, test::kPreloadingEmbedderHistgramSuffixForTesting, true, |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 561 | no_vary_search_data, PrefetchPriority::kHighest, additional_headers, |
kenoss | 70bfbfe | 2025-06-10 08:04:42 | [diff] [blame] | 562 | std::move(request_status_listener), ttl, |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 563 | /*should_append_variations_header=*/true, |
| 564 | should_disable_block_until_head_timeout); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 565 | } |
| 566 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 567 | int RequestCount() { return test_url_loader_factory_.NumPending(); } |
| 568 | |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 569 | void ClearCompletedRequests() { |
| 570 | std::vector<network::TestURLLoaderFactory::PendingRequest>* requests = |
| 571 | test_url_loader_factory_.pending_requests(); |
| 572 | |
Andrew Rayskiy | dae52e9 | 2024-03-05 17:53:36 | [diff] [blame] | 573 | std::erase_if( |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 574 | *requests, |
| 575 | [](const network::TestURLLoaderFactory::PendingRequest& request) { |
| 576 | return !request.client.is_connected(); |
| 577 | }); |
| 578 | } |
| 579 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 580 | struct VerifyCommonRequestStateOptions { |
| 581 | bool use_prefetch_proxy = false; |
| 582 | net::RequestPriority expected_priority = net::RequestPriority::IDLE; |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 583 | std::optional<std::string> sec_purpose_header_value = std::nullopt; |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 584 | net::HttpRequestHeaders additional_headers; |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 585 | }; |
| 586 | |
| 587 | void VerifyCommonRequestState(const GURL& url) { |
| 588 | VerifyCommonRequestState(url, {}); |
| 589 | } |
| 590 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 591 | void VerifyCommonRequestStateForWebContentsPrefetch( |
Taiyo Mizuhashi | 2bef668 | 2025-03-07 08:58:45 | [diff] [blame] | 592 | const GURL& url, |
| 593 | const VerifyCommonRequestStateOptions& options) { |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 594 | VerifyCommonRequestStateOptions options_override = options; |
| 595 | options_override.expected_priority = |
| 596 | base::FeatureList::IsEnabled( |
| 597 | features::kPrefetchNetworkPriorityForEmbedders) |
| 598 | ? net::RequestPriority::MEDIUM |
| 599 | : net::RequestPriority::IDLE; |
| 600 | VerifyCommonRequestState(url, options_override); |
| 601 | } |
| 602 | |
| 603 | void VerifyCommonRequestStateForBrowserContextPrefetch( |
| 604 | const GURL& url, |
| 605 | const VerifyCommonRequestStateOptions& options) { |
| 606 | VerifyCommonRequestStateOptions options_override = options; |
| 607 | options_override.expected_priority = net::RequestPriority::HIGHEST; |
| 608 | VerifyCommonRequestState(url, options_override); |
Taiyo Mizuhashi | 2bef668 | 2025-03-07 08:58:45 | [diff] [blame] | 609 | } |
| 610 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 611 | void VerifyCommonRequestState( |
| 612 | const GURL& url, |
| 613 | const VerifyCommonRequestStateOptions& options) { |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 614 | SCOPED_TRACE(url.spec()); |
| 615 | EXPECT_EQ(RequestCount(), 1); |
| 616 | |
| 617 | network::TestURLLoaderFactory::PendingRequest* request = |
| 618 | test_url_loader_factory_.GetPendingRequest(0); |
| 619 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 620 | VerifyCommonRequestState(url, options, request); |
| 621 | } |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 622 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 623 | void VerifyCommonRequestStateByUrl(const GURL& url) { |
| 624 | VerifyCommonRequestStateByUrl(url, {}); |
| 625 | } |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 626 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 627 | void VerifyCommonRequestStateByUrl( |
| 628 | const GURL& url, |
| 629 | const VerifyCommonRequestStateOptions& options) { |
| 630 | SCOPED_TRACE(url.spec()); |
| 631 | auto* pending_request = GetPendingRequestByUrl(url); |
| 632 | ASSERT_TRUE(pending_request); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 633 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 634 | VerifyCommonRequestState(url, options, pending_request); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 635 | } |
| 636 | |
Lingqi Chi | 5b01e6a | 2024-08-26 04:53:01 | [diff] [blame] | 637 | // Verify a prefetch attempt is pending (eligible but not started yet, to |
| 638 | // ensure prefetches are sequential); |
| 639 | void VerifyPrefetchAttemptIsPending(const GURL& url) { |
| 640 | PrefetchContainer::Key prefetch_key(MainDocumentToken(), url); |
| 641 | base::WeakPtr<PrefetchContainer> prefetch_container = |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 642 | BrowserContextImpl::From(browser_context()) |
| 643 | ->GetPrefetchService() |
| 644 | ->MatchUrl(prefetch_key); |
Lingqi Chi | 5b01e6a | 2024-08-26 04:53:01 | [diff] [blame] | 645 | ASSERT_TRUE(prefetch_container); |
| 646 | ASSERT_FALSE(prefetch_container->GetResourceRequest()); |
| 647 | ASSERT_EQ(prefetch_container->GetLoadState(), |
| 648 | PrefetchContainer::LoadState::kEligible); |
| 649 | } |
| 650 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 651 | void VerifyIsolationInfo(const net::IsolationInfo& isolation_info) { |
| 652 | EXPECT_FALSE(isolation_info.IsEmpty()); |
| 653 | EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated()); |
| 654 | EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient()); |
| 655 | EXPECT_FALSE(isolation_info.site_for_cookies().IsNull()); |
| 656 | } |
| 657 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 658 | network::mojom::URLResponseHeadPtr CreateURLResponseHeadForPrefetch( |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 659 | net::HttpStatusCode http_status, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 660 | const std::string mime_type, |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 661 | bool use_prefetch_proxy, |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 662 | const std::vector<std::pair<std::string, std::string>>& headers, |
| 663 | const GURL& request_url) { |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 664 | auto head = network::CreateURLResponseHead(http_status); |
| 665 | |
| 666 | head->response_time = base::Time::Now(); |
| 667 | head->request_time = |
| 668 | head->response_time - base::Milliseconds(kTotalTimeDuration); |
| 669 | |
| 670 | head->load_timing.connect_timing.connect_end = |
| 671 | base::TimeTicks::Now() - base::Minutes(2); |
| 672 | head->load_timing.connect_timing.connect_start = |
| 673 | head->load_timing.connect_timing.connect_end - |
| 674 | base::Milliseconds(kConnectTimeDuration); |
| 675 | |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 676 | head->load_timing.receive_headers_end = base::TimeTicks::Now(); |
| 677 | head->load_timing.request_start = head->load_timing.receive_headers_end - |
| 678 | base::Milliseconds(kHeaderLatency); |
| 679 | |
Andrew Williams | 8a9e242 | 2023-11-06 20:32:57 | [diff] [blame] | 680 | head->proxy_chain = |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 681 | use_prefetch_proxy |
Andrew Williams | 8a9e242 | 2023-11-06 20:32:57 | [diff] [blame] | 682 | ? net::ProxyChain::FromSchemeHostAndPort( |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 683 | net::ProxyServer::Scheme::SCHEME_HTTPS, |
Jeremy Roman | e561b41 | 2024-02-15 18:31:34 | [diff] [blame] | 684 | PrefetchProxyHost( |
| 685 | GURL(MockPrefetchServiceDelegate::kPrefetchProxyAddress)) |
| 686 | .spec(), |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 687 | std::nullopt) |
Andrew Williams | 8a9e242 | 2023-11-06 20:32:57 | [diff] [blame] | 688 | : net::ProxyChain::Direct(); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 689 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 690 | head->mime_type = mime_type; |
| 691 | for (const auto& header : headers) { |
| 692 | head->headers->AddHeader(header.first, header.second); |
| 693 | } |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 694 | if (!head->parsed_headers) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 695 | head->parsed_headers = |
| 696 | network::PopulateParsedHeaders(head->headers.get(), request_url); |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 697 | } |
| 698 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 699 | return head; |
| 700 | } |
| 701 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 702 | void MakeSingleRedirectAndWait( |
| 703 | const net::RedirectInfo& redirect_info, |
| 704 | network::mojom::URLResponseHeadPtr redirect_head) { |
| 705 | network::TestURLLoaderFactory::PendingRequest* request = |
| 706 | test_url_loader_factory_.GetPendingRequest(0); |
| 707 | ASSERT_TRUE(request); |
| 708 | ASSERT_TRUE(request->client); |
| 709 | |
| 710 | request->client->OnReceiveRedirect(redirect_info, redirect_head.Clone()); |
| 711 | task_environment()->RunUntilIdle(); |
| 712 | } |
| 713 | |
| 714 | void VerifyFollowRedirectParams(size_t expected_follow_redirect_params_size) { |
| 715 | network::TestURLLoaderFactory::PendingRequest* request = |
| 716 | test_url_loader_factory_.GetPendingRequest(0); |
| 717 | ASSERT_TRUE(request); |
| 718 | ASSERT_TRUE(request->test_url_loader); |
| 719 | |
| 720 | const auto& follow_redirect_params = |
| 721 | request->test_url_loader->follow_redirect_params(); |
| 722 | EXPECT_EQ(follow_redirect_params.size(), |
| 723 | expected_follow_redirect_params_size); |
| 724 | |
| 725 | for (const auto& follow_redirect_param : follow_redirect_params) { |
| 726 | EXPECT_EQ(follow_redirect_param.removed_headers.size(), 0U); |
| 727 | EXPECT_TRUE(follow_redirect_param.modified_headers.IsEmpty()); |
| 728 | EXPECT_TRUE(follow_redirect_param.modified_cors_exempt_headers.IsEmpty()); |
| 729 | EXPECT_FALSE(follow_redirect_param.new_url); |
| 730 | } |
| 731 | } |
| 732 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 733 | void MakeResponseAndWait( |
| 734 | net::HttpStatusCode http_status, |
| 735 | net::Error net_error, |
| 736 | const std::string mime_type, |
| 737 | bool use_prefetch_proxy, |
| 738 | std::vector<std::pair<std::string, std::string>> headers, |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 739 | const std::string& body) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 740 | network::TestURLLoaderFactory::PendingRequest* request = |
| 741 | test_url_loader_factory_.GetPendingRequest(0); |
| 742 | ASSERT_TRUE(request); |
| 743 | |
| 744 | auto head = CreateURLResponseHeadForPrefetch(http_status, mime_type, |
| 745 | use_prefetch_proxy, headers, |
| 746 | request->request.url); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 747 | network::URLLoaderCompletionStatus status(net_error); |
| 748 | test_url_loader_factory_.AddResponse(request->request.url, std::move(head), |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 749 | body, status); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 750 | task_environment()->RunUntilIdle(); |
| 751 | // Clear responses in the network service so we can inspect the next request |
| 752 | // that comes in before it is responded to. |
| 753 | test_url_loader_factory_.ClearResponses(); |
| 754 | } |
| 755 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 756 | void SendHeadOfResponseAndWait( |
| 757 | net::HttpStatusCode http_status, |
| 758 | const std::string mime_type, |
| 759 | bool use_prefetch_proxy, |
| 760 | std::vector<std::pair<std::string, std::string>> headers, |
| 761 | uint32_t expected_total_body_size) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 762 | network::TestURLLoaderFactory::PendingRequest* request = |
| 763 | test_url_loader_factory_.GetPendingRequest(0); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 764 | ASSERT_FALSE(producer_handle_for_gurl_.count(request->request.url)); |
| 765 | ASSERT_TRUE(request); |
| 766 | SendHeadOfResponseAndWait(http_status, mime_type, use_prefetch_proxy, |
| 767 | headers, expected_total_body_size, request); |
| 768 | ASSERT_TRUE(producer_handle_for_gurl_.count(request->request.url)); |
| 769 | } |
| 770 | |
| 771 | void SendHeadOfResponseForUrlAndWait( |
| 772 | const GURL& request_url, |
| 773 | net::HttpStatusCode http_status, |
| 774 | const std::string mime_type, |
| 775 | bool use_prefetch_proxy, |
| 776 | std::vector<std::pair<std::string, std::string>> headers, |
| 777 | uint32_t expected_total_body_size) { |
| 778 | auto* request = GetPendingRequestByUrl(request_url); |
| 779 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 780 | ASSERT_TRUE(request); |
| 781 | ASSERT_TRUE(request->client); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 782 | ASSERT_FALSE(producer_handle_for_gurl_.count(request->request.url)); |
| 783 | SendHeadOfResponseAndWait(http_status, mime_type, use_prefetch_proxy, |
| 784 | headers, expected_total_body_size, request); |
| 785 | ASSERT_TRUE(producer_handle_for_gurl_.count(request->request.url)); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 786 | } |
| 787 | |
| 788 | void SendBodyContentOfResponseAndWait(const std::string& body) { |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 789 | network::TestURLLoaderFactory::PendingRequest* request = |
| 790 | test_url_loader_factory_.GetPendingRequest(0); |
| 791 | ASSERT_TRUE(request); |
| 792 | SendBodyContentOfResponseAndWait(body, request); |
| 793 | } |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 794 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 795 | void SendBodyContentOfResponseForUrlAndWait(const GURL& url, |
| 796 | const std::string& body) { |
| 797 | auto* request = GetPendingRequestByUrl(url); |
| 798 | ASSERT_TRUE(request); |
| 799 | SendBodyContentOfResponseAndWait(body, request); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 800 | } |
| 801 | |
| 802 | void CompleteResponseAndWait(net::Error net_error, |
| 803 | uint32_t expected_total_body_size) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 804 | network::TestURLLoaderFactory::PendingRequest* request = |
| 805 | test_url_loader_factory_.GetPendingRequest(0); |
| 806 | ASSERT_TRUE(request); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 807 | CompleteResponseAndWait(net_error, expected_total_body_size, request); |
| 808 | } |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 809 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 810 | void CompleteResponseForUrlAndWait(const GURL& url, |
| 811 | net::Error net_error, |
| 812 | uint32_t expected_total_body_size) { |
| 813 | auto* request = GetPendingRequestByUrl(url); |
| 814 | ASSERT_TRUE(request); |
| 815 | CompleteResponseAndWait(net_error, expected_total_body_size, request); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 816 | } |
| 817 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 818 | bool SetCookie(const GURL& url, const std::string& value) { |
Ari Chivukula | 92851c3 | 2024-04-09 12:37:44 | [diff] [blame] | 819 | std::unique_ptr<net::CanonicalCookie> cookie( |
| 820 | net::CanonicalCookie::CreateForTesting(url, value, base::Time::Now())); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 821 | |
| 822 | EXPECT_TRUE(cookie.get()); |
| 823 | |
| 824 | bool result = false; |
| 825 | base::RunLoop run_loop; |
| 826 | |
| 827 | net::CookieOptions options; |
| 828 | options.set_include_httponly(); |
| 829 | options.set_same_site_cookie_context( |
| 830 | net::CookieOptions::SameSiteCookieContext::MakeInclusive()); |
| 831 | |
| 832 | cookie_manager_->SetCanonicalCookie( |
| 833 | *cookie.get(), url, options, |
| 834 | base::BindOnce( |
| 835 | [](bool* result, base::RunLoop* run_loop, |
| 836 | net::CookieAccessResult set_cookie_access_result) { |
| 837 | *result = set_cookie_access_result.status.IsInclude(); |
| 838 | run_loop->Quit(); |
| 839 | }, |
| 840 | &result, &run_loop)); |
| 841 | run_loop.Run(); |
| 842 | return result; |
| 843 | } |
| 844 | |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 845 | void Navigate( |
| 846 | const GURL& url, |
| 847 | int initiator_process_id, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 848 | const std::optional<blink::LocalFrameToken>& initiator_local_frame_token, |
| 849 | const std::optional<blink::DocumentToken>& initiator_document_token) { |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 850 | mock_navigation_handle_ = |
| 851 | std::make_unique<testing::NiceMock<MockNavigationHandle>>( |
| 852 | web_contents()); |
| 853 | mock_navigation_handle_->set_url(url); |
Hiroshige Hayashizaki | 0de58d3 | 2023-10-23 08:58:43 | [diff] [blame] | 854 | mock_navigation_handle_->set_initiator_process_id(initiator_process_id); |
Hiroshige Hayashizaki | 96f3d6313 | 2023-05-23 23:14:52 | [diff] [blame] | 855 | mock_navigation_handle_->set_initiator_frame_token( |
| 856 | base::OptionalToPtr(initiator_local_frame_token)); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 857 | |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 858 | // Simulate how `NavigationRequest` calls |
| 859 | // `PrefetchServingPageMetricsContainer::GetOrCreateForNavigationHandle()`. |
| 860 | if (initiator_document_token && |
| 861 | PrefetchDocumentManager::FromDocumentToken(initiator_process_id, |
| 862 | *initiator_document_token)) { |
| 863 | PrefetchServingPageMetricsContainer::GetOrCreateForNavigationHandle( |
| 864 | *mock_navigation_handle_); |
| 865 | } |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 866 | } |
| 867 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 868 | void NavigateInitiatedByRenderer(const GURL& url) { |
Emily Andrews | d15fd76 | 2024-12-10 20:41:54 | [diff] [blame] | 869 | Navigate(url, main_rfh()->GetProcess()->GetDeprecatedID(), |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 870 | main_rfh()->GetFrameToken(), MainDocumentToken()); |
Hiroshige Hayashizaki | 0de58d3 | 2023-10-23 08:58:43 | [diff] [blame] | 871 | } |
| 872 | |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 873 | void NavigateInitiatedByBrowser(const GURL& url) { |
| 874 | Navigate(url, ChildProcessHost::kInvalidUniqueID, std::nullopt, |
| 875 | std::nullopt); |
| 876 | } |
| 877 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 878 | std::optional<PrefetchServingPageMetrics> |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 879 | GetMetricsForMostRecentNavigation() { |
| 880 | if (!mock_navigation_handle_) |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 881 | return std::nullopt; |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 882 | |
| 883 | return PrefetchServingPageMetrics::GetForNavigationHandle( |
| 884 | *mock_navigation_handle_); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 885 | } |
| 886 | |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 887 | base::WeakPtr<PrefetchServingPageMetricsContainer> |
| 888 | GetServingPageMetricsContainerForMostRecentNavigation() { |
| 889 | if (!mock_navigation_handle_) { |
| 890 | return nullptr; |
| 891 | } |
| 892 | |
| 893 | auto* serving_page_metrics_container = |
| 894 | PrefetchServingPageMetricsContainer::GetForNavigationHandle( |
| 895 | *mock_navigation_handle_); |
| 896 | if (!serving_page_metrics_container) { |
| 897 | return nullptr; |
| 898 | } |
| 899 | return serving_page_metrics_container->GetWeakPtr(); |
| 900 | } |
| 901 | |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 902 | blink::DocumentToken MainDocumentToken() { |
| 903 | return static_cast<RenderFrameHostImpl*>(main_rfh())->GetDocumentToken(); |
| 904 | } |
| 905 | |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 906 | void GetPrefetchToServe( |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 907 | base::test::TestFuture<PrefetchServingHandle>& future, |
Hiroshige Hayashizaki | 6e9a189 | 2023-04-17 06:47:38 | [diff] [blame] | 908 | const GURL& url, |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 909 | std::optional<blink::DocumentToken> initiator_document_token) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 910 | auto callback = base::BindOnce( |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 911 | [](base::test::TestFuture<PrefetchServingHandle>* future, |
Hiroshige Hayashizaki | c853c030 | 2023-09-13 08:51:07 | [diff] [blame] | 912 | std::vector<PrefetchRequestHandler>* request_handler_keep_alive, |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 913 | PrefetchServingHandle prefetch_to_serve) { |
Hiroshige Hayashizaki | a580b33 | 2023-09-06 00:16:54 | [diff] [blame] | 914 | if (prefetch_to_serve) { |
| 915 | // When GetPrefetchToServe() is successful, also call |
| 916 | // `CreateRequestHandler()` to simulate |
| 917 | // `PrefetchURLLoaderInterceptor::OnGetPrefetchComplete()` behavior, |
| 918 | // which is the primary non-test `GetPrefetchToServe()` code path. |
Hiroshige Hayashizaki | 055871f2 | 2025-03-14 03:27:38 | [diff] [blame] | 919 | auto request_handler = |
| 920 | prefetch_to_serve.CreateRequestHandler().first; |
Hiroshige Hayashizaki | a580b33 | 2023-09-06 00:16:54 | [diff] [blame] | 921 | CHECK(request_handler); |
Hiroshige Hayashizaki | c853c030 | 2023-09-13 08:51:07 | [diff] [blame] | 922 | // Keep-alive the PrefetchRequestHandler, because destructing |
Hiroshige Hayashizaki | a580b33 | 2023-09-06 00:16:54 | [diff] [blame] | 923 | // `request_handler` here can signal that the serving is finished, |
| 924 | // and e.g. close body mojo pipe. |
| 925 | request_handler_keep_alive->push_back(std::move(request_handler)); |
| 926 | } |
| 927 | future->SetValue(std::move(prefetch_to_serve)); |
| 928 | }, |
| 929 | base::Unretained(&future), |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 930 | base::Unretained(&request_handler_keep_alive_)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 931 | PrefetchService* prefetch_service = |
| 932 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 933 | auto key = PrefetchContainer::Key(initiator_document_token, url); |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 934 | PrefetchMatchResolver::FindPrefetch( |
Hiroshige Hayashizaki | b4af4c2d | 2025-03-17 18:59:10 | [diff] [blame] | 935 | std::move(key), PrefetchServiceWorkerState::kDisallowed, |
| 936 | /*is_nav_prerender=*/false, *prefetch_service, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 937 | GetServingPageMetricsContainerForMostRecentNavigation(), |
| 938 | std::move(callback)); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 939 | } |
| 940 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 941 | PrefetchServingHandle GetPrefetchToServe( |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 942 | const GURL& url, |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 943 | std::optional<blink::DocumentToken> initiator_document_token) { |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 944 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 945 | GetPrefetchToServe(future, url, std::move(initiator_document_token)); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 946 | return future.Take(); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 947 | } |
| 948 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 949 | PrefetchServingHandle GetPrefetchToServe(const GURL& url) { |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 950 | return GetPrefetchToServe(url, MainDocumentToken()); |
| 951 | } |
| 952 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 953 | // Simulates part of navigation. |
| 954 | // |
| 955 | // - Creates MockNavigationHandle. |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 956 | // - Starts matching of prefetch `PrefetchMatchResolver::FindPrefetch()`. |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 957 | // |
| 958 | // Note that these are very small part of navigation. For example, |
| 959 | // post-matching process `OnGotPrefetchToServe()` and redirects are not |
| 960 | // handled. |
| 961 | std::unique_ptr<NavigationResult> SimulatePartOfNavigation( |
| 962 | const GURL& url, |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 963 | bool is_renderer_initiated, |
| 964 | bool is_nav_prerender) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 965 | return is_renderer_initiated |
| 966 | ? SimulatePartOfNavigation( |
Emily Andrews | d15fd76 | 2024-12-10 20:41:54 | [diff] [blame] | 967 | url, is_nav_prerender, |
| 968 | main_rfh()->GetProcess()->GetDeprecatedID(), |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 969 | main_rfh()->GetFrameToken(), MainDocumentToken()) |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 970 | : SimulatePartOfNavigation(url, is_nav_prerender, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 971 | ChildProcessHost::kInvalidUniqueID, |
| 972 | std::nullopt, std::nullopt); |
| 973 | } |
| 974 | |
| 975 | std::unique_ptr<NavigationResult> SimulatePartOfNavigation( |
| 976 | const GURL& url, |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 977 | bool is_nav_prerender, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 978 | int initiator_process_id, |
| 979 | const std::optional<blink::LocalFrameToken>& initiator_local_frame_token, |
| 980 | const std::optional<blink::DocumentToken>& initiator_document_token) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 981 | // Use std::unique_ptr as the below uses raw pointers and references. |
| 982 | auto res = std::make_unique<NavigationResult>(); |
| 983 | |
| 984 | res->navigation_handle = |
| 985 | std::make_unique<testing::NiceMock<MockNavigationHandle>>( |
| 986 | web_contents()); |
| 987 | res->navigation_handle->set_url(url); |
| 988 | res->navigation_handle->set_initiator_process_id(initiator_process_id); |
| 989 | res->navigation_handle->set_initiator_frame_token( |
| 990 | base::OptionalToPtr(initiator_local_frame_token)); |
| 991 | |
| 992 | // Simulate how `NavigationRequest` calls |
| 993 | // `PrefetchServingPageMetricsContainer::GetOrCreateForNavigationHandle()`. |
| 994 | if (initiator_document_token && |
| 995 | PrefetchDocumentManager::FromDocumentToken(initiator_process_id, |
| 996 | *initiator_document_token)) { |
| 997 | PrefetchServingPageMetricsContainer::GetOrCreateForNavigationHandle( |
| 998 | *res->navigation_handle); |
| 999 | } |
| 1000 | |
| 1001 | auto callback = base::BindOnce( |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1002 | [](base::test::TestFuture<PrefetchServingHandle>& serving_handle_future, |
| 1003 | PrefetchServingHandle serving_handle) { |
| 1004 | serving_handle_future.SetValue(std::move(serving_handle)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1005 | }, |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1006 | std::ref(res->serving_handle_future)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1007 | auto serving_page_metrics_container = |
| 1008 | [&res]() -> base::WeakPtr<PrefetchServingPageMetricsContainer> { |
| 1009 | auto* serving_page_metrics_container = |
| 1010 | PrefetchServingPageMetricsContainer::GetForNavigationHandle( |
| 1011 | *res->navigation_handle); |
| 1012 | if (!serving_page_metrics_container) { |
| 1013 | return nullptr; |
| 1014 | } |
| 1015 | |
| 1016 | return serving_page_metrics_container->GetWeakPtr(); |
| 1017 | }(); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1018 | PrefetchService* prefetch_service = |
| 1019 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1020 | auto key = PrefetchContainer::Key(initiator_document_token, url); |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 1021 | PrefetchMatchResolver::FindPrefetch( |
Hiroshige Hayashizaki | b4af4c2d | 2025-03-17 18:59:10 | [diff] [blame] | 1022 | std::move(key), PrefetchServiceWorkerState::kDisallowed, |
| 1023 | is_nav_prerender, *prefetch_service, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1024 | std::move(serving_page_metrics_container), std::move(callback)); |
| 1025 | |
| 1026 | return res; |
| 1027 | } |
| 1028 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1029 | ScopedPrefetchServiceContentBrowserClient* test_content_browser_client() { |
| 1030 | return test_content_browser_client_.get(); |
| 1031 | } |
| 1032 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1033 | // ##### Helpers for serving-related metrics ##### |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1034 | static void ExpectServingMetrics( |
| 1035 | const base::Location& location, |
| 1036 | std::optional<PrefetchServingPageMetrics> serving_page_metrics, |
| 1037 | PrefetchStatus expected_prefetch_status, |
| 1038 | std::optional<base::TimeDelta> prefetch_header_latency, |
| 1039 | bool required_private_prefetch_proxy) { |
| 1040 | SCOPED_TRACE(::testing::Message() << "callsite: " << location.ToString()); |
| 1041 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1042 | ASSERT_TRUE(serving_page_metrics); |
| 1043 | ASSERT_TRUE(serving_page_metrics->prefetch_status); |
| 1044 | EXPECT_EQ(serving_page_metrics->prefetch_status.value(), |
| 1045 | static_cast<int>(expected_prefetch_status)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1046 | EXPECT_EQ(serving_page_metrics->prefetch_header_latency, |
| 1047 | prefetch_header_latency); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1048 | EXPECT_EQ(serving_page_metrics->required_private_prefetch_proxy, |
| 1049 | required_private_prefetch_proxy); |
| 1050 | EXPECT_TRUE(serving_page_metrics->same_tab_as_prefetching_tab); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1051 | } |
| 1052 | |
| 1053 | void ExpectServingMetrics(PrefetchStatus expected_prefetch_status, |
| 1054 | bool prefetch_header_latency = false, |
| 1055 | bool required_private_prefetch_proxy = true) { |
| 1056 | // std::optional<base::TimeDelta> prefetch_header_latency_value = |
| 1057 | // prefetch_header_latency ? base::Milliseconds(kHeaderLatency) : |
| 1058 | // std::nullopt; |
| 1059 | std::optional<base::TimeDelta> prefetch_header_latency_value; |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1060 | if (prefetch_header_latency) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1061 | prefetch_header_latency_value = base::Milliseconds(kHeaderLatency); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1062 | } |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1063 | ExpectServingMetrics(FROM_HERE, GetMetricsForMostRecentNavigation(), |
| 1064 | expected_prefetch_status, |
| 1065 | std::move(prefetch_header_latency_value), |
| 1066 | required_private_prefetch_proxy); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1067 | } |
| 1068 | |
| 1069 | void ExpectServingMetricsSuccess( |
| 1070 | bool required_private_prefetch_proxy = true) { |
| 1071 | ExpectServingMetrics(PrefetchStatus::kPrefetchSuccessful, |
| 1072 | /*prefetch_header_latency=*/true, |
| 1073 | required_private_prefetch_proxy); |
| 1074 | } |
| 1075 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1076 | struct ExpectServingMetricsArgs { |
| 1077 | PrefetchStatus prefetch_status; |
| 1078 | std::optional<base::TimeDelta> prefetch_header_latency; |
| 1079 | bool required_private_prefetch_proxy; |
| 1080 | }; |
| 1081 | static void ExpectServingMetrics( |
| 1082 | const base::Location& location, |
| 1083 | const std::unique_ptr<NavigationResult>& nav_res, |
| 1084 | ExpectServingMetricsArgs args) { |
| 1085 | ExpectServingMetrics(location, |
| 1086 | PrefetchServingPageMetrics::GetForNavigationHandle( |
| 1087 | *nav_res->navigation_handle), |
| 1088 | args.prefetch_status, args.prefetch_header_latency, |
| 1089 | args.required_private_prefetch_proxy); |
| 1090 | } |
| 1091 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1092 | static void ExpectServingReaderSuccess( |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1093 | const PrefetchServingHandle& serving_handle) { |
| 1094 | ExpectServingReaderSuccess(FROM_HERE, serving_handle); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1095 | } |
| 1096 | |
| 1097 | static void ExpectServingReaderSuccess( |
| 1098 | const base::Location& location, |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1099 | const PrefetchServingHandle& serving_handle) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1100 | SCOPED_TRACE(::testing::Message() << "callsite: " << location.ToString()); |
| 1101 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1102 | ASSERT_TRUE(serving_handle); |
| 1103 | EXPECT_TRUE(serving_handle.HasPrefetchStatus()); |
| 1104 | EXPECT_EQ(serving_handle.GetPrefetchStatus(), |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1105 | PrefetchStatus::kPrefetchSuccessful); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1106 | EXPECT_EQ(serving_handle.GetServableState(base::TimeDelta::Max()), |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 1107 | PrefetchServableState::kServable); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1108 | ASSERT_TRUE(serving_handle.GetPrefetchContainer()->GetNonRedirectHead()); |
| 1109 | EXPECT_TRUE(serving_handle.GetPrefetchContainer() |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 1110 | ->GetNonRedirectHead() |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1111 | ->was_in_prefetch_cache); |
| 1112 | } |
| 1113 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 1114 | protected: |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1115 | network::TestURLLoaderFactory::PendingRequest* GetPendingRequestByUrl( |
| 1116 | const GURL& url) { |
| 1117 | auto& pending_requests = *test_url_loader_factory_.pending_requests(); |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 1118 | auto it = std::ranges::find(pending_requests, url, |
| 1119 | [](const auto& pending_request) { |
| 1120 | return pending_request.request.url; |
| 1121 | }); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1122 | if (it == pending_requests.end()) { |
| 1123 | return nullptr; |
| 1124 | } |
| 1125 | network::TestURLLoaderFactory::PendingRequest* request = &*it; |
| 1126 | return request; |
| 1127 | } |
| 1128 | |
| 1129 | void VerifyCommonRequestState( |
| 1130 | const GURL& url, |
| 1131 | const VerifyCommonRequestStateOptions& options, |
| 1132 | const network::TestURLLoaderFactory::PendingRequest* request) { |
| 1133 | ASSERT_TRUE(request); |
| 1134 | |
| 1135 | EXPECT_EQ(request->request.url, url); |
| 1136 | EXPECT_EQ(request->request.method, "GET"); |
| 1137 | EXPECT_TRUE(request->request.enable_load_timing); |
Adithya Srinivasan | efc29493 | 2023-12-11 17:48:20 | [diff] [blame] | 1138 | EXPECT_EQ(request->request.load_flags, net::LOAD_PREFETCH); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1139 | EXPECT_EQ(request->request.credentials_mode, |
| 1140 | network::mojom::CredentialsMode::kInclude); |
| 1141 | |
David Risney | a1dd2bf | 2025-03-06 03:40:42 | [diff] [blame] | 1142 | EXPECT_THAT( |
| 1143 | request->request.headers.GetHeader(blink::kPurposeHeaderName), |
| 1144 | testing::Optional(std::string(blink::kSecPurposePrefetchHeaderValue))); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1145 | |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 1146 | std::string sec_purpose_header_value; |
| 1147 | if (options.sec_purpose_header_value) { |
| 1148 | sec_purpose_header_value = options.sec_purpose_header_value.value(); |
| 1149 | } else { |
David Risney | a1dd2bf | 2025-03-06 03:40:42 | [diff] [blame] | 1150 | sec_purpose_header_value = |
| 1151 | options.use_prefetch_proxy |
| 1152 | ? blink::kSecPurposePrefetchAnonymousClientIpHeaderValue |
| 1153 | : blink::kSecPurposePrefetchHeaderValue; |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 1154 | } |
David Risney | a1dd2bf | 2025-03-06 03:40:42 | [diff] [blame] | 1155 | EXPECT_THAT( |
| 1156 | request->request.headers.GetHeader(blink::kSecPurposeHeaderName), |
| 1157 | testing::Optional(sec_purpose_header_value)); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1158 | |
Chris Fredrickson | d923c68 | 2024-07-30 18:19:34 | [diff] [blame] | 1159 | EXPECT_THAT(request->request.headers.GetHeader("Accept"), |
| 1160 | testing::Optional(FrameAcceptHeaderValue( |
| 1161 | /*allow_sxg_responses=*/true, browser_context()))); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1162 | |
Chris Fredrickson | d923c68 | 2024-07-30 18:19:34 | [diff] [blame] | 1163 | EXPECT_THAT(request->request.headers.GetHeader("Upgrade-Insecure-Requests"), |
| 1164 | testing::Optional(std::string("1"))); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1165 | |
| 1166 | ASSERT_TRUE(request->request.trusted_params.has_value()); |
| 1167 | VerifyIsolationInfo(request->request.trusted_params->isolation_info); |
| 1168 | |
| 1169 | EXPECT_EQ(request->request.priority, options.expected_priority); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1170 | |
| 1171 | net::HttpRequestHeaders::Iterator header_it(options.additional_headers); |
| 1172 | while (header_it.GetNext()) { |
| 1173 | EXPECT_THAT(request->request.headers.GetHeader(header_it.name()), |
| 1174 | testing::Optional(header_it.value())); |
| 1175 | } |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1176 | } |
| 1177 | |
| 1178 | void SendHeadOfResponseAndWait( |
| 1179 | net::HttpStatusCode http_status, |
| 1180 | const std::string mime_type, |
| 1181 | bool use_prefetch_proxy, |
| 1182 | std::vector<std::pair<std::string, std::string>> headers, |
| 1183 | uint32_t expected_total_body_size, |
| 1184 | network::TestURLLoaderFactory::PendingRequest* request) { |
| 1185 | ASSERT_FALSE(producer_handle_for_gurl_.count(request->request.url)); |
| 1186 | ASSERT_TRUE(request); |
| 1187 | ASSERT_TRUE(request->client); |
| 1188 | |
| 1189 | auto head = CreateURLResponseHeadForPrefetch(http_status, mime_type, |
| 1190 | use_prefetch_proxy, headers, |
| 1191 | request->request.url); |
| 1192 | |
| 1193 | mojo::ScopedDataPipeConsumerHandle body; |
| 1194 | EXPECT_EQ(mojo::CreateDataPipe( |
| 1195 | expected_total_body_size, |
| 1196 | producer_handle_for_gurl_[request->request.url], body), |
| 1197 | MOJO_RESULT_OK); |
| 1198 | |
| 1199 | request->client->OnReceiveResponse(std::move(head), std::move(body), |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 1200 | std::nullopt); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1201 | task_environment()->RunUntilIdle(); |
| 1202 | } |
| 1203 | |
| 1204 | void SendBodyContentOfResponseAndWait( |
| 1205 | const std::string& body, |
| 1206 | network::TestURLLoaderFactory::PendingRequest* request) { |
| 1207 | ASSERT_TRUE(producer_handle_for_gurl_.count(request->request.url)); |
| 1208 | ASSERT_TRUE(producer_handle_for_gurl_[request->request.url]); |
| 1209 | |
Lukasz Anforowicz | 0339afd | 2024-06-24 19:57:19 | [diff] [blame] | 1210 | EXPECT_EQ(producer_handle_for_gurl_[request->request.url]->WriteAllData( |
| 1211 | base::as_byte_span(body)), |
Lukasz Anforowicz | 2a672e3 | 2024-06-14 17:27:49 | [diff] [blame] | 1212 | MOJO_RESULT_OK); |
| 1213 | // Ok to ignore `actually_written_bytes` because of `...ALL_OR_NONE`. |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1214 | task_environment()->RunUntilIdle(); |
| 1215 | } |
| 1216 | |
| 1217 | void CompleteResponseAndWait( |
| 1218 | net::Error net_error, |
| 1219 | uint32_t expected_total_body_size, |
| 1220 | network::TestURLLoaderFactory::PendingRequest* request) { |
| 1221 | ASSERT_TRUE(request); |
| 1222 | ASSERT_TRUE(request->client); |
| 1223 | if (producer_handle_for_gurl_.count(request->request.url)) { |
| 1224 | producer_handle_for_gurl_[request->request.url].reset(); |
| 1225 | producer_handle_for_gurl_.erase(request->request.url); |
| 1226 | } |
| 1227 | |
| 1228 | network::URLLoaderCompletionStatus completion_status(net_error); |
| 1229 | completion_status.decoded_body_length = expected_total_body_size; |
| 1230 | request->client->OnComplete(completion_status); |
| 1231 | task_environment()->RunUntilIdle(); |
| 1232 | |
| 1233 | test_url_loader_factory_.ClearResponses(); |
| 1234 | } |
| 1235 | |
Anthony Vallée-Dubois | 4b297791 | 2024-11-22 16:28:51 | [diff] [blame] | 1236 | base::ScopedMockElapsedTimersForTest scoped_test_timer_; |
| 1237 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 1238 | std::unique_ptr<PrefetchFakeServiceWorkerContext> service_worker_context_; |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 1239 | mojo::Remote<network::mojom::CookieManager> cookie_manager_; |
| 1240 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 1241 | network::TestURLLoaderFactory test_url_loader_factory_; |
| 1242 | scoped_refptr<network::SharedURLLoaderFactory> |
| 1243 | test_shared_url_loader_factory_; |
| 1244 | |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 1245 | base::test::ScopedFeatureList scoped_feature_list_base_params_; |
Simon Pelchat | b2ce6df | 2023-07-26 21:48:37 | [diff] [blame] | 1246 | // Disable sampling of UKM preloading logs. |
| 1247 | content::test::PreloadingConfigOverride preloading_config_override_; |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1248 | |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 1249 | std::unique_ptr<testing::NiceMock<MockNavigationHandle>> |
| 1250 | mock_navigation_handle_; |
| 1251 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1252 | std::unique_ptr<ScopedPrefetchServiceContentBrowserClient> |
| 1253 | test_content_browser_client_; |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 1254 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 1255 | std::map<GURL, mojo::ScopedDataPipeProducerHandle> producer_handle_for_gurl_; |
William Liu | 60e005f | 2023-01-18 16:17:22 | [diff] [blame] | 1256 | |
Hiroshige Hayashizaki | c853c030 | 2023-09-13 08:51:07 | [diff] [blame] | 1257 | std::vector<PrefetchRequestHandler> request_handler_keep_alive_; |
Liviu Tinta | 2e1ffe2 | 2024-06-21 21:01:33 | [diff] [blame] | 1258 | |
| 1259 | variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{ |
| 1260 | variations::VariationsIdsProvider::Mode::kIgnoreSignedInState}; |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 1261 | }; |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 1262 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1263 | class PrefetchServiceTest |
| 1264 | : public PrefetchServiceTestBase, |
| 1265 | public WithPrefetchServiceRearchParam, |
| 1266 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
| 1267 | public: |
| 1268 | PrefetchServiceTest() : WithPrefetchServiceRearchParam(GetParam()) {} |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 1269 | |
| 1270 | void InitScopedFeatureList() override { |
| 1271 | InitBaseParams(); |
| 1272 | InitRearchFeatures(); |
| 1273 | } |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1274 | }; |
| 1275 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1276 | INSTANTIATE_TEST_SUITE_P( |
| 1277 | ParametrizedTests, |
| 1278 | PrefetchServiceTest, |
| 1279 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 1280 | |
| 1281 | TEST_P(PrefetchServiceTest, SuccessCase) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 1282 | base::HistogramTester histogram_tester; |
| 1283 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1284 | MakePrefetchService( |
| 1285 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 1286 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1287 | const PrefetchType prefetch_type = |
| 1288 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 1289 | /*use_prefetch_proxy=*/true, |
| 1290 | blink::mojom::SpeculationEagerness::kImmediate); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 1291 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 1292 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 1293 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 1294 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 1295 | {.use_prefetch_proxy = true}); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 1296 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 1297 | /*use_prefetch_proxy=*/true, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 1298 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1299 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1300 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 1301 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 1302 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 1303 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1304 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 1305 | ExpectServingMetricsSuccess(); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 1306 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 1307 | histogram_tester.ExpectUniqueSample( |
| 1308 | "PrefetchProxy.AfterClick.RedirectChainSize", 1, 1); |
| 1309 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 1310 | histogram_tester.ExpectUniqueSample( |
| 1311 | base::StringPrintf( |
| 1312 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 1313 | GetMetricsSuffixTriggerTypeAndEagerness( |
| 1314 | prefetch_type, /*embedder_histogram_suffix=*/std::nullopt)), |
| 1315 | false, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 1316 | |
| 1317 | histogram_tester.ExpectUniqueSample( |
| 1318 | base::StrCat( |
| 1319 | {"Prefetch.PrefetchPotentialCandidateServingResult." |
| 1320 | "PerMatchingCandidate.", |
| 1321 | GetMetricsSuffixTriggerTypeAndEagerness( |
| 1322 | prefetch_type, /*embedder_histogram_suffix=*/std::nullopt)}), |
| 1323 | PrefetchPotentialCandidateServingResult::kServed, 1); |
kenoss | 57793e4 | 2024-08-16 20:00:27 | [diff] [blame] | 1324 | } |
| 1325 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1326 | TEST_P(PrefetchServiceTest, SuccessCase_Browser) { |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1327 | base::HistogramTester histogram_tester; |
| 1328 | MakePrefetchService( |
| 1329 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1330 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1331 | |
| 1332 | net::HttpRequestHeaders request_additional_headers = {}; |
| 1333 | request_additional_headers.SetHeader("foo", "bar"); |
| 1334 | request_additional_headers.SetHeader("foo1", "bar1"); |
| 1335 | |
| 1336 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 1337 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 1338 | |
| 1339 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 1340 | request_status_listener = |
| 1341 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 1342 | probe_listener->GetWeakPtr()); |
| 1343 | |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 1344 | std::unique_ptr<content::PrefetchHandle> handle = |
| 1345 | MakePrefetchFromBrowserContext(GURL("https://example.com?b=1"), |
| 1346 | std::nullopt, request_additional_headers, |
| 1347 | std::move(request_status_listener)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1348 | task_environment()->RunUntilIdle(); |
| 1349 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1350 | VerifyCommonRequestStateForBrowserContextPrefetch( |
Taiyo Mizuhashi | 2bef668 | 2025-03-07 08:58:45 | [diff] [blame] | 1351 | GURL("https://example.com?b=1"), |
| 1352 | {.use_prefetch_proxy = false, |
| 1353 | .additional_headers = request_additional_headers}); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1354 | |
| 1355 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1356 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1357 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1358 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1359 | |
| 1360 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 1361 | /*use_prefetch_proxy=*/false, |
| 1362 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1363 | |
| 1364 | histogram_tester.ExpectUniqueSample( |
| 1365 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 1366 | histogram_tester.ExpectUniqueSample( |
| 1367 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 1368 | histogram_tester.ExpectUniqueSample( |
| 1369 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 1370 | histogram_tester.ExpectUniqueSample( |
| 1371 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 1372 | histogram_tester.ExpectUniqueSample( |
| 1373 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 1374 | histogram_tester.ExpectUniqueSample( |
| 1375 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 1376 | |
| 1377 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1378 | EXPECT_TRUE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1379 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1380 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1381 | |
| 1382 | NavigateInitiatedByBrowser(GURL("https://example.com?b=1")); |
| 1383 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1384 | PrefetchServingHandle serving_handle = |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1385 | GetPrefetchToServe(GURL("https://example.com?b=1"), std::nullopt); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1386 | ExpectServingReaderSuccess(serving_handle); |
| 1387 | EXPECT_EQ(serving_handle.GetPrefetchContainer()->GetURL(), |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1388 | GURL("https://example.com/?b=1")); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 1389 | |
| 1390 | histogram_tester.ExpectUniqueSample( |
| 1391 | base::StringPrintf( |
| 1392 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 1393 | GetMetricsSuffixTriggerTypeAndEagerness( |
| 1394 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 1395 | /*use_prefetch_proxy=*/false), |
| 1396 | test::kPreloadingEmbedderHistgramSuffixForTesting)), |
| 1397 | false, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 1398 | |
| 1399 | histogram_tester.ExpectUniqueSample( |
| 1400 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 1401 | "PerMatchingCandidate.", |
| 1402 | GetMetricsSuffixTriggerTypeAndEagerness( |
| 1403 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 1404 | /*use_prefetch_proxy=*/false), |
| 1405 | test::kPreloadingEmbedderHistgramSuffixForTesting)}), |
| 1406 | PrefetchPotentialCandidateServingResult::kServed, 1); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1407 | } |
| 1408 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1409 | TEST_P(PrefetchServiceTest, SuccessCase_Browser_NoVarySearch) { |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1410 | base::HistogramTester histogram_tester; |
| 1411 | MakePrefetchService( |
| 1412 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1413 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1414 | |
| 1415 | net::HttpRequestHeaders request_additional_headers = {}; |
| 1416 | request_additional_headers.SetHeader("foo", "bar"); |
| 1417 | request_additional_headers.SetHeader("foo1", "bar1"); |
| 1418 | |
| 1419 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 1420 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 1421 | |
| 1422 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 1423 | request_status_listener = |
| 1424 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 1425 | probe_listener->GetWeakPtr()); |
| 1426 | |
| 1427 | net::HttpNoVarySearchData nvs_data = |
| 1428 | net::HttpNoVarySearchData::CreateFromNoVaryParams({"a"}, false); |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 1429 | std::unique_ptr<content::PrefetchHandle> handle = |
| 1430 | MakePrefetchFromBrowserContext(GURL("https://example.com?a=1"), nvs_data, |
| 1431 | request_additional_headers, |
| 1432 | std::move(request_status_listener)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1433 | task_environment()->RunUntilIdle(); |
| 1434 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1435 | VerifyCommonRequestStateForBrowserContextPrefetch( |
Taiyo Mizuhashi | 2bef668 | 2025-03-07 08:58:45 | [diff] [blame] | 1436 | GURL("https://example.com?a=1"), |
| 1437 | {.use_prefetch_proxy = false, |
| 1438 | .additional_headers = request_additional_headers}); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1439 | |
| 1440 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1441 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1442 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1443 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1444 | |
| 1445 | MakeResponseAndWait( |
| 1446 | net::HTTP_OK, net::OK, kHTMLMimeType, |
| 1447 | /*use_prefetch_proxy=*/false, |
| 1448 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", R"(params=("a"))"}}, |
| 1449 | kHTMLBody); |
| 1450 | |
| 1451 | histogram_tester.ExpectUniqueSample( |
| 1452 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 1453 | histogram_tester.ExpectUniqueSample( |
| 1454 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 1455 | histogram_tester.ExpectUniqueSample( |
| 1456 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 1457 | histogram_tester.ExpectUniqueSample( |
| 1458 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 1459 | histogram_tester.ExpectUniqueSample( |
| 1460 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 1461 | histogram_tester.ExpectUniqueSample( |
| 1462 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 1463 | |
| 1464 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1465 | EXPECT_TRUE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1466 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1467 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1468 | |
| 1469 | NavigateInitiatedByBrowser(GURL("https://example.com")); |
| 1470 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1471 | PrefetchServingHandle serving_handle = |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1472 | GetPrefetchToServe(GURL("https://example.com"), std::nullopt); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1473 | ExpectServingReaderSuccess(serving_handle); |
| 1474 | EXPECT_EQ(serving_handle.GetPrefetchContainer()->GetURL(), |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1475 | GURL("https://example.com/?a=1")); |
| 1476 | } |
| 1477 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1478 | TEST_P(PrefetchServiceTest, FailureCase_Browser_ServerErrorResponseCode) { |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1479 | base::HistogramTester histogram_tester; |
| 1480 | MakePrefetchService( |
| 1481 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1482 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1483 | |
| 1484 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 1485 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 1486 | |
| 1487 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 1488 | request_status_listener = |
| 1489 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 1490 | probe_listener->GetWeakPtr()); |
| 1491 | |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 1492 | std::unique_ptr<content::PrefetchHandle> handle = |
| 1493 | MakePrefetchFromBrowserContext(GURL("https://example.com?b=1"), |
| 1494 | std::nullopt, {}, |
| 1495 | std::move(request_status_listener)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1496 | task_environment()->RunUntilIdle(); |
| 1497 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1498 | VerifyCommonRequestStateForBrowserContextPrefetch( |
| 1499 | GURL("https://example.com?b=1"), {.use_prefetch_proxy = false}); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1500 | |
| 1501 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1502 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1503 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1504 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1505 | |
| 1506 | MakeResponseAndWait(net::HTTP_INTERNAL_SERVER_ERROR, net::OK, kHTMLMimeType, |
| 1507 | /*use_prefetch_proxy=*/false, {}, kHTMLBodyServerError); |
| 1508 | |
| 1509 | histogram_tester.ExpectUniqueSample( |
| 1510 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 1511 | histogram_tester.ExpectUniqueSample( |
| 1512 | "PrefetchProxy.Prefetch.Mainframe.RespCode", |
| 1513 | net::HTTP_INTERNAL_SERVER_ERROR, 1); |
| 1514 | histogram_tester.ExpectUniqueSample( |
| 1515 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 1516 | histogram_tester.ExpectUniqueSample( |
| 1517 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", |
| 1518 | std::size(kHTMLBodyServerError), 1); |
| 1519 | histogram_tester.ExpectUniqueSample( |
| 1520 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 1521 | histogram_tester.ExpectUniqueSample( |
| 1522 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 1523 | |
| 1524 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1525 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1526 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1527 | EXPECT_TRUE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1528 | |
| 1529 | NavigateInitiatedByBrowser(GURL("https://example.com?b=1")); |
| 1530 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com?b=1"))); |
| 1531 | } |
| 1532 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1533 | TEST_P(PrefetchServiceTest, FailureCase_Browser_NetError) { |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1534 | base::HistogramTester histogram_tester; |
| 1535 | MakePrefetchService( |
| 1536 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1537 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1538 | |
| 1539 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 1540 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 1541 | |
| 1542 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 1543 | request_status_listener = |
| 1544 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 1545 | probe_listener->GetWeakPtr()); |
| 1546 | |
| 1547 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1548 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1549 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1550 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1551 | |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 1552 | std::unique_ptr<content::PrefetchHandle> handle = |
| 1553 | MakePrefetchFromBrowserContext(GURL("https://example.com?c=1"), |
| 1554 | std::nullopt, {}, |
| 1555 | std::move(request_status_listener)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1556 | task_environment()->RunUntilIdle(); |
| 1557 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1558 | VerifyCommonRequestStateForBrowserContextPrefetch( |
| 1559 | GURL("https://example.com?c=1"), {.use_prefetch_proxy = false}); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1560 | MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED, kHTMLMimeType, |
| 1561 | /*use_prefetch_proxy=*/false, |
| 1562 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1563 | |
| 1564 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1565 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1566 | EXPECT_TRUE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1567 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1568 | |
| 1569 | ExpectPrefetchFailedNetError(histogram_tester, net::ERR_FAILED, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1570 | blink::mojom::SpeculationEagerness::kImmediate, |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1571 | /*is_accurate_triggering=*/false, |
| 1572 | /*browser_initiated_prefetch=*/true); |
| 1573 | |
| 1574 | NavigateInitiatedByBrowser(GURL("https://example.com?c=1")); |
| 1575 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com?c=1"))); |
| 1576 | } |
| 1577 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1578 | TEST_P(PrefetchServiceTest, FailureCase_Browser_NotEligibleNonHttps) { |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1579 | base::HistogramTester histogram_tester; |
| 1580 | MakePrefetchService( |
| 1581 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1582 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1583 | |
| 1584 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 1585 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 1586 | |
| 1587 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 1588 | request_status_listener = |
| 1589 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 1590 | probe_listener->GetWeakPtr()); |
| 1591 | |
| 1592 | EXPECT_FALSE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1593 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1594 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1595 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1596 | |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 1597 | std::unique_ptr<content::PrefetchHandle> handle = |
| 1598 | MakePrefetchFromBrowserContext(GURL("http://example.com"), std::nullopt, |
| 1599 | {}, std::move(request_status_listener)); |
Wayne Jackson Jr. | 88f3db6 | 2025-01-07 12:53:34 | [diff] [blame] | 1600 | task_environment()->RunUntilIdle(); |
| 1601 | |
| 1602 | EXPECT_TRUE(probe_listener->GetPrefetchStartFailedCalled()); |
| 1603 | EXPECT_FALSE(probe_listener->GetPrefetchResponseCompletedCalled()); |
| 1604 | EXPECT_FALSE(probe_listener->GetPrefetchResponseErrorCalled()); |
| 1605 | EXPECT_FALSE(probe_listener->GetPrefetchResponseServerErrorCalled()); |
| 1606 | |
| 1607 | EXPECT_EQ(RequestCount(), 0); |
| 1608 | |
| 1609 | histogram_tester.ExpectUniqueSample( |
| 1610 | "Preloading.Prefetch.PrefetchStatus", |
| 1611 | PrefetchStatus::kPrefetchIneligibleSchemeIsNotHttps, 1); |
| 1612 | ExpectPrefetchNotEligible( |
| 1613 | histogram_tester, PreloadingEligibility::kSchemeIsNotHttps, |
| 1614 | /*is_accurate=*/false, /*browser_initiated_prefetch=*/true); |
| 1615 | |
| 1616 | NavigateInitiatedByBrowser(GURL("http://example.com")); |
| 1617 | EXPECT_FALSE(GetPrefetchToServe(GURL("http://example.com"))); |
| 1618 | } |
| 1619 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1620 | TEST_P(PrefetchServiceTest, BrowserContextPrefetchRespectsTTL) { |
elabadysayed | 909e1a3 | 2025-02-13 11:06:07 | [diff] [blame] | 1621 | base::HistogramTester histogram_tester; |
| 1622 | MakePrefetchService( |
| 1623 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1624 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1625 | |
| 1626 | net::HttpRequestHeaders request_additional_headers = {}; |
| 1627 | request_additional_headers.SetHeader("foo", "bar"); |
| 1628 | request_additional_headers.SetHeader("foo1", "bar1"); |
| 1629 | |
| 1630 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 1631 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 1632 | |
| 1633 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 1634 | request_status_listener = |
| 1635 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 1636 | probe_listener->GetWeakPtr()); |
| 1637 | |
elabadysayed | ab1b97c0 | 2025-02-13 11:06:26 | [diff] [blame] | 1638 | std::unique_ptr<content::PrefetchHandle> handle = |
| 1639 | MakePrefetchFromBrowserContext(GURL("https://example.com?b=1"), |
| 1640 | std::nullopt, request_additional_headers, |
| 1641 | std::move(request_status_listener), |
| 1642 | base::Minutes(5)); |
elabadysayed | 909e1a3 | 2025-02-13 11:06:07 | [diff] [blame] | 1643 | task_environment()->RunUntilIdle(); |
| 1644 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1645 | VerifyCommonRequestStateForBrowserContextPrefetch( |
Taiyo Mizuhashi | 2bef668 | 2025-03-07 08:58:45 | [diff] [blame] | 1646 | GURL("https://example.com?b=1"), |
| 1647 | {.use_prefetch_proxy = false, |
| 1648 | .additional_headers = request_additional_headers}); |
elabadysayed | 909e1a3 | 2025-02-13 11:06:07 | [diff] [blame] | 1649 | |
| 1650 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 1651 | /*use_prefetch_proxy=*/false, |
| 1652 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1653 | NavigateInitiatedByBrowser(GURL("https://example.com?b=1")); |
| 1654 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1655 | PrefetchServingHandle serving_handle = |
elabadysayed | 909e1a3 | 2025-02-13 11:06:07 | [diff] [blame] | 1656 | GetPrefetchToServe(GURL("https://example.com?b=1"), std::nullopt); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1657 | EXPECT_EQ(serving_handle.GetPrefetchContainer()->GetURL(), |
elabadysayed | 909e1a3 | 2025-02-13 11:06:07 | [diff] [blame] | 1658 | GURL("https://example.com?b=1")); |
| 1659 | |
| 1660 | task_environment()->FastForwardBy(base::Minutes(5)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 1661 | EXPECT_FALSE(serving_handle); |
elabadysayed | 909e1a3 | 2025-02-13 11:06:07 | [diff] [blame] | 1662 | } |
| 1663 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1664 | TEST_P(PrefetchServiceTest, PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch) { |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1665 | base::HistogramTester histogram_tester; |
| 1666 | |
| 1667 | MakePrefetchService( |
| 1668 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 1669 | |
| 1670 | MakePrefetchOnMainFrame( |
| 1671 | GURL("https://example.com"), |
| 1672 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 1673 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1674 | blink::mojom::SpeculationEagerness::kImmediate)); |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1675 | task_environment()->RunUntilIdle(); |
| 1676 | |
| 1677 | VerifyCommonRequestState(GURL("https://example.com"), |
| 1678 | {.use_prefetch_proxy = true}); |
| 1679 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 1680 | /*use_prefetch_proxy=*/true, |
| 1681 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1682 | |
| 1683 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
| 1684 | |
| 1685 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
| 1686 | |
| 1687 | // No servable PrefetchContainer is returned for different DocumentToken. |
| 1688 | blink::DocumentToken different_document_token; |
| 1689 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"), |
| 1690 | different_document_token)); |
| 1691 | } |
| 1692 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1693 | TEST_P(PrefetchServiceTest, SuccessCase_Embedder) { |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1694 | base::HistogramTester histogram_tester; |
| 1695 | MakePrefetchService( |
| 1696 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1697 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 1698 | const PrefetchType prefetch_type = PrefetchType( |
| 1699 | PreloadingTriggerType::kEmbedder, /*use_prefetch_proxy=*/false); |
Hiroshige Hayashizaki | 40a2532f | 2025-03-07 21:42:00 | [diff] [blame] | 1700 | auto handle = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 1701 | MakePrefetchFromEmbedder(GURL("https://example.com"), prefetch_type); |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1702 | task_environment()->RunUntilIdle(); |
| 1703 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1704 | VerifyCommonRequestStateForWebContentsPrefetch(GURL("https://example.com"), |
| 1705 | {.use_prefetch_proxy = false}); |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1706 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 1707 | /*use_prefetch_proxy=*/false, |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1708 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1709 | |
| 1710 | // Verify that the prefetch request was successful. |
| 1711 | // TODO(crbug.com/40269462): Revise current helper functions (ExpectPrefetch*) |
| 1712 | // for browser-initiated prefetch. |
| 1713 | histogram_tester.ExpectUniqueSample( |
| 1714 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 1715 | histogram_tester.ExpectUniqueSample( |
| 1716 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 1717 | histogram_tester.ExpectUniqueSample( |
| 1718 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 1719 | histogram_tester.ExpectUniqueSample( |
| 1720 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 1721 | histogram_tester.ExpectUniqueSample( |
| 1722 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 1723 | histogram_tester.ExpectUniqueSample( |
| 1724 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 1725 | |
| 1726 | NavigateInitiatedByBrowser(GURL("https://example.com")); |
| 1727 | |
| 1728 | ExpectServingReaderSuccess( |
| 1729 | GetPrefetchToServe(GURL("https://example.com"), std::nullopt)); |
| 1730 | |
| 1731 | histogram_tester.ExpectUniqueSample( |
| 1732 | "PrefetchProxy.AfterClick.RedirectChainSize", 1, 1); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 1733 | histogram_tester.ExpectUniqueSample( |
| 1734 | base::StringPrintf( |
| 1735 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 1736 | GetMetricsSuffixTriggerTypeAndEagerness( |
| 1737 | prefetch_type, |
| 1738 | test::kPreloadingEmbedderHistgramSuffixForTesting)), |
| 1739 | false, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 1740 | |
| 1741 | histogram_tester.ExpectUniqueSample( |
| 1742 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 1743 | "PerMatchingCandidate.", |
| 1744 | GetMetricsSuffixTriggerTypeAndEagerness( |
| 1745 | prefetch_type, |
| 1746 | test::kPreloadingEmbedderHistgramSuffixForTesting)}), |
| 1747 | PrefetchPotentialCandidateServingResult::kServed, 1); |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1748 | } |
| 1749 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1750 | TEST_P(PrefetchServiceTest, |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 1751 | PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch_Embedder) { |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 1752 | base::HistogramTester histogram_tester; |
| 1753 | MakePrefetchService( |
| 1754 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1755 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 1756 | |
Hiroshige Hayashizaki | 40a2532f | 2025-03-07 21:42:00 | [diff] [blame] | 1757 | auto handle = |
| 1758 | MakePrefetchFromEmbedder(GURL("https://example.com"), |
| 1759 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 1760 | /*use_prefetch_proxy=*/false)); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 1761 | task_environment()->RunUntilIdle(); |
| 1762 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 1763 | VerifyCommonRequestStateForWebContentsPrefetch(GURL("https://example.com"), |
| 1764 | {.use_prefetch_proxy = false}); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 1765 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 1766 | /*use_prefetch_proxy=*/false, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 1767 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1768 | |
| 1769 | // Verify that the prefetch request was successful. |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 1770 | // TODO(crbug.com/40269462): Revise current helper functions (ExpectPrefetch*) |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 1771 | // for browser-initiated prefetch. |
| 1772 | histogram_tester.ExpectUniqueSample( |
| 1773 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 1774 | histogram_tester.ExpectUniqueSample( |
| 1775 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 1776 | histogram_tester.ExpectUniqueSample( |
| 1777 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 1778 | histogram_tester.ExpectUniqueSample( |
| 1779 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 1780 | histogram_tester.ExpectUniqueSample( |
| 1781 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 1782 | histogram_tester.ExpectUniqueSample( |
| 1783 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 1784 | |
| 1785 | NavigateInitiatedByBrowser(GURL("https://example.com")); |
| 1786 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1787 | // No servable PrefetchContainer is returned for different DocumentToken. |
| 1788 | EXPECT_FALSE( |
| 1789 | GetPrefetchToServe(GURL("https://example.com"), MainDocumentToken())); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 1790 | } |
| 1791 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1792 | TEST_P(PrefetchServiceTest, NoPrefetchingPreloadingDisabled) { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1793 | base::HistogramTester histogram_tester; |
| 1794 | |
| 1795 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 1796 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1797 | /*num_on_prefetch_likely_calls=*/0); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1798 | |
| 1799 | // When preloading is disabled, then |PrefetchService| doesn't take the |
| 1800 | // prefetch at all. |
| 1801 | EXPECT_CALL(*mock_prefetch_service_delegate, IsSomePreloadingEnabled) |
| 1802 | .Times(1) |
Johann | 41a6083 | 2023-01-25 16:20:33 | [diff] [blame] | 1803 | .WillOnce(testing::Return(PreloadingEligibility::kPreloadingDisabled)); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1804 | |
| 1805 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 1806 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 1807 | MakePrefetchOnMainFrame( |
| 1808 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 1809 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 1810 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1811 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 1812 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1813 | |
| 1814 | EXPECT_EQ(RequestCount(), 0); |
| 1815 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 1816 | histogram_tester.ExpectUniqueSample( |
| 1817 | "Preloading.Prefetch.PrefetchStatus", |
| 1818 | PrefetchStatus::kPrefetchIneligiblePreloadingDisabled, 1); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1819 | ExpectPrefetchNotEligible(histogram_tester, |
| 1820 | PreloadingEligibility::kPreloadingDisabled); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 1821 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 1822 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1823 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 1824 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligiblePreloadingDisabled); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1825 | } |
| 1826 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1827 | TEST_P(PrefetchServiceTest, NoPrefetchingDomainNotInAllowList) { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1828 | base::HistogramTester histogram_tester; |
| 1829 | |
| 1830 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 1831 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 1832 | /*num_on_prefetch_likely_calls=*/0); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1833 | |
| 1834 | // When referring page is not in allow list, then |PrefetchService| doesn't |
| 1835 | // take the prefetch at all. |
| 1836 | EXPECT_CALL(*mock_prefetch_service_delegate, |
| 1837 | IsDomainInPrefetchAllowList(testing::_)) |
| 1838 | .Times(1) |
| 1839 | .WillOnce(testing::Return(false)); |
| 1840 | |
| 1841 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 1842 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 1843 | MakePrefetchOnMainFrame( |
| 1844 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 1845 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 1846 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1847 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 1848 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1849 | |
| 1850 | EXPECT_EQ(RequestCount(), 0); |
| 1851 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1852 | // `IsDomainInPrefetchAllowList` returns false so we did not reach the |
| 1853 | // eligibility check. |
| 1854 | ExpectPrefetchNotEligible(histogram_tester, |
| 1855 | PreloadingEligibility::kUnspecified); |
Hiroshige Hayashizaki | af5be31 | 2023-10-23 09:27:27 | [diff] [blame] | 1856 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 1857 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | af5be31 | 2023-10-23 09:27:27 | [diff] [blame] | 1858 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
| 1859 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 1860 | std::optional<PrefetchServingPageMetrics> serving_page_metrics = |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 1861 | GetMetricsForMostRecentNavigation(); |
| 1862 | ASSERT_TRUE(serving_page_metrics); |
| 1863 | EXPECT_FALSE(serving_page_metrics->prefetch_status); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1864 | } |
| 1865 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1866 | class PrefetchServiceAllowAllDomainsTest |
| 1867 | : public PrefetchServiceTestBase, |
| 1868 | public WithPrefetchServiceRearchParam, |
| 1869 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1870 | public: |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1871 | PrefetchServiceAllowAllDomainsTest() |
| 1872 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 1873 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1874 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 1875 | InitBaseParams(); |
| 1876 | InitRearchFeatures(); |
| 1877 | // Override `kPrefetchUseContentRefactor`. |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 1878 | scoped_feature_list_.InitWithFeaturesAndParameters( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 1879 | {{features::kPrefetchUseContentRefactor, |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 1880 | {{"ineligible_decoy_request_probability", "0"}, |
| 1881 | {"prefetch_container_lifetime_s", "-1"}, |
| 1882 | {"allow_all_domains", "true"}}}}, |
Liviu Tinta | 5043cae5 | 2024-06-26 00:07:29 | [diff] [blame] | 1883 | {}); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1884 | } |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 1885 | |
| 1886 | private: |
| 1887 | base::test::ScopedFeatureList scoped_feature_list_; |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1888 | }; |
| 1889 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1890 | INSTANTIATE_TEST_SUITE_P( |
| 1891 | ParametrizedTests, |
| 1892 | PrefetchServiceAllowAllDomainsTest, |
| 1893 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 1894 | |
| 1895 | TEST_P(PrefetchServiceAllowAllDomainsTest, AllowAllDomains) { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1896 | base::HistogramTester histogram_tester; |
| 1897 | |
| 1898 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 1899 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 1900 | |
| 1901 | // When "allow_all_domains" is set to true, then we can prefetch from all |
| 1902 | // domains, not just those in the allow list. |
| 1903 | EXPECT_CALL(*mock_prefetch_service_delegate, |
| 1904 | IsDomainInPrefetchAllowList(testing::_)) |
| 1905 | .Times(0); |
| 1906 | |
| 1907 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 1908 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 1909 | MakePrefetchOnMainFrame( |
| 1910 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 1911 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 1912 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1913 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 1914 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1915 | |
| 1916 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 1917 | {.use_prefetch_proxy = true}); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1918 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 1919 | /*use_prefetch_proxy=*/true, |
| 1920 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1921 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1922 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 1923 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 1924 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1925 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 1926 | ExpectServingMetricsSuccess(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1927 | } |
| 1928 | |
| 1929 | class PrefetchServiceAllowAllDomainsForExtendedPreloadingTest |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1930 | : public PrefetchServiceTestBase, |
| 1931 | public WithPrefetchServiceRearchParam, |
| 1932 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1933 | public: |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1934 | PrefetchServiceAllowAllDomainsForExtendedPreloadingTest() |
| 1935 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 1936 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1937 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 1938 | InitBaseParams(); |
| 1939 | InitRearchFeatures(); |
| 1940 | // Override `kPrefetchUseContentRefactor`. |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 1941 | scoped_feature_list_.InitWithFeaturesAndParameters( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 1942 | {{features::kPrefetchUseContentRefactor, |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 1943 | {{"ineligible_decoy_request_probability", "0"}, |
| 1944 | {"prefetch_container_lifetime_s", "-1"}, |
| 1945 | {"allow_all_domains_for_extended_preloading", "true"}}}}, |
Liviu Tinta | 5043cae5 | 2024-06-26 00:07:29 | [diff] [blame] | 1946 | {}); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1947 | } |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 1948 | |
| 1949 | private: |
| 1950 | base::test::ScopedFeatureList scoped_feature_list_; |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1951 | }; |
| 1952 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1953 | INSTANTIATE_TEST_SUITE_P( |
| 1954 | ParametrizedTests, |
| 1955 | PrefetchServiceAllowAllDomainsForExtendedPreloadingTest, |
| 1956 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 1957 | |
| 1958 | TEST_P(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest, |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1959 | ExtendedPreloadingEnabled) { |
| 1960 | base::HistogramTester histogram_tester; |
| 1961 | |
| 1962 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 1963 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 1964 | |
| 1965 | // Allow all domains if and only if extended preloading is enabled. |
| 1966 | EXPECT_CALL(*mock_prefetch_service_delegate, IsExtendedPreloadingEnabled) |
| 1967 | .Times(1) |
| 1968 | .WillOnce(testing::Return(true)); |
| 1969 | EXPECT_CALL(*mock_prefetch_service_delegate, |
| 1970 | IsDomainInPrefetchAllowList(testing::_)) |
| 1971 | .Times(0); |
| 1972 | |
| 1973 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 1974 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 1975 | MakePrefetchOnMainFrame( |
| 1976 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 1977 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 1978 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 1979 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 1980 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1981 | |
| 1982 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 1983 | {.use_prefetch_proxy = true}); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1984 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 1985 | /*use_prefetch_proxy=*/true, |
| 1986 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 1987 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1988 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1989 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 1990 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 1991 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 1992 | ExpectServingMetricsSuccess(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1993 | } |
| 1994 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 1995 | TEST_P(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest, |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 1996 | ExtendedPreloadingDisabled) { |
| 1997 | base::HistogramTester histogram_tester; |
| 1998 | |
| 1999 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 2000 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 2001 | /*num_on_prefetch_likely_calls=*/0); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2002 | |
| 2003 | // If extended preloading is disabled, then we check the allow list. |
| 2004 | EXPECT_CALL(*mock_prefetch_service_delegate, IsExtendedPreloadingEnabled) |
| 2005 | .Times(1) |
| 2006 | .WillOnce(testing::Return(false)); |
| 2007 | EXPECT_CALL(*mock_prefetch_service_delegate, |
| 2008 | IsDomainInPrefetchAllowList(testing::_)) |
| 2009 | .Times(1) |
| 2010 | .WillOnce(testing::Return(false)); |
| 2011 | |
| 2012 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 2013 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2014 | MakePrefetchOnMainFrame( |
| 2015 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2016 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2017 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2018 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2019 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2020 | |
| 2021 | EXPECT_EQ(RequestCount(), 0); |
| 2022 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2023 | ExpectPrefetchNotEligible(histogram_tester, |
| 2024 | PreloadingEligibility::kUnspecified); |
Hiroshige Hayashizaki | af5be31 | 2023-10-23 09:27:27 | [diff] [blame] | 2025 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2026 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | af5be31 | 2023-10-23 09:27:27 | [diff] [blame] | 2027 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
| 2028 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 2029 | std::optional<PrefetchServingPageMetrics> serving_page_metrics = |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 2030 | GetMetricsForMostRecentNavigation(); |
| 2031 | ASSERT_TRUE(serving_page_metrics); |
| 2032 | EXPECT_FALSE(serving_page_metrics->prefetch_status); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2033 | } |
| 2034 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2035 | TEST_P(PrefetchServiceTest, NonProxiedPrefetchDoesNotRequireAllowList) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 2036 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 2037 | web_contents(), GURL("https://example.com/referrer")); |
Jeremy Roman | 95c2194d | 2022-11-30 17:20:25 | [diff] [blame] | 2038 | base::HistogramTester histogram_tester; |
| 2039 | |
| 2040 | // Assume we have a delegate which will not grant access to the proxy for this |
| 2041 | // domain. Nonetheless a non-proxied prefetch should work. |
| 2042 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 2043 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 2044 | ON_CALL(*mock_prefetch_service_delegate, IsExtendedPreloadingEnabled) |
| 2045 | .WillByDefault(testing::Return(false)); |
| 2046 | ON_CALL(*mock_prefetch_service_delegate, |
| 2047 | IsDomainInPrefetchAllowList(testing::_)) |
| 2048 | .WillByDefault(testing::Return(false)); |
| 2049 | |
| 2050 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 2051 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2052 | MakePrefetchOnMainFrame( |
| 2053 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2054 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2055 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2056 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2057 | task_environment()->RunUntilIdle(); |
Jeremy Roman | 95c2194d | 2022-11-30 17:20:25 | [diff] [blame] | 2058 | |
| 2059 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2060 | {.use_prefetch_proxy = false}); |
Jeremy Roman | 95c2194d | 2022-11-30 17:20:25 | [diff] [blame] | 2061 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2062 | /*use_prefetch_proxy=*/false, |
| 2063 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2064 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2065 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Jeremy Roman | 95c2194d | 2022-11-30 17:20:25 | [diff] [blame] | 2066 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2067 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2068 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2069 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Jeremy Roman | 95c2194d | 2022-11-30 17:20:25 | [diff] [blame] | 2070 | } |
| 2071 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2072 | TEST_P(PrefetchServiceTest, NotEligibleHostnameNonUnique) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2073 | base::HistogramTester histogram_tester; |
| 2074 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2075 | MakePrefetchService( |
| 2076 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2077 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2078 | PrefetchService::SetHostNonUniqueFilterForTesting( |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 2079 | [](std::string_view) { return true; }); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2080 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2081 | MakePrefetchOnMainFrame( |
| 2082 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2083 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2084 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2085 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2086 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2087 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2088 | EXPECT_EQ(RequestCount(), 0); |
| 2089 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2090 | histogram_tester.ExpectUniqueSample( |
| 2091 | "Preloading.Prefetch.PrefetchStatus", |
| 2092 | PrefetchStatus::kPrefetchIneligibleHostIsNonUnique, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2093 | ExpectPrefetchNotEligible(histogram_tester, |
| 2094 | PreloadingEligibility::kHostIsNonUnique); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2095 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2096 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2097 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2098 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleHostIsNonUnique); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2099 | } |
| 2100 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2101 | TEST_P(PrefetchServiceTest, NotEligibleDataSaverEnabled) { |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 2102 | base::HistogramTester histogram_tester; |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2103 | |
Johann | 41a6083 | 2023-01-25 16:20:33 | [diff] [blame] | 2104 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 2105 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 2106 | /*num_on_prefetch_likely_calls=*/0); |
| 2107 | |
| 2108 | // When data saver is enabled, then |PrefetchService| doesn't start the |
| 2109 | // prefetch at all. |
| 2110 | EXPECT_CALL(*mock_prefetch_service_delegate, IsSomePreloadingEnabled) |
| 2111 | .Times(1) |
| 2112 | .WillOnce(testing::Return(PreloadingEligibility::kDataSaverEnabled)); |
| 2113 | |
| 2114 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 2115 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2116 | MakePrefetchOnMainFrame( |
| 2117 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2118 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2119 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2120 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2121 | task_environment()->RunUntilIdle(); |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 2122 | |
| 2123 | EXPECT_EQ(RequestCount(), 0); |
| 2124 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2125 | histogram_tester.ExpectUniqueSample( |
| 2126 | "Preloading.Prefetch.PrefetchStatus", |
| 2127 | PrefetchStatus::kPrefetchIneligibleDataSaverEnabled, 1); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2128 | ExpectPrefetchNotEligible(histogram_tester, |
| 2129 | PreloadingEligibility::kDataSaverEnabled); |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 2130 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2131 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2132 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2133 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleDataSaverEnabled); |
Jeremy Roman | bae6a42 | 2022-05-17 22:41:17 | [diff] [blame] | 2134 | } |
| 2135 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2136 | TEST_P(PrefetchServiceTest, NotEligibleNonHttps) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2137 | base::HistogramTester histogram_tester; |
| 2138 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2139 | MakePrefetchService( |
| 2140 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2141 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2142 | MakePrefetchOnMainFrame( |
| 2143 | GURL("http://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2144 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2145 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2146 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2147 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2148 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2149 | EXPECT_EQ(RequestCount(), 0); |
| 2150 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2151 | histogram_tester.ExpectUniqueSample( |
| 2152 | "Preloading.Prefetch.PrefetchStatus", |
| 2153 | PrefetchStatus::kPrefetchIneligibleSchemeIsNotHttps, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2154 | ExpectPrefetchNotEligible(histogram_tester, |
| 2155 | PreloadingEligibility::kSchemeIsNotHttps); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2156 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2157 | NavigateInitiatedByRenderer(GURL("http://example.com")); |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 2158 | EXPECT_FALSE(GetPrefetchToServe(GURL("http://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2159 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleSchemeIsNotHttps); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2160 | } |
| 2161 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2162 | TEST_P(PrefetchServiceTest, NotEligiblePrefetchProxyNotAvailable) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2163 | base::HistogramTester histogram_tester; |
| 2164 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2165 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 2166 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 2167 | |
| 2168 | // If the prefetch proxy URL is invalid, then we can't make prefetches that |
| 2169 | // require the proxy. However, non-proxied prefetches are fine. |
| 2170 | EXPECT_CALL(*mock_prefetch_service_delegate, GetDefaultPrefetchProxyHost) |
| 2171 | .Times(1) |
| 2172 | .WillOnce(testing::Return(GURL(""))); |
| 2173 | |
| 2174 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 2175 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2176 | MakePrefetchOnMainFrame( |
| 2177 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2178 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2179 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2180 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2181 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2182 | |
| 2183 | EXPECT_EQ(RequestCount(), 0); |
| 2184 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2185 | histogram_tester.ExpectUniqueSample( |
| 2186 | "Preloading.Prefetch.PrefetchStatus", |
| 2187 | PrefetchStatus::kPrefetchIneligiblePrefetchProxyNotAvailable, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2188 | ExpectPrefetchNotEligible(histogram_tester, |
| 2189 | PreloadingEligibility::kPrefetchProxyNotAvailable); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2190 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2191 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2192 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2193 | ExpectServingMetrics( |
| 2194 | PrefetchStatus::kPrefetchIneligiblePrefetchProxyNotAvailable); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2195 | } |
| 2196 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2197 | TEST_P(PrefetchServiceTest, |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2198 | EligiblePrefetchProxyNotAvailableNonProxiedPrefetch) { |
| 2199 | base::HistogramTester histogram_tester; |
| 2200 | |
| 2201 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 2202 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 2203 | |
| 2204 | // If the prefetch proxy URL is invalid, then we can't make prefetches that |
| 2205 | // require the proxy. However, non-proxied prefetches are fine. |
| 2206 | EXPECT_CALL(*mock_prefetch_service_delegate, GetDefaultPrefetchProxyHost) |
| 2207 | .Times(1) |
| 2208 | .WillOnce(testing::Return(GURL(""))); |
| 2209 | |
| 2210 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 2211 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2212 | MakePrefetchOnMainFrame( |
| 2213 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2214 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2215 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2216 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2217 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2218 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2219 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2220 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2221 | /*use_prefetch_proxy=*/false, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2222 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2223 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2224 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2225 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2226 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2227 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2228 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2229 | } |
| 2230 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2231 | TEST_P(PrefetchServiceTest, NotEligibleOriginWithinRetryAfterWindow) { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2232 | base::HistogramTester histogram_tester; |
| 2233 | |
| 2234 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 2235 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 2236 | |
| 2237 | EXPECT_CALL(*mock_prefetch_service_delegate, |
| 2238 | IsOriginOutsideRetryAfterWindow(GURL("https://example.com"))) |
| 2239 | .Times(1) |
Max Curran | 0215324 | 2022-07-15 17:40:04 | [diff] [blame] | 2240 | .WillOnce(testing::Return(false)); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2241 | |
| 2242 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 2243 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2244 | MakePrefetchOnMainFrame( |
| 2245 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2246 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2247 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2248 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2249 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2250 | |
| 2251 | EXPECT_EQ(RequestCount(), 0); |
| 2252 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2253 | histogram_tester.ExpectUniqueSample( |
| 2254 | "Preloading.Prefetch.PrefetchStatus", |
| 2255 | PrefetchStatus::kPrefetchIneligibleRetryAfter, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2256 | ExpectPrefetchNotEligible(histogram_tester, |
| 2257 | PreloadingEligibility::kRetryAfter); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2258 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2259 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2260 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2261 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleRetryAfter); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2262 | } |
| 2263 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2264 | TEST_P(PrefetchServiceTest, EligibleNonHttpsNonProxiedPotentiallyTrustworthy) { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2265 | base::HistogramTester histogram_tester; |
| 2266 | |
| 2267 | MakePrefetchService( |
| 2268 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2269 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2270 | MakePrefetchOnMainFrame( |
| 2271 | GURL("https://localhost"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2272 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2273 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2274 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2275 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2276 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2277 | VerifyCommonRequestState(GURL("https://localhost")); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2278 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2279 | /*use_prefetch_proxy=*/false, |
| 2280 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2281 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2282 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2283 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2284 | NavigateInitiatedByRenderer(GURL("https://localhost")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2285 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://localhost"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2286 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2287 | } |
| 2288 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2289 | TEST_P(PrefetchServiceTest, NotEligibleServiceWorkerRegistered) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2290 | base::HistogramTester histogram_tester; |
| 2291 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2292 | MakePrefetchService( |
| 2293 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2294 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2295 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
Ari Chivukula | c81e13e | 2023-02-15 20:44:57 | [diff] [blame] | 2296 | blink::StorageKey::CreateFromStringForTesting("https://example.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2297 | service_worker_context_->AddServiceWorkerScope( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2298 | GURL("https://example.com"), |
| 2299 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2300 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2301 | MakePrefetchOnMainFrame( |
| 2302 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2303 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2304 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2305 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2306 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2307 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2308 | EXPECT_EQ(RequestCount(), 0); |
| 2309 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2310 | histogram_tester.ExpectUniqueSample( |
| 2311 | "Preloading.Prefetch.PrefetchStatus", |
| 2312 | PrefetchStatus::kPrefetchIneligibleUserHasServiceWorker, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2313 | ExpectPrefetchNotEligible(histogram_tester, |
| 2314 | PreloadingEligibility::kUserHasServiceWorker); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2315 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2316 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2317 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2318 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasServiceWorker); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2319 | } |
| 2320 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2321 | TEST_P(PrefetchServiceTest, |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2322 | NotEligibleServiceWorkerRegisteredServiceWorkerCheckUKM) { |
| 2323 | // ukm::TestAutoSetUkmRecorder ukm_recorder; |
| 2324 | MakePrefetchService( |
| 2325 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2326 | |
| 2327 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
| 2328 | blink::StorageKey::CreateFromStringForTesting("https://example.com")); |
| 2329 | service_worker_context_->AddServiceWorkerScope( |
| 2330 | GURL("https://example.com"), |
| 2331 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
| 2332 | service_worker_context_->SetServiceWorkerCheckDuration( |
| 2333 | base::Microseconds(kServiceWorkerCheckDuration)); |
| 2334 | |
| 2335 | MakePrefetchOnMainFrame( |
| 2336 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2337 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2338 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2339 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2340 | task_environment()->RunUntilIdle(); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2341 | |
| 2342 | EXPECT_EQ(RequestCount(), 0); |
| 2343 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2344 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2345 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2346 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2347 | |
| 2348 | ForceLogsUploadAndGetUkmId(); |
| 2349 | // Now check the UKM records. |
| 2350 | using UkmEntry = ukm::builders::Preloading_Attempt; |
| 2351 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 2352 | UkmEntry::kEntryName, |
| 2353 | { |
| 2354 | UkmEntry::kPrefetchServiceWorkerRegisteredCheckName, |
| 2355 | UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName, |
| 2356 | }); |
| 2357 | EXPECT_EQ(actual_attempts.size(), 1u); |
| 2358 | ASSERT_TRUE(actual_attempts[0].metrics.count( |
| 2359 | UkmEntry::kPrefetchServiceWorkerRegisteredCheckName)); |
| 2360 | EXPECT_EQ(actual_attempts[0] |
| 2361 | .metrics[UkmEntry::kPrefetchServiceWorkerRegisteredCheckName], |
| 2362 | static_cast<int64_t>( |
| 2363 | PreloadingAttemptImpl::ServiceWorkerRegisteredCheck::kPath)); |
| 2364 | ASSERT_TRUE(actual_attempts[0].metrics.count( |
| 2365 | UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName)); |
| 2366 | EXPECT_EQ( |
| 2367 | actual_attempts[0].metrics |
| 2368 | [UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName], |
| 2369 | ukm::GetExponentialBucketMin( |
| 2370 | kServiceWorkerCheckDuration, |
| 2371 | PreloadingAttemptImpl:: |
| 2372 | kServiceWorkerRegisteredCheckDurationBucketSpacing)); |
| 2373 | } |
| 2374 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2375 | TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegistered) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2376 | base::HistogramTester histogram_tester; |
| 2377 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2378 | MakePrefetchService( |
| 2379 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2380 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2381 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
Ari Chivukula | c81e13e | 2023-02-15 20:44:57 | [diff] [blame] | 2382 | blink::StorageKey::CreateFromStringForTesting("https://other.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2383 | service_worker_context_->AddServiceWorkerScope( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2384 | GURL("https://other.com"), |
| 2385 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2386 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2387 | MakePrefetchOnMainFrame( |
| 2388 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2389 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2390 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2391 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2392 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2393 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2394 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2395 | {.use_prefetch_proxy = true}); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2396 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2397 | /*use_prefetch_proxy=*/true, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2398 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2399 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2400 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2401 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2402 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2403 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2404 | ExpectServingMetricsSuccess(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2405 | } |
| 2406 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2407 | TEST_P(PrefetchServiceTest, |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2408 | EligibleServiceWorkerNotRegisteredServiceWorkerCheckUKM) { |
| 2409 | MakePrefetchService( |
| 2410 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2411 | |
| 2412 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
| 2413 | blink::StorageKey::CreateFromStringForTesting("https://other.com")); |
| 2414 | service_worker_context_->AddServiceWorkerScope( |
| 2415 | GURL("https://other.com"), |
| 2416 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
| 2417 | |
| 2418 | MakePrefetchOnMainFrame( |
| 2419 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2420 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2421 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2422 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2423 | task_environment()->RunUntilIdle(); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2424 | |
| 2425 | VerifyCommonRequestState(GURL("https://example.com"), |
| 2426 | {.use_prefetch_proxy = true}); |
| 2427 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2428 | /*use_prefetch_proxy=*/true, |
| 2429 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2430 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2431 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2432 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2433 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2434 | |
| 2435 | ForceLogsUploadAndGetUkmId(); |
| 2436 | // Now check the UKM records. |
| 2437 | using UkmEntry = ukm::builders::Preloading_Attempt; |
| 2438 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 2439 | UkmEntry::kEntryName, |
| 2440 | { |
| 2441 | UkmEntry::kPrefetchServiceWorkerRegisteredCheckName, |
| 2442 | UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName, |
| 2443 | }); |
| 2444 | EXPECT_EQ(actual_attempts.size(), 1u); |
| 2445 | |
| 2446 | ASSERT_TRUE(actual_attempts[0].metrics.count( |
| 2447 | UkmEntry::kPrefetchServiceWorkerRegisteredCheckName)); |
| 2448 | EXPECT_EQ( |
| 2449 | actual_attempts[0] |
| 2450 | .metrics[UkmEntry::kPrefetchServiceWorkerRegisteredCheckName], |
| 2451 | static_cast<int64_t>( |
| 2452 | PreloadingAttemptImpl::ServiceWorkerRegisteredCheck::kOriginOnly)); |
| 2453 | ASSERT_TRUE(actual_attempts[0].metrics.count( |
| 2454 | UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName)); |
| 2455 | EXPECT_EQ( |
| 2456 | actual_attempts[0].metrics |
| 2457 | [UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName], |
| 2458 | ukm::GetExponentialBucketMin( |
| 2459 | 0, PreloadingAttemptImpl:: |
| 2460 | kServiceWorkerRegisteredCheckDurationBucketSpacing)); |
| 2461 | } |
| 2462 | |
Hiroshige Hayashizaki | e354fb63 | 2025-08-04 21:31:39 | [diff] [blame] | 2463 | TEST_P(PrefetchServiceTest, NotEligibleServiceWorkerNoFetchHandlerRegistered) { |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2464 | base::HistogramTester histogram_tester; |
| 2465 | |
| 2466 | MakePrefetchService( |
| 2467 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2468 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2469 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2470 | blink::StorageKey::CreateFromStringForTesting("https://example.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2471 | service_worker_context_->AddServiceWorkerScope( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2472 | GURL("https://example.com"), |
| 2473 | ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER); |
| 2474 | |
| 2475 | MakePrefetchOnMainFrame( |
| 2476 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2477 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2478 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2479 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2480 | task_environment()->RunUntilIdle(); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2481 | |
Hiroshige Hayashizaki | e354fb63 | 2025-08-04 21:31:39 | [diff] [blame] | 2482 | EXPECT_EQ(RequestCount(), 0); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2483 | |
Hiroshige Hayashizaki | e354fb63 | 2025-08-04 21:31:39 | [diff] [blame] | 2484 | histogram_tester.ExpectUniqueSample( |
| 2485 | "Preloading.Prefetch.PrefetchStatus", |
| 2486 | PrefetchStatus::kPrefetchIneligibleUserHasServiceWorkerNoFetchHandler, 1); |
| 2487 | ExpectPrefetchNotEligible( |
| 2488 | histogram_tester, |
| 2489 | PreloadingEligibility::kUserHasServiceWorkerNoFetchHandler); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2490 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2491 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | e354fb63 | 2025-08-04 21:31:39 | [diff] [blame] | 2492 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
| 2493 | ExpectServingMetrics( |
| 2494 | PrefetchStatus::kPrefetchIneligibleUserHasServiceWorkerNoFetchHandler); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2495 | } |
| 2496 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2497 | TEST_P(PrefetchServiceTest, |
Hiroshige Hayashizaki | e354fb63 | 2025-08-04 21:31:39 | [diff] [blame] | 2498 | NotEligibleServiceWorkerNoFetchHandlerRegisteredServiceWorkerCheckUKM) { |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2499 | ukm::TestAutoSetUkmRecorder ukm_recorder; |
| 2500 | MakePrefetchService( |
| 2501 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2502 | |
| 2503 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
| 2504 | blink::StorageKey::CreateFromStringForTesting("https://example.com")); |
| 2505 | service_worker_context_->AddServiceWorkerScope( |
| 2506 | GURL("https://example.com"), |
| 2507 | ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER); |
| 2508 | service_worker_context_->SetServiceWorkerCheckDuration( |
| 2509 | base::Microseconds(kServiceWorkerCheckDuration)); |
| 2510 | |
| 2511 | MakePrefetchOnMainFrame( |
| 2512 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2513 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2514 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2515 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2516 | task_environment()->RunUntilIdle(); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2517 | |
Hiroshige Hayashizaki | e354fb63 | 2025-08-04 21:31:39 | [diff] [blame] | 2518 | EXPECT_EQ(RequestCount(), 0); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2519 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2520 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2521 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2522 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2523 | |
| 2524 | ForceLogsUploadAndGetUkmId(); |
| 2525 | // Now check the UKM records. |
| 2526 | using UkmEntry = ukm::builders::Preloading_Attempt; |
| 2527 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 2528 | UkmEntry::kEntryName, |
| 2529 | { |
| 2530 | UkmEntry::kPrefetchServiceWorkerRegisteredCheckName, |
| 2531 | UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName, |
| 2532 | }); |
| 2533 | EXPECT_EQ(actual_attempts.size(), 1u); |
| 2534 | |
| 2535 | ASSERT_TRUE(actual_attempts[0].metrics.count( |
| 2536 | UkmEntry::kPrefetchServiceWorkerRegisteredCheckName)); |
| 2537 | EXPECT_EQ(actual_attempts[0] |
| 2538 | .metrics[UkmEntry::kPrefetchServiceWorkerRegisteredCheckName], |
| 2539 | static_cast<int64_t>( |
| 2540 | PreloadingAttemptImpl::ServiceWorkerRegisteredCheck::kPath)); |
| 2541 | ASSERT_TRUE(actual_attempts[0].metrics.count( |
| 2542 | UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName)); |
| 2543 | EXPECT_EQ( |
| 2544 | actual_attempts[0].metrics |
| 2545 | [UkmEntry::kPrefetchServiceWorkerRegisteredForURLCheckDurationName], |
| 2546 | ukm::GetExponentialBucketMin( |
| 2547 | kServiceWorkerCheckDuration, |
| 2548 | PreloadingAttemptImpl:: |
| 2549 | kServiceWorkerRegisteredCheckDurationBucketSpacing)); |
| 2550 | } |
| 2551 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2552 | TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegisteredAtThisPath) { |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2553 | base::HistogramTester histogram_tester; |
| 2554 | |
| 2555 | MakePrefetchService( |
| 2556 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2557 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2558 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2559 | blink::StorageKey::CreateFromStringForTesting("https://example.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 2560 | service_worker_context_->AddServiceWorkerScope( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2561 | GURL("https://example.com/sw"), |
| 2562 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
| 2563 | |
| 2564 | MakePrefetchOnMainFrame( |
| 2565 | GURL("https://example.com/non_sw/index.html"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2566 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2567 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2568 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2569 | task_environment()->RunUntilIdle(); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2570 | |
| 2571 | VerifyCommonRequestState(GURL("https://example.com/non_sw/index.html"), |
| 2572 | {.use_prefetch_proxy = true}); |
| 2573 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2574 | /*use_prefetch_proxy=*/true, |
| 2575 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2576 | |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2577 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
| 2578 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2579 | NavigateInitiatedByRenderer(GURL("https://example.com/non_sw/index.html")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2580 | ExpectServingReaderSuccess( |
| 2581 | GetPrefetchToServe(GURL("https://example.com/non_sw/index.html"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2582 | ExpectServingMetricsSuccess(); |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 2583 | } |
| 2584 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2585 | TEST_P(PrefetchServiceTest, NotEligibleUserHasCookies) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2586 | base::HistogramTester histogram_tester; |
| 2587 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2588 | MakePrefetchService( |
| 2589 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2590 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2591 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 2592 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2593 | MakePrefetchOnMainFrame( |
| 2594 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2595 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2596 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2597 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2598 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2599 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2600 | EXPECT_EQ(RequestCount(), 0); |
| 2601 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2602 | histogram_tester.ExpectUniqueSample( |
| 2603 | "Preloading.Prefetch.PrefetchStatus", |
| 2604 | PrefetchStatus::kPrefetchIneligibleUserHasCookies, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2605 | ExpectPrefetchNotEligible(histogram_tester, |
| 2606 | PreloadingEligibility::kUserHasCookies); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2607 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2608 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2609 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2610 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasCookies); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2611 | } |
| 2612 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2613 | TEST_P(PrefetchServiceTest, EligibleUserHasCookiesForDifferentUrl) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2614 | base::HistogramTester histogram_tester; |
| 2615 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2616 | MakePrefetchService( |
| 2617 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2618 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2619 | ASSERT_TRUE(SetCookie(GURL("https://other.com"), "testing")); |
| 2620 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2621 | MakePrefetchOnMainFrame( |
| 2622 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2623 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2624 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2625 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2626 | task_environment()->RunUntilIdle(); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 2627 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2628 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2629 | {.use_prefetch_proxy = true}); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2630 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2631 | /*use_prefetch_proxy=*/true, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2632 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2633 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2634 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2635 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2636 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2637 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2638 | ExpectServingMetricsSuccess(); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2639 | } |
| 2640 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2641 | TEST_P(PrefetchServiceTest, EligibleSameOriginPrefetchCanHaveExistingCookies) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 2642 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 2643 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2644 | base::HistogramTester histogram_tester; |
| 2645 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2646 | MakePrefetchService( |
| 2647 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2648 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2649 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 2650 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2651 | MakePrefetchOnMainFrame( |
| 2652 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2653 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2654 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2655 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2656 | task_environment()->RunUntilIdle(); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2657 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2658 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2659 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2660 | /*use_prefetch_proxy=*/false, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 2661 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2662 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2663 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2664 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2665 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2666 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2667 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2668 | } |
| 2669 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 2670 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2671 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 2672 | DISABLED_CHROMEOS(FailedCookiesChangedAfterPrefetchStarted)) { |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2673 | base::HistogramTester histogram_tester; |
| 2674 | |
| 2675 | MakePrefetchService( |
| 2676 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2677 | |
| 2678 | MakePrefetchOnMainFrame( |
| 2679 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2680 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2681 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2682 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2683 | task_environment()->RunUntilIdle(); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2684 | |
| 2685 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2686 | {.use_prefetch_proxy = true}); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2687 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2688 | /*use_prefetch_proxy=*/true, |
| 2689 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2690 | |
| 2691 | // Adding a cookie after the prefetch has started will cause it to fail when |
| 2692 | // being served. |
| 2693 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2694 | task_environment()->RunUntilIdle(); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2695 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2696 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2697 | |
| 2698 | histogram_tester.ExpectUniqueSample( |
| 2699 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 2700 | histogram_tester.ExpectUniqueSample( |
| 2701 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 2702 | histogram_tester.ExpectUniqueSample( |
| 2703 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 2704 | histogram_tester.ExpectUniqueSample( |
| 2705 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 2706 | histogram_tester.ExpectUniqueSample( |
| 2707 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 2708 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 2709 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2710 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 2711 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 1); |
| 2712 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 1); |
| 2713 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 1); |
| 2714 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2715 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | c79f2bbc | 2023-05-26 22:08:39 | [diff] [blame] | 2716 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2717 | ExpectServingMetrics(PrefetchStatus::kPrefetchNotUsedCookiesChanged, |
| 2718 | /*prefetch_header_latency=*/true); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2719 | |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2720 | // ReadyTime will be included in the UKM, because the prefetch was ready, and |
| 2721 | // then failed. |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 2722 | ExpectCorrectUkmLogs({.outcome = PreloadingTriggeringOutcome::kFailure, |
| 2723 | .failure = ToPreloadingFailureReason( |
| 2724 | PrefetchStatus::kPrefetchNotUsedCookiesChanged), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 2725 | .is_accurate = true, |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 2726 | .expect_ready_time = true}); |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2727 | histogram_tester.ExpectUniqueSample( |
| 2728 | "Preloading.Prefetch.PrefetchStatus", |
| 2729 | PrefetchStatus::kPrefetchNotUsedCookiesChanged, 1); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 2730 | } |
| 2731 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 2732 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2733 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 2734 | DISABLED_CHROMEOS(SameOriginPrefetchIgnoresProxyRequirement)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 2735 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 2736 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2737 | base::HistogramTester histogram_tester; |
| 2738 | |
| 2739 | MakePrefetchService( |
| 2740 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2741 | |
| 2742 | // Make a same-origin prefetch that requires the proxy. The proxy requirement |
| 2743 | // is only enforced for cross-origin requests. |
| 2744 | MakePrefetchOnMainFrame( |
| 2745 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2746 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2747 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2748 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2749 | task_environment()->RunUntilIdle(); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2750 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2751 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2752 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2753 | /*use_prefetch_proxy=*/false, |
| 2754 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2755 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2756 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2757 | |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2758 | // serving_page_metrics->required_private_prefetch_proxy will be true if the |
| 2759 | // prefetch is marked as requiring the proxy when cross origin, even if only |
| 2760 | // prefetch request was same-origin. |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2761 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2762 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2763 | ExpectServingMetricsSuccess(); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2764 | } |
| 2765 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 2766 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2767 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 2768 | DISABLED_CHROMEOS(NotEligibleSameSiteCrossOriginPrefetchRequiresProxy)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 2769 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 2770 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2771 | base::HistogramTester histogram_tester; |
| 2772 | |
| 2773 | MakePrefetchService( |
| 2774 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2775 | |
| 2776 | // Make a same-site cross-origin prefetch that requires the proxy. These types |
| 2777 | // of prefetches are blocked. |
| 2778 | MakePrefetchOnMainFrame( |
| 2779 | GURL("https://other.example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2780 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2781 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2782 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2783 | task_environment()->RunUntilIdle(); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2784 | |
| 2785 | EXPECT_EQ(RequestCount(), 0); |
| 2786 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2787 | histogram_tester.ExpectUniqueSample( |
| 2788 | "Preloading.Prefetch.PrefetchStatus", |
| 2789 | PrefetchStatus:: |
| 2790 | kPrefetchIneligibleSameSiteCrossOriginPrefetchRequiredProxy, |
| 2791 | 1); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2792 | ExpectPrefetchNotEligible( |
| 2793 | histogram_tester, |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2794 | PreloadingEligibility::kSameSiteCrossOriginPrefetchRequiredProxy); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2795 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2796 | NavigateInitiatedByRenderer(GURL("https://other.example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2797 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://other.example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2798 | ExpectServingMetrics( |
| 2799 | PrefetchStatus:: |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2800 | kPrefetchIneligibleSameSiteCrossOriginPrefetchRequiredProxy); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 2801 | } |
| 2802 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2803 | TEST_P(PrefetchServiceTest, NotEligibleExistingConnectProxy) { |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2804 | base::HistogramTester histogram_tester; |
| 2805 | |
| 2806 | MakePrefetchService( |
| 2807 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2808 | |
| 2809 | net::ProxyInfo proxy_info; |
| 2810 | proxy_info.UseNamedProxy("proxy.com"); |
| 2811 | TestNetworkContext network_context_for_proxy_lookup(proxy_info); |
| 2812 | PrefetchService::SetNetworkContextForProxyLookupForTesting( |
| 2813 | &network_context_for_proxy_lookup); |
| 2814 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2815 | MakePrefetchOnMainFrame( |
| 2816 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2817 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2818 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2819 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2820 | task_environment()->RunUntilIdle(); |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2821 | |
| 2822 | EXPECT_EQ(RequestCount(), 0); |
| 2823 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 2824 | histogram_tester.ExpectUniqueSample( |
| 2825 | "Preloading.Prefetch.PrefetchStatus", |
| 2826 | PrefetchStatus::kPrefetchIneligibleExistingProxy, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 2827 | ExpectPrefetchNotEligible(histogram_tester, |
| 2828 | PreloadingEligibility::kExistingProxy); |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2829 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2830 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2831 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 2832 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleExistingProxy); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 2833 | |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2834 | PrefetchService::SetNetworkContextForProxyLookupForTesting(nullptr); |
| 2835 | } |
| 2836 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2837 | TEST_P(PrefetchServiceTest, EligibleExistingConnectProxyButSameOriginPrefetch) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 2838 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 2839 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2840 | base::HistogramTester histogram_tester; |
| 2841 | |
| 2842 | MakePrefetchService( |
| 2843 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2844 | |
| 2845 | net::ProxyInfo proxy_info; |
| 2846 | proxy_info.UseNamedProxy("proxy.com"); |
| 2847 | TestNetworkContext network_context_for_proxy_lookup(proxy_info); |
| 2848 | PrefetchService::SetNetworkContextForProxyLookupForTesting( |
| 2849 | &network_context_for_proxy_lookup); |
| 2850 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2851 | MakePrefetchOnMainFrame( |
| 2852 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2853 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2854 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2855 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2856 | task_environment()->RunUntilIdle(); |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2857 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2858 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2859 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 2860 | /*use_prefetch_proxy=*/false, |
| 2861 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2862 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2863 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2864 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2865 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2866 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2867 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 2868 | |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 2869 | PrefetchService::SetNetworkContextForProxyLookupForTesting(nullptr); |
| 2870 | } |
| 2871 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2872 | TEST_P(PrefetchServiceTest, FailedNon2XXResponseCode) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2873 | base::HistogramTester histogram_tester; |
| 2874 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2875 | MakePrefetchService( |
| 2876 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2877 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2878 | MakePrefetchOnMainFrame( |
| 2879 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2880 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2881 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2882 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2883 | task_environment()->RunUntilIdle(); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2884 | |
| 2885 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2886 | {.use_prefetch_proxy = true}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2887 | MakeResponseAndWait(net::HTTP_NOT_FOUND, net::OK, kHTMLMimeType, |
| 2888 | /*use_prefetch_proxy=*/true, |
| 2889 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2890 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2891 | ExpectPrefetchFailedAfterResponseReceived( |
| 2892 | histogram_tester, net::HTTP_NOT_FOUND, std::size(kHTMLBody), |
| 2893 | PrefetchStatus::kPrefetchFailedNon2XX); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2894 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2895 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2896 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2897 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNon2XX, |
| 2898 | /*prefetch_header_latency=*/true); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2899 | } |
| 2900 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2901 | TEST_P(PrefetchServiceTest, FailedNetError) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2902 | base::HistogramTester histogram_tester; |
| 2903 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2904 | MakePrefetchService( |
| 2905 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2906 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2907 | MakePrefetchOnMainFrame( |
| 2908 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2909 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2910 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2911 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2912 | task_environment()->RunUntilIdle(); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2913 | |
| 2914 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2915 | {.use_prefetch_proxy = true}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2916 | MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED, kHTMLMimeType, |
| 2917 | /*use_prefetch_proxy=*/true, |
| 2918 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 2919 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2920 | ExpectPrefetchFailedNetError(histogram_tester, net::ERR_FAILED); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2921 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2922 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2923 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2924 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2925 | } |
| 2926 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2927 | TEST_P(PrefetchServiceTest, HandleRetryAfterResponse) { |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2928 | base::HistogramTester histogram_tester; |
| 2929 | |
| 2930 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 2931 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 2932 | |
| 2933 | EXPECT_CALL( |
| 2934 | *mock_prefetch_service_delegate, |
| 2935 | ReportOriginRetryAfter(GURL("https://example.com"), base::Seconds(1234))) |
| 2936 | .Times(1); |
| 2937 | |
| 2938 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 2939 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2940 | MakePrefetchOnMainFrame( |
| 2941 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2942 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2943 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2944 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2945 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2946 | |
| 2947 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2948 | {.use_prefetch_proxy = true}); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2949 | |
| 2950 | // Simulate the origin responding with a "retry-after" header. |
| 2951 | MakeResponseAndWait(net::HTTP_SERVICE_UNAVAILABLE, net::OK, kHTMLMimeType, |
| 2952 | /*use_prefetch_proxy=*/true, |
| 2953 | {{"Retry-After", "1234"}, {"X-Testing", "Hello World"}}, |
| 2954 | ""); |
| 2955 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2956 | ExpectPrefetchFailedAfterResponseReceived( |
| 2957 | histogram_tester, net::HTTP_SERVICE_UNAVAILABLE, 0, |
| 2958 | PrefetchStatus::kPrefetchFailedNon2XX); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2959 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2960 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2961 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2962 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNon2XX, |
| 2963 | /*prefetch_header_latency=*/true); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2964 | } |
| 2965 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2966 | TEST_P(PrefetchServiceTest, SuccessNonHTML) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2967 | base::HistogramTester histogram_tester; |
| 2968 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 2969 | MakePrefetchService( |
| 2970 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 2971 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 2972 | MakePrefetchOnMainFrame( |
| 2973 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 2974 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 2975 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 2976 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 2977 | task_environment()->RunUntilIdle(); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2978 | |
| 2979 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 2980 | {.use_prefetch_proxy = true}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2981 | |
| 2982 | std::string body = "fake PDF"; |
| 2983 | MakeResponseAndWait(net::HTTP_OK, net::OK, "application/pdf", |
| 2984 | /*use_prefetch_proxy=*/true, |
| 2985 | {{"X-Testing", "Hello World"}}, body); |
| 2986 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2987 | ExpectPrefetchSuccess(histogram_tester, body.size()); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 2988 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 2989 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 2990 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 2991 | ExpectServingMetricsSuccess(); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 2992 | } |
| 2993 | |
Adithya Srinivasan | ad5158e | 2024-01-26 15:41:55 | [diff] [blame] | 2994 | // Regression test for crbug.com/1491889. Completes a prefetch, and then changes |
| 2995 | // the cookies for the prefetched URL. It then creates two NavigationRequests |
| 2996 | // (to the same URL) and calls GetPrefetchToServe for each request. This can |
| 2997 | // happen in practice when a user clicks on a link to a URL twice). |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 2998 | TEST_P(PrefetchServiceTest, |
Adithya Srinivasan | ad5158e | 2024-01-26 15:41:55 | [diff] [blame] | 2999 | MultipleNavigationRequestsCallGetPrefetchAfterCookieChange) { |
| 3000 | MakePrefetchService( |
| 3001 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3002 | |
| 3003 | MakePrefetchOnMainFrame( |
| 3004 | GURL("https://example.com"), |
| 3005 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3006 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3007 | blink::mojom::SpeculationEagerness::kImmediate)); |
Adithya Srinivasan | ad5158e | 2024-01-26 15:41:55 | [diff] [blame] | 3008 | task_environment()->RunUntilIdle(); |
| 3009 | |
| 3010 | VerifyCommonRequestState(GURL("https://example.com"), |
| 3011 | {.use_prefetch_proxy = true}); |
| 3012 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3013 | /*use_prefetch_proxy=*/true, |
| 3014 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3015 | |
| 3016 | // Adding a cookie after the prefetch has started will cause it to fail when |
| 3017 | // being served. |
| 3018 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 3019 | task_environment()->RunUntilIdle(); |
| 3020 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3021 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3022 | base::test::TestFuture<PrefetchServingHandle> future_1; |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3023 | GetPrefetchToServe(future_1, GURL("https://example.com"), |
| 3024 | MainDocumentToken()); |
Adithya Srinivasan | ad5158e | 2024-01-26 15:41:55 | [diff] [blame] | 3025 | EXPECT_TRUE(future_1.IsReady()); |
| 3026 | // No prefetch should be returned (the example.com prefetch had its cookies |
| 3027 | // changed). |
| 3028 | EXPECT_FALSE(future_1.Get().GetPrefetchContainer()); |
| 3029 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3030 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3031 | base::test::TestFuture<PrefetchServingHandle> future_2; |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3032 | GetPrefetchToServe(future_2, GURL("https://example.com"), |
| 3033 | MainDocumentToken()); |
Adithya Srinivasan | ad5158e | 2024-01-26 15:41:55 | [diff] [blame] | 3034 | EXPECT_TRUE(future_2.IsReady()); |
| 3035 | EXPECT_FALSE(future_2.Get().GetPrefetchContainer()); |
| 3036 | } |
| 3037 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3038 | TEST_P(PrefetchServiceTest, NotServeableNavigationInDifferentRenderFrameHost) { |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 3039 | base::HistogramTester histogram_tester; |
| 3040 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3041 | MakePrefetchService( |
| 3042 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3043 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3044 | MakePrefetchOnMainFrame( |
| 3045 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3046 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3047 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3048 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3049 | task_environment()->RunUntilIdle(); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 3050 | |
| 3051 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3052 | {.use_prefetch_proxy = true}); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 3053 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3054 | /*use_prefetch_proxy=*/true, |
| 3055 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3056 | |
Hiroshige Hayashizaki | 96f3d6313 | 2023-05-23 23:14:52 | [diff] [blame] | 3057 | // Since the navigation is occurring in a LocalFrameToken other than where the |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 3058 | // prefetch was requested from, we cannot use it. |
Hiroshige Hayashizaki | 96f3d6313 | 2023-05-23 23:14:52 | [diff] [blame] | 3059 | blink::LocalFrameToken other_token(base::UnguessableToken::Create()); |
| 3060 | ASSERT_NE(other_token, main_rfh()->GetFrameToken()); |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 3061 | blink::DocumentToken different_document_token; |
| 3062 | ASSERT_NE(different_document_token, MainDocumentToken()); |
Emily Andrews | d15fd76 | 2024-12-10 20:41:54 | [diff] [blame] | 3063 | Navigate(GURL("https://example.com"), |
| 3064 | main_rfh()->GetProcess()->GetDeprecatedID(), other_token, |
| 3065 | different_document_token); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 3066 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3067 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 3068 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"), |
| 3069 | different_document_token)); |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 3070 | std::optional<PrefetchServingPageMetrics> serving_page_metrics = |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 3071 | GetMetricsForMostRecentNavigation(); |
| 3072 | EXPECT_FALSE(serving_page_metrics); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3073 | } |
| 3074 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3075 | class PrefetchServiceWithHTMLOnlyTest |
| 3076 | : public PrefetchServiceTestBase, |
| 3077 | public WithPrefetchServiceRearchParam, |
| 3078 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3079 | public: |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3080 | PrefetchServiceWithHTMLOnlyTest() |
| 3081 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 3082 | |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3083 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 3084 | InitBaseParams(); |
| 3085 | InitRearchFeatures(); |
| 3086 | // Override `kPrefetchUseContentRefactor`. |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 3087 | scoped_feature_list_.InitWithFeaturesAndParameters( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 3088 | {{features::kPrefetchUseContentRefactor, |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 3089 | {{"ineligible_decoy_request_probability", "0"}, |
| 3090 | {"prefetch_container_lifetime_s", "-1"}, |
| 3091 | {"html_only", "true"}}}}, |
Liviu Tinta | 5043cae5 | 2024-06-26 00:07:29 | [diff] [blame] | 3092 | {}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3093 | } |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 3094 | |
| 3095 | private: |
| 3096 | base::test::ScopedFeatureList scoped_feature_list_; |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3097 | }; |
| 3098 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3099 | INSTANTIATE_TEST_SUITE_P( |
| 3100 | ParametrizedTests, |
| 3101 | PrefetchServiceWithHTMLOnlyTest, |
| 3102 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 3103 | |
| 3104 | TEST_P(PrefetchServiceWithHTMLOnlyTest, FailedNonHTMLWithHTMLOnly) { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3105 | base::HistogramTester histogram_tester; |
| 3106 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3107 | MakePrefetchService( |
| 3108 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3109 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3110 | MakePrefetchOnMainFrame( |
| 3111 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3112 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3113 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3114 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3115 | task_environment()->RunUntilIdle(); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3116 | |
| 3117 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3118 | {.use_prefetch_proxy = true}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3119 | |
| 3120 | std::string body = "fake PDF"; |
| 3121 | MakeResponseAndWait(net::HTTP_OK, net::OK, "application/pdf", |
| 3122 | /*use_prefetch_proxy=*/true, |
| 3123 | {{"X-Testing", "Hello World"}}, body); |
| 3124 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3125 | ExpectPrefetchFailedAfterResponseReceived( |
| 3126 | histogram_tester, net::HTTP_OK, body.size(), |
| 3127 | PrefetchStatus::kPrefetchFailedMIMENotSupported); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3128 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3129 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3130 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3131 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedMIMENotSupported, |
| 3132 | /*prefetch_header_latency=*/true); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3133 | } |
| 3134 | |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 3135 | class PrefetchServiceAlwaysMakeDecoyRequestTest |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3136 | : public PrefetchServiceTestBase, |
| 3137 | public WithPrefetchServiceRearchParam, |
| 3138 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3139 | public: |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3140 | PrefetchServiceAlwaysMakeDecoyRequestTest() |
| 3141 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 3142 | |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3143 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 3144 | InitBaseParams(); |
| 3145 | InitRearchFeatures(); |
| 3146 | // Override `kPrefetchUseContentRefactor`. |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 3147 | scoped_feature_list_.InitWithFeaturesAndParameters( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 3148 | {{features::kPrefetchUseContentRefactor, |
Liviu Tinta | 9145516 | 2022-12-14 22:06:23 | [diff] [blame] | 3149 | {{"ineligible_decoy_request_probability", "1"}, |
Jeremy Roman | 337e495 | 2024-07-04 20:36:49 | [diff] [blame] | 3150 | {"prefetch_container_lifetime_s", "-1"}}}}, |
Liviu Tinta | 5043cae5 | 2024-06-26 00:07:29 | [diff] [blame] | 3151 | {}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3152 | } |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 3153 | |
| 3154 | private: |
| 3155 | base::test::ScopedFeatureList scoped_feature_list_; |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3156 | }; |
| 3157 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3158 | INSTANTIATE_TEST_SUITE_P( |
| 3159 | ParametrizedTests, |
| 3160 | PrefetchServiceAlwaysMakeDecoyRequestTest, |
| 3161 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 3162 | |
| 3163 | TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest, DecoyRequest) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3164 | base::HistogramTester histogram_tester; |
| 3165 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3166 | MakePrefetchService( |
| 3167 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3168 | |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3169 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 3170 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3171 | MakePrefetchOnMainFrame( |
| 3172 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3173 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3174 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3175 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3176 | task_environment()->RunUntilIdle(); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3177 | |
| 3178 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3179 | {.use_prefetch_proxy = true}); |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 3180 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3181 | /*use_prefetch_proxy=*/true, |
| 3182 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3183 | |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3184 | // A decoy is considered a failure. |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3185 | ExpectPrefetchFailedBeforeResponseReceived( |
| 3186 | histogram_tester, PrefetchStatus::kPrefetchIsPrivacyDecoy); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3187 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3188 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3189 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3190 | ExpectServingMetrics(PrefetchStatus::kPrefetchIsPrivacyDecoy, |
| 3191 | /*prefetch_header_latency=*/true); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 3192 | } |
| 3193 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3194 | TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest, |
Adithya Srinivasan | 7c65f14 | 2024-01-29 19:02:03 | [diff] [blame] | 3195 | NavigateBeforeDecoyResponseReceived) { |
| 3196 | base::HistogramTester histogram_tester; |
| 3197 | |
| 3198 | MakePrefetchService( |
| 3199 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3200 | |
| 3201 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 3202 | |
| 3203 | MakePrefetchOnMainFrame( |
| 3204 | GURL("https://example.com"), |
| 3205 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3206 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3207 | blink::mojom::SpeculationEagerness::kImmediate)); |
Adithya Srinivasan | 7c65f14 | 2024-01-29 19:02:03 | [diff] [blame] | 3208 | task_environment()->RunUntilIdle(); |
| 3209 | |
| 3210 | VerifyCommonRequestState(GURL("https://example.com"), |
| 3211 | {.use_prefetch_proxy = true}); |
| 3212 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3213 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Adithya Srinivasan | 7c65f14 | 2024-01-29 19:02:03 | [diff] [blame] | 3214 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
| 3215 | |
| 3216 | ExpectCorrectUkmLogs({.outcome = PreloadingTriggeringOutcome::kUnspecified}); |
| 3217 | } |
| 3218 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3219 | TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest, |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3220 | NoDecoyRequestDisableDecoysBasedOnUserSettings) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3221 | base::HistogramTester histogram_tester; |
| 3222 | |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3223 | std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate = |
| 3224 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(); |
| 3225 | |
| 3226 | EXPECT_CALL(*mock_prefetch_service_delegate, DisableDecoysBasedOnUserSettings) |
| 3227 | .Times(1) |
| 3228 | .WillOnce(testing::Return(true)); |
| 3229 | |
| 3230 | MakePrefetchService(std::move(mock_prefetch_service_delegate)); |
| 3231 | |
| 3232 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 3233 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3234 | MakePrefetchOnMainFrame( |
| 3235 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3236 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3237 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3238 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3239 | task_environment()->RunUntilIdle(); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3240 | |
| 3241 | EXPECT_EQ(RequestCount(), 0); |
| 3242 | |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 3243 | ExpectPrefetchNotEligible(histogram_tester, |
| 3244 | PreloadingEligibility::kUserHasCookies); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3245 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3246 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3247 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 238198d8 | 2023-10-23 23:04:12 | [diff] [blame] | 3248 | ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasCookies); |
Max Curran | ead64a6 | 2022-06-22 01:10:52 | [diff] [blame] | 3249 | } |
| 3250 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3251 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3252 | TEST_P(PrefetchServiceAlwaysMakeDecoyRequestTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3253 | DISABLED_CHROMEOS(RedirectDecoyRequest)) { |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3254 | base::HistogramTester histogram_tester; |
| 3255 | |
| 3256 | MakePrefetchService( |
| 3257 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3258 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 3259 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3260 | blink::StorageKey::CreateFromStringForTesting("https://redirect.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 3261 | service_worker_context_->AddServiceWorkerScope( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 3262 | GURL("https://redirect.com"), |
| 3263 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3264 | |
| 3265 | MakePrefetchOnMainFrame( |
| 3266 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3267 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3268 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3269 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3270 | task_environment()->RunUntilIdle(); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3271 | |
| 3272 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3273 | {.use_prefetch_proxy = true}); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3274 | VerifyFollowRedirectParams(0); |
| 3275 | |
| 3276 | net::RedirectInfo redirect_info; |
| 3277 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3278 | redirect_info.new_referrer_policy = |
| 3279 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3280 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3281 | MakeSingleRedirectAndWait( |
| 3282 | redirect_info, |
| 3283 | CreateURLResponseHeadForPrefetch( |
| 3284 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3285 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
| 3286 | |
| 3287 | // The redirect is ineligible, but will be followed since the prefetch is now |
| 3288 | // a decoy. |
| 3289 | VerifyFollowRedirectParams(1); |
| 3290 | |
| 3291 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3292 | /*use_prefetch_proxy=*/true, |
| 3293 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3294 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3295 | ExpectPrefetchFailedBeforeResponseReceived( |
| 3296 | histogram_tester, PrefetchStatus::kPrefetchIsPrivacyDecoy); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3297 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3298 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3299 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3300 | ExpectServingMetrics(PrefetchStatus::kPrefetchIsPrivacyDecoy, |
| 3301 | /*prefetch_header_latency=*/true); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3302 | } |
| 3303 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3304 | class PrefetchServiceIncognitoTest |
| 3305 | : public PrefetchServiceTestBase, |
| 3306 | public WithPrefetchServiceRearchParam, |
| 3307 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
| 3308 | public: |
| 3309 | PrefetchServiceIncognitoTest() : WithPrefetchServiceRearchParam(GetParam()) {} |
| 3310 | |
| 3311 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 3312 | InitBaseParams(); |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3313 | InitRearchFeatures(); |
| 3314 | } |
| 3315 | |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3316 | protected: |
| 3317 | std::unique_ptr<BrowserContext> CreateBrowserContext() override { |
| 3318 | auto browser_context = std::make_unique<TestBrowserContext>(); |
| 3319 | browser_context->set_is_off_the_record(true); |
| 3320 | return browser_context; |
| 3321 | } |
| 3322 | }; |
| 3323 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3324 | INSTANTIATE_TEST_SUITE_P( |
| 3325 | ParametrizedTests, |
| 3326 | PrefetchServiceIncognitoTest, |
| 3327 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 3328 | |
| 3329 | TEST_P(PrefetchServiceIncognitoTest, OffTheRecordEligible) { |
Jeremy Roman | cc6e4e6 | 2024-05-13 21:29:03 | [diff] [blame] | 3330 | base::HistogramTester histogram_tester; |
| 3331 | |
| 3332 | MakePrefetchService( |
| 3333 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3334 | |
| 3335 | MakePrefetchOnMainFrame( |
| 3336 | GURL("https://example.com/"), |
| 3337 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3338 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3339 | blink::mojom::SpeculationEagerness::kImmediate)); |
Jeremy Roman | cc6e4e6 | 2024-05-13 21:29:03 | [diff] [blame] | 3340 | task_environment()->RunUntilIdle(); |
| 3341 | |
| 3342 | VerifyCommonRequestState(GURL("https://example.com/")); |
| 3343 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3344 | /*use_prefetch_proxy=*/false, {}, kHTMLBody); |
| 3345 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
| 3346 | } |
| 3347 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3348 | TEST_P(PrefetchServiceTest, NonDefaultStoragePartition) { |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3349 | base::HistogramTester histogram_tester; |
| 3350 | |
| 3351 | MakePrefetchService( |
| 3352 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3353 | test_content_browser_client_->UseOffTheRecordContextForStoragePartition(true); |
| 3354 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3355 | MakePrefetchOnMainFrame( |
| 3356 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3357 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Jeremy Roman | cc6e4e6 | 2024-05-13 21:29:03 | [diff] [blame] | 3358 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3359 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3360 | task_environment()->RunUntilIdle(); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3361 | |
| 3362 | EXPECT_EQ(RequestCount(), 0); |
| 3363 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 3364 | histogram_tester.ExpectUniqueSample( |
| 3365 | "Preloading.Prefetch.PrefetchStatus", |
| 3366 | PrefetchStatus::kPrefetchIneligibleNonDefaultStoragePartition, 1); |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 3367 | ExpectPrefetchNotEligible(histogram_tester, |
| 3368 | PreloadingEligibility::kNonDefaultStoragePartition); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3369 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3370 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3371 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3372 | ExpectServingMetrics( |
Jeremy Roman | cc6e4e6 | 2024-05-13 21:29:03 | [diff] [blame] | 3373 | PrefetchStatus::kPrefetchIneligibleNonDefaultStoragePartition, |
| 3374 | /*prefetch_header_latency=*/false, |
| 3375 | /*required_private_prefetch_proxy=*/false); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3376 | } |
| 3377 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3378 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3379 | TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(StreamingURLLoaderSuccessCase)) { |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3380 | base::HistogramTester histogram_tester; |
| 3381 | |
| 3382 | MakePrefetchService( |
| 3383 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3384 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3385 | MakePrefetchOnMainFrame( |
| 3386 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3387 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3388 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3389 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3390 | task_environment()->RunUntilIdle(); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3391 | |
| 3392 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3393 | {.use_prefetch_proxy = true}); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3394 | |
| 3395 | // Send the head of the navigation. The prefetch should be servable after this |
| 3396 | // point. The body of the response will be streaming to the serving URL loader |
| 3397 | // as its received. |
| 3398 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 3399 | /*use_prefetch_proxy=*/true, |
| 3400 | {{"X-Testing", "Hello World"}}, |
| 3401 | std::size(kHTMLBody)); |
| 3402 | |
| 3403 | // Navigate to the URL before the prefetch response is complete. |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3404 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3405 | |
| 3406 | // Check the metrics while the prefetch is still in progress. |
| 3407 | histogram_tester.ExpectUniqueSample( |
| 3408 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 3409 | histogram_tester.ExpectUniqueSample( |
| 3410 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 3411 | histogram_tester.ExpectTotalCount("PrefetchProxy.Prefetch.Mainframe.NetError", |
| 3412 | 0); |
| 3413 | histogram_tester.ExpectTotalCount( |
| 3414 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", 0); |
| 3415 | histogram_tester.ExpectUniqueSample( |
| 3416 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 3417 | histogram_tester.ExpectUniqueSample( |
| 3418 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 3419 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 3420 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3421 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 3422 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 1); |
| 3423 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 1); |
| 3424 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 0); |
| 3425 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3426 | PrefetchServingHandle serving_handle = |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3427 | GetPrefetchToServe(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3428 | ASSERT_TRUE(serving_handle); |
| 3429 | EXPECT_TRUE(serving_handle.HasPrefetchStatus()); |
| 3430 | EXPECT_EQ(serving_handle.GetPrefetchStatus(), |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3431 | PrefetchStatus::kPrefetchNotFinishedInTime); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3432 | EXPECT_EQ(serving_handle.GetServableState(base::TimeDelta::Max()), |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 3433 | PrefetchServableState::kServable); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3434 | EXPECT_TRUE(serving_handle.GetPrefetchContainer()->GetNonRedirectHead()); |
| 3435 | EXPECT_TRUE(serving_handle.GetPrefetchContainer() |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 3436 | ->GetNonRedirectHead() |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 3437 | ->was_in_prefetch_cache); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3438 | |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3439 | ExpectServingMetrics(PrefetchStatus::kPrefetchNotFinishedInTime); |
| 3440 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3441 | // Send the body and completion status of the request, then recheck all of the |
| 3442 | // metrics. |
| 3443 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 3444 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 3445 | |
| 3446 | // Check the metrics now that the prefetch is complete. |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 3447 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3448 | blink::mojom::SpeculationEagerness::kImmediate, |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 3449 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3450 | ExpectServingReaderSuccess(serving_handle); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3451 | ExpectServingMetricsSuccess(); |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 3452 | } |
| 3453 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3454 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3455 | TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(NoVarySearchSuccessCase)) { |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3456 | base::HistogramTester histogram_tester; |
| 3457 | |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 3458 | MakePrefetchService( |
| 3459 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3460 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3461 | MakePrefetchOnMainFrame( |
| 3462 | GURL("https://example.com/?a=1"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3463 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3464 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3465 | blink::mojom::SpeculationEagerness::kImmediate), |
Liviu Tinta | 5043cae5 | 2024-06-26 00:07:29 | [diff] [blame] | 3466 | /*referrer=*/blink::mojom::Referrer()); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3467 | task_environment()->RunUntilIdle(); |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 3468 | |
| 3469 | VerifyCommonRequestState(GURL("https://example.com/?a=1"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3470 | {.use_prefetch_proxy = true}); |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 3471 | MakeResponseAndWait( |
| 3472 | net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3473 | /*use_prefetch_proxy=*/true, |
| 3474 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", R"(params=("a"))"}}, |
| 3475 | kHTMLBody); |
| 3476 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3477 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3478 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3479 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3480 | PrefetchServingHandle serving_handle = |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3481 | GetPrefetchToServe(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3482 | ExpectServingReaderSuccess(serving_handle); |
| 3483 | EXPECT_EQ(serving_handle.GetPrefetchContainer()->GetURL(), |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 3484 | GURL("https://example.com/?a=1")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3485 | ExpectServingMetricsSuccess(); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3486 | } |
| 3487 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3488 | TEST_P(PrefetchServiceTest, NoVarySearchSuccessCase_Embedder) { |
Taiyo Mizuhashi | 9a1ab988 | 2024-11-28 08:29:08 | [diff] [blame] | 3489 | base::HistogramTester histogram_tester; |
| 3490 | |
| 3491 | MakePrefetchService( |
| 3492 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 3493 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 3494 | |
Hiroshige Hayashizaki | 40a2532f | 2025-03-07 21:42:00 | [diff] [blame] | 3495 | auto handle = |
| 3496 | MakePrefetchFromEmbedder(GURL("https://example.com?a=1"), |
| 3497 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 3498 | /*use_prefetch_proxy=*/false)); |
Taiyo Mizuhashi | 9a1ab988 | 2024-11-28 08:29:08 | [diff] [blame] | 3499 | task_environment()->RunUntilIdle(); |
| 3500 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 3501 | VerifyCommonRequestStateForWebContentsPrefetch( |
| 3502 | GURL("https://example.com?a=1"), {.use_prefetch_proxy = false}); |
Taiyo Mizuhashi | 9a1ab988 | 2024-11-28 08:29:08 | [diff] [blame] | 3503 | MakeResponseAndWait( |
| 3504 | net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3505 | /*use_prefetch_proxy=*/false, |
| 3506 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", R"(params=("a"))"}}, |
| 3507 | kHTMLBody); |
| 3508 | |
| 3509 | // TODO(crbug.com/40269462): Revise current helper functions (ExpectPrefetch*) |
| 3510 | // for browser-initiated prefetch. |
| 3511 | histogram_tester.ExpectUniqueSample( |
| 3512 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); |
| 3513 | histogram_tester.ExpectUniqueSample( |
| 3514 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 3515 | histogram_tester.ExpectUniqueSample( |
| 3516 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 3517 | histogram_tester.ExpectUniqueSample( |
| 3518 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 3519 | histogram_tester.ExpectUniqueSample( |
| 3520 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 3521 | histogram_tester.ExpectUniqueSample( |
| 3522 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 3523 | |
| 3524 | NavigateInitiatedByBrowser(GURL("https://example.com")); |
| 3525 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3526 | PrefetchServingHandle serving_handle = |
Taiyo Mizuhashi | 9a1ab988 | 2024-11-28 08:29:08 | [diff] [blame] | 3527 | GetPrefetchToServe(GURL("https://example.com"), std::nullopt); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3528 | ExpectServingReaderSuccess(serving_handle); |
| 3529 | EXPECT_EQ(serving_handle.GetPrefetchContainer()->GetURL(), |
Taiyo Mizuhashi | 9a1ab988 | 2024-11-28 08:29:08 | [diff] [blame] | 3530 | GURL("https://example.com/?a=1")); |
| 3531 | } |
| 3532 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3533 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3534 | TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(PrefetchEligibleRedirect)) { |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3535 | base::HistogramTester histogram_tester; |
| 3536 | |
| 3537 | MakePrefetchService( |
| 3538 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3539 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 3540 | MakePrefetchOnMainFrame( |
| 3541 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3542 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3543 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3544 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3545 | task_environment()->RunUntilIdle(); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3546 | |
| 3547 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3548 | {.use_prefetch_proxy = true}); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3549 | VerifyFollowRedirectParams(0); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3550 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3551 | net::RedirectInfo redirect_info; |
| 3552 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3553 | redirect_info.new_referrer_policy = |
| 3554 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3555 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3556 | MakeSingleRedirectAndWait( |
| 3557 | redirect_info, |
| 3558 | CreateURLResponseHeadForPrefetch( |
| 3559 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3560 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
| 3561 | VerifyFollowRedirectParams(1); |
| 3562 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3563 | histogram_tester.ExpectUniqueSample( |
| 3564 | "PrefetchProxy.Redirect.Result", |
| 3565 | PrefetchRedirectResult::kSuccessRedirectFollowed, 1); |
| 3566 | histogram_tester.ExpectUniqueSample( |
| 3567 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3568 | PrefetchRedirectNetworkContextTransition::kIsolatedToIsolated, 1); |
| 3569 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3570 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3571 | /*use_prefetch_proxy=*/true, |
| 3572 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3573 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3574 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3575 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3576 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3577 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3578 | ExpectServingMetricsSuccess(); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3579 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3580 | histogram_tester.ExpectUniqueSample( |
| 3581 | "PrefetchProxy.AfterClick.RedirectChainSize", 2, 1); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3582 | } |
| 3583 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3584 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3585 | TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(IneligibleRedirectCookies)) { |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3586 | base::HistogramTester histogram_tester; |
| 3587 | |
| 3588 | MakePrefetchService( |
| 3589 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3590 | |
| 3591 | ASSERT_TRUE(SetCookie(GURL("https://redirect.com"), "testing")); |
| 3592 | |
| 3593 | MakePrefetchOnMainFrame( |
| 3594 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3595 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3596 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3597 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3598 | task_environment()->RunUntilIdle(); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3599 | |
| 3600 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3601 | {.use_prefetch_proxy = true}); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3602 | VerifyFollowRedirectParams(0); |
| 3603 | |
kenoss | b277682 | 2024-09-13 16:07:56 | [diff] [blame] | 3604 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 3605 | base::test::TestFuture<PrefetchServingHandle> future; |
kenoss | b277682 | 2024-09-13 16:07:56 | [diff] [blame] | 3606 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
| 3607 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3608 | net::RedirectInfo redirect_info; |
| 3609 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3610 | redirect_info.new_referrer_policy = |
| 3611 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3612 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3613 | MakeSingleRedirectAndWait( |
| 3614 | redirect_info, |
| 3615 | CreateURLResponseHeadForPrefetch( |
| 3616 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3617 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
| 3618 | |
| 3619 | // Since the redirect URL has cookies, it is ineligible for prefetching and |
| 3620 | // causes the prefetch to fail. Also since checking if the URL has cookies |
| 3621 | // requires mojo, the eligibility check will not complete immediately. |
| 3622 | VerifyFollowRedirectParams(0); |
| 3623 | |
kenoss | b277682 | 2024-09-13 16:07:56 | [diff] [blame] | 3624 | // Falls back to normal navigation. |
| 3625 | EXPECT_FALSE(future.Take()); |
| 3626 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3627 | histogram_tester.ExpectUniqueSample("PrefetchProxy.Redirect.Result", |
| 3628 | PrefetchRedirectResult::kFailedIneligible, |
| 3629 | 1); |
| 3630 | histogram_tester.ExpectUniqueSample( |
| 3631 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3632 | PrefetchRedirectNetworkContextTransition::kIsolatedToIsolated, 1); |
| 3633 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3634 | ExpectPrefetchFailedBeforeResponseReceived( |
kenoss | b277682 | 2024-09-13 16:07:56 | [diff] [blame] | 3635 | histogram_tester, PrefetchStatus::kPrefetchFailedIneligibleRedirect, |
| 3636 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3637 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3638 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3639 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3640 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedIneligibleRedirect); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3641 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3642 | histogram_tester.ExpectTotalCount( |
| 3643 | "PrefetchProxy.AfterClick.RedirectChainSize", 0); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3644 | } |
| 3645 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3646 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3647 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3648 | DISABLED_CHROMEOS(IneligibleRedirectServiceWorker)) { |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3649 | base::HistogramTester histogram_tester; |
| 3650 | |
| 3651 | MakePrefetchService( |
| 3652 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3653 | |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 3654 | service_worker_context_->AddRegistrationToRegisteredStorageKeys( |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3655 | blink::StorageKey::CreateFromStringForTesting("https://redirect.com")); |
Liviu Tinta | 9120230 | 2023-09-26 17:49:11 | [diff] [blame] | 3656 | service_worker_context_->AddServiceWorkerScope( |
Liviu Tinta | f7d62a7 | 2023-08-29 21:48:39 | [diff] [blame] | 3657 | GURL("https://redirect.com"), |
| 3658 | ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3659 | |
| 3660 | MakePrefetchOnMainFrame( |
| 3661 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3662 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3663 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3664 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3665 | task_environment()->RunUntilIdle(); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3666 | |
| 3667 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3668 | {.use_prefetch_proxy = true}); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3669 | VerifyFollowRedirectParams(0); |
| 3670 | |
| 3671 | net::RedirectInfo redirect_info; |
| 3672 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3673 | redirect_info.new_referrer_policy = |
| 3674 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3675 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3676 | MakeSingleRedirectAndWait( |
| 3677 | redirect_info, |
| 3678 | CreateURLResponseHeadForPrefetch( |
| 3679 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3680 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
| 3681 | |
| 3682 | // Since the redirect URL has cookies, it is ineligible for prefetching and |
| 3683 | // causes the prefetch to fail. Also the eligibility check should fail |
| 3684 | // immediately. |
| 3685 | VerifyFollowRedirectParams(0); |
| 3686 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3687 | histogram_tester.ExpectUniqueSample("PrefetchProxy.Redirect.Result", |
| 3688 | PrefetchRedirectResult::kFailedIneligible, |
| 3689 | 1); |
| 3690 | histogram_tester.ExpectUniqueSample( |
| 3691 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3692 | PrefetchRedirectNetworkContextTransition::kIsolatedToIsolated, 1); |
| 3693 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3694 | ExpectPrefetchFailedBeforeResponseReceived( |
| 3695 | histogram_tester, PrefetchStatus::kPrefetchFailedIneligibleRedirect); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3696 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3697 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3698 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3699 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedIneligibleRedirect); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3700 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3701 | histogram_tester.ExpectTotalCount( |
| 3702 | "PrefetchProxy.AfterClick.RedirectChainSize", 0); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3703 | } |
| 3704 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3705 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3706 | TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(InvalidRedirect)) { |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3707 | base::HistogramTester histogram_tester; |
| 3708 | |
| 3709 | MakePrefetchService( |
| 3710 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3711 | |
| 3712 | MakePrefetchOnMainFrame( |
| 3713 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3714 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3715 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3716 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3717 | task_environment()->RunUntilIdle(); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3718 | |
| 3719 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3720 | {.use_prefetch_proxy = true}); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3721 | VerifyFollowRedirectParams(0); |
| 3722 | |
| 3723 | // The redirect is considered invalid because it has a non-3XX HTTP code. |
| 3724 | net::RedirectInfo redirect_info; |
| 3725 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3726 | redirect_info.new_referrer_policy = |
| 3727 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 3728 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3729 | MakeSingleRedirectAndWait(redirect_info, CreateURLResponseHeadForPrefetch( |
| 3730 | net::HTTP_OK, kHTMLMimeType, |
| 3731 | /*use_prefetch_proxy=*/true, {}, |
| 3732 | GURL("https://redirect.com"))); |
| 3733 | VerifyFollowRedirectParams(0); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3734 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3735 | histogram_tester.ExpectUniqueSample( |
| 3736 | "PrefetchProxy.Redirect.Result", |
| 3737 | PrefetchRedirectResult::kFailedInvalidResponseCode, 1); |
| 3738 | histogram_tester.ExpectTotalCount( |
| 3739 | "PrefetchProxy.Redirect.NetworkContextStateTransition", 0); |
| 3740 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3741 | ExpectPrefetchFailedBeforeResponseReceived( |
| 3742 | histogram_tester, PrefetchStatus::kPrefetchFailedInvalidRedirect); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3743 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3744 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3745 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3746 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedInvalidRedirect); |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 3747 | |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3748 | histogram_tester.ExpectTotalCount( |
| 3749 | "PrefetchProxy.AfterClick.RedirectChainSize", 0); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3750 | } |
| 3751 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3752 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3753 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3754 | DISABLED_CHROMEOS(PrefetchSameOriginEligibleRedirect)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 3755 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 3756 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3757 | base::HistogramTester histogram_tester; |
| 3758 | |
| 3759 | MakePrefetchService( |
| 3760 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3761 | |
| 3762 | MakePrefetchOnMainFrame( |
| 3763 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3764 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3765 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3766 | blink::mojom::SpeculationEagerness::kImmediate)); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3767 | |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3768 | task_environment()->RunUntilIdle(); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3769 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3770 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3771 | VerifyFollowRedirectParams(0); |
| 3772 | |
| 3773 | net::RedirectInfo redirect_info; |
| 3774 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3775 | redirect_info.new_referrer_policy = |
| 3776 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3777 | redirect_info.new_url = GURL("https://example.com/redirect"); |
| 3778 | MakeSingleRedirectAndWait(redirect_info, |
| 3779 | CreateURLResponseHeadForPrefetch( |
| 3780 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3781 | /*use_prefetch_proxy=*/true, {}, |
| 3782 | GURL("https://example.com/redirect"))); |
| 3783 | VerifyFollowRedirectParams(1); |
| 3784 | |
| 3785 | histogram_tester.ExpectUniqueSample( |
| 3786 | "PrefetchProxy.Redirect.Result", |
| 3787 | PrefetchRedirectResult::kSuccessRedirectFollowed, 1); |
| 3788 | histogram_tester.ExpectUniqueSample( |
| 3789 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3790 | PrefetchRedirectNetworkContextTransition::kDefaultToDefault, 1); |
| 3791 | |
| 3792 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3793 | /*use_prefetch_proxy=*/false, |
| 3794 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3795 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3796 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3797 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3798 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3799 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3800 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3801 | |
| 3802 | histogram_tester.ExpectUniqueSample( |
| 3803 | "PrefetchProxy.AfterClick.RedirectChainSize", 2, 1); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3804 | } |
| 3805 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3806 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 3807 | // TODO(crbug.com/40265797): This test is testing the current |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3808 | // functionality, and should be removed while fixing this bug. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3809 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3810 | DISABLED_CHROMEOS(IneligibleSameSiteCrossOriginRequiresProxyRedirect)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 3811 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 3812 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3813 | base::HistogramTester histogram_tester; |
| 3814 | |
| 3815 | MakePrefetchService( |
| 3816 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3817 | |
| 3818 | MakePrefetchOnMainFrame( |
| 3819 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3820 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3821 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3822 | blink::mojom::SpeculationEagerness::kImmediate)); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3823 | |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3824 | task_environment()->RunUntilIdle(); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3825 | |
| 3826 | // The request to the same-origin prefetch URL should ignore the proxy |
| 3827 | // requirement, since it only applies to cross-origin prefetches. |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3828 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3829 | VerifyFollowRedirectParams(0); |
| 3830 | |
| 3831 | // Redirect to a same-site cross-origin URL. The proxy requirement should |
| 3832 | // apply to this URL, and result in the redirect being marked as ineligible, |
| 3833 | // because we cannot make same-site cross-origin requests that require the |
| 3834 | // proxy. |
| 3835 | net::RedirectInfo redirect_info; |
| 3836 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3837 | redirect_info.new_referrer_policy = |
| 3838 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3839 | redirect_info.new_url = GURL("https://other.example.com/redirect"); |
| 3840 | MakeSingleRedirectAndWait(redirect_info, |
| 3841 | CreateURLResponseHeadForPrefetch( |
| 3842 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3843 | /*use_prefetch_proxy=*/true, {}, |
| 3844 | GURL("https://example.com/redirect"))); |
| 3845 | VerifyFollowRedirectParams(0); |
| 3846 | |
| 3847 | histogram_tester.ExpectUniqueSample("PrefetchProxy.Redirect.Result", |
| 3848 | PrefetchRedirectResult::kFailedIneligible, |
| 3849 | 1); |
| 3850 | histogram_tester.ExpectUniqueSample( |
| 3851 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3852 | PrefetchRedirectNetworkContextTransition::kDefaultToDefault, 1); |
| 3853 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3854 | ExpectPrefetchFailedBeforeResponseReceived( |
| 3855 | histogram_tester, PrefetchStatus::kPrefetchFailedIneligibleRedirect); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3856 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3857 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3858 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
| 3859 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedIneligibleRedirect); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3860 | histogram_tester.ExpectTotalCount( |
| 3861 | "PrefetchProxy.AfterClick.RedirectChainSize", 0); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 3862 | } |
| 3863 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3864 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3865 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3866 | DISABLED_CHROMEOS(RedirectDefaultToIsolatedNetworkContextTransition)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 3867 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 3868 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3869 | base::HistogramTester histogram_tester; |
| 3870 | |
| 3871 | MakePrefetchService( |
| 3872 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3873 | |
| 3874 | MakePrefetchOnMainFrame( |
| 3875 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3876 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3877 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3878 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3879 | task_environment()->RunUntilIdle(); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3880 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3881 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3882 | VerifyFollowRedirectParams(0); |
| 3883 | |
| 3884 | net::RedirectInfo redirect_info; |
| 3885 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3886 | redirect_info.new_referrer_policy = |
| 3887 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3888 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3889 | MakeSingleRedirectAndWait( |
| 3890 | redirect_info, |
| 3891 | CreateURLResponseHeadForPrefetch( |
| 3892 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3893 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3894 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3895 | |
| 3896 | // Since the redirect is cross-site compared to the referrer. A new request |
| 3897 | // will be started in an isolated network context, and the redirect will not |
| 3898 | // be followed directly. |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3899 | VerifyFollowRedirectParams(0); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3900 | ClearCompletedRequests(); |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3901 | VerifyCommonRequestState(GURL("https://redirect.com")); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3902 | |
| 3903 | histogram_tester.ExpectUniqueSample( |
| 3904 | "PrefetchProxy.Redirect.Result", |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3905 | PrefetchRedirectResult::kSuccessRedirectFollowed, 1); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3906 | histogram_tester.ExpectUniqueSample( |
| 3907 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3908 | PrefetchRedirectNetworkContextTransition::kDefaultToIsolated, 1); |
| 3909 | |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3910 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3911 | /*use_prefetch_proxy=*/false, |
| 3912 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3913 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3914 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3915 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3916 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3917 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3918 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | 7d2578b | 2023-04-12 19:19:28 | [diff] [blame] | 3919 | |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3920 | histogram_tester.ExpectUniqueSample( |
| 3921 | "PrefetchProxy.AfterClick.RedirectChainSize", 2, 1); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3922 | } |
| 3923 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3924 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3925 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3926 | DISABLED_CHROMEOS( |
| 3927 | RedirectDefaultToIsolatedNetworkContextTransitionWithProxy)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 3928 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 3929 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3930 | base::HistogramTester histogram_tester; |
| 3931 | |
| 3932 | MakePrefetchService( |
| 3933 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3934 | |
| 3935 | MakePrefetchOnMainFrame( |
| 3936 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 3937 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 3938 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 3939 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3940 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3941 | |
| 3942 | // The same-origin request should not use the proxy. |
| 3943 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3944 | {.use_prefetch_proxy = false}); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3945 | VerifyFollowRedirectParams(0); |
| 3946 | |
| 3947 | net::RedirectInfo redirect_info; |
| 3948 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 3949 | redirect_info.new_referrer_policy = |
| 3950 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3951 | redirect_info.new_url = GURL("https://redirect.com"); |
| 3952 | MakeSingleRedirectAndWait( |
| 3953 | redirect_info, |
| 3954 | CreateURLResponseHeadForPrefetch( |
| 3955 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 3956 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 3957 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3958 | |
| 3959 | // Since the redirect is cross-site compared to the referrer. A new request |
| 3960 | // will be started in an isolated network context, and the redirect will not |
| 3961 | // be followed directly. The new request should use the proxy. |
| 3962 | VerifyFollowRedirectParams(0); |
| 3963 | ClearCompletedRequests(); |
| 3964 | VerifyCommonRequestState(GURL("https://redirect.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 3965 | {.use_prefetch_proxy = true}); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3966 | |
| 3967 | histogram_tester.ExpectUniqueSample( |
| 3968 | "PrefetchProxy.Redirect.Result", |
| 3969 | PrefetchRedirectResult::kSuccessRedirectFollowed, 1); |
| 3970 | histogram_tester.ExpectUniqueSample( |
| 3971 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 3972 | PrefetchRedirectNetworkContextTransition::kDefaultToIsolated, 1); |
| 3973 | |
| 3974 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 3975 | /*use_prefetch_proxy=*/false, |
| 3976 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 3977 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3978 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3979 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 3980 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 3981 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 3982 | ExpectServingMetricsSuccess(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3983 | |
| 3984 | histogram_tester.ExpectUniqueSample( |
| 3985 | "PrefetchProxy.AfterClick.RedirectChainSize", 2, 1); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3986 | } |
| 3987 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 3988 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 3989 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 3990 | DISABLED_CHROMEOS(RedirectIsolatedToDefaultNetworkContextTransition)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 3991 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 3992 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 3993 | base::HistogramTester histogram_tester; |
| 3994 | |
| 3995 | MakePrefetchService( |
| 3996 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 3997 | |
| 3998 | MakePrefetchOnMainFrame( |
| 3999 | GURL("https://other.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4000 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 4001 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 4002 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4003 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4004 | |
| 4005 | VerifyCommonRequestState(GURL("https://other.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4006 | {.use_prefetch_proxy = false}); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4007 | VerifyFollowRedirectParams(0); |
| 4008 | |
| 4009 | net::RedirectInfo redirect_info; |
| 4010 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4011 | redirect_info.new_referrer_policy = |
| 4012 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4013 | redirect_info.new_url = GURL("https://example.com/redirect"); |
| 4014 | MakeSingleRedirectAndWait(redirect_info, |
| 4015 | CreateURLResponseHeadForPrefetch( |
| 4016 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 4017 | /*use_prefetch_proxy=*/true, {}, |
| 4018 | GURL("https://example.com/redirect"))); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4019 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4020 | |
| 4021 | // Since the redirect is same-site compared to the referrer. A new request |
| 4022 | // will be started in the default network context, and the redirect will not |
| 4023 | // be followed directly. |
| 4024 | VerifyFollowRedirectParams(0); |
| 4025 | ClearCompletedRequests(); |
| 4026 | VerifyCommonRequestState(GURL("https://example.com/redirect"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4027 | {.use_prefetch_proxy = false}); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4028 | |
| 4029 | histogram_tester.ExpectUniqueSample( |
| 4030 | "PrefetchProxy.Redirect.Result", |
| 4031 | PrefetchRedirectResult::kSuccessRedirectFollowed, 1); |
| 4032 | histogram_tester.ExpectUniqueSample( |
| 4033 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 4034 | PrefetchRedirectNetworkContextTransition::kIsolatedToDefault, 1); |
| 4035 | |
| 4036 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 4037 | /*use_prefetch_proxy=*/false, |
| 4038 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 4039 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4040 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4041 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4042 | NavigateInitiatedByRenderer(GURL("https://other.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4043 | ExpectServingReaderSuccess(GetPrefetchToServe(GURL("https://other.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4044 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4045 | |
| 4046 | histogram_tester.ExpectUniqueSample( |
| 4047 | "PrefetchProxy.AfterClick.RedirectChainSize", 2, 1); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4048 | } |
| 4049 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4050 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4051 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4052 | DISABLED_CHROMEOS(RedirectNetworkContextTransitionBlockUntilHead)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 4053 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 4054 | web_contents(), GURL("https://example.com/referrer")); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4055 | base::HistogramTester histogram_tester; |
| 4056 | |
| 4057 | MakePrefetchService( |
| 4058 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4059 | |
| 4060 | MakePrefetchOnMainFrame( |
| 4061 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4062 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 4063 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 4064 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4065 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4066 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4067 | VerifyCommonRequestState(GURL("https://example.com")); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4068 | VerifyFollowRedirectParams(0); |
| 4069 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4070 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4071 | |
| 4072 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4073 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4074 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4075 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4076 | EXPECT_FALSE(future.IsReady()); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4077 | |
| 4078 | net::RedirectInfo redirect_info; |
| 4079 | redirect_info.new_method = "GET"; |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4080 | redirect_info.new_referrer_policy = |
| 4081 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4082 | redirect_info.new_url = GURL("https://redirect.com"); |
| 4083 | MakeSingleRedirectAndWait( |
| 4084 | redirect_info, |
| 4085 | CreateURLResponseHeadForPrefetch( |
| 4086 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 4087 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4088 | task_environment()->RunUntilIdle(); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4089 | |
| 4090 | // Since the redirect is cross-site compared to the referrer. A new request |
| 4091 | // will be started in an isolated network context, and the redirect will not |
| 4092 | // be followed directly. |
| 4093 | VerifyFollowRedirectParams(0); |
| 4094 | ClearCompletedRequests(); |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4095 | VerifyCommonRequestState(GURL("https://redirect.com")); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4096 | |
| 4097 | histogram_tester.ExpectUniqueSample( |
| 4098 | "PrefetchProxy.Redirect.Result", |
| 4099 | PrefetchRedirectResult::kSuccessRedirectFollowed, 1); |
| 4100 | histogram_tester.ExpectUniqueSample( |
| 4101 | "PrefetchProxy.Redirect.NetworkContextStateTransition", |
| 4102 | PrefetchRedirectNetworkContextTransition::kDefaultToIsolated, 1); |
| 4103 | |
| 4104 | // Once the final response to the prefetch is received, then callback given to |
| 4105 | // |GetPrefetchToServe| should be run. |
| 4106 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 4107 | /*use_prefetch_proxy=*/false, |
| 4108 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4109 | PrefetchServingHandle serving_handle = future.Take(); |
| 4110 | ASSERT_TRUE(serving_handle); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4111 | |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 4112 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 4113 | blink::mojom::SpeculationEagerness::kImmediate, |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 4114 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4115 | ExpectServingReaderSuccess(serving_handle); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4116 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 4117 | |
| 4118 | histogram_tester.ExpectUniqueSample( |
| 4119 | "PrefetchProxy.AfterClick.RedirectChainSize", 2, 1); |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 4120 | } |
| 4121 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4122 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4123 | TEST_P(PrefetchServiceTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4124 | DISABLED_CHROMEOS(RedirectInsufficientReferrerPolicy)) { |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 4125 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 4126 | web_contents(), GURL("https://referrer.com")); |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4127 | base::HistogramTester histogram_tester; |
| 4128 | |
| 4129 | MakePrefetchService( |
| 4130 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4131 | |
| 4132 | blink::mojom::Referrer referrer; |
| 4133 | referrer.url = GURL("https://referrer.com"); |
| 4134 | referrer.policy = network::mojom::ReferrerPolicy::kDefault; |
| 4135 | MakePrefetchOnMainFrame( |
| 4136 | GURL("https://example.com"), |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4137 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 4138 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 4139 | blink::mojom::SpeculationEagerness::kImmediate), |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4140 | /*referrer=*/referrer); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4141 | task_environment()->RunUntilIdle(); |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4142 | |
| 4143 | VerifyCommonRequestState(GURL("https://example.com"), |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4144 | {.use_prefetch_proxy = true}); |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4145 | VerifyFollowRedirectParams(0); |
| 4146 | |
| 4147 | // Redirect to a different site. This will check the referrer policy, but |
| 4148 | // since it is not sufficiently strict, the redirect should fail. |
| 4149 | net::RedirectInfo redirect_info; |
| 4150 | redirect_info.new_method = "GET"; |
| 4151 | redirect_info.new_referrer_policy = net::ReferrerPolicy::NEVER_CLEAR; |
| 4152 | redirect_info.new_url = GURL("https://redirect.com"); |
| 4153 | MakeSingleRedirectAndWait( |
| 4154 | redirect_info, |
| 4155 | CreateURLResponseHeadForPrefetch( |
| 4156 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 4157 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com"))); |
| 4158 | VerifyFollowRedirectParams(0); |
| 4159 | |
| 4160 | histogram_tester.ExpectUniqueSample( |
| 4161 | "PrefetchProxy.Redirect.Result", |
| 4162 | PrefetchRedirectResult::kFailedInsufficientReferrerPolicy, 1); |
| 4163 | histogram_tester.ExpectTotalCount( |
| 4164 | "PrefetchProxy.Redirect.NetworkContextStateTransition", 0); |
| 4165 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4166 | ExpectPrefetchFailedBeforeResponseReceived( |
| 4167 | histogram_tester, PrefetchStatus::kPrefetchFailedInvalidRedirect); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4168 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4169 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4170 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com"))); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4171 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedInvalidRedirect); |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4172 | |
| 4173 | histogram_tester.ExpectTotalCount( |
| 4174 | "PrefetchProxy.AfterClick.RedirectChainSize", 0); |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4175 | } |
| 4176 | |
Iman Saboori | 6e3bb0c | 2023-01-13 19:57:08 | [diff] [blame] | 4177 | class PrefetchServiceAlwaysBlockUntilHeadTest |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 4178 | : public PrefetchServiceTestBase, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4179 | public WithPrefetchServiceRearchParam, |
| 4180 | public ::testing::WithParamInterface< |
| 4181 | std::tuple<PrefetchServiceRearchParam::Arg, |
| 4182 | blink::mojom::SpeculationEagerness>> { |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4183 | public: |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4184 | PrefetchServiceAlwaysBlockUntilHeadTest() |
| 4185 | : WithPrefetchServiceRearchParam(std::get<0>(GetParam())) {} |
| 4186 | |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4187 | const int kPrefetchTimeout = 10000; |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4188 | const int kBlockUntilHeadTimeout = 1000; |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4189 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 4190 | InitBaseParams(); |
| 4191 | InitRearchFeatures(); |
| 4192 | // Override `kPrefetchUseContentRefactor`. |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4193 | scoped_feature_list_.InitWithFeaturesAndParameters( |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 4194 | {{features::kPrefetchUseContentRefactor, |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 4195 | { |
| 4196 | {"ineligible_decoy_request_probability", "0"}, |
| 4197 | {"prefetch_container_lifetime_s", "-1"}, |
| 4198 | {"prefetch_timeout_ms", "10000"}, |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4199 | // Initialize timeouts > 0ms for testing purposes. |
Takashi Nakayama | c96a5de | 2025-06-24 04:07:43 | [diff] [blame] | 4200 | {"block_until_head_timeout_immediate_prefetch", "1000"}, |
Takashi Nakayama | 8ec9dbf | 2025-06-27 04:03:15 | [diff] [blame] | 4201 | {"block_until_head_timeout_eager_prefetch", "1000"}, |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4202 | {"block_until_head_timeout_moderate_prefetch", "1000"}, |
| 4203 | {"block_until_head_timeout_conservative_prefetch", "1000"}, |
kenoss | c6c712a | 2025-03-10 23:17:02 | [diff] [blame] | 4204 | }}}, |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4205 | {}); |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4206 | } |
| 4207 | |
| 4208 | blink::mojom::SpeculationEagerness GetEagernessParam() { |
| 4209 | return std::get<1>(GetParam()); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4210 | } |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 4211 | |
| 4212 | private: |
| 4213 | base::test::ScopedFeatureList scoped_feature_list_; |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4214 | }; |
| 4215 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4216 | INSTANTIATE_TEST_SUITE_P( |
| 4217 | ParametrizedTests, |
| 4218 | PrefetchServiceAlwaysBlockUntilHeadTest, |
| 4219 | testing::Combine( |
| 4220 | testing::ValuesIn(PrefetchServiceRearchParam::Params()), |
| 4221 | testing::Values(blink::mojom::SpeculationEagerness::kModerate, |
| 4222 | blink::mojom::SpeculationEagerness::kConservative))); |
| 4223 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4224 | // TODO(crbug.com/40249481): Test flaky on trybots. |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4225 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
| 4226 | DISABLED_CHROMEOS(BlockUntilHeadReceived)) { |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4227 | base::HistogramTester histogram_tester; |
| 4228 | |
| 4229 | MakePrefetchService( |
| 4230 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4231 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4232 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4233 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4234 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 4235 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4236 | task_environment()->RunUntilIdle(); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4237 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4238 | VerifyCommonRequestState( |
| 4239 | GURL("https://example.com"), |
| 4240 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4241 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4242 | |
| 4243 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4244 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4245 | |
| 4246 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4247 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4248 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4249 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4250 | EXPECT_FALSE(future.IsReady()); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4251 | |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4252 | task_environment()->FastForwardBy(base::Milliseconds(500)); |
| 4253 | |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4254 | // Sends the head of the prefetch response. This should trigger the above |
| 4255 | // callback. |
| 4256 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 4257 | /*use_prefetch_proxy=*/true, |
| 4258 | {{"X-Testing", "Hello World"}}, |
| 4259 | std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4260 | PrefetchServingHandle serving_handle = future.Take(); |
| 4261 | ASSERT_TRUE(serving_handle); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4262 | |
| 4263 | // Send the body and completion status of the request, |
| 4264 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 4265 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 4266 | |
| 4267 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4268 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 4269 | GetEagernessParam(), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 4270 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4271 | ExpectServingReaderSuccess(serving_handle); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4272 | ExpectServingMetricsSuccess(); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4273 | |
| 4274 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4275 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4276 | histogram_tester.ExpectUniqueTimeSample( |
| 4277 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4278 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4279 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4280 | base::Milliseconds(500), 1); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4281 | histogram_tester.ExpectTotalCount( |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4282 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4283 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4284 | histogram_suffix), |
| 4285 | 0); |
| 4286 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4287 | base::StringPrintf( |
| 4288 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4289 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4290 | true, 1); |
Max Curran | 2e83b5d | 2022-12-29 18:53:38 | [diff] [blame] | 4291 | } |
| 4292 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4293 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4294 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4295 | DISABLED_CHROMEOS(NVSBlockUntilHeadReceived)) { |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4296 | base::HistogramTester histogram_tester; |
| 4297 | |
| 4298 | MakePrefetchService( |
| 4299 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4300 | |
| 4301 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 4302 | network::mojom::NoVarySearch::New(); |
| 4303 | no_vary_search_hint->vary_on_key_order = true; |
| 4304 | no_vary_search_hint->search_variance = |
| 4305 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 4306 | std::vector<std::string>({"a"})); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4307 | const PrefetchType prefetch_type = |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4308 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4309 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 4310 | MakePrefetchOnMainFrame( |
| 4311 | GURL("https://example.com/index.html?a=5"), prefetch_type, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4312 | /* referrer */ blink::mojom::Referrer(), std::move(no_vary_search_hint)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4313 | task_environment()->RunUntilIdle(); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4314 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4315 | VerifyCommonRequestState( |
| 4316 | GURL("https://example.com/index.html?a=5"), |
| 4317 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4318 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4319 | |
| 4320 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4321 | NavigateInitiatedByRenderer(GURL("https://example.com/index.html")); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4322 | |
| 4323 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4324 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4325 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4326 | GetPrefetchToServe(future, GURL("https://example.com/index.html"), |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4327 | MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4328 | EXPECT_FALSE(future.IsReady()); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4329 | task_environment()->FastForwardBy(base::Milliseconds(600)); |
| 4330 | |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4331 | // Sends the head of the prefetch response. This should trigger the above |
| 4332 | // callback. |
| 4333 | SendHeadOfResponseAndWait( |
| 4334 | net::HTTP_OK, kHTMLMimeType, |
| 4335 | /*use_prefetch_proxy=*/true, |
| 4336 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"a\")"}}, |
| 4337 | std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4338 | PrefetchServingHandle serving_handle = future.Take(); |
| 4339 | ASSERT_TRUE(serving_handle); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4340 | |
| 4341 | // Send the body and completion status of the request, |
| 4342 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 4343 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 4344 | |
| 4345 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4346 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 4347 | GetEagernessParam(), |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4348 | /* is_accurate=*/true); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4349 | ExpectServingReaderSuccess(serving_handle); |
Hiroshige Hayashizaki | 3d7b94a | 2023-10-21 01:19:36 | [diff] [blame] | 4350 | ExpectServingMetricsSuccess(); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4351 | |
| 4352 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4353 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4354 | histogram_tester.ExpectUniqueTimeSample( |
| 4355 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4356 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4357 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4358 | base::Milliseconds(600), 1); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4359 | histogram_tester.ExpectTotalCount( |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4360 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4361 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4362 | histogram_suffix), |
| 4363 | 0); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4364 | histogram_tester.ExpectTotalCount( |
| 4365 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4366 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4367 | histogram_suffix), |
| 4368 | 0); |
| 4369 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4370 | base::StringPrintf( |
| 4371 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4372 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4373 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 4374 | |
| 4375 | histogram_tester.ExpectUniqueSample( |
| 4376 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 4377 | "PerMatchingCandidate.", |
| 4378 | histogram_suffix}), |
| 4379 | PrefetchPotentialCandidateServingResult::kServed, 1); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4380 | } |
| 4381 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4382 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4383 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4384 | DISABLED_CHROMEOS(NVSBlockUntilHeadReceivedNoMatchNoNVSHeader)) { |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4385 | base::HistogramTester histogram_tester; |
| 4386 | |
| 4387 | MakePrefetchService( |
| 4388 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4389 | |
| 4390 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 4391 | network::mojom::NoVarySearch::New(); |
| 4392 | no_vary_search_hint->vary_on_key_order = true; |
| 4393 | no_vary_search_hint->search_variance = |
| 4394 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 4395 | std::vector<std::string>({"a"})); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4396 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4397 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4398 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 4399 | MakePrefetchOnMainFrame( |
| 4400 | GURL("https://example.com/index.html?a=5"), prefetch_type, |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4401 | /* referrer */ blink::mojom::Referrer(), |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4402 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4403 | task_environment()->RunUntilIdle(); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4404 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4405 | VerifyCommonRequestState( |
| 4406 | GURL("https://example.com/index.html?a=5"), |
| 4407 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4408 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4409 | |
| 4410 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4411 | NavigateInitiatedByRenderer(GURL("https://example.com/index.html")); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4412 | |
| 4413 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4414 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4415 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4416 | GetPrefetchToServe(future, GURL("https://example.com/index.html"), |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4417 | MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4418 | EXPECT_FALSE(future.IsReady()); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4419 | |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4420 | task_environment()->FastForwardBy(base::Milliseconds(700)); |
| 4421 | |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4422 | // Sends the head of the prefetch response. This should trigger the above |
| 4423 | // callback with a nullptr argument. |
| 4424 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 4425 | /*use_prefetch_proxy=*/true, |
| 4426 | {{"X-Testing", "Hello World"}}, |
| 4427 | std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4428 | PrefetchServingHandle serving_handle = future.Take(); |
| 4429 | ASSERT_FALSE(serving_handle); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4430 | |
| 4431 | // Send the body and completion status of the request, |
| 4432 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 4433 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 4434 | |
| 4435 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4436 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 4437 | GetEagernessParam()); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4438 | ExpectServingMetricsSuccess(); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4439 | |
| 4440 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4441 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4442 | histogram_tester.ExpectTotalCount( |
| 4443 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4444 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4445 | histogram_suffix), |
| 4446 | 0); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4447 | histogram_tester.ExpectUniqueTimeSample( |
| 4448 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4449 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4450 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4451 | base::Milliseconds(700), 1); |
| 4452 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4453 | base::StringPrintf( |
| 4454 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4455 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4456 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 4457 | |
| 4458 | histogram_tester.ExpectUniqueSample( |
| 4459 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 4460 | "PerMatchingCandidate.", |
| 4461 | histogram_suffix}), |
| 4462 | PrefetchPotentialCandidateServingResult:: |
| 4463 | kNotServedDeterminedNVSHeaderMismatch, |
| 4464 | 1); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4465 | } |
| 4466 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4467 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4468 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4469 | DISABLED_CHROMEOS(NVSBlockUntilHeadReceivedNoMatchByNVSHeader)) { |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4470 | base::HistogramTester histogram_tester; |
| 4471 | |
| 4472 | MakePrefetchService( |
| 4473 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4474 | |
| 4475 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 4476 | network::mojom::NoVarySearch::New(); |
| 4477 | no_vary_search_hint->vary_on_key_order = true; |
| 4478 | no_vary_search_hint->search_variance = |
| 4479 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 4480 | std::vector<std::string>({"a"})); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4481 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4482 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4483 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 4484 | MakePrefetchOnMainFrame( |
| 4485 | GURL("https://example.com/index.html?a=5"), prefetch_type, |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 4486 | /* referrer */ blink::mojom::Referrer(), |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4487 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4488 | task_environment()->RunUntilIdle(); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4489 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4490 | VerifyCommonRequestState( |
| 4491 | GURL("https://example.com/index.html?a=5"), |
| 4492 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4493 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4494 | |
| 4495 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4496 | NavigateInitiatedByRenderer(GURL("https://example.com/index.html")); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4497 | |
| 4498 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4499 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4500 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4501 | GetPrefetchToServe(future, GURL("https://example.com/index.html"), |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4502 | MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4503 | EXPECT_FALSE(future.IsReady()); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4504 | |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 4505 | task_environment()->FastForwardBy( |
| 4506 | base::Milliseconds(kAddedToURLRequestStartLatency + kHeaderLatency)); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4507 | |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4508 | // Sends the head of the prefetch response. This should trigger the above |
| 4509 | // callback with a nullptr argument. |
| 4510 | SendHeadOfResponseAndWait( |
| 4511 | net::HTTP_OK, kHTMLMimeType, |
| 4512 | /*use_prefetch_proxy=*/true, |
| 4513 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"b\")"}}, |
| 4514 | std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4515 | PrefetchServingHandle serving_handle = future.Take(); |
| 4516 | ASSERT_FALSE(serving_handle); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4517 | |
| 4518 | // Send the body and completion status of the request, |
| 4519 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 4520 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 4521 | |
| 4522 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4523 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 4524 | GetEagernessParam()); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4525 | ExpectServingMetricsSuccess(); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4526 | |
| 4527 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4528 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4529 | histogram_tester.ExpectTotalCount( |
| 4530 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4531 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4532 | histogram_suffix), |
| 4533 | 0); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4534 | histogram_tester.ExpectUniqueTimeSample( |
| 4535 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4536 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4537 | histogram_suffix), |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 4538 | base::Milliseconds(kAddedToURLRequestStartLatency + kHeaderLatency), 1); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4539 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4540 | base::StringPrintf( |
| 4541 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4542 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4543 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 4544 | |
| 4545 | histogram_tester.ExpectUniqueSample( |
| 4546 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 4547 | "PerMatchingCandidate.", |
| 4548 | histogram_suffix}), |
| 4549 | PrefetchPotentialCandidateServingResult:: |
| 4550 | kNotServedDeterminedNVSHeaderMismatch, |
| 4551 | 1); |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 4552 | } |
| 4553 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4554 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4555 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4556 | DISABLED_CHROMEOS(FailedCookiesChangedWhileBlockUntilHead)) { |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4557 | base::HistogramTester histogram_tester; |
| 4558 | |
| 4559 | MakePrefetchService( |
| 4560 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4561 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4562 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4563 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 4564 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4565 | task_environment()->RunUntilIdle(); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4566 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4567 | VerifyCommonRequestState( |
| 4568 | GURL("https://example.com"), |
| 4569 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4570 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4571 | |
| 4572 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4573 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4574 | |
| 4575 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4576 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4577 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4578 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4579 | EXPECT_FALSE(future.IsReady()); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4580 | |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4581 | task_environment()->FastForwardBy(base::Milliseconds(800)); |
| 4582 | |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4583 | // Adding a cookie after while blocking until the head is received will cause |
| 4584 | // it to fail. |
| 4585 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4586 | task_environment()->RunUntilIdle(); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4587 | |
| 4588 | // Sends the head of the prefetch response. This should trigger the above |
| 4589 | // callback. |
| 4590 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 4591 | /*use_prefetch_proxy=*/true, |
| 4592 | {{"X-Testing", "Hello World"}}, |
| 4593 | std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4594 | PrefetchServingHandle serving_handle = future.Take(); |
| 4595 | EXPECT_FALSE(serving_handle); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4596 | |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4597 | histogram_tester.ExpectUniqueSample( |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4598 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
Max Curran | 59b8ab99 | 2023-07-26 21:58:12 | [diff] [blame] | 4599 | histogram_tester.ExpectTotalCount("PrefetchProxy.Prefetch.Mainframe.NetError", |
| 4600 | 0); |
| 4601 | histogram_tester.ExpectTotalCount( |
| 4602 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", 0); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4603 | histogram_tester.ExpectUniqueSample( |
| 4604 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 4605 | histogram_tester.ExpectUniqueSample( |
| 4606 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 4607 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 4608 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4609 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 4610 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 1); |
| 4611 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 1); |
Max Curran | 59b8ab99 | 2023-07-26 21:58:12 | [diff] [blame] | 4612 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 0); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4613 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4614 | ExpectServingMetrics(PrefetchStatus::kPrefetchNotUsedCookiesChanged); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4615 | |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 4616 | ExpectCorrectUkmLogs({.outcome = PreloadingTriggeringOutcome::kFailure, |
| 4617 | .failure = ToPreloadingFailureReason( |
| 4618 | PrefetchStatus::kPrefetchNotUsedCookiesChanged), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 4619 | .is_accurate = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4620 | .eagerness = GetEagernessParam()}); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4621 | |
| 4622 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4623 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4624 | histogram_tester.ExpectTotalCount( |
| 4625 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4626 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4627 | histogram_suffix), |
| 4628 | 0); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4629 | histogram_tester.ExpectUniqueTimeSample( |
| 4630 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4631 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4632 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4633 | base::Milliseconds(800), 1); |
| 4634 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4635 | base::StringPrintf( |
| 4636 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4637 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4638 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 4639 | |
| 4640 | histogram_tester.ExpectUniqueSample( |
| 4641 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 4642 | "PerMatchingCandidate.", |
| 4643 | histogram_suffix}), |
| 4644 | PrefetchPotentialCandidateServingResult::kNotServedCookiesChanged, 1); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4645 | } |
| 4646 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4647 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4648 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4649 | DISABLED_CHROMEOS(FailedTimeoutWhileBlockUntilHead)) { |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4650 | base::HistogramTester histogram_tester; |
| 4651 | |
| 4652 | MakePrefetchService( |
| 4653 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 4654 | |
Taiyo Mizuhashi | 6b0a495 | 2024-03-18 22:40:37 | [diff] [blame] | 4655 | PrefetchType prefetch_type(PreloadingTriggerType::kSpeculationRule, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4656 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
Taiyo Mizuhashi | 6b0a495 | 2024-03-18 22:40:37 | [diff] [blame] | 4657 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4658 | task_environment()->RunUntilIdle(); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4659 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4660 | VerifyCommonRequestState( |
| 4661 | GURL("https://example.com"), |
| 4662 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4663 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4664 | |
| 4665 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4666 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4667 | |
| 4668 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4669 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4670 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4671 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4672 | EXPECT_FALSE(future.IsReady()); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4673 | |
| 4674 | // If the prefetch times out while PrefetchService is blocking until head, |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4675 | // then it should unblock without setting serving_handle. |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4676 | task_environment()->FastForwardBy(base::Milliseconds(kPrefetchTimeout)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4677 | PrefetchServingHandle serving_handle = future.Take(); |
| 4678 | EXPECT_FALSE(serving_handle); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4679 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4680 | ExpectPrefetchFailedNetError(histogram_tester, net::ERR_TIMED_OUT, |
| 4681 | GetEagernessParam(), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 4682 | /*is_accurate_triggering=*/true); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4683 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4684 | |
| 4685 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4686 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 4687 | base::TimeDelta block_until_head_timeout = PrefetchBlockUntilHeadTimeout( |
| 4688 | prefetch_type, /*should_disable_block_until_head_timeout=*/false, |
| 4689 | /*is_nav_prerender=*/false); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4690 | histogram_tester.ExpectTotalCount( |
| 4691 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4692 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4693 | histogram_suffix), |
| 4694 | 0); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4695 | histogram_tester.ExpectUniqueTimeSample( |
| 4696 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4697 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4698 | histogram_suffix), |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4699 | block_until_head_timeout, 1); |
| 4700 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4701 | base::StringPrintf( |
| 4702 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4703 | histogram_suffix), |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4704 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 4705 | |
| 4706 | histogram_tester.ExpectUniqueSample( |
| 4707 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 4708 | "PerMatchingCandidate.", |
| 4709 | histogram_suffix}), |
| 4710 | PrefetchPotentialCandidateServingResult::kNotServedBlockUntilHeadTimeout, |
| 4711 | 1); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4712 | } |
| 4713 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4714 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4715 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4716 | DISABLED_CHROMEOS(FailedTimeoutWhileBlockUntilHeadForOlderNavigation)) { |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4717 | base::HistogramTester histogram_tester; |
| 4718 | |
| 4719 | MakePrefetchService( |
| 4720 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4721 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4722 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4723 | /*use_prefetch_proxy=*/false, GetEagernessParam()); |
| 4724 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4725 | task_environment()->RunUntilIdle(); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4726 | |
| 4727 | VerifyCommonRequestState( |
| 4728 | GURL("https://example.com"), |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4729 | {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4730 | |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4731 | // The first navigation is started and then gone before the head of the |
| 4732 | // prefetch response is received. The given callback shouldn't be called (and |
| 4733 | // the metrics shouldn't be recorded) because the navigation is gone before |
| 4734 | // the request is unblocked. |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4735 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4736 | base::test::TestFuture<PrefetchServingHandle> first_future; |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4737 | GetPrefetchToServe(first_future, GURL("https://example.com"), |
| 4738 | MainDocumentToken()); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 4739 | EXPECT_FALSE(first_future.IsReady()); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4740 | |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4741 | // The second navigation is started before the head of the prefetch response |
| 4742 | // is received. |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4743 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4744 | base::test::TestFuture<PrefetchServingHandle> second_future; |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4745 | GetPrefetchToServe(second_future, GURL("https://example.com"), |
| 4746 | MainDocumentToken()); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 4747 | EXPECT_FALSE(second_future.IsReady()); |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4748 | |
| 4749 | // The prefetch times out while PrefetchService is blocking until head. |
| 4750 | // This should unblock the request after `kBlockUntilHeadTimeout` msec without |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4751 | // setting serving_handle. |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4752 | task_environment()->FastForwardBy(base::Milliseconds(kPrefetchTimeout)); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4753 | |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4754 | EXPECT_TRUE(first_future.IsReady()); |
| 4755 | EXPECT_TRUE(second_future.IsReady()); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4756 | PrefetchServingHandle serving_handle = second_future.Take(); |
| 4757 | EXPECT_FALSE(serving_handle); |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4758 | ExpectPrefetchFailedNetError(histogram_tester, net::ERR_TIMED_OUT, |
| 4759 | GetEagernessParam(), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 4760 | /*is_accurate_triggering=*/true); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4761 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError, |
| 4762 | /*prefetch_header_latency=*/false, |
| 4763 | /*required_private_prefetch_proxy=*/false); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4764 | |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4765 | // The metrics are recorded for the first and the second navigation, as the |
| 4766 | // PrefetchContainers were initially considered as a candidate at the time of |
| 4767 | // navigation start but decided not to be used later (after |
| 4768 | // `kBlockUntilHeadTimeout` msec) due to timeout. |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4769 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4770 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4771 | histogram_tester.ExpectTotalCount( |
| 4772 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4773 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4774 | histogram_suffix), |
| 4775 | 0); |
Liviu Tinta | 1fe1a6d | 2023-09-20 19:44:04 | [diff] [blame] | 4776 | histogram_tester.ExpectUniqueTimeSample( |
| 4777 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4778 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4779 | histogram_suffix), |
| 4780 | base::Milliseconds(kBlockUntilHeadTimeout), 2); |
| 4781 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4782 | base::StringPrintf( |
| 4783 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4784 | histogram_suffix), |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4785 | true, 2); |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4786 | |
| 4787 | // The third navigation is started after the PrefetchContainer became not |
| 4788 | // servable. |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4789 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4790 | base::test::TestFuture<PrefetchServingHandle> third_future; |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4791 | GetPrefetchToServe(third_future, GURL("https://example.com"), |
| 4792 | MainDocumentToken()); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4793 | serving_handle = third_future.Take(); |
| 4794 | EXPECT_FALSE(serving_handle); |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4795 | |
| 4796 | // The metric should not be recorded for the third navigation, because the |
| 4797 | // PrefetchContainer was not servable when the third navigation starts and |
| 4798 | // thus shouldn't be considered as a candidate in the first place. |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4799 | histogram_tester.ExpectTotalCount( |
| 4800 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4801 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4802 | histogram_suffix), |
| 4803 | 0); |
Hiroshige Hayashizaki | b35b100 | 2023-10-18 02:13:25 | [diff] [blame] | 4804 | histogram_tester.ExpectUniqueTimeSample( |
Hiroshige Hayashizaki | 8d4cc04 | 2023-10-18 01:13:54 | [diff] [blame] | 4805 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4806 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4807 | histogram_suffix), |
| 4808 | base::Milliseconds(kBlockUntilHeadTimeout), 2); |
| 4809 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4810 | base::StringPrintf( |
| 4811 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4812 | histogram_suffix), |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4813 | true, 2); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4814 | } |
| 4815 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4816 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4817 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 4818 | DISABLED_CHROMEOS(FailedNetErrorWhileBlockUntilHead)) { |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4819 | base::HistogramTester histogram_tester; |
| 4820 | |
| 4821 | MakePrefetchService( |
| 4822 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4823 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 4824 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4825 | /*use_prefetch_proxy=*/false, GetEagernessParam()); |
| 4826 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 4827 | task_environment()->RunUntilIdle(); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4828 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 4829 | VerifyCommonRequestState( |
| 4830 | GURL("https://example.com"), |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4831 | {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4832 | |
| 4833 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 4834 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4835 | |
| 4836 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 4837 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4838 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 4839 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 4840 | EXPECT_FALSE(future.IsReady()); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4841 | |
| 4842 | task_environment()->FastForwardBy(base::Milliseconds(300)); |
| 4843 | |
| 4844 | // If the prefetch encounters a net error while PrefetchService is blocking |
| 4845 | // until head, then it should unblock without setting |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4846 | // serving_handle. |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4847 | CompleteResponseAndWait(net::ERR_ACCESS_DENIED, 0); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4848 | PrefetchServingHandle serving_handle = future.Take(); |
| 4849 | EXPECT_FALSE(serving_handle); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4850 | |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4851 | ExpectPrefetchFailedNetError(histogram_tester, net::ERR_ACCESS_DENIED, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4852 | GetEagernessParam(), |
| 4853 | /*is_accurate_triggering=*/true); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 4854 | ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError, |
| 4855 | /*prefetch_header_latency=*/false, |
| 4856 | /*required_private_prefetch_proxy=*/false); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4857 | |
| 4858 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4859 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4860 | histogram_tester.ExpectTotalCount( |
| 4861 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4862 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4863 | histogram_suffix), |
| 4864 | 0); |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4865 | histogram_tester.ExpectUniqueTimeSample( |
| 4866 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4867 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4868 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4869 | base::Milliseconds(300), 1); |
| 4870 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4871 | base::StringPrintf( |
| 4872 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 4873 | histogram_suffix), |
Max Curran | d74e811f | 2023-06-01 19:40:04 | [diff] [blame] | 4874 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 4875 | |
| 4876 | histogram_tester.ExpectUniqueSample( |
| 4877 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 4878 | "PerMatchingCandidate.", |
| 4879 | histogram_suffix}), |
| 4880 | PrefetchPotentialCandidateServingResult:: |
| 4881 | kNotServedUnsatisfiedPrefetchServeableState, |
| 4882 | 1); |
Max Curran | 5b4806eb | 2023-05-25 20:07:20 | [diff] [blame] | 4883 | } |
| 4884 | |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4885 | // TODO(crbug.com/40064525): For NVSBlockUntilHeadReceivedOneMatchOneTimeout, |
| 4886 | // FailedCookiesChangedAfterPrefetchStartedTimedoutNVSHintPrefetch, |
| 4887 | // FailedCookiesChangedAfterPrefetchStartedNVSHintPrefetch and |
| 4888 | // NVSBlockUntilHeadReceivedMultipleMatchesByNVSHint, consider only keeping one |
| 4889 | // of them and removing the remaining, as they almost test the same logic. |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 4890 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4891 | TEST_P( |
| 4892 | PrefetchServiceAlwaysBlockUntilHeadTest, |
| 4893 | DISABLED_CHROMEOS_AND_CASTOS(NVSBlockUntilHeadReceivedOneMatchOneTimeout)) { |
| 4894 | // The scenario is: |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4895 | // * Prefetch https://example.com/index.html?a=5 with NVS hint to |
| 4896 | // ignore "a" and send request. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4897 | // * Queue a prefetch for https://example.com/index.html?b=3 with NVS hint to |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4898 | // match but send no request. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4899 | // * Navigate to https://example.com/index.html. |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4900 | // * Receive a response for the first prefetch containing NVS header |
| 4901 | // equivalent to the NVS hint. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4902 | // * Expect https://example.com/index.html?a=5 to be served. |
| 4903 | const std::string kTestUrl = "https://example.com/index.html"; |
| 4904 | base::HistogramTester histogram_tester; |
| 4905 | |
| 4906 | MakePrefetchService( |
| 4907 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(2)); |
| 4908 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4909 | const PrefetchType prefetch_type = |
| 4910 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 4911 | /*use_prefetch_proxy=*/false, GetEagernessParam()); |
| 4912 | |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4913 | { |
| 4914 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 4915 | network::mojom::NoVarySearch::New(); |
| 4916 | no_vary_search_hint->vary_on_key_order = true; |
| 4917 | no_vary_search_hint->search_variance = |
| 4918 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 4919 | std::vector<std::string>({"a"})); |
| 4920 | MakePrefetchOnMainFrame( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4921 | GURL(kTestUrl + "?a=5"), prefetch_type, |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4922 | /* referrer */ blink::mojom::Referrer(), |
| 4923 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
| 4924 | task_environment()->RunUntilIdle(); |
| 4925 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 4926 | VerifyCommonRequestState(GURL(kTestUrl + "?a=5"), |
| 4927 | {.expected_priority = ExpectedPriorityForEagerness( |
| 4928 | GetEagernessParam())}); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4929 | } |
| 4930 | { |
| 4931 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 4932 | network::mojom::NoVarySearch::New(); |
| 4933 | no_vary_search_hint->vary_on_key_order = true; |
| 4934 | no_vary_search_hint->search_variance = |
| 4935 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 4936 | std::vector<std::string>({"b"})); |
| 4937 | MakePrefetchOnMainFrame( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4938 | GURL(kTestUrl + "?b=3"), prefetch_type, |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4939 | /* referrer */ blink::mojom::Referrer(), |
| 4940 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
| 4941 | task_environment()->RunUntilIdle(); |
| 4942 | |
| 4943 | VerifyPrefetchAttemptIsPending(GURL(kTestUrl + "?b=3")); |
| 4944 | } |
| 4945 | // Navigate to the URL before the head of the prefetch response is received |
| 4946 | NavigateInitiatedByRenderer(GURL(kTestUrl)); |
| 4947 | |
| 4948 | // Request the prefetch from the PrefetchService. `future` should be blocked |
| 4949 | // until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4950 | base::test::TestFuture<PrefetchServingHandle> future; |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4951 | GetPrefetchToServe(future, GURL(kTestUrl), MainDocumentToken()); |
| 4952 | |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 4953 | task_environment()->FastForwardBy( |
| 4954 | base::Milliseconds(kAddedToURLRequestStartLatency + kHeaderLatency)); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4955 | EXPECT_FALSE(future.IsReady()); |
| 4956 | |
| 4957 | // Sends the head of the prefetch response. This should unblock `future`. |
| 4958 | SendHeadOfResponseAndWait( |
| 4959 | net::HTTP_OK, kHTMLMimeType, |
| 4960 | /*use_prefetch_proxy=*/false, |
| 4961 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"a\")"}}, |
| 4962 | std::size(kHTMLBody)); |
| 4963 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 4964 | PrefetchServingHandle serving_handle = future.Take(); |
| 4965 | ASSERT_TRUE(serving_handle); |
| 4966 | EXPECT_EQ(serving_handle.GetPrefetchContainer()->GetURL(), |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 4967 | GURL(kTestUrl + "?a=5")); |
| 4968 | |
| 4969 | // Send the body and completion status of the request, |
| 4970 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 4971 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 4972 | |
| 4973 | // Check the metrics now that the prefetch is complete. |
| 4974 | histogram_tester.ExpectUniqueSample( |
| 4975 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 2); |
| 4976 | histogram_tester.ExpectUniqueSample( |
| 4977 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 4978 | histogram_tester.ExpectUniqueSample( |
| 4979 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 4980 | histogram_tester.ExpectUniqueSample( |
| 4981 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 4982 | histogram_tester.ExpectUniqueSample( |
| 4983 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 4984 | histogram_tester.ExpectUniqueSample( |
| 4985 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 4986 | |
| 4987 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
| 4988 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 4989 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 2); |
| 4990 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 2); |
| 4991 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 1); |
| 4992 | |
| 4993 | ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false); |
| 4994 | |
| 4995 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4996 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 4997 | histogram_tester.ExpectUniqueTimeSample( |
| 4998 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 4999 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5000 | histogram_suffix), |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 5001 | base::Milliseconds(kAddedToURLRequestStartLatency + kHeaderLatency), 1); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5002 | histogram_tester.ExpectTotalCount( |
| 5003 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5004 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5005 | histogram_suffix), |
| 5006 | 0); |
| 5007 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5008 | base::StringPrintf( |
| 5009 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5010 | histogram_suffix), |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5011 | true, 1); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5012 | } |
| 5013 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 5014 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5015 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
| 5016 | DISABLED_CHROMEOS_AND_CASTOS( |
| 5017 | FailedCookiesChangedAfterPrefetchStartedTimedoutNVSHintPrefetch)) { |
| 5018 | // The scenario is: |
| 5019 | // * Prefetch https://example.com/index.html. |
| 5020 | // * Queue a prefetch for https://example.com/index.html?a=1 with NVS hint to |
| 5021 | // match but send no head/body. |
| 5022 | // * Change the cookies. |
| 5023 | // * Navigate to https://example.com/index.html. |
| 5024 | // * Expect no prefetch to be served. |
| 5025 | const std::string kTestUrl = "https://example.com/index.html"; |
| 5026 | base::HistogramTester histogram_tester; |
| 5027 | |
| 5028 | MakePrefetchService( |
| 5029 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(2)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 5030 | |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5031 | MakePrefetchOnMainFrame( |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5032 | GURL(kTestUrl), |
| 5033 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 5034 | /*use_prefetch_proxy=*/false, GetEagernessParam())); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5035 | VerifyCommonRequestState( |
| 5036 | GURL(kTestUrl), |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5037 | {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5038 | task_environment()->RunUntilIdle(); |
| 5039 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 5040 | /*use_prefetch_proxy=*/false, |
| 5041 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 5042 | |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5043 | { |
| 5044 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 5045 | network::mojom::NoVarySearch::New(); |
| 5046 | no_vary_search_hint->vary_on_key_order = true; |
| 5047 | no_vary_search_hint->search_variance = |
| 5048 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 5049 | std::vector<std::string>({"a"})); |
| 5050 | MakePrefetchOnMainFrame( |
| 5051 | GURL(kTestUrl + "?a=1"), |
| 5052 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5053 | /*use_prefetch_proxy=*/false, GetEagernessParam()), |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5054 | /* referrer */ blink::mojom::Referrer(), |
| 5055 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
| 5056 | task_environment()->RunUntilIdle(); |
| 5057 | VerifyCommonRequestStateByUrl( |
| 5058 | GURL(kTestUrl + "?a=1"), |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5059 | {.expected_priority = |
| 5060 | ExpectedPriorityForEagerness(GetEagernessParam())}); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5061 | } |
| 5062 | |
| 5063 | // Adding a cookie after the prefetch has started will cause it to fail when |
| 5064 | // being served. |
| 5065 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 5066 | task_environment()->RunUntilIdle(); |
| 5067 | |
| 5068 | NavigateInitiatedByRenderer(GURL(kTestUrl)); |
| 5069 | |
| 5070 | histogram_tester.ExpectUniqueSample( |
| 5071 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 5072 | histogram_tester.ExpectUniqueSample( |
| 5073 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); |
| 5074 | histogram_tester.ExpectUniqueSample( |
| 5075 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); |
| 5076 | histogram_tester.ExpectUniqueSample( |
| 5077 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 5078 | histogram_tester.ExpectUniqueSample( |
| 5079 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 5080 | |
| 5081 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
| 5082 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 5083 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 2); |
| 5084 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 2); |
| 5085 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 1); |
| 5086 | |
| 5087 | // Request the prefetch from the PrefetchService. Since both prefetch |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5088 | // candidates are not eligible serving_handle will be falsy. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5089 | EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com/index.html"))); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5090 | } |
| 5091 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 5092 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5093 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
| 5094 | DISABLED_CHROMEOS_AND_CASTOS( |
| 5095 | FailedCookiesChangedAfterPrefetchStartedNVSHintPrefetch)) { |
| 5096 | // The scenario is: |
| 5097 | // * Start prefetching https://example.com/index.html but send no head/body. |
| 5098 | // * Queue a prefetch for https://example.com/index.html?a=1 with NVS hint to |
| 5099 | // match but send no head/body. |
| 5100 | // * Change the cookies. |
| 5101 | // * Navigate to https://example.com/index.html. |
| 5102 | // * Send head/body for https://example.com/index.html. |
| 5103 | // * Verify that the navigation is not waiting anymore on |
| 5104 | // https://example.com/index.html?a=1 head. |
| 5105 | // * Expect no prefetch to be served. |
| 5106 | const std::string kTestUrl = "https://example.com/index.html"; |
| 5107 | base::HistogramTester histogram_tester; |
| 5108 | |
| 5109 | MakePrefetchService( |
| 5110 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(2)); |
| 5111 | MakePrefetchOnMainFrame( |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5112 | GURL(kTestUrl), |
| 5113 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 5114 | /*use_prefetch_proxy=*/false, GetEagernessParam())); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5115 | VerifyCommonRequestState( |
| 5116 | GURL(kTestUrl), |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5117 | {.expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5118 | task_environment()->RunUntilIdle(); |
| 5119 | { |
| 5120 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 5121 | network::mojom::NoVarySearch::New(); |
| 5122 | no_vary_search_hint->vary_on_key_order = true; |
| 5123 | no_vary_search_hint->search_variance = |
| 5124 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 5125 | std::vector<std::string>({"a"})); |
| 5126 | GURL url_2{kTestUrl + "?a=1"}; |
| 5127 | MakePrefetchOnMainFrame( |
| 5128 | url_2, |
| 5129 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5130 | /*use_prefetch_proxy=*/false, GetEagernessParam()), |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5131 | /* referrer */ blink::mojom::Referrer(), |
| 5132 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
| 5133 | task_environment()->RunUntilIdle(); |
| 5134 | VerifyPrefetchAttemptIsPending(url_2); |
| 5135 | } |
| 5136 | |
| 5137 | // Adding a cookie after the prefetch has started will cause it to fail when |
| 5138 | // being served. |
| 5139 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 5140 | task_environment()->RunUntilIdle(); |
| 5141 | |
| 5142 | NavigateInitiatedByRenderer(GURL(kTestUrl)); |
| 5143 | |
| 5144 | // Request the prefetch from the PrefetchService. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5145 | base::test::TestFuture<PrefetchServingHandle> future; |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5146 | GetPrefetchToServe(future, GURL(kTestUrl), MainDocumentToken()); |
| 5147 | EXPECT_FALSE(future.IsReady()); |
| 5148 | task_environment()->RunUntilIdle(); |
| 5149 | EXPECT_FALSE(future.IsReady()); |
| 5150 | |
| 5151 | // Sends the head of the prefetch response. This should not trigger the above |
| 5152 | // callback. |
| 5153 | SendHeadOfResponseAndWait( |
| 5154 | net::HTTP_OK, kHTMLMimeType, |
| 5155 | /*use_prefetch_proxy=*/false, |
| 5156 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"e\")"}}, |
| 5157 | std::size(kHTMLBody)); |
| 5158 | |
| 5159 | EXPECT_TRUE(future.IsReady()); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5160 | PrefetchServingHandle serving_handle = future.Take(); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5161 | // Both prefetch candidates are not eligible. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5162 | EXPECT_FALSE(serving_handle); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5163 | |
| 5164 | // Send the body and completion status of the request, |
| 5165 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 5166 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 5167 | |
| 5168 | histogram_tester.ExpectUniqueSample( |
| 5169 | "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); |
| 5170 | // We cancel the streaming of this prefetch because we know we cannot use it. |
| 5171 | histogram_tester.ExpectUniqueSample( |
| 5172 | "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 0); |
| 5173 | histogram_tester.ExpectUniqueSample( |
| 5174 | "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 0); |
| 5175 | histogram_tester.ExpectUniqueSample( |
| 5176 | "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); |
| 5177 | histogram_tester.ExpectUniqueSample( |
| 5178 | "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); |
| 5179 | |
| 5180 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
| 5181 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 5182 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 2); |
| 5183 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 2); |
| 5184 | // None of the prefetches were successful because of the cookie change. |
| 5185 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 0); |
| 5186 | |
| 5187 | // Serving page metrics prefetch_header_latency is logged at response |
| 5188 | // complete. Since we cancel streaming the response, this should not be set. |
| 5189 | ExpectServingMetrics(PrefetchStatus::kPrefetchNotUsedCookiesChanged, |
| 5190 | /*prefetch_header_latency=*/false, |
| 5191 | /*required_private_prefetch_proxy=*/false); |
| 5192 | } |
| 5193 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 5194 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5195 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
| 5196 | DISABLED_CHROMEOS_AND_CASTOS( |
| 5197 | NVSBlockUntilHeadReceivedMultipleMatchesByNVSHint)) { |
| 5198 | // The scenario is: |
| 5199 | // * Prefetch https://example.com/index.html?a=5 with NVS hint to ignore "a" |
| 5200 | // but mismatched NVS header and send head/body. |
| 5201 | // * Queue a prefetch for https://example.com/index.html?b=3 with NVS hint/NVS |
| 5202 | // header to ignore "b" and send head/body. |
| 5203 | // * Navigate to https://example.com/index.html. |
| 5204 | // * Make sure to receive ?a=5 prefetch before ?b=3. |
| 5205 | // * Expect https://example.com/index.html?b=3 not to be served, because it |
| 5206 | // cannot improve the performance (even worse, it would block the real |
| 5207 | // navigation). |
| 5208 | const std::string kTestUrl = "https://example.com/index.html"; |
| 5209 | base::HistogramTester histogram_tester; |
| 5210 | |
| 5211 | MakePrefetchService( |
| 5212 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(2)); |
| 5213 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5214 | const PrefetchType prefetch_type = |
| 5215 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 5216 | /*use_prefetch_proxy=*/false, GetEagernessParam()); |
| 5217 | |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5218 | { |
| 5219 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 5220 | network::mojom::NoVarySearch::New(); |
| 5221 | no_vary_search_hint->vary_on_key_order = true; |
| 5222 | no_vary_search_hint->search_variance = |
| 5223 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 5224 | std::vector<std::string>({"a"})); |
| 5225 | GURL not_matched_url = GURL(kTestUrl + "?a=5"); |
| 5226 | MakePrefetchOnMainFrame( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5227 | not_matched_url, prefetch_type, |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5228 | /* referrer */ blink::mojom::Referrer(), |
| 5229 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
| 5230 | task_environment()->RunUntilIdle(); |
| 5231 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5232 | VerifyCommonRequestState(not_matched_url, |
| 5233 | {.expected_priority = ExpectedPriorityForEagerness( |
| 5234 | GetEagernessParam())}); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5235 | } |
| 5236 | { |
| 5237 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 5238 | network::mojom::NoVarySearch::New(); |
| 5239 | no_vary_search_hint->vary_on_key_order = true; |
| 5240 | no_vary_search_hint->search_variance = |
| 5241 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 5242 | std::vector<std::string>({"b"})); |
| 5243 | GURL matched_url = GURL(kTestUrl + "?b=3"); |
| 5244 | MakePrefetchOnMainFrame( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5245 | matched_url, prefetch_type, |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5246 | /* referrer */ blink::mojom::Referrer(), |
| 5247 | /* no_vary_search_hint */ std::move(no_vary_search_hint)); |
| 5248 | task_environment()->RunUntilIdle(); |
| 5249 | VerifyPrefetchAttemptIsPending(matched_url); |
| 5250 | } |
| 5251 | // Navigate to the URL before the head of the prefetch response is received |
| 5252 | NavigateInitiatedByRenderer(GURL(kTestUrl)); |
| 5253 | |
| 5254 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 5255 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5256 | base::test::TestFuture<PrefetchServingHandle> future; |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5257 | GetPrefetchToServe(future, GURL(kTestUrl), MainDocumentToken()); |
| 5258 | EXPECT_FALSE(future.IsReady()); |
| 5259 | task_environment()->RunUntilIdle(); |
| 5260 | // Sends the head of the prefetch response. This should not trigger the above |
| 5261 | // callback. |
| 5262 | SendHeadOfResponseAndWait( |
| 5263 | net::HTTP_OK, kHTMLMimeType, |
| 5264 | /*use_prefetch_proxy=*/false, |
| 5265 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"e\")"}}, |
| 5266 | std::size(kHTMLBody)); |
| 5267 | |
| 5268 | // The second should not be used for a real navigation. The rationale is that: |
| 5269 | // if a prefetch request has not started before a real navigation starts, then |
| 5270 | // it cannot help improve the performance, and in the worst case it would |
| 5271 | // block the real navigation. |
| 5272 | EXPECT_TRUE(future.IsReady()); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5273 | PrefetchServingHandle serving_handle = future.Take(); |
| 5274 | ASSERT_FALSE(serving_handle); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5275 | |
| 5276 | // Send the body and completion status of the request, |
| 5277 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 5278 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 5279 | |
| 5280 | SendHeadOfResponseForUrlAndWait( |
| 5281 | GURL(kTestUrl + "?b=3"), net::HTTP_OK, kHTMLMimeType, |
| 5282 | /*use_prefetch_proxy=*/false, |
| 5283 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"b\")"}}, |
| 5284 | std::size(kHTMLBody)); |
| 5285 | // Check the metrics now that the prefetch is complete. |
| 5286 | histogram_tester.ExpectUniqueSample( |
| 5287 | "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 2); |
| 5288 | |
| 5289 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
| 5290 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
| 5291 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 2); |
| 5292 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 2); |
| 5293 | |
| 5294 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5295 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5296 | histogram_tester.ExpectTotalCount( |
| 5297 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5298 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5299 | histogram_suffix), |
| 5300 | 0); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5301 | histogram_tester.ExpectUniqueTimeSample( |
| 5302 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5303 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5304 | histogram_suffix), |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5305 | base::Milliseconds(0), 1); |
| 5306 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5307 | base::StringPrintf( |
| 5308 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5309 | histogram_suffix), |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 5310 | true, 1); |
| 5311 | } |
| 5312 | |
Hiroshige Hayashizaki | ce728e4a | 2025-03-13 20:29:10 | [diff] [blame] | 5313 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 5314 | DISABLED_CHROMEOS(BlockUntilHeadTimedout)) { |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5315 | base::HistogramTester histogram_tester; |
| 5316 | |
| 5317 | MakePrefetchService( |
| 5318 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 5319 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5320 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 5321 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5322 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 5323 | |
| 5324 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 5325 | task_environment()->RunUntilIdle(); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5326 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 5327 | VerifyCommonRequestState( |
| 5328 | GURL("https://example.com"), |
| 5329 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5330 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5331 | |
| 5332 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 5333 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5334 | |
| 5335 | // Request the prefetch from the PrefetchService. The given callback should be |
| 5336 | // triggered once the timeout is exceeded. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5337 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 5338 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 5339 | EXPECT_FALSE(future.IsReady()); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5340 | |
| 5341 | task_environment()->FastForwardBy(base::Milliseconds(1000)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5342 | PrefetchServingHandle serving_handle = future.Take(); |
| 5343 | EXPECT_FALSE(serving_handle); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5344 | |
| 5345 | // If the prefetch is received after the block until head has timed out, it |
| 5346 | // will not be used. |
| 5347 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 5348 | /*use_prefetch_proxy=*/true, |
| 5349 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 5350 | |
| 5351 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5352 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 5353 | GetEagernessParam(), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 5354 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 5355 | ExpectServingMetricsSuccess(); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5356 | EXPECT_FALSE(serving_handle); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5357 | |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5358 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5359 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5360 | histogram_tester.ExpectTotalCount( |
| 5361 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5362 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5363 | histogram_suffix), |
| 5364 | 0); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5365 | histogram_tester.ExpectUniqueTimeSample( |
| 5366 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5367 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5368 | histogram_suffix), |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5369 | base::Milliseconds(1000), 1); |
| 5370 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5371 | base::StringPrintf( |
| 5372 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5373 | histogram_suffix), |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5374 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 5375 | |
| 5376 | histogram_tester.ExpectUniqueSample( |
| 5377 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 5378 | "PerMatchingCandidate.", |
| 5379 | histogram_suffix}), |
| 5380 | PrefetchPotentialCandidateServingResult::kNotServedBlockUntilHeadTimeout, |
| 5381 | 1); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5382 | } |
| 5383 | |
Hiroshige Hayashizaki | ce728e4a | 2025-03-13 20:29:10 | [diff] [blame] | 5384 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 5385 | DISABLED_CHROMEOS(HeadReceivedBeforeTimeout)) { |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5386 | base::HistogramTester histogram_tester; |
| 5387 | |
| 5388 | MakePrefetchService( |
| 5389 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 5390 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5391 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 5392 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5393 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 5394 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 5395 | task_environment()->RunUntilIdle(); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5396 | |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 5397 | VerifyCommonRequestState( |
| 5398 | GURL("https://example.com"), |
| 5399 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5400 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5401 | |
| 5402 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 5403 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5404 | |
| 5405 | // Request the prefetch from the PrefetchService. The given callback should be |
| 5406 | // triggered once the timeout is exceeded. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5407 | base::test::TestFuture<PrefetchServingHandle> future; |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 5408 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
Hiroshige Hayashizaki | bc78062 | 2023-09-05 19:07:33 | [diff] [blame] | 5409 | EXPECT_FALSE(future.IsReady()); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5410 | |
| 5411 | task_environment()->FastForwardBy(base::Milliseconds(1000)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5412 | PrefetchServingHandle serving_handle = future.Take(); |
| 5413 | EXPECT_FALSE(serving_handle); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5414 | |
| 5415 | // If the prefetch is received after the block until head has timed out, it |
| 5416 | // will not be used. |
| 5417 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 5418 | /*use_prefetch_proxy=*/true, |
| 5419 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 5420 | |
| 5421 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5422 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 5423 | GetEagernessParam(), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 5424 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 5425 | ExpectServingMetricsSuccess(); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5426 | EXPECT_FALSE(serving_handle); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5427 | |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5428 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5429 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5430 | histogram_tester.ExpectTotalCount( |
| 5431 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5432 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5433 | histogram_suffix), |
| 5434 | 0); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5435 | histogram_tester.ExpectUniqueTimeSample( |
| 5436 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5437 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5438 | histogram_suffix), |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5439 | base::Milliseconds(1000), 1); |
| 5440 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5441 | base::StringPrintf( |
| 5442 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5443 | histogram_suffix), |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5444 | true, 1); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 5445 | |
| 5446 | histogram_tester.ExpectUniqueSample( |
| 5447 | base::StrCat({"Prefetch.PrefetchPotentialCandidateServingResult." |
| 5448 | "PerMatchingCandidate.", |
| 5449 | histogram_suffix}), |
| 5450 | PrefetchPotentialCandidateServingResult::kNotServedBlockUntilHeadTimeout, |
| 5451 | 1); |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 5452 | } |
| 5453 | |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 5454 | // TODO(crbug.com/40249481): Test flaky on trybots. |
Hiroshige Hayashizaki | ce728e4a | 2025-03-13 20:29:10 | [diff] [blame] | 5455 | TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, |
kenoss | da6656b | 2024-07-23 02:18:48 | [diff] [blame] | 5456 | DISABLED_CHROMEOS(MultipleGetPrefetchToServe)) { |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 5457 | base::HistogramTester histogram_tester; |
| 5458 | |
| 5459 | MakePrefetchService( |
| 5460 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 5461 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5462 | const PrefetchType prefetch_type = |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 5463 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5464 | /*use_prefetch_proxy=*/true, GetEagernessParam()); |
| 5465 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 5466 | task_environment()->RunUntilIdle(); |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 5467 | |
| 5468 | VerifyCommonRequestState( |
| 5469 | GURL("https://example.com"), |
| 5470 | {.use_prefetch_proxy = true, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5471 | .expected_priority = ExpectedPriorityForEagerness(GetEagernessParam())}); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 5472 | |
| 5473 | // Navigate to the URL before the head of the prefetch response is received |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 5474 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 5475 | // Request the prefetch from the PrefetchService. The same prefetch will be |
| 5476 | // requested again, so this callback will not be called. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5477 | base::test::TestFuture<PrefetchServingHandle> first_future; |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 5478 | GetPrefetchToServe(first_future, GURL("https://example.com"), |
| 5479 | MainDocumentToken()); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 5480 | |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 5481 | NavigateInitiatedByRenderer(GURL("https://example.com")); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 5482 | // Request the prefetch from the PrefetchService a second time. This |
| 5483 | // callback should be triggered once the timeout is exceeded. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5484 | base::test::TestFuture<PrefetchServingHandle> second_future; |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 5485 | GetPrefetchToServe(second_future, GURL("https://example.com"), |
| 5486 | MainDocumentToken()); |
| 5487 | EXPECT_FALSE(second_future.IsReady()); |
| 5488 | task_environment()->FastForwardBy(base::Milliseconds(1000)); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5489 | EXPECT_TRUE(first_future.IsReady()); |
| 5490 | EXPECT_TRUE(second_future.IsReady()); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5491 | PrefetchServingHandle serving_handle = second_future.Take(); |
| 5492 | EXPECT_FALSE(serving_handle); |
Hiroshige Hayashizaki | fc691c5 | 2023-10-23 10:07:54 | [diff] [blame] | 5493 | |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 5494 | // If the prefetch is received after the block until head has timed out, it |
| 5495 | // will not be used. |
| 5496 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 5497 | /*use_prefetch_proxy=*/true, |
| 5498 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 5499 | |
| 5500 | // Check the metrics now that the prefetch is complete. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5501 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
| 5502 | GetEagernessParam(), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 5503 | /*is_accurate=*/true); |
Hiroshige Hayashizaki | 120cc23d | 2023-10-21 00:44:46 | [diff] [blame] | 5504 | ExpectServingMetricsSuccess(); |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 5505 | |
| 5506 | std::string histogram_suffix = |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5507 | GetMetricsSuffixTriggerTypeAndEagerness(prefetch_type, std::nullopt); |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5508 | histogram_tester.ExpectTotalCount( |
| 5509 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5510 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5511 | histogram_suffix), |
| 5512 | 0); |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 5513 | histogram_tester.ExpectUniqueTimeSample( |
| 5514 | base::StringPrintf( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5515 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5516 | histogram_suffix), |
| 5517 | base::Milliseconds(1000), 2); |
| 5518 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 5519 | base::StringPrintf( |
| 5520 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5521 | histogram_suffix), |
kenoss | 968f5dd | 2025-03-10 06:27:40 | [diff] [blame] | 5522 | true, 2); |
Max Curran | aefeb77 | 2023-08-01 18:03:10 | [diff] [blame] | 5523 | } |
| 5524 | |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5525 | class PrefetchServiceDisableBlockUntilHeadTimeoutTest |
| 5526 | : public PrefetchServiceTestBase, |
| 5527 | public WithPrefetchServiceRearchParam, |
| 5528 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
| 5529 | public: |
| 5530 | PrefetchServiceDisableBlockUntilHeadTimeoutTest() |
| 5531 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 5532 | |
| 5533 | static constexpr int kBlockUntilHeadTimeout = 1000; |
| 5534 | |
| 5535 | void InitScopedFeatureList() override { |
| 5536 | InitBaseParams(); |
| 5537 | InitRearchFeatures(); |
| 5538 | // Override `kPrefetchUseContentRefactor`. |
| 5539 | scoped_feature_list_.InitWithFeaturesAndParameters( |
| 5540 | {{features::kPrefetchUseContentRefactor, |
| 5541 | { |
| 5542 | {"ineligible_decoy_request_probability", "0"}, |
| 5543 | {"prefetch_container_lifetime_s", "-1"}, |
| 5544 | {"prefetch_timeout_ms", "10000"}, |
| 5545 | // Initialize > 0ms timeouts for testing purposes. |
| 5546 | {"block_until_head_timeout_embedder_prefetch", |
| 5547 | base::NumberToString(kBlockUntilHeadTimeout)}, |
| 5548 | }}}, |
| 5549 | {}); |
| 5550 | } |
| 5551 | |
| 5552 | private: |
| 5553 | base::test::ScopedFeatureList scoped_feature_list_; |
| 5554 | }; |
| 5555 | |
| 5556 | INSTANTIATE_TEST_SUITE_P( |
| 5557 | ParametrizedTests, |
| 5558 | PrefetchServiceDisableBlockUntilHeadTimeoutTest, |
| 5559 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 5560 | |
| 5561 | // Tests that the default `BlockUntilHeadTimeout` is used if |
| 5562 | // `should_disable_block_until_head_timeout` is false. |
| 5563 | TEST_P(PrefetchServiceDisableBlockUntilHeadTimeoutTest, |
| 5564 | DISABLED_CHROMEOS(DisableBlockUntilHeadTimeoutFalse)) { |
| 5565 | base::HistogramTester histogram_tester; |
| 5566 | MakePrefetchService( |
| 5567 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 5568 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 5569 | |
| 5570 | // Set `should_disable_block_until_head_timeout` to false. |
| 5571 | std::unique_ptr<content::PrefetchHandle> handle = |
| 5572 | MakePrefetchFromBrowserContext( |
| 5573 | GURL("https://example.com"), |
| 5574 | /*no_vary_search_data=*/std::nullopt, /*additional_headers=*/{}, |
| 5575 | /*request_status_listener=*/nullptr, |
| 5576 | base::Seconds(/* 10 minutes */ 60 * 10), |
| 5577 | /*should_disable_block_until_head_timeout=*/false); |
| 5578 | task_environment()->RunUntilIdle(); |
| 5579 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 5580 | VerifyCommonRequestStateForBrowserContextPrefetch( |
| 5581 | GURL("https://example.com"), {.use_prefetch_proxy = false}); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5582 | |
| 5583 | // Simulate a navigation. The prefetch should not be served after a timeout. |
| 5584 | std::unique_ptr<NavigationResult> navigation_result = |
| 5585 | SimulatePartOfNavigation(GURL("https://example.com"), |
| 5586 | /*is_renderer_initiated=*/false, |
| 5587 | /*is_nav_prerender=*/false); |
| 5588 | task_environment()->RunUntilIdle(); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5589 | ASSERT_FALSE(navigation_result->serving_handle_future.IsReady()); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5590 | task_environment()->FastForwardBy(base::Milliseconds(kBlockUntilHeadTimeout)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5591 | EXPECT_TRUE(navigation_result->serving_handle_future.IsReady()); |
| 5592 | EXPECT_FALSE(navigation_result->serving_handle_future.Take()); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5593 | |
| 5594 | auto metrics_suffix = GetMetricsSuffixTriggerTypeAndEagerness( |
| 5595 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 5596 | /*use_prefetch_proxy=*/false), |
| 5597 | test::kPreloadingEmbedderHistgramSuffixForTesting); |
| 5598 | histogram_tester.ExpectUniqueSample( |
| 5599 | base::StringPrintf( |
| 5600 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5601 | metrics_suffix), |
| 5602 | true, 1); |
| 5603 | histogram_tester.ExpectUniqueTimeSample( |
| 5604 | base::StringPrintf( |
| 5605 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
| 5606 | metrics_suffix), |
| 5607 | base::Milliseconds(kBlockUntilHeadTimeout), 1); |
| 5608 | histogram_tester.ExpectTotalCount( |
| 5609 | base::StringPrintf( |
| 5610 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
| 5611 | metrics_suffix), |
| 5612 | 0); |
| 5613 | } |
| 5614 | |
| 5615 | // Tests that the default `BlockUntilHeadTimeout` is ignored if |
| 5616 | // `should_disable_block_until_head_timeout` is true. |
| 5617 | TEST_P(PrefetchServiceDisableBlockUntilHeadTimeoutTest, |
| 5618 | DISABLED_CHROMEOS(DisableBlockUntilHeadTimeoutTrue)) { |
| 5619 | base::HistogramTester histogram_tester; |
| 5620 | MakePrefetchService( |
| 5621 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 5622 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 5623 | |
| 5624 | // Set `should_disable_block_until_head_timeout` to true. |
| 5625 | std::unique_ptr<content::PrefetchHandle> handle = |
| 5626 | MakePrefetchFromBrowserContext( |
| 5627 | GURL("https://example.com"), |
| 5628 | /*no_vary_search_data=*/std::nullopt, /*additional_headers=*/{}, |
| 5629 | /*request_status_listener=*/nullptr, |
| 5630 | base::Seconds(/* 10 minutes */ 60 * 10), |
| 5631 | /*should_disable_block_until_head_timeout=*/true); |
| 5632 | task_environment()->RunUntilIdle(); |
| 5633 | |
Taiyo Mizuhashi | d13f8ca | 2025-06-23 13:29:02 | [diff] [blame] | 5634 | VerifyCommonRequestStateForBrowserContextPrefetch( |
| 5635 | GURL("https://example.com"), {.use_prefetch_proxy = false}); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5636 | |
| 5637 | // Simulate a navigation. The prefetch still blocks the navigation, after the |
| 5638 | // default timeout/ |
| 5639 | std::unique_ptr<NavigationResult> navigation_result = |
| 5640 | SimulatePartOfNavigation(GURL("https://example.com"), |
| 5641 | /*is_renderer_initiated=*/false, |
| 5642 | /*is_nav_prerender=*/false); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5643 | ASSERT_FALSE(navigation_result->serving_handle_future.IsReady()); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5644 | task_environment()->FastForwardBy(base::Milliseconds(kBlockUntilHeadTimeout)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5645 | EXPECT_FALSE(navigation_result->serving_handle_future.IsReady()); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5646 | |
| 5647 | // It is eventually served after creating a response head. |
| 5648 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 5649 | /*use_prefetch_proxy=*/true, |
| 5650 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5651 | EXPECT_TRUE(navigation_result->serving_handle_future.IsReady()); |
| 5652 | EXPECT_TRUE(navigation_result->serving_handle_future.Take()); |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 5653 | |
| 5654 | auto metrics_suffix = GetMetricsSuffixTriggerTypeAndEagerness( |
| 5655 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 5656 | /*use_prefetch_proxy=*/false), |
| 5657 | test::kPreloadingEmbedderHistgramSuffixForTesting); |
| 5658 | histogram_tester.ExpectUniqueSample( |
| 5659 | base::StringPrintf( |
| 5660 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate.%s", |
| 5661 | metrics_suffix), |
| 5662 | true, 1); |
| 5663 | histogram_tester.ExpectUniqueTimeSample( |
| 5664 | base::StringPrintf( |
| 5665 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served.%s", |
| 5666 | metrics_suffix), |
| 5667 | base::Milliseconds(kBlockUntilHeadTimeout), 1); |
| 5668 | histogram_tester.ExpectTotalCount( |
| 5669 | base::StringPrintf( |
| 5670 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed.%s", |
| 5671 | metrics_suffix), |
| 5672 | 0); |
| 5673 | } |
| 5674 | |
Taiyo Mizuhashi | af23c43 | 2025-06-23 07:41:37 | [diff] [blame] | 5675 | // Tests that browsing data removal for prefetch is performed per 1) its |
| 5676 | // `referring_origin` 2) if that is std::nullopt, then prefetch url. |
| 5677 | TEST_P(PrefetchServiceTest, PrefetchEviction) { |
| 5678 | base::HistogramTester histogram_tester; |
| 5679 | |
| 5680 | struct TestCase { |
| 5681 | const std::optional<url::Origin> referring_origin; |
| 5682 | const GURL prefetch_url; |
| 5683 | }; |
| 5684 | const std::vector<TestCase> test_cases = { |
| 5685 | {url::Origin::Create(GURL("https://a.test")), GURL("https://a.test/0")}, |
| 5686 | {url::Origin::Create(GURL("https://a.test")), GURL("https://b.test/1")}, |
| 5687 | {url::Origin::Create(GURL("https://b.test")), GURL("https://a.test/2")}, |
| 5688 | {url::Origin::Create(GURL("https://b.test")), GURL("https://b.test/3")}, |
| 5689 | {std::nullopt, GURL("https://a.test/4")}, |
| 5690 | {std::nullopt, GURL("https://b.test/5")}, |
| 5691 | }; |
| 5692 | |
| 5693 | MakePrefetchService( |
| 5694 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 5695 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 5696 | PrefetchService* prefetch_service = |
| 5697 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 5698 | |
| 5699 | std::vector<std::unique_ptr<PrefetchHandle>> handles; |
| 5700 | for (const auto& test_case : test_cases) { |
| 5701 | handles.push_back( |
| 5702 | MakePrefetchFromEmbedder(test_case.prefetch_url, |
| 5703 | PrefetchType(PreloadingTriggerType::kEmbedder, |
| 5704 | /*use_prefetch_proxy=*/false), |
| 5705 | /*referrer=*/{}, test_case.referring_origin)); |
| 5706 | } |
| 5707 | task_environment()->RunUntilIdle(); |
| 5708 | |
| 5709 | // Evict prefetches from "a.test". The prefetch for "a.test" with no |
| 5710 | // `referring_origin` should also be removed. |
| 5711 | auto filter_builder = BrowsingDataFilterBuilder::Create( |
| 5712 | BrowsingDataFilterBuilder::Mode::kDelete); |
| 5713 | filter_builder->AddOrigin(url::Origin::Create(GURL("https://a.test"))); |
| 5714 | auto filter = filter_builder->BuildStorageKeyFilter(); |
| 5715 | prefetch_service->EvictPrefetchesForBrowsingDataRemoval( |
| 5716 | filter, PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved); |
| 5717 | task_environment()->RunUntilIdle(); |
| 5718 | EXPECT_FALSE(handles[0]->IsAlive()); |
| 5719 | EXPECT_FALSE(handles[1]->IsAlive()); |
| 5720 | EXPECT_FALSE(handles[4]->IsAlive()); |
| 5721 | EXPECT_TRUE(handles[2]->IsAlive()); |
| 5722 | EXPECT_TRUE(handles[3]->IsAlive()); |
| 5723 | EXPECT_TRUE(handles[5]->IsAlive()); |
| 5724 | histogram_tester.ExpectUniqueSample( |
| 5725 | "Preloading.Prefetch.PrefetchStatus", |
| 5726 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved, 3); |
| 5727 | |
| 5728 | // Attempt to clear all the cache. The remaining prefetches are also removed. |
| 5729 | prefetch_service->EvictPrefetchesForBrowsingDataRemoval( |
| 5730 | BrowsingDataFilterBuilder::Create( |
| 5731 | BrowsingDataFilterBuilder::Mode::kPreserve) |
| 5732 | ->BuildStorageKeyFilter(), |
| 5733 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved); |
| 5734 | task_environment()->RunUntilIdle(); |
| 5735 | EXPECT_FALSE(handles[2]->IsAlive()); |
| 5736 | EXPECT_FALSE(handles[3]->IsAlive()); |
| 5737 | EXPECT_FALSE(handles[5]->IsAlive()); |
| 5738 | histogram_tester.ExpectUniqueSample( |
| 5739 | "Preloading.Prefetch.PrefetchStatus", |
| 5740 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved, 6); |
| 5741 | } |
| 5742 | |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5743 | // Tests that the prefetch eviction for eligible but not started triggers (i.e. |
| 5744 | // `PreloadingAttempt`'s `PreloadingHoldbackStatus` is `kUnspecified`) causes no |
| 5745 | // crash. This is a regression test of crbug.com/404703517. |
| 5746 | TEST_P(PrefetchServiceTest, PrefetchEvictionForEligibleButNotStartedPrefetch) { |
| 5747 | NavigateAndCommit(GURL("https://example.com")); |
| 5748 | MakePrefetchService( |
| 5749 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 5750 | /*num_on_prefetch_likely_calls=*/2)); |
| 5751 | |
| 5752 | const auto url_1 = GURL("https://example.com/one"); |
| 5753 | const auto url_2 = GURL("https://example.com/two"); |
| 5754 | auto candidate_1 = blink::mojom::SpeculationCandidate::New(); |
| 5755 | candidate_1->url = url_1; |
| 5756 | candidate_1->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5757 | candidate_1->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5758 | candidate_1->referrer = blink::mojom::Referrer::New(); |
| 5759 | auto candidate_2 = candidate_1.Clone(); |
| 5760 | candidate_2->url = url_2; |
| 5761 | |
| 5762 | // Send `candidate_1` and `candidate_2`. |
| 5763 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 5764 | candidates.push_back(candidate_1.Clone()); |
| 5765 | candidates.push_back(candidate_2.Clone()); |
| 5766 | auto* prefetch_document_manager = |
| 5767 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 5768 | prefetch_document_manager->ProcessCandidates(candidates); |
| 5769 | task_environment()->RunUntilIdle(); |
| 5770 | |
| 5771 | PrefetchService* prefetch_service = |
| 5772 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 5773 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2; |
| 5774 | std::tie(std::ignore, prefetch_container1) = |
| 5775 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 5776 | PrefetchContainer::Key(MainDocumentToken(), url_1))[0]; |
| 5777 | std::tie(std::ignore, prefetch_container2) = |
| 5778 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 5779 | PrefetchContainer::Key(MainDocumentToken(), url_2))[0]; |
| 5780 | |
| 5781 | // `candidate_1` should be started, while `candidate_2` stays in a queue. |
| 5782 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 5783 | PrefetchContainer::LoadState::kStarted); |
| 5784 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 5785 | PrefetchContainer::LoadState::kEligible); |
| 5786 | |
| 5787 | // Try to evict. |
| 5788 | prefetch_service->EvictPrefetchesForBrowsingDataRemoval( |
| 5789 | BrowsingDataFilterBuilder::Create( |
| 5790 | BrowsingDataFilterBuilder::Mode::kPreserve) |
| 5791 | ->BuildStorageKeyFilter(), |
| 5792 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved); |
| 5793 | |
| 5794 | // - `candidate_1` should have `PreloadingEligibility::kEligible`, |
| 5795 | // `PreloadingHoldbackStatus::kAllowed` and |
| 5796 | // `PreloadingTriggeringOutcome::kFailure` as |
| 5797 | // `kPrefetchEvictedAfterBrowsingDataRemoved`. |
| 5798 | // - `candidate_2` should have `PreloadingEligibility::kEligible` but |
| 5799 | // `PreloadingHoldbackStatus::kUnspecified` (as the holdback status will be |
| 5800 | // determined when the prefetch is actually started) and |
| 5801 | // `PreloadingTriggeringOutcome::kUnspecified`. |
| 5802 | { |
| 5803 | const auto source_id = ForceLogsUploadAndGetUkmId(); |
| 5804 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 5805 | ukm::builders::Preloading_Attempt::kEntryName, |
| 5806 | test::kPreloadingAttemptUkmMetrics); |
| 5807 | ASSERT_EQ(actual_attempts.size(), 2u); |
| 5808 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> expected_attempts = |
| 5809 | {attempt_entry_builder()->BuildEntry( |
| 5810 | source_id, PreloadingType::kPrefetch, |
| 5811 | PreloadingEligibility::kEligible, |
| 5812 | PreloadingHoldbackStatus::kAllowed, |
| 5813 | PreloadingTriggeringOutcome::kFailure, |
| 5814 | ToPreloadingFailureReason( |
| 5815 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved), |
| 5816 | /*accurate=*/false, |
| 5817 | /*ready_time=*/std::nullopt, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5818 | blink::mojom::SpeculationEagerness::kImmediate), |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5819 | attempt_entry_builder()->BuildEntry( |
| 5820 | source_id, PreloadingType::kPrefetch, |
| 5821 | PreloadingEligibility::kEligible, |
| 5822 | PreloadingHoldbackStatus::kUnspecified, |
| 5823 | PreloadingTriggeringOutcome::kUnspecified, |
| 5824 | PreloadingFailureReason::kUnspecified, |
| 5825 | /*accurate=*/false, |
| 5826 | /*ready_time=*/std::nullopt, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5827 | blink::mojom::SpeculationEagerness::kImmediate)}; |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5828 | ASSERT_THAT(actual_attempts, |
| 5829 | testing::UnorderedElementsAreArray(expected_attempts)) |
| 5830 | << test::ActualVsExpectedUkmEntriesToString(actual_attempts, |
| 5831 | expected_attempts); |
| 5832 | } |
| 5833 | } |
| 5834 | |
| 5835 | // Tests that the prefetch eviction during eligiblity check (i.e. |
| 5836 | // `PreloadingAttempt`'s `PreloadingEligibility` is `kUnspecified`) causes no |
| 5837 | // crash. This is a regression test of crbug.com/404703517. |
| 5838 | TEST_P(PrefetchServiceTest, PrefetchEvictionDuringEligiblityCheck) { |
| 5839 | NavigateAndCommit(GURL("https://example.com")); |
| 5840 | MakePrefetchService( |
| 5841 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 5842 | /*num_on_prefetch_likely_calls=*/1)); |
| 5843 | PrefetchService* prefetch_service = |
| 5844 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 5845 | |
| 5846 | // Pause the elibility check. |
| 5847 | base::test::TestFuture<base::OnceClosure> eligibility_check_callback_future; |
| 5848 | prefetch_service->SetDelayEligibilityCheckForTesting(base::BindRepeating( |
| 5849 | [](base::test::TestFuture<base::OnceClosure>* |
| 5850 | eligibility_check_callback_future, |
| 5851 | base::OnceClosure callback) { |
| 5852 | eligibility_check_callback_future->SetValue(std::move(callback)); |
| 5853 | }, |
| 5854 | base::Unretained(&eligibility_check_callback_future))); |
| 5855 | |
| 5856 | const auto url_1 = GURL("https://example.com/one"); |
| 5857 | auto candidate_1 = blink::mojom::SpeculationCandidate::New(); |
| 5858 | candidate_1->url = url_1; |
| 5859 | candidate_1->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5860 | candidate_1->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5861 | candidate_1->referrer = blink::mojom::Referrer::New(); |
| 5862 | |
| 5863 | // Send `candidate_1`; |
| 5864 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 5865 | candidates.push_back(candidate_1.Clone()); |
| 5866 | auto* prefetch_document_manager = |
| 5867 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 5868 | prefetch_document_manager->ProcessCandidates(candidates); |
| 5869 | task_environment()->RunUntilIdle(); |
| 5870 | |
| 5871 | base::WeakPtr<PrefetchContainer> prefetch_container1; |
| 5872 | std::tie(std::ignore, prefetch_container1) = |
| 5873 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 5874 | PrefetchContainer::Key(MainDocumentToken(), url_1))[0]; |
| 5875 | |
| 5876 | // `candidate_1` should be on a way of eligibility check. |
| 5877 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 5878 | PrefetchContainer::LoadState::kNotStarted); |
| 5879 | |
| 5880 | // Try to evict. |
| 5881 | prefetch_service->EvictPrefetchesForBrowsingDataRemoval( |
| 5882 | BrowsingDataFilterBuilder::Create( |
| 5883 | BrowsingDataFilterBuilder::Mode::kPreserve) |
| 5884 | ->BuildStorageKeyFilter(), |
| 5885 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved); |
| 5886 | { |
| 5887 | const auto source_id = ForceLogsUploadAndGetUkmId(); |
| 5888 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 5889 | ukm::builders::Preloading_Attempt::kEntryName, |
| 5890 | test::kPreloadingAttemptUkmMetrics); |
| 5891 | ASSERT_EQ(actual_attempts.size(), 1u); |
| 5892 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> expected_attempts = |
| 5893 | {attempt_entry_builder()->BuildEntry( |
| 5894 | source_id, PreloadingType::kPrefetch, |
| 5895 | PreloadingEligibility::kUnspecified, |
| 5896 | PreloadingHoldbackStatus::kUnspecified, |
| 5897 | PreloadingTriggeringOutcome::kUnspecified, |
| 5898 | PreloadingFailureReason::kUnspecified, |
| 5899 | /*accurate=*/false, |
| 5900 | /*ready_time=*/std::nullopt, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5901 | blink::mojom::SpeculationEagerness::kImmediate)}; |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5902 | ASSERT_THAT(actual_attempts, |
| 5903 | testing::UnorderedElementsAreArray(expected_attempts)) |
| 5904 | << test::ActualVsExpectedUkmEntriesToString(actual_attempts, |
| 5905 | expected_attempts); |
| 5906 | } |
| 5907 | |
Hiroshige Hayashizaki | f4fc2260 | 2025-07-23 01:01:02 | [diff] [blame] | 5908 | // Resume the elibility check (currently this is just to satisfy the preferred |
| 5909 | // invariant that `PrefetchService::OnGotEligibility*()` is always called for |
| 5910 | // each eligibility check. |
| 5911 | eligibility_check_callback_future.Take().Run(); |
| 5912 | |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5913 | prefetch_service->SetDelayEligibilityCheckForTesting(base::NullCallback()); |
| 5914 | } |
| 5915 | |
| 5916 | // Tests that the prefetch eviction for heldback triggers causes no crash. This |
| 5917 | // is a regression test of crbug.com/404703517. |
| 5918 | TEST_P(PrefetchServiceTest, PrefetchEvictionWhenHoldback) { |
| 5919 | content::test::PreloadingConfigOverride preloading_config_override; |
| 5920 | preloading_config_override.SetHoldback( |
| 5921 | PreloadingType::kPrefetch, |
| 5922 | content_preloading_predictor::kSpeculationRules, true); |
| 5923 | |
| 5924 | NavigateAndCommit(GURL("https://example.com")); |
| 5925 | MakePrefetchService( |
| 5926 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 5927 | /*num_on_prefetch_likely_calls=*/1)); |
| 5928 | PrefetchService* prefetch_service = |
| 5929 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 5930 | |
| 5931 | const auto url_1 = GURL("https://example.com/one"); |
| 5932 | auto candidate_1 = blink::mojom::SpeculationCandidate::New(); |
| 5933 | candidate_1->url = url_1; |
| 5934 | candidate_1->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5935 | candidate_1->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5936 | candidate_1->referrer = blink::mojom::Referrer::New(); |
| 5937 | |
| 5938 | // Send `candidate_1`; |
| 5939 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 5940 | candidates.push_back(candidate_1.Clone()); |
| 5941 | auto* prefetch_document_manager = |
| 5942 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 5943 | prefetch_document_manager->ProcessCandidates(candidates); |
| 5944 | task_environment()->RunUntilIdle(); |
| 5945 | |
| 5946 | base::WeakPtr<PrefetchContainer> prefetch_container1; |
| 5947 | std::tie(std::ignore, prefetch_container1) = |
| 5948 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 5949 | PrefetchContainer::Key(MainDocumentToken(), url_1))[0]; |
| 5950 | task_environment()->RunUntilIdle(); |
| 5951 | |
| 5952 | // `candidate_1` should be failed as heldback |
| 5953 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 5954 | PrefetchContainer::LoadState::kFailedHeldback); |
| 5955 | |
| 5956 | // Try to evict. |
| 5957 | prefetch_service->EvictPrefetchesForBrowsingDataRemoval( |
| 5958 | BrowsingDataFilterBuilder::Create( |
| 5959 | BrowsingDataFilterBuilder::Mode::kPreserve) |
| 5960 | ->BuildStorageKeyFilter(), |
| 5961 | PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved); |
| 5962 | { |
| 5963 | const auto source_id = ForceLogsUploadAndGetUkmId(); |
| 5964 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 5965 | ukm::builders::Preloading_Attempt::kEntryName, |
| 5966 | test::kPreloadingAttemptUkmMetrics); |
| 5967 | ASSERT_EQ(actual_attempts.size(), 1u); |
| 5968 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> expected_attempts = |
| 5969 | {attempt_entry_builder()->BuildEntry( |
| 5970 | source_id, PreloadingType::kPrefetch, |
| 5971 | PreloadingEligibility::kEligible, |
| 5972 | PreloadingHoldbackStatus::kHoldback, |
| 5973 | PreloadingTriggeringOutcome::kUnspecified, |
| 5974 | PreloadingFailureReason::kUnspecified, |
| 5975 | /*accurate=*/false, |
| 5976 | /*ready_time=*/std::nullopt, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 5977 | blink::mojom::SpeculationEagerness::kImmediate)}; |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 5978 | ASSERT_THAT(actual_attempts, |
| 5979 | testing::UnorderedElementsAreArray(expected_attempts)) |
| 5980 | << test::ActualVsExpectedUkmEntriesToString(actual_attempts, |
| 5981 | expected_attempts); |
| 5982 | } |
| 5983 | } |
| 5984 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 5985 | class PrefetchServiceLimitsTest |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5986 | : public PrefetchServiceTestBase, |
| 5987 | public WithPrefetchServiceRearchParam, |
| 5988 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 5989 | public: |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 5990 | PrefetchServiceLimitsTest() : WithPrefetchServiceRearchParam(GetParam()) {} |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 5991 | |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 5992 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 5993 | InitBaseParams(); |
| 5994 | InitRearchFeatures(); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 5995 | } |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 5996 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 5997 | PrefetchServingHandle CompletePrefetch( |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 5998 | GURL url, |
| 5999 | blink::mojom::SpeculationEagerness eagerness) { |
| 6000 | MakePrefetchOnMainFrame( |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 6001 | url, PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 6002 | /*use_prefetch_proxy=*/false, eagerness)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6003 | task_environment()->RunUntilIdle(); |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6004 | return CompleteExistingPrefetch( |
| 6005 | url, {.expected_priority = ExpectedPriorityForEagerness(eagerness)}); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6006 | } |
| 6007 | |
| 6008 | // Unlike the above method, this expects the prefetch for |url| to have |
| 6009 | // already been triggered. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 6010 | PrefetchServingHandle CompleteExistingPrefetch( |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6011 | GURL url, |
| 6012 | const VerifyCommonRequestStateOptions& common_options = {}) { |
| 6013 | VerifyCommonRequestState(url, common_options); |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6014 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 6015 | /*use_prefetch_proxy=*/false, |
| 6016 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 6017 | NavigateInitiatedByRenderer(url); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6018 | return GetPrefetchToServe(url); |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6019 | } |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6020 | }; |
| 6021 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6022 | INSTANTIATE_TEST_SUITE_P( |
| 6023 | ParametrizedTests, |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6024 | PrefetchServiceLimitsTest, |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6025 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 6026 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6027 | TEST_P(PrefetchServiceLimitsTest, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6028 | NonImmediatePrefetchAllowedWhenImmediateLimitIsReached) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6029 | const GURL url_over_limit = GURL("https://example.com/over_limit"); |
| 6030 | const GURL url_conservative = GURL("https://example.com/conservative"); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6031 | |
| 6032 | NavigateAndCommit(GURL("https://example.com")); |
| 6033 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6034 | MakePrefetchService(std::make_unique< |
| 6035 | testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6036 | /*num_on_prefetch_likely_calls=*/kMaxNumberOfImmediatePrefetchesPerPage + |
| 6037 | 2)); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6038 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6039 | for (int i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6040 | const GURL url("https://example.com/" + base::NumberToString(i)); |
| 6041 | ASSERT_TRUE( |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6042 | CompletePrefetch(url, blink::mojom::SpeculationEagerness::kImmediate)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6043 | } |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6044 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6045 | // Note: |url_over_limit| is not prefetched as the limit for immediate |
| 6046 | // prefetches has been reached. |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6047 | MakePrefetchOnMainFrame( |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6048 | url_over_limit, |
| 6049 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 6050 | /*use_prefetch_proxy=*/false, |
| 6051 | blink::mojom::SpeculationEagerness::kImmediate)); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6052 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6053 | EXPECT_EQ(RequestCount(), 0); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6054 | NavigateInitiatedByRenderer(url_over_limit); |
| 6055 | ASSERT_FALSE(GetPrefetchToServe(url_over_limit)); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6056 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6057 | // We can still prefetch |url_conservative| as it is a conservative prefetch. |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6058 | auto non_immediate_prefetch = CompletePrefetch( |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6059 | url_conservative, blink::mojom::SpeculationEagerness::kConservative); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6060 | ASSERT_TRUE(non_immediate_prefetch); |
| 6061 | EXPECT_EQ(non_immediate_prefetch.GetPrefetchStatus(), |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6062 | PrefetchStatus::kPrefetchSuccessful); |
| 6063 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 6064 | std::optional<PrefetchReferringPageMetrics> referring_page_metrics = |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6065 | PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6066 | EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6067 | kMaxNumberOfImmediatePrefetchesPerPage + 2); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6068 | EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6069 | kMaxNumberOfImmediatePrefetchesPerPage + 2); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6070 | EXPECT_EQ(referring_page_metrics->prefetch_successful_count, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6071 | kMaxNumberOfImmediatePrefetchesPerPage + 1); |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6072 | } |
| 6073 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6074 | TEST_P(PrefetchServiceLimitsTest, NonImmediatePrefetchEvictedAtLimit) { |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6075 | const GURL url_1 = GURL("https://example.com/one"); |
| 6076 | const GURL url_2 = GURL("https://example.com/two"); |
| 6077 | const GURL url_3 = GURL("https://example.com/three"); |
| 6078 | const GURL url_4 = GURL("https://example.com/four"); |
| 6079 | |
| 6080 | NavigateAndCommit(GURL("https://example.com")); |
| 6081 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6082 | // This test is written to assume this specific limit and will need |
| 6083 | // modification if it changes. |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6084 | ASSERT_EQ(kMaxNumberOfNonImmediatePrefetchesPerPage, 2); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6085 | |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6086 | MakePrefetchService( |
| 6087 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6088 | /*num_on_prefetch_likely_calls=*/4)); |
| 6089 | |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6090 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6091 | EXPECT_CALL(mock_destruction_callback, Run(url_1)).Times(1); |
| 6092 | EXPECT_CALL(mock_destruction_callback, Run(url_2)).Times(1); |
Adithya Srinivasan | d1c68ba | 2023-05-30 19:54:25 | [diff] [blame] | 6093 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()) |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6094 | ->SetPrefetchDestructionCallback(mock_destruction_callback.Get()); |
Adithya Srinivasan | d1c68ba | 2023-05-30 19:54:25 | [diff] [blame] | 6095 | |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6096 | auto prefetch_1 = |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6097 | CompletePrefetch(url_1, blink::mojom::SpeculationEagerness::kModerate); |
| 6098 | ASSERT_TRUE(prefetch_1); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6099 | EXPECT_EQ(prefetch_1.GetPrefetchStatus(), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6100 | PrefetchStatus::kPrefetchSuccessful); |
| 6101 | |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6102 | auto prefetch_2 = |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6103 | CompletePrefetch(url_2, blink::mojom::SpeculationEagerness::kModerate); |
| 6104 | ASSERT_TRUE(prefetch_2); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6105 | EXPECT_EQ(prefetch_2.GetPrefetchStatus(), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6106 | PrefetchStatus::kPrefetchSuccessful); |
| 6107 | ASSERT_TRUE(prefetch_1); |
| 6108 | |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6109 | auto prefetch_3 = |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6110 | CompletePrefetch(url_3, blink::mojom::SpeculationEagerness::kModerate); |
| 6111 | ASSERT_TRUE(prefetch_3); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6112 | EXPECT_EQ(prefetch_3.GetPrefetchStatus(), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6113 | PrefetchStatus::kPrefetchSuccessful); |
| 6114 | // Prefetch for |url_1| should have been evicted to allow a prefetch of |
| 6115 | // |url_3|. |
| 6116 | ASSERT_FALSE(prefetch_1); |
| 6117 | ASSERT_TRUE(prefetch_2); |
| 6118 | |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6119 | auto prefetch_4 = |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6120 | CompletePrefetch(url_4, blink::mojom::SpeculationEagerness::kModerate); |
| 6121 | ASSERT_TRUE(prefetch_4); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6122 | EXPECT_EQ(prefetch_4.GetPrefetchStatus(), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6123 | PrefetchStatus::kPrefetchSuccessful); |
| 6124 | // Prefetch for |url_2| should have been evicted to allow a prefetch of |
| 6125 | // |url_4|. |
| 6126 | ASSERT_FALSE(prefetch_2); |
| 6127 | ASSERT_TRUE(prefetch_3); |
| 6128 | |
| 6129 | // The first and second prefetches should have failure reason set to |
| 6130 | // 'kPrefetchEvicted'. |
| 6131 | { |
| 6132 | const auto source_id = ForceLogsUploadAndGetUkmId(); |
| 6133 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 6134 | ukm::builders::Preloading_Attempt::kEntryName, |
| 6135 | test::kPreloadingAttemptUkmMetrics); |
| 6136 | EXPECT_EQ(actual_attempts.size(), 4u); |
| 6137 | |
| 6138 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> expected_attempts = |
| 6139 | {attempt_entry_builder()->BuildEntry( |
| 6140 | source_id, PreloadingType::kPrefetch, |
| 6141 | PreloadingEligibility::kEligible, |
| 6142 | PreloadingHoldbackStatus::kAllowed, |
| 6143 | PreloadingTriggeringOutcome::kFailure, |
| 6144 | ToPreloadingFailureReason( |
Adithya Srinivasan | b7f08b4 | 2023-12-05 15:49:36 | [diff] [blame] | 6145 | content::PrefetchStatus::kPrefetchEvictedForNewerPrefetch), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 6146 | /*accurate=*/true, |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6147 | /*ready_time=*/ |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 6148 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
| 6149 | blink::mojom::SpeculationEagerness::kModerate), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6150 | attempt_entry_builder()->BuildEntry( |
| 6151 | source_id, PreloadingType::kPrefetch, |
| 6152 | PreloadingEligibility::kEligible, |
| 6153 | PreloadingHoldbackStatus::kAllowed, |
| 6154 | PreloadingTriggeringOutcome::kFailure, |
| 6155 | ToPreloadingFailureReason( |
Adithya Srinivasan | b7f08b4 | 2023-12-05 15:49:36 | [diff] [blame] | 6156 | content::PrefetchStatus::kPrefetchEvictedForNewerPrefetch), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 6157 | /*accurate=*/true, |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6158 | /*ready_time=*/ |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 6159 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
| 6160 | blink::mojom::SpeculationEagerness::kModerate), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6161 | attempt_entry_builder()->BuildEntry( |
| 6162 | source_id, PreloadingType::kPrefetch, |
| 6163 | PreloadingEligibility::kEligible, |
| 6164 | PreloadingHoldbackStatus::kAllowed, |
| 6165 | PreloadingTriggeringOutcome::kReady, |
| 6166 | PreloadingFailureReason::kUnspecified, |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 6167 | /*accurate=*/true, |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6168 | /*ready_time=*/ |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 6169 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
| 6170 | blink::mojom::SpeculationEagerness::kModerate), |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6171 | attempt_entry_builder()->BuildEntry( |
| 6172 | source_id, PreloadingType::kPrefetch, |
| 6173 | PreloadingEligibility::kEligible, |
| 6174 | PreloadingHoldbackStatus::kAllowed, |
| 6175 | PreloadingTriggeringOutcome::kReady, |
| 6176 | PreloadingFailureReason::kUnspecified, |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 6177 | /*accurate=*/true, |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6178 | /*ready_time=*/ |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 6179 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
| 6180 | blink::mojom::SpeculationEagerness::kModerate)}; |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 6181 | EXPECT_THAT(actual_attempts, |
| 6182 | testing::UnorderedElementsAreArray(expected_attempts)) |
| 6183 | << test::ActualVsExpectedUkmEntriesToString(actual_attempts, |
| 6184 | expected_attempts); |
| 6185 | } |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 6186 | } |
| 6187 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6188 | TEST_P(PrefetchServiceLimitsTest, PrefetchWithNoCandidateIsNotStarted) { |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6189 | const GURL url_1 = GURL("https://example.com/one"); |
| 6190 | const GURL url_2 = GURL("https://example.com/two"); |
| 6191 | const GURL url_3 = GURL("https://example.com/three"); |
| 6192 | |
| 6193 | NavigateAndCommit(GURL("https://example.com")); |
| 6194 | |
| 6195 | MakePrefetchService( |
| 6196 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6197 | /*num_on_prefetch_likely_calls=*/3)); |
| 6198 | |
| 6199 | auto candidate_1 = blink::mojom::SpeculationCandidate::New(); |
| 6200 | candidate_1->url = url_1; |
| 6201 | candidate_1->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6202 | candidate_1->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6203 | candidate_1->referrer = blink::mojom::Referrer::New(); |
| 6204 | auto candidate_2 = candidate_1.Clone(); |
| 6205 | candidate_2->url = url_2; |
| 6206 | auto candidate_3 = candidate_1.Clone(); |
| 6207 | candidate_3->url = url_3; |
| 6208 | |
| 6209 | auto* prefetch_document_manager = |
| 6210 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6211 | ASSERT_TRUE(prefetch_document_manager); |
| 6212 | |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6213 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6214 | EXPECT_CALL(mock_destruction_callback, Run(url_2)).Times(1); |
| 6215 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6216 | mock_destruction_callback.Get()); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6217 | |
| 6218 | // Send 3 candidates to PrefetchDocumentManager. |
| 6219 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 6220 | candidates.push_back(candidate_1.Clone()); |
| 6221 | candidates.push_back(candidate_2.Clone()); |
| 6222 | candidates.push_back(candidate_3.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6223 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6224 | task_environment()->RunUntilIdle(); |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6225 | VerifyCommonRequestState(url_1); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6226 | |
| 6227 | // Remove |url_2| from the list of candidates while a prefetch for |url_1| is |
| 6228 | // in progress. |
| 6229 | candidates.clear(); |
| 6230 | candidates.push_back(candidate_1.Clone()); |
| 6231 | candidates.push_back(candidate_3.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6232 | prefetch_document_manager->ProcessCandidates(candidates); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6233 | |
| 6234 | // Finish prefetch of |url_1|. |
| 6235 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 6236 | /*use_prefetch_proxy=*/false, |
| 6237 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 6238 | // PrefetchService skips |url_2| because its candidate was removed, and starts |
| 6239 | // prefetching |url_3| instead. |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6240 | VerifyCommonRequestState(url_3); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6241 | // Finish prefetch of |url_2|. |
| 6242 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 6243 | /*use_prefetch_proxy=*/false, |
| 6244 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 6245 | // There should be no pending prefetch requests. |
| 6246 | EXPECT_EQ(RequestCount(), 0); |
| 6247 | } |
| 6248 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6249 | TEST_P(PrefetchServiceLimitsTest, |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6250 | InProgressPrefetchWithNoCandidateIsCancelled) { |
| 6251 | const GURL url_1 = GURL("https://example.com/one"); |
| 6252 | const GURL url_2 = GURL("https://example.com/two"); |
| 6253 | |
| 6254 | NavigateAndCommit(GURL("https://example.com")); |
| 6255 | |
| 6256 | MakePrefetchService( |
| 6257 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6258 | /*num_on_prefetch_likely_calls=*/2)); |
| 6259 | |
| 6260 | auto candidate_1 = blink::mojom::SpeculationCandidate::New(); |
| 6261 | candidate_1->url = url_1; |
| 6262 | candidate_1->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6263 | candidate_1->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6264 | candidate_1->referrer = blink::mojom::Referrer::New(); |
| 6265 | auto candidate_2 = candidate_1.Clone(); |
| 6266 | candidate_2->url = url_2; |
| 6267 | |
| 6268 | auto* prefetch_document_manager = |
| 6269 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6270 | ASSERT_TRUE(prefetch_document_manager); |
| 6271 | |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6272 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6273 | EXPECT_CALL(mock_destruction_callback, Run(url_1)).Times(1); |
| 6274 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6275 | mock_destruction_callback.Get()); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6276 | |
| 6277 | // Send 2 candidates to PrefetchDocumentManager. |
| 6278 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 6279 | candidates.push_back(candidate_1.Clone()); |
| 6280 | candidates.push_back(candidate_2.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6281 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6282 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6283 | |
| 6284 | // Prefetch for |url_1| should have started. |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6285 | VerifyCommonRequestState(url_1); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6286 | |
| 6287 | // Remove |candidate_1|. |
| 6288 | candidates.clear(); |
| 6289 | candidates.push_back(candidate_2.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6290 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6291 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6292 | |
| 6293 | // The prefetch for |url_1| should be cancelled, and prefetch for |url_2| |
| 6294 | // should have started. |
| 6295 | |
| 6296 | EXPECT_EQ(test_url_loader_factory_.pending_requests()->size(), 2u); |
| 6297 | // The client for the first request should be disconnected. |
| 6298 | EXPECT_FALSE( |
| 6299 | test_url_loader_factory_.GetPendingRequest(0)->client.is_connected()); |
| 6300 | // Clears out first request. |
| 6301 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 6302 | /*use_prefetch_proxy=*/false, |
| 6303 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6304 | VerifyCommonRequestState(url_2); |
Taiyo Mizuhashi | 01d86af2 | 2024-03-27 14:27:42 | [diff] [blame] | 6305 | NavigateInitiatedByRenderer(url_1); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 6306 | PrefetchServingHandle serving_handle = GetPrefetchToServe(url_1); |
| 6307 | EXPECT_FALSE(serving_handle); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6308 | } |
| 6309 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6310 | TEST_P(PrefetchServiceLimitsTest, CompletedPrefetchWithNoCandidateIsEvicted) { |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6311 | const GURL url_1 = GURL("https://example.com/one"); |
| 6312 | const GURL url_2 = GURL("https://example.com/two"); |
| 6313 | const GURL url_3 = GURL("https://example.com/three"); |
| 6314 | |
| 6315 | NavigateAndCommit(GURL("https://example.com")); |
| 6316 | |
| 6317 | MakePrefetchService( |
| 6318 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6319 | /*num_on_prefetch_likely_calls=*/2)); |
| 6320 | |
| 6321 | auto candidate_1 = blink::mojom::SpeculationCandidate::New(); |
| 6322 | candidate_1->url = url_1; |
| 6323 | candidate_1->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6324 | candidate_1->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6325 | candidate_1->referrer = blink::mojom::Referrer::New(); |
| 6326 | auto candidate_2 = candidate_1.Clone(); |
| 6327 | candidate_2->url = url_2; |
| 6328 | |
| 6329 | auto* prefetch_document_manager = |
| 6330 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6331 | ASSERT_TRUE(prefetch_document_manager); |
| 6332 | |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6333 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6334 | EXPECT_CALL(mock_destruction_callback, Run(url_1)).Times(1); |
| 6335 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6336 | mock_destruction_callback.Get()); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6337 | |
| 6338 | // Send 2 candidates to PrefetchDocumentManager. |
| 6339 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 6340 | candidates.push_back(candidate_1.Clone()); |
| 6341 | candidates.push_back(candidate_2.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6342 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6343 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6344 | |
| 6345 | // Complete prefetches for |url_1| and |url_2|. |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6346 | auto prefetch_1 = CompleteExistingPrefetch(url_1); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6347 | ASSERT_TRUE(prefetch_1); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6348 | auto prefetch_2 = CompleteExistingPrefetch(url_2); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6349 | ASSERT_TRUE(prefetch_2); |
| 6350 | |
| 6351 | // Remove |candidate_1|. |
| 6352 | candidates.clear(); |
| 6353 | candidates.push_back(candidate_2.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6354 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6355 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 6356 | // |prefetch_1| should have been removed. |
| 6357 | EXPECT_FALSE(prefetch_1); |
| 6358 | EXPECT_TRUE(prefetch_2); |
| 6359 | } |
| 6360 | |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6361 | // Test to see if we can re-prefetch a url whose previous prefetch expired. |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6362 | TEST_P(PrefetchServiceLimitsTest, PrefetchReset) { |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6363 | base::test::ScopedFeatureList scoped_feature_list; |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 6364 | // Override `kPrefetchUseContentRefactor`. |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6365 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 6366 | {{features::kPrefetchUseContentRefactor, |
| 6367 | {{"ineligible_decoy_request_probability", "0"}, |
| 6368 | {"prefetch_container_lifetime_s", "1"}}}}, |
| 6369 | {}); |
| 6370 | |
| 6371 | NavigateAndCommit(GURL("https://example.com")); |
| 6372 | MakePrefetchService( |
| 6373 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6374 | /*num_on_prefetch_likely_calls=*/2)); |
| 6375 | |
| 6376 | auto* prefetch_document_manager = |
| 6377 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6378 | |
| 6379 | const auto url = GURL("https://example.com/one"); |
| 6380 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6381 | EXPECT_CALL(mock_destruction_callback, Run(url)).Times(1); |
| 6382 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6383 | mock_destruction_callback.Get()); |
| 6384 | |
| 6385 | auto candidate = blink::mojom::SpeculationCandidate::New(); |
| 6386 | candidate->url = url; |
| 6387 | candidate->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6388 | candidate->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6389 | candidate->referrer = blink::mojom::Referrer::New(); |
| 6390 | |
| 6391 | // Start and complete prefetch of |url|. |
| 6392 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 6393 | candidates.push_back(candidate.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6394 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6395 | auto prefetch = CompleteExistingPrefetch(url); |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6396 | ASSERT_TRUE(prefetch); |
Hiroshige Hayashizaki | 00b3f00 | 2023-07-15 00:32:48 | [diff] [blame] | 6397 | EXPECT_EQ(prefetch.GetPrefetchStatus(), PrefetchStatus::kPrefetchSuccessful); |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6398 | |
| 6399 | // Fast forward by a second and expire |prefetch|. |
| 6400 | task_environment()->FastForwardBy(base::Seconds(1)); |
| 6401 | EXPECT_FALSE(prefetch); |
| 6402 | |
| 6403 | // Try reprefetching |url|. |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 6404 | // TODO(crbug.com/40064525): Ideally this prefetch would be requeued |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6405 | // automatically. |
| 6406 | candidates.clear(); |
| 6407 | candidates.push_back(candidate.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6408 | prefetch_document_manager->ProcessCandidates(candidates); |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6409 | // Prefetch for |url| should have started again. |
Jeremy Roman | 4c952421 | 2023-07-27 22:01:05 | [diff] [blame] | 6410 | VerifyCommonRequestState(url); |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6411 | |
| 6412 | { |
| 6413 | const auto source_id = ForceLogsUploadAndGetUkmId(); |
| 6414 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 6415 | ukm::builders::Preloading_Attempt::kEntryName, |
| 6416 | test::kPreloadingAttemptUkmMetrics); |
| 6417 | EXPECT_EQ(actual_attempts.size(), 2u); |
| 6418 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> expected_attempts = |
| 6419 | {attempt_entry_builder()->BuildEntry( |
| 6420 | source_id, PreloadingType::kPrefetch, |
| 6421 | PreloadingEligibility::kEligible, |
| 6422 | PreloadingHoldbackStatus::kAllowed, |
| 6423 | PreloadingTriggeringOutcome::kFailure, |
| 6424 | ToPreloadingFailureReason(PrefetchStatus::kPrefetchIsStale), |
kenoss | be8fbf2 | 2024-08-14 12:18:21 | [diff] [blame] | 6425 | /*accurate=*/true, |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6426 | /*ready_time=*/ |
| 6427 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6428 | blink::mojom::SpeculationEagerness::kImmediate), |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6429 | attempt_entry_builder()->BuildEntry( |
| 6430 | source_id, PreloadingType::kPrefetch, |
| 6431 | PreloadingEligibility::kEligible, |
| 6432 | PreloadingHoldbackStatus::kAllowed, |
| 6433 | PreloadingTriggeringOutcome::kRunning, |
| 6434 | PreloadingFailureReason::kUnspecified, |
| 6435 | /*accurate=*/false, |
| 6436 | /*ready_time=*/std::nullopt, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6437 | blink::mojom::SpeculationEagerness::kImmediate)}; |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6438 | EXPECT_THAT(actual_attempts, |
| 6439 | testing::UnorderedElementsAreArray(expected_attempts)) |
| 6440 | << test::ActualVsExpectedUkmEntriesToString(actual_attempts, |
| 6441 | expected_attempts); |
| 6442 | } |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 6443 | } |
| 6444 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6445 | TEST_P(PrefetchServiceLimitsTest, NextPrefetchQueuedImmediatelyAfterReset) { |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6446 | base::test::ScopedFeatureList scoped_feature_list; |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 6447 | // Override `kPrefetchUseContentRefactor`. |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6448 | scoped_feature_list.InitWithFeaturesAndParameters( |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6449 | { |
| 6450 | {features::kPrefetchUseContentRefactor, |
| 6451 | {{"ineligible_decoy_request_probability", "0"}, |
| 6452 | {"prefetch_container_lifetime_s", "1"}}}, |
| 6453 | }, |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6454 | {}); |
| 6455 | |
| 6456 | NavigateAndCommit(GURL("https://example.com")); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6457 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6458 | MakePrefetchService(std::make_unique< |
| 6459 | testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6460 | /*num_on_prefetch_likely_calls=*/kMaxNumberOfImmediatePrefetchesPerPage + |
| 6461 | 1)); |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6462 | |
| 6463 | auto* prefetch_document_manager = |
| 6464 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6465 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6466 | // Create kMaxNumberOfImmediatePrefetchesPerPage + 1 URLs to exceed the limit |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6467 | std::vector<GURL> urls; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6468 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage + 1; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6469 | urls.emplace_back("https://example.com/" + base::NumberToString(i)); |
| 6470 | } |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6471 | |
| 6472 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6473 | // All URLs but the last will expire and be destroyed |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6474 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6475 | EXPECT_CALL(mock_destruction_callback, Run(urls[i])).Times(1); |
| 6476 | } |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6477 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6478 | mock_destruction_callback.Get()); |
| 6479 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6480 | auto base_candidate = blink::mojom::SpeculationCandidate::New(); |
| 6481 | base_candidate->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6482 | base_candidate->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6483 | base_candidate->referrer = blink::mojom::Referrer::New(); |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6484 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6485 | // Add all candidates (one more than the limit) |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6486 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6487 | for (const auto& url : urls) { |
| 6488 | auto candidate = base_candidate.Clone(); |
| 6489 | candidate->url = url; |
| 6490 | candidates.push_back(std::move(candidate)); |
| 6491 | } |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6492 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6493 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6494 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6495 | // Complete prefetches up to the limit |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 6496 | std::vector<PrefetchServingHandle> prefetches; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6497 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6498 | auto prefetch = CompleteExistingPrefetch(urls[i]); |
| 6499 | ASSERT_TRUE(prefetch); |
| 6500 | EXPECT_EQ(prefetch.GetPrefetchStatus(), |
| 6501 | PrefetchStatus::kPrefetchSuccessful); |
| 6502 | prefetches.push_back(std::move(prefetch)); |
| 6503 | } |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6504 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6505 | // The last URL should not be queued because we are at the limit |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6506 | EXPECT_EQ(RequestCount(), 0); |
| 6507 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6508 | // Fast forward by a second to expire the |
| 6509 | // kMaxNumberOfImmediatePrefetchesPerPage prefetches |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6510 | task_environment()->FastForwardBy(base::Seconds(1)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6511 | for (auto& prefetch : prefetches) { |
| 6512 | EXPECT_FALSE(prefetch); |
| 6513 | } |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6514 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6515 | // The last URL should now be queued and prefetched |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6516 | VerifyCommonRequestState(urls[kMaxNumberOfImmediatePrefetchesPerPage]); |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 6517 | } |
| 6518 | |
Taiyo Mizuhashi | 4e624a2 | 2025-05-15 11:28:54 | [diff] [blame] | 6519 | // Tests that the prefetch queue is not stuck when resetting the running |
| 6520 | // prefetch during waiting its response. Regression test for |
| 6521 | // crbug.com/400233773. |
| 6522 | TEST_P(PrefetchServiceTest, PrefetchQueueNotStuckWhenResettingRunningPrefetch) { |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6523 | NavigateAndCommit(GURL("https://example.com")); |
| 6524 | MakePrefetchService( |
| 6525 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6526 | /*num_on_prefetch_likely_calls=*/0)); |
Taiyo Mizuhashi | 4e624a2 | 2025-05-15 11:28:54 | [diff] [blame] | 6527 | PrefetchService* prefetch_service = |
| 6528 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6529 | |
| 6530 | const auto url_1 = GURL("https://example.com/one"); |
| 6531 | const auto url_2 = GURL("https://example.com/two"); |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6532 | auto handle_1 = |
| 6533 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 6534 | auto handle_2 = |
| 6535 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
Taiyo Mizuhashi | 4e624a2 | 2025-05-15 11:28:54 | [diff] [blame] | 6536 | task_environment()->RunUntilIdle(); |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6537 | |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6538 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2; |
| 6539 | std::tie(std::ignore, prefetch_container1) = |
| 6540 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 6541 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 6542 | std::tie(std::ignore, prefetch_container2) = |
| 6543 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 6544 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 6545 | |
| 6546 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 6547 | PrefetchContainer::LoadState::kStarted); |
| 6548 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 6549 | PrefetchContainer::LoadState::kEligible); |
| 6550 | |
| 6551 | // Reset the first prefetch during waiting its response. Note that it will |
| 6552 | // eventually destruct the loader. |
| 6553 | handle_1.reset(); |
| 6554 | task_environment()->RunUntilIdle(); |
Taiyo Mizuhashi | 4e624a2 | 2025-05-15 11:28:54 | [diff] [blame] | 6555 | |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6556 | EXPECT_FALSE(prefetch_container1); |
Taiyo Mizuhashi | 4e624a2 | 2025-05-15 11:28:54 | [diff] [blame] | 6557 | // https://crbug.com/400233773 is fixed. |
Taiyo Mizuhashi | 9aa95a9 | 2025-03-05 19:35:04 | [diff] [blame] | 6558 | EXPECT_EQ(prefetch_container2->GetLoadState(), |
| 6559 | PrefetchContainer::LoadState::kStarted); |
| 6560 | } |
| 6561 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6562 | TEST_P(PrefetchServiceLimitsTest, PrefetchFailsAndIsReset) { |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 6563 | base::HistogramTester histogram_tester; |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6564 | base::test::ScopedFeatureList scoped_feature_list; |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 6565 | // Override `kPrefetchUseContentRefactor`. |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6566 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 6567 | {{features::kPrefetchUseContentRefactor, |
| 6568 | {{"ineligible_decoy_request_probability", "0"}, |
| 6569 | {"prefetch_container_lifetime_s", "1"}}}}, |
| 6570 | {}); |
| 6571 | |
| 6572 | NavigateAndCommit(GURL("https://example.com")); |
| 6573 | MakePrefetchService( |
| 6574 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6575 | /*num_on_prefetch_likely_calls=*/1)); |
| 6576 | |
| 6577 | auto* prefetch_document_manager = |
| 6578 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6579 | |
| 6580 | const auto url = GURL("https://example.com/one"); |
| 6581 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6582 | EXPECT_CALL(mock_destruction_callback, Run(url)).Times(1); |
| 6583 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6584 | mock_destruction_callback.Get()); |
| 6585 | |
| 6586 | auto candidate = blink::mojom::SpeculationCandidate::New(); |
| 6587 | candidate->url = url; |
| 6588 | candidate->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6589 | candidate->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6590 | candidate->referrer = blink::mojom::Referrer::New(); |
| 6591 | |
| 6592 | // Start prefetch of |url|. |
| 6593 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 6594 | candidates.push_back(candidate.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6595 | prefetch_document_manager->ProcessCandidates(candidates); |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6596 | base::RunLoop().RunUntilIdle(); |
| 6597 | VerifyCommonRequestState(url); |
| 6598 | MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED, kHTMLMimeType, |
| 6599 | /*use_prefetch_proxy=*/true, |
| 6600 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 6601 | |
| 6602 | // Fast forward by a second and expire existing PrefetchContainer. |
| 6603 | task_environment()->FastForwardBy(base::Seconds(1)); |
| 6604 | // The failure reason recorded (failed due to net error) should not be |
| 6605 | // overwritten when the prefetch is timed out (marked as stale). |
| 6606 | ExpectCorrectUkmLogs({.outcome = PreloadingTriggeringOutcome::kFailure, |
| 6607 | .failure = ToPreloadingFailureReason( |
| 6608 | PrefetchStatus::kPrefetchFailedNetError)}); |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 6609 | histogram_tester.ExpectUniqueSample("Preloading.Prefetch.PrefetchStatus", |
| 6610 | PrefetchStatus::kPrefetchFailedNetError, |
| 6611 | 1); |
Adithya Srinivasan | 006b365 | 2023-12-14 14:52:12 | [diff] [blame] | 6612 | } |
| 6613 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6614 | TEST_P(PrefetchServiceLimitsTest, ImmediatePrefetchLimitIsDynamic) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6615 | // The test only makes sense with limits >=2 |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6616 | ASSERT_GE(kMaxNumberOfImmediatePrefetchesPerPage, 2u); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6617 | |
| 6618 | std::vector<GURL> urls; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6619 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage + 1; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6620 | urls.emplace_back("https://example.com/" + base::NumberToString(i)); |
| 6621 | } |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6622 | |
| 6623 | NavigateAndCommit(GURL("https://example.com")); |
| 6624 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6625 | MakePrefetchService(std::make_unique< |
| 6626 | testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6627 | /*num_on_prefetch_likely_calls=*/kMaxNumberOfImmediatePrefetchesPerPage + |
| 6628 | 2)); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6629 | |
| 6630 | auto* prefetch_document_manager = |
| 6631 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6632 | ASSERT_TRUE(prefetch_document_manager); |
| 6633 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6634 | base::MockRepeatingCallback<void(const GURL&)> destruction_cb; |
| 6635 | EXPECT_CALL(destruction_cb, Run(urls[0])).Times(1); |
| 6636 | EXPECT_CALL(destruction_cb, Run(urls[1])).Times(1); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6637 | prefetch_document_manager->SetPrefetchDestructionCallback( |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6638 | destruction_cb.Get()); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6639 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6640 | auto base_candidate = blink::mojom::SpeculationCandidate::New(); |
| 6641 | base_candidate->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6642 | base_candidate->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6643 | base_candidate->referrer = blink::mojom::Referrer::New(); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6644 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6645 | // Send candidates up to the limit |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6646 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6647 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6648 | auto candidate = base_candidate.Clone(); |
| 6649 | candidate->url = urls[i]; |
| 6650 | candidates.push_back(std::move(candidate)); |
| 6651 | } |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6652 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6653 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6654 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6655 | // Complete all prefetches up to the limit |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 6656 | std::vector<PrefetchServingHandle> prefetches; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6657 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6658 | auto prefetch = CompleteExistingPrefetch(urls[i]); |
| 6659 | ASSERT_TRUE(prefetch); |
| 6660 | EXPECT_EQ(prefetch.GetPrefetchStatus(), |
| 6661 | PrefetchStatus::kPrefetchSuccessful); |
| 6662 | prefetches.push_back(std::move(prefetch)); |
| 6663 | } |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6664 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6665 | // Process candidates for urls[1] through |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6666 | // urls[kMaxNumberOfImmediatePrefetchesPerPage] |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6667 | candidates.clear(); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6668 | for (size_t i = 1; i < kMaxNumberOfImmediatePrefetchesPerPage + 1; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6669 | auto candidate = base_candidate.Clone(); |
| 6670 | candidate->url = urls[i]; |
| 6671 | candidates.push_back(std::move(candidate)); |
| 6672 | } |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6673 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6674 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6675 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6676 | // The new prefetch should succeed, and the 0th should be evicted |
| 6677 | auto prefetch_extra = |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6678 | CompleteExistingPrefetch(urls[kMaxNumberOfImmediatePrefetchesPerPage]); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6679 | ASSERT_TRUE(prefetch_extra); |
| 6680 | EXPECT_EQ(prefetch_extra.GetPrefetchStatus(), |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6681 | PrefetchStatus::kPrefetchSuccessful); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6682 | EXPECT_FALSE(prefetches[0]); // 0th prefetch should be evicted |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6683 | for (size_t i = 1; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6684 | EXPECT_TRUE(prefetches[i]); // Others should still be valid |
| 6685 | } |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6686 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6687 | // Now process candidates for urls[0] through |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6688 | // urls[kMaxNumberOfImmediatePrefetchesPerPage] (which will exceed the limit) |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6689 | candidates.clear(); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6690 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage + 1; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6691 | auto candidate = base_candidate.Clone(); |
| 6692 | candidate->url = urls[i]; |
| 6693 | candidates.push_back(std::move(candidate)); |
| 6694 | } |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6695 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6696 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6697 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6698 | // Should not reprefetch urls[0] because we are at the limit |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6699 | EXPECT_EQ(RequestCount(), 0); |
| 6700 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6701 | // Now process candidates for urls[0] plus urls[2] through |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6702 | // urls[kMaxNumberOfImmediatePrefetchesPerPage] (back under the limit) |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6703 | candidates.clear(); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6704 | for (size_t i = 0; i < kMaxNumberOfImmediatePrefetchesPerPage + 1; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6705 | if (i != 1) { |
| 6706 | auto candidate = base_candidate.Clone(); |
| 6707 | candidate->url = urls[i]; |
| 6708 | candidates.push_back(std::move(candidate)); |
| 6709 | } |
| 6710 | } |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6711 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6712 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6713 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6714 | // Now urls[0] should be prefetched successfully, and urls[1] evicted |
| 6715 | auto prefetch_0_new = CompleteExistingPrefetch(urls[0]); |
| 6716 | ASSERT_TRUE(prefetch_0_new); |
| 6717 | EXPECT_EQ(prefetch_0_new.GetPrefetchStatus(), |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6718 | PrefetchStatus::kPrefetchSuccessful); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6719 | EXPECT_FALSE(prefetches[1]); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6720 | for (size_t i = 2; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6721 | EXPECT_TRUE(prefetches[i]); // Others should still be valid |
| 6722 | } |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6723 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6724 | // Verify UKM entries |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6725 | { |
| 6726 | const auto source_id = ForceLogsUploadAndGetUkmId(); |
| 6727 | auto actual_attempts = test_ukm_recorder()->GetEntries( |
| 6728 | ukm::builders::Preloading_Attempt::kEntryName, |
| 6729 | test::kPreloadingAttemptUkmMetrics); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6730 | EXPECT_EQ(actual_attempts.size(), |
| 6731 | kMaxNumberOfImmediatePrefetchesPerPage + 2); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6732 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6733 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> expected_attempts; |
| 6734 | |
| 6735 | // urls[0], attempt #1 (evicted) |
| 6736 | expected_attempts.push_back(attempt_entry_builder()->BuildEntry( |
| 6737 | source_id, PreloadingType::kPrefetch, PreloadingEligibility::kEligible, |
| 6738 | PreloadingHoldbackStatus::kAllowed, |
| 6739 | PreloadingTriggeringOutcome::kFailure, |
| 6740 | ToPreloadingFailureReason( |
| 6741 | content::PrefetchStatus::kPrefetchEvictedAfterCandidateRemoved), |
| 6742 | /*accurate=*/true, |
| 6743 | /*ready_time=*/ |
| 6744 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6745 | blink::mojom::SpeculationEagerness::kImmediate)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6746 | |
| 6747 | // urls[1] (evicted) |
| 6748 | expected_attempts.push_back(attempt_entry_builder()->BuildEntry( |
| 6749 | source_id, PreloadingType::kPrefetch, PreloadingEligibility::kEligible, |
| 6750 | PreloadingHoldbackStatus::kAllowed, |
| 6751 | PreloadingTriggeringOutcome::kFailure, |
| 6752 | ToPreloadingFailureReason( |
| 6753 | content::PrefetchStatus::kPrefetchEvictedAfterCandidateRemoved), |
| 6754 | /*accurate=*/true, |
| 6755 | /*ready_time=*/ |
| 6756 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6757 | blink::mojom::SpeculationEagerness::kImmediate)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6758 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6759 | // urls[2] through urls[kMaxNumberOfImmediatePrefetchesPerPage-1] (ready) |
| 6760 | for (size_t i = 2; i < kMaxNumberOfImmediatePrefetchesPerPage; ++i) { |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6761 | expected_attempts.push_back(attempt_entry_builder()->BuildEntry( |
| 6762 | source_id, PreloadingType::kPrefetch, |
| 6763 | PreloadingEligibility::kEligible, PreloadingHoldbackStatus::kAllowed, |
| 6764 | PreloadingTriggeringOutcome::kReady, |
| 6765 | PreloadingFailureReason::kUnspecified, |
| 6766 | /*accurate=*/true, |
| 6767 | /*ready_time=*/ |
| 6768 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6769 | blink::mojom::SpeculationEagerness::kImmediate)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6770 | } |
| 6771 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6772 | // urls[kMaxNumberOfImmediatePrefetchesPerPage] (ready) |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6773 | expected_attempts.push_back(attempt_entry_builder()->BuildEntry( |
| 6774 | source_id, PreloadingType::kPrefetch, PreloadingEligibility::kEligible, |
| 6775 | PreloadingHoldbackStatus::kAllowed, PreloadingTriggeringOutcome::kReady, |
| 6776 | PreloadingFailureReason::kUnspecified, |
| 6777 | /*accurate=*/true, |
| 6778 | /*ready_time=*/ |
| 6779 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6780 | blink::mojom::SpeculationEagerness::kImmediate)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6781 | |
| 6782 | // urls[0], attempt #2 (ready) |
| 6783 | expected_attempts.push_back(attempt_entry_builder()->BuildEntry( |
| 6784 | source_id, PreloadingType::kPrefetch, PreloadingEligibility::kEligible, |
| 6785 | PreloadingHoldbackStatus::kAllowed, PreloadingTriggeringOutcome::kReady, |
| 6786 | PreloadingFailureReason::kUnspecified, |
| 6787 | /*accurate=*/true, |
| 6788 | /*ready_time=*/ |
| 6789 | base::ScopedMockElapsedTimersForTest::kMockElapsedTime, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6790 | blink::mojom::SpeculationEagerness::kImmediate)); |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6791 | |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 6792 | EXPECT_THAT(actual_attempts, |
| 6793 | testing::UnorderedElementsAreArray(expected_attempts)) |
| 6794 | << test::ActualVsExpectedUkmEntriesToString(actual_attempts, |
| 6795 | expected_attempts); |
| 6796 | } |
| 6797 | } |
| 6798 | |
Domenic Denicola | 7eaf450e | 2025-06-17 02:00:04 | [diff] [blame] | 6799 | TEST_P(PrefetchServiceLimitsTest, RemoveCandidateForFailedPrefetch) { |
Adithya Srinivasan | bedbca61 | 2023-08-31 21:51:38 | [diff] [blame] | 6800 | const GURL url = GURL("https://example.com/one"); |
| 6801 | |
| 6802 | NavigateAndCommit(GURL("https://example.com")); |
| 6803 | |
| 6804 | MakePrefetchService( |
| 6805 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 6806 | /*num_on_prefetch_likely_calls=*/1)); |
| 6807 | |
| 6808 | auto candidate = blink::mojom::SpeculationCandidate::New(); |
| 6809 | candidate->url = url; |
| 6810 | candidate->action = blink::mojom::SpeculationAction::kPrefetch; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6811 | candidate->eagerness = blink::mojom::SpeculationEagerness::kImmediate; |
Adithya Srinivasan | bedbca61 | 2023-08-31 21:51:38 | [diff] [blame] | 6812 | candidate->referrer = blink::mojom::Referrer::New(); |
| 6813 | |
| 6814 | auto* prefetch_document_manager = |
| 6815 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 6816 | ASSERT_TRUE(prefetch_document_manager); |
| 6817 | |
| 6818 | base::MockRepeatingCallback<void(const GURL& url)> mock_destruction_callback; |
| 6819 | EXPECT_CALL(mock_destruction_callback, Run(url)).Times(1); |
| 6820 | prefetch_document_manager->SetPrefetchDestructionCallback( |
| 6821 | mock_destruction_callback.Get()); |
| 6822 | |
| 6823 | // Send canadidate to PrefetchDocumentManager. |
| 6824 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
| 6825 | candidates.push_back(candidate.Clone()); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6826 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6827 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | bedbca61 | 2023-08-31 21:51:38 | [diff] [blame] | 6828 | |
| 6829 | // Prefetch for |url| should have started. |
| 6830 | VerifyCommonRequestState(url); |
| 6831 | // Send error response for prefetch of |url| |
| 6832 | MakeResponseAndWait(net::HTTP_OK, net::ERR_FAILED, kHTMLMimeType, |
| 6833 | /*use_prefetch_proxy=*/false, |
| 6834 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 6835 | |
| 6836 | // Remove |candidate|. |
| 6837 | candidates.clear(); |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 6838 | prefetch_document_manager->ProcessCandidates(candidates); |
Hiroshige Hayashizaki | b6a84d99 | 2023-10-02 17:57:54 | [diff] [blame] | 6839 | task_environment()->RunUntilIdle(); |
Adithya Srinivasan | bedbca61 | 2023-08-31 21:51:38 | [diff] [blame] | 6840 | |
| 6841 | ExpectCorrectUkmLogs({.outcome = PreloadingTriggeringOutcome::kFailure, |
| 6842 | .failure = ToPreloadingFailureReason( |
| 6843 | PrefetchStatus::kPrefetchFailedNetError)}); |
| 6844 | } |
| 6845 | |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6846 | blink::UserAgentMetadata GetFakeUserAgentMetadata() { |
| 6847 | blink::UserAgentMetadata metadata; |
| 6848 | metadata.brand_version_list.emplace_back("fake", "42"); |
| 6849 | metadata.brand_full_version_list.emplace_back("fake", "42.0.1701.99"); |
| 6850 | metadata.full_version = "42.0.1701.99"; |
| 6851 | return metadata; |
| 6852 | } |
| 6853 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6854 | class PrefetchServiceClientHintsTest |
| 6855 | : public PrefetchServiceTestBase, |
| 6856 | public WithPrefetchServiceRearchParam, |
| 6857 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
| 6858 | public: |
| 6859 | PrefetchServiceClientHintsTest() |
| 6860 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 6861 | |
| 6862 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 6863 | InitBaseParams(); |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6864 | InitRearchFeatures(); |
| 6865 | } |
| 6866 | |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6867 | protected: |
| 6868 | std::unique_ptr<BrowserContext> CreateBrowserContext() override { |
kenoss | 972e868 | 2024-09-05 00:20:14 | [diff] [blame] | 6869 | auto browser_context = PrefetchServiceTestBase::CreateBrowserContext(); |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6870 | TestBrowserContext::FromBrowserContext(browser_context.get()) |
| 6871 | ->SetClientHintsControllerDelegate(&client_hints_controller_delegate_); |
| 6872 | return browser_context; |
| 6873 | } |
| 6874 | |
| 6875 | MockClientHintsControllerDelegate& client_hints_controller_delegate() { |
| 6876 | return client_hints_controller_delegate_; |
| 6877 | } |
| 6878 | |
| 6879 | private: |
| 6880 | MockClientHintsControllerDelegate client_hints_controller_delegate_{ |
| 6881 | GetFakeUserAgentMetadata()}; |
| 6882 | }; |
| 6883 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6884 | INSTANTIATE_TEST_SUITE_P( |
| 6885 | ParametrizedTests, |
| 6886 | PrefetchServiceClientHintsTest, |
| 6887 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 6888 | |
| 6889 | TEST_P(PrefetchServiceClientHintsTest, NoClientHintsWhenDisabled) { |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6890 | base::test::ScopedFeatureList disable_prefetch_ch; |
| 6891 | disable_prefetch_ch.InitAndDisableFeature(features::kPrefetchClientHints); |
| 6892 | |
| 6893 | MakePrefetchService( |
| 6894 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 6895 | NavigateAndCommit(GURL("https://example.com/")); |
| 6896 | |
| 6897 | MakePrefetchOnMainFrame( |
| 6898 | GURL("https://example.com/two"), |
| 6899 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 6900 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6901 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6902 | blink::mojom::Referrer(GURL("https://example.com/"), |
| 6903 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 6904 | task_environment()->RunUntilIdle(); |
| 6905 | |
| 6906 | auto* pending = test_url_loader_factory_.GetPendingRequest(0); |
| 6907 | ASSERT_TRUE(pending); |
| 6908 | EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-UA")); |
| 6909 | } |
| 6910 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6911 | TEST_P(PrefetchServiceClientHintsTest, LowEntropyClientHints) { |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6912 | base::test::ScopedFeatureList enable_prefetch_ch; |
| 6913 | enable_prefetch_ch.InitAndEnableFeature(features::kPrefetchClientHints); |
| 6914 | |
| 6915 | MakePrefetchService( |
| 6916 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 6917 | NavigateAndCommit(GURL("https://example.com/")); |
| 6918 | |
| 6919 | MakePrefetchOnMainFrame( |
| 6920 | GURL("https://example.com/two"), |
| 6921 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 6922 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6923 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6924 | blink::mojom::Referrer(GURL("https://example.com/"), |
| 6925 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 6926 | task_environment()->RunUntilIdle(); |
| 6927 | |
| 6928 | auto* pending = test_url_loader_factory_.GetPendingRequest(0); |
| 6929 | ASSERT_TRUE(pending); |
| 6930 | EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-UA")); |
| 6931 | } |
| 6932 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6933 | TEST_P(PrefetchServiceClientHintsTest, HighEntropyClientHints) { |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6934 | base::test::ScopedFeatureList enable_prefetch_ch; |
| 6935 | enable_prefetch_ch.InitAndEnableFeature(features::kPrefetchClientHints); |
| 6936 | |
| 6937 | MakePrefetchService( |
| 6938 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 6939 | NavigateAndCommit(GURL("https://example.com/")); |
| 6940 | client_hints_controller_delegate().SetMostRecentMainFrameViewportSize( |
| 6941 | gfx::Size(800, 600)); |
| 6942 | client_hints_controller_delegate().PersistClientHints( |
| 6943 | url::Origin::Create(GURL("https://example.com/")), |
| 6944 | /*parent_rfh=*/nullptr, |
| 6945 | {network::mojom::WebClientHintsType::kViewportWidth}); |
| 6946 | |
| 6947 | MakePrefetchOnMainFrame( |
| 6948 | GURL("https://example.com/two"), |
| 6949 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 6950 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6951 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6952 | blink::mojom::Referrer(GURL("https://example.com/"), |
| 6953 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 6954 | task_environment()->RunUntilIdle(); |
| 6955 | |
| 6956 | auto* pending = test_url_loader_factory_.GetPendingRequest(0); |
| 6957 | ASSERT_TRUE(pending); |
| 6958 | EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-UA")); |
Chris Fredrickson | d923c68 | 2024-07-30 18:19:34 | [diff] [blame] | 6959 | std::optional<std::string> viewport_width = |
| 6960 | pending->request.headers.GetHeader("Sec-CH-Viewport-Width"); |
| 6961 | EXPECT_TRUE(viewport_width.has_value()); |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6962 | |
| 6963 | // Even though we hinted it above, if the actual RenderWidgetHostView reports |
| 6964 | // its size that gets used above. So accept any positive integer. (This |
| 6965 | // notably affects the results on Android.) |
| 6966 | int viewport_width_int; |
Chris Fredrickson | d923c68 | 2024-07-30 18:19:34 | [diff] [blame] | 6967 | EXPECT_TRUE(base::StringToInt(*viewport_width, &viewport_width_int)); |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6968 | EXPECT_GT(viewport_width_int, 0); |
| 6969 | } |
| 6970 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 6971 | TEST_P(PrefetchServiceClientHintsTest, CrossSiteNone) { |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6972 | base::test::ScopedFeatureList enable_prefetch_ch; |
| 6973 | enable_prefetch_ch.InitAndEnableFeatureWithParameters( |
| 6974 | features::kPrefetchClientHints, {{"cross_site_behavior", "none"}}); |
| 6975 | |
| 6976 | MakePrefetchService( |
| 6977 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 6978 | NavigateAndCommit(GURL("https://a.test/")); |
| 6979 | client_hints_controller_delegate().SetMostRecentMainFrameViewportSize( |
| 6980 | gfx::Size(800, 600)); |
| 6981 | client_hints_controller_delegate().PersistClientHints( |
| 6982 | url::Origin::Create(GURL("https://b.test/")), |
| 6983 | /*parent_rfh=*/nullptr, |
| 6984 | {network::mojom::WebClientHintsType::kViewportWidth}); |
| 6985 | |
| 6986 | MakePrefetchOnMainFrame( |
| 6987 | GURL("https://b.test/"), |
| 6988 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 6989 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 6990 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 6991 | blink::mojom::Referrer(GURL("https://a.test/"), |
| 6992 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 6993 | task_environment()->RunUntilIdle(); |
| 6994 | |
| 6995 | auto* pending = test_url_loader_factory_.GetPendingRequest(0); |
| 6996 | ASSERT_TRUE(pending); |
| 6997 | EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-UA")); |
| 6998 | EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width")); |
| 6999 | } |
| 7000 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7001 | TEST_P(PrefetchServiceClientHintsTest, CrossSiteLowEntropy) { |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 7002 | base::test::ScopedFeatureList enable_prefetch_ch; |
| 7003 | enable_prefetch_ch.InitAndEnableFeatureWithParameters( |
| 7004 | features::kPrefetchClientHints, {{"cross_site_behavior", "low_entropy"}}); |
| 7005 | |
| 7006 | MakePrefetchService( |
| 7007 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7008 | NavigateAndCommit(GURL("https://a.test/")); |
| 7009 | client_hints_controller_delegate().SetMostRecentMainFrameViewportSize( |
| 7010 | gfx::Size(800, 600)); |
| 7011 | client_hints_controller_delegate().PersistClientHints( |
| 7012 | url::Origin::Create(GURL("https://b.test/")), |
| 7013 | /*parent_rfh=*/nullptr, |
| 7014 | {network::mojom::WebClientHintsType::kViewportWidth}); |
| 7015 | |
| 7016 | MakePrefetchOnMainFrame( |
| 7017 | GURL("https://b.test/"), |
| 7018 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7019 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7020 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 7021 | blink::mojom::Referrer(GURL("https://a.test/"), |
| 7022 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 7023 | task_environment()->RunUntilIdle(); |
| 7024 | |
| 7025 | auto* pending = test_url_loader_factory_.GetPendingRequest(0); |
| 7026 | ASSERT_TRUE(pending); |
| 7027 | EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-UA")); |
| 7028 | EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width")); |
| 7029 | } |
| 7030 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7031 | TEST_P(PrefetchServiceClientHintsTest, CrossSiteAll) { |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 7032 | base::test::ScopedFeatureList enable_prefetch_ch; |
| 7033 | enable_prefetch_ch.InitAndEnableFeatureWithParameters( |
| 7034 | features::kPrefetchClientHints, {{"cross_site_behavior", "all"}}); |
| 7035 | |
| 7036 | MakePrefetchService( |
| 7037 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7038 | NavigateAndCommit(GURL("https://a.test/")); |
| 7039 | client_hints_controller_delegate().SetMostRecentMainFrameViewportSize( |
| 7040 | gfx::Size(800, 600)); |
| 7041 | client_hints_controller_delegate().PersistClientHints( |
| 7042 | url::Origin::Create(GURL("https://b.test/")), |
| 7043 | /*parent_rfh=*/nullptr, |
| 7044 | {network::mojom::WebClientHintsType::kViewportWidth}); |
| 7045 | |
| 7046 | MakePrefetchOnMainFrame( |
| 7047 | GURL("https://b.test/"), |
| 7048 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7049 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7050 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 7051 | blink::mojom::Referrer(GURL("https://a.test/"), |
| 7052 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 7053 | task_environment()->RunUntilIdle(); |
| 7054 | |
| 7055 | auto* pending = test_url_loader_factory_.GetPendingRequest(0); |
| 7056 | ASSERT_TRUE(pending); |
| 7057 | EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-UA")); |
| 7058 | EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width")); |
| 7059 | } |
| 7060 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7061 | TEST_P(PrefetchServiceTest, CancelWhileBlockedOnHead) { |
Jeremy Roman | 796d9ec | 2024-05-28 18:33:29 | [diff] [blame] | 7062 | MakePrefetchService( |
| 7063 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7064 | NavigateAndCommit(GURL("https://example.com/")); |
| 7065 | |
| 7066 | GURL next_url("https://example.com/two"); |
| 7067 | MakePrefetchOnMainFrame( |
| 7068 | next_url, |
| 7069 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7070 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7071 | blink::mojom::SpeculationEagerness::kImmediate), |
Jeremy Roman | 796d9ec | 2024-05-28 18:33:29 | [diff] [blame] | 7072 | blink::mojom::Referrer(GURL("https://example.com/"), |
| 7073 | network::mojom::ReferrerPolicy::kStrictOrigin)); |
| 7074 | task_environment()->RunUntilIdle(); |
| 7075 | |
| 7076 | // Start a navigation to the URL (one must be running for GetPrefetchToServe |
| 7077 | // to work, at present). |
| 7078 | NavigateInitiatedByRenderer(next_url); |
| 7079 | |
| 7080 | // Try to access the outcome of the prefetch, like the serving path does. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7081 | base::test::TestFuture<PrefetchServingHandle> future; |
Jeremy Roman | 796d9ec | 2024-05-28 18:33:29 | [diff] [blame] | 7082 | GetPrefetchToServe(future, next_url, MainDocumentToken()); |
| 7083 | EXPECT_FALSE(future.IsReady()); |
| 7084 | |
| 7085 | // Cancel the prefetch. |
| 7086 | auto* prefetch_document_manager = |
| 7087 | PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); |
| 7088 | std::vector<blink::mojom::SpeculationCandidatePtr> candidates; |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 7089 | prefetch_document_manager->ProcessCandidates(candidates); |
Jeremy Roman | 796d9ec | 2024-05-28 18:33:29 | [diff] [blame] | 7090 | task_environment()->RunUntilIdle(); |
| 7091 | |
| 7092 | // If all goes well, the service has reported that the prefetch cannot be |
| 7093 | // served. This could be changed in the future to instead wait for the |
| 7094 | // prefetch rather than cancelling it, but what's key here is that it doesn't |
| 7095 | // hang. |
| 7096 | ASSERT_TRUE(future.IsReady()); |
| 7097 | EXPECT_FALSE(future.Get()); |
| 7098 | } |
| 7099 | |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7100 | // Tests that the `PrefetchStreamingURLLoader` disconnection during |
| 7101 | // `PrefetchService`'s redirection handling (starts from |
| 7102 | // `PrefetchStreamingURLLoader::OnReceiveRedirect`, and ends until |
| 7103 | // `PrefetchService` calls `PrefetchStreamingURLLoader::HandleRedirect`) causes |
| 7104 | // no crash, and the corresponding prefetch should not be served. |
| 7105 | // A regression test for crbug.com/396133768. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7106 | TEST_P( |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7107 | PrefetchServiceTest, |
| 7108 | DISABLED_CHROMEOS(URLLoaderDisconnectedWhileHandlingRedirectEligibilty)) { |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7109 | MakePrefetchService( |
| 7110 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7111 | PrefetchService* prefetch_service = |
| 7112 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 7113 | |
| 7114 | MakePrefetchOnMainFrame( |
| 7115 | GURL("https://example.com"), |
| 7116 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7117 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7118 | blink::mojom::SpeculationEagerness::kImmediate)); |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7119 | task_environment()->RunUntilIdle(); |
| 7120 | VerifyCommonRequestState(GURL("https://example.com"), |
| 7121 | {.use_prefetch_proxy = true}); |
| 7122 | VerifyFollowRedirectParams(0); |
| 7123 | |
| 7124 | // Set a handler so that the eligibility check sequences invocked after |
| 7125 | // `PrefetchService::OnPrefetchRedirect` will be paused. |
| 7126 | base::test::TestFuture<base::OnceClosure> |
| 7127 | redirect_eligibility_check_callback_future; |
| 7128 | prefetch_service->SetDelayEligibilityCheckForTesting(base::BindRepeating( |
| 7129 | [](base::test::TestFuture<base::OnceClosure>* |
| 7130 | redirect_eligibility_check_callback_future, |
| 7131 | base::OnceClosure callback) { |
| 7132 | redirect_eligibility_check_callback_future->SetValue( |
| 7133 | std::move(callback)); |
| 7134 | }, |
| 7135 | base::Unretained(&redirect_eligibility_check_callback_future))); |
| 7136 | |
| 7137 | net::RedirectInfo redirect_info; |
| 7138 | redirect_info.new_method = "GET"; |
| 7139 | redirect_info.new_referrer_policy = |
| 7140 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
| 7141 | redirect_info.new_url = GURL("https://redirect.com"); |
| 7142 | network::TestURLLoaderFactory::PendingRequest* request = |
| 7143 | test_url_loader_factory_.GetPendingRequest(0); |
| 7144 | ASSERT_TRUE(request); |
| 7145 | ASSERT_TRUE(request->client); |
| 7146 | auto redirect_head = CreateURLResponseHeadForPrefetch( |
| 7147 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 7148 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com")); |
| 7149 | |
| 7150 | request->client->OnReceiveRedirect(redirect_info, redirect_head.Clone()); |
| 7151 | task_environment()->RunUntilIdle(); |
| 7152 | |
| 7153 | // Now the redirect handling is paused right before |
| 7154 | // `PrefetchService::OnPrefetchRedirect.` |
| 7155 | |
| 7156 | // Disconnect URLLoader. |
| 7157 | base::test::TestFuture<void> disconnect_future; |
| 7158 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7159 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 7160 | PrefetchContainer::Key(MainDocumentToken(), |
| 7161 | GURL("https://example.com"))); |
| 7162 | ASSERT_EQ(1u, prefetches.size()); |
| 7163 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7164 | prefetch_container->GetStreamingURLLoader()->SetOnDeletionScheduledForTests( |
| 7165 | disconnect_future.GetCallback()); |
| 7166 | request->client.reset(); |
| 7167 | ASSERT_TRUE(disconnect_future.Wait()); |
| 7168 | |
| 7169 | // Resume the eligibility check. |
| 7170 | redirect_eligibility_check_callback_future.Take().Run(); |
| 7171 | task_environment()->RunUntilIdle(); |
| 7172 | |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 7173 | // Now `PrefetchServableState` should be `kNotServable` since we don't |
| 7174 | // have a non-redirect response but `PrefetchStreamingURLLoader` is gone. |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7175 | EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()), |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 7176 | PrefetchServableState::kNotServable); |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7177 | |
| 7178 | // Start a navigation. The prefetch should not be served. |
| 7179 | std::unique_ptr<NavigationResult> navigation_result = |
| 7180 | SimulatePartOfNavigation(GURL("https://example.com"), |
| 7181 | /*is_renderer_initiated=*/true, |
| 7182 | /*is_nav_prerender=*/true); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7183 | ASSERT_TRUE(navigation_result->serving_handle_future.IsReady()); |
| 7184 | EXPECT_FALSE(navigation_result->serving_handle_future.Take()); |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7185 | |
| 7186 | prefetch_service->SetDelayEligibilityCheckForTesting(base::NullCallback()); |
| 7187 | } |
| 7188 | |
| 7189 | // Tests that the `PrefetchStreamingURLLoader` disconnection during |
| 7190 | // `PrefetchService`'s redirection handling causes no crash, and successfully |
| 7191 | // unblocks the navigation that potentially matches the corresponding |
| 7192 | // prefetch and thus was blocked in the match resolver (BlockUntilHead). |
| 7193 | // A regression test for crbug.com/396133768.√ |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7194 | TEST_P( |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7195 | PrefetchServiceTest, |
| 7196 | DISABLED_CHROMEOS( |
| 7197 | URLLoaderDisconnectedWhileHandlingRedirectEligibilty_BlockUntilHead)) { |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7198 | MakePrefetchService( |
| 7199 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7200 | PrefetchService* prefetch_service = |
| 7201 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 7202 | |
| 7203 | MakePrefetchOnMainFrame( |
| 7204 | GURL("https://example.com"), |
| 7205 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7206 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7207 | blink::mojom::SpeculationEagerness::kImmediate)); |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7208 | task_environment()->RunUntilIdle(); |
| 7209 | VerifyCommonRequestState(GURL("https://example.com"), |
| 7210 | {.use_prefetch_proxy = true}); |
| 7211 | VerifyFollowRedirectParams(0); |
| 7212 | |
| 7213 | // Start a navigation and invoke FindPrefetch to start a wait loop. |
| 7214 | std::unique_ptr<NavigationResult> navigation_result = |
| 7215 | SimulatePartOfNavigation(GURL("https://example.com"), |
| 7216 | /*is_renderer_initiated=*/true, |
| 7217 | /*is_nav_prerender=*/true); |
| 7218 | task_environment()->RunUntilIdle(); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7219 | ASSERT_FALSE(navigation_result->serving_handle_future.IsReady()); |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7220 | |
| 7221 | // Set a handler so that the eligibility check sequences invocked after |
| 7222 | // `PrefetchService::OnPrefetchRedirect` will be paused. |
| 7223 | base::test::TestFuture<base::OnceClosure> |
| 7224 | redirect_eligibility_check_callback_future; |
| 7225 | prefetch_service->SetDelayEligibilityCheckForTesting(base::BindRepeating( |
| 7226 | [](base::test::TestFuture<base::OnceClosure>* |
| 7227 | redirect_eligibility_check_callback_future, |
| 7228 | base::OnceClosure callback) { |
| 7229 | redirect_eligibility_check_callback_future->SetValue( |
| 7230 | std::move(callback)); |
| 7231 | }, |
| 7232 | base::Unretained(&redirect_eligibility_check_callback_future))); |
| 7233 | |
| 7234 | // Start redirecting. |
| 7235 | net::RedirectInfo redirect_info; |
| 7236 | redirect_info.new_method = "GET"; |
| 7237 | redirect_info.new_referrer_policy = |
| 7238 | net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
| 7239 | redirect_info.new_url = GURL("https://redirect.com"); |
| 7240 | network::TestURLLoaderFactory::PendingRequest* request = |
| 7241 | test_url_loader_factory_.GetPendingRequest(0); |
| 7242 | ASSERT_TRUE(request); |
| 7243 | ASSERT_TRUE(request->client); |
| 7244 | auto redirect_head = CreateURLResponseHeadForPrefetch( |
| 7245 | net::HTTP_PERMANENT_REDIRECT, kHTMLMimeType, |
| 7246 | /*use_prefetch_proxy=*/true, {}, GURL("https://redirect.com")); |
| 7247 | |
| 7248 | request->client->OnReceiveRedirect(redirect_info, redirect_head.Clone()); |
| 7249 | task_environment()->RunUntilIdle(); |
| 7250 | |
| 7251 | // Now the redirect handling is paused right before |
| 7252 | // `PrefetchService::OnPrefetchRedirect.` |
| 7253 | |
| 7254 | // Disconnect URLLoader. |
| 7255 | base::test::TestFuture<void> disconnect_future; |
| 7256 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7257 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 7258 | PrefetchContainer::Key(MainDocumentToken(), |
| 7259 | GURL("https://example.com"))); |
| 7260 | ASSERT_EQ(1u, prefetches.size()); |
| 7261 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7262 | prefetch_container->GetStreamingURLLoader()->SetOnDeletionScheduledForTests( |
| 7263 | disconnect_future.GetCallback()); |
| 7264 | request->client.reset(); |
| 7265 | ASSERT_TRUE(disconnect_future.Wait()); |
| 7266 | // `PrefetchStreamingURLLoader::DisconnectPrefetchURLLoaderMojo` will directly |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 7267 | // invoke `PrefetchMatchResolver::OnHeadDetermine`. At this point the |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 7268 | // container's `PrefetchServableState` should be |
| 7269 | // `kShouldBlockUntilHeadReceived` (same with a normal case of an ineligible |
| 7270 | // redirect), so it should be unblocked for unmatched. |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7271 | // TODO(crbug.com/396133768): Explicitly check more detailed Servable/Load |
| 7272 | // states. |
| 7273 | redirect_eligibility_check_callback_future.Take().Run(); |
| 7274 | task_environment()->RunUntilIdle(); |
| 7275 | // The prefetch should not be served. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7276 | EXPECT_FALSE(navigation_result->serving_handle_future.Take()); |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 7277 | |
| 7278 | prefetch_service->SetDelayEligibilityCheckForTesting(base::NullCallback()); |
| 7279 | } |
| 7280 | |
kenoss | 8fb8285 | 2025-03-11 02:20:42 | [diff] [blame] | 7281 | // Test that multiple concurrent navigations are handled correctly. |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7282 | // |
| 7283 | // Scenario: |
| 7284 | // |
| 7285 | // - Prefetch A started. |
| 7286 | // - A received non-redirect header. |
| 7287 | // - Navigation X started, which matches to A. Unblocked synchronously as |
| 7288 | // success. |
| 7289 | // - Navigation Y started, which matches to A. Unblocked synchronously as |
| 7290 | // success. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7291 | TEST_P( |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7292 | PrefetchServiceTest, |
| 7293 | DISABLED_CHROMEOS(MultipleConcurrentNavigationSuccessBeforeNavigations)) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7294 | base::HistogramTester histogram_tester; |
| 7295 | |
| 7296 | MakePrefetchService( |
| 7297 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7298 | |
| 7299 | MakePrefetchOnMainFrame( |
| 7300 | GURL("https://example.com"), |
| 7301 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7302 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7303 | blink::mojom::SpeculationEagerness::kImmediate)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7304 | task_environment()->RunUntilIdle(); |
| 7305 | |
| 7306 | VerifyCommonRequestState(GURL("https://example.com"), |
| 7307 | {.use_prefetch_proxy = true}); |
| 7308 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 7309 | /*use_prefetch_proxy=*/true, |
| 7310 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 7311 | |
| 7312 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody)); |
| 7313 | |
| 7314 | std::unique_ptr<NavigationResult> nav_res1 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7315 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7316 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7317 | std::unique_ptr<NavigationResult> nav_res2 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7318 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7319 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7320 | task_environment()->RunUntilIdle(); |
| 7321 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7322 | ExpectServingReaderSuccess(FROM_HERE, nav_res1->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7323 | ExpectServingMetrics( |
| 7324 | FROM_HERE, nav_res1, |
| 7325 | {.prefetch_status = PrefetchStatus::kPrefetchSuccessful, |
| 7326 | .prefetch_header_latency = base::Milliseconds(kHeaderLatency), |
| 7327 | .required_private_prefetch_proxy = true}); |
| 7328 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7329 | ExpectServingReaderSuccess(FROM_HERE, nav_res2->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7330 | ExpectServingMetrics( |
| 7331 | FROM_HERE, nav_res2, |
| 7332 | {.prefetch_status = PrefetchStatus::kPrefetchSuccessful, |
| 7333 | .prefetch_header_latency = base::Milliseconds(kHeaderLatency), |
| 7334 | .required_private_prefetch_proxy = true}); |
| 7335 | |
| 7336 | histogram_tester.ExpectUniqueSample( |
| 7337 | "PrefetchProxy.AfterClick.RedirectChainSize", 1, 2); |
| 7338 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 7339 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
| 7340 | "SpeculationRule_" |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 7341 | "Immediate2", |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7342 | false, 2); |
Taiyo Mizuhashi | a009caf | 2025-08-05 07:34:22 | [diff] [blame] | 7343 | // Call `PrefetchContainer` dtor to record the UMA. |
| 7344 | PrefetchDocumentManager::DeleteForCurrentDocument(main_rfh()); |
| 7345 | histogram_tester.ExpectUniqueSample( |
| 7346 | "Prefetch.PrefetchContainer.ServedCount.SpeculationRule_Immediate2", 2, |
| 7347 | 1); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7348 | } |
| 7349 | |
| 7350 | // Scenario: |
| 7351 | // |
| 7352 | // - Prefetch A started. |
| 7353 | // - Navigation X started, which matches to A. Blocked by A. |
| 7354 | // - Navigation Y started, which matches to A. Blocked by A. |
| 7355 | // - A received non-redirect header. Unblocks them as success. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7356 | TEST_P( |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7357 | PrefetchServiceTest, |
| 7358 | DISABLED_CHROMEOS(MultipleConcurrentNavigationBlockUntilHeadThenSuccess)) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7359 | base::HistogramTester histogram_tester; |
| 7360 | |
| 7361 | MakePrefetchService( |
| 7362 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7363 | |
| 7364 | MakePrefetchOnMainFrame( |
| 7365 | GURL("https://example.com"), |
| 7366 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7367 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7368 | blink::mojom::SpeculationEagerness::kImmediate)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7369 | task_environment()->RunUntilIdle(); |
| 7370 | |
| 7371 | VerifyCommonRequestState(GURL("https://example.com"), |
| 7372 | {.use_prefetch_proxy = true}); |
| 7373 | |
| 7374 | std::unique_ptr<NavigationResult> nav_res1 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7375 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7376 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7377 | std::unique_ptr<NavigationResult> nav_res2 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7378 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7379 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7380 | task_environment()->RunUntilIdle(); |
| 7381 | |
| 7382 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 7383 | /*use_prefetch_proxy=*/true, |
| 7384 | {{"X-Testing", "Hello World"}}, |
| 7385 | std::size(kHTMLBody)); |
| 7386 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 7387 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 7388 | |
| 7389 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7390 | blink::mojom::SpeculationEagerness::kImmediate, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7391 | /*is_accurate=*/true); |
| 7392 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7393 | ExpectServingReaderSuccess(FROM_HERE, nav_res1->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7394 | // TODO(crbug.com/356540465): See the bug. Make PrefetchServingMetrics |
| 7395 | // available for multiple concurrent navigations. |
| 7396 | ExpectServingMetrics( |
| 7397 | FROM_HERE, nav_res1, |
| 7398 | {.prefetch_status = PrefetchStatus::kPrefetchNotFinishedInTime, |
| 7399 | .prefetch_header_latency = std::nullopt, |
| 7400 | .required_private_prefetch_proxy = true}); |
| 7401 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7402 | ExpectServingReaderSuccess(FROM_HERE, nav_res2->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7403 | ExpectServingMetrics( |
| 7404 | FROM_HERE, nav_res2, |
| 7405 | {.prefetch_status = PrefetchStatus::kPrefetchSuccessful, |
| 7406 | .prefetch_header_latency = base::Milliseconds(kHeaderLatency), |
| 7407 | .required_private_prefetch_proxy = true}); |
| 7408 | |
| 7409 | histogram_tester.ExpectUniqueSample( |
| 7410 | "PrefetchProxy.AfterClick.RedirectChainSize", 1, 2); |
| 7411 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 7412 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
| 7413 | "SpeculationRule_" |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 7414 | "Immediate2", |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7415 | true, 2); |
Taiyo Mizuhashi | a009caf | 2025-08-05 07:34:22 | [diff] [blame] | 7416 | // Call `PrefetchContainer` dtor to record the UMA. |
| 7417 | PrefetchDocumentManager::DeleteForCurrentDocument(main_rfh()); |
| 7418 | histogram_tester.ExpectUniqueSample( |
| 7419 | "Prefetch.PrefetchContainer.ServedCount.SpeculationRule_Immediate2", 2, |
| 7420 | 1); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7421 | } |
| 7422 | |
| 7423 | // Scenario: |
| 7424 | // |
| 7425 | // - Prefetch A started with NVS hint. |
| 7426 | // - Navigation X started, which is potentially matches and eventually matches |
| 7427 | // to A. Blocked by A. |
| 7428 | // - Navigation Y started, which is potentially matches and not eventually |
| 7429 | // matches to A. Blocked by A. |
| 7430 | // - A received non-redirect header. Unblocks them as success/fail. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7431 | TEST_P(PrefetchServiceTest, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7432 | DISABLED_CHROMEOS( |
| 7433 | MultipleConcurrentNavigationBlockUntilHeadThenSuccessFail)) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7434 | base::HistogramTester histogram_tester; |
| 7435 | |
| 7436 | MakePrefetchService( |
| 7437 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7438 | |
| 7439 | network::mojom::NoVarySearchPtr no_vary_search_hint = |
| 7440 | network::mojom::NoVarySearch::New(); |
| 7441 | no_vary_search_hint->vary_on_key_order = true; |
| 7442 | no_vary_search_hint->search_variance = |
| 7443 | network::mojom::SearchParamsVariance::NewNoVaryParams( |
| 7444 | std::vector<std::string>({"match", "notEventuallyMatch"})); |
| 7445 | |
| 7446 | MakePrefetchOnMainFrame( |
| 7447 | GURL("https://example.com/?match=0"), |
| 7448 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7449 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7450 | blink::mojom::SpeculationEagerness::kImmediate), |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7451 | /* referrer */ blink::mojom::Referrer(), std::move(no_vary_search_hint)); |
| 7452 | task_environment()->RunUntilIdle(); |
| 7453 | |
| 7454 | VerifyCommonRequestState(GURL("https://example.com/?match=0"), |
| 7455 | {.use_prefetch_proxy = true}); |
| 7456 | |
| 7457 | std::unique_ptr<NavigationResult> nav_res1 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7458 | GURL("https://example.com/?match=1"), /*is_renderer_initiated=*/true, |
| 7459 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7460 | std::unique_ptr<NavigationResult> nav_res2 = SimulatePartOfNavigation( |
| 7461 | GURL("https://example.com/?notEventuallyMatch=1"), |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7462 | /*is_renderer_initiated=*/true, /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7463 | task_environment()->RunUntilIdle(); |
| 7464 | |
| 7465 | SendHeadOfResponseAndWait( |
| 7466 | net::HTTP_OK, kHTMLMimeType, |
| 7467 | /*use_prefetch_proxy=*/true, |
| 7468 | {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"match\")"}}, |
| 7469 | std::size(kHTMLBody)); |
| 7470 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 7471 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 7472 | |
| 7473 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7474 | blink::mojom::SpeculationEagerness::kImmediate, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7475 | /*is_accurate=*/true); |
| 7476 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7477 | ExpectServingReaderSuccess(FROM_HERE, nav_res1->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7478 | // TODO(crbug.com/356540465): See the bug. Make PrefetchServingMetrics |
| 7479 | // available for multiple concurrent navigations. |
| 7480 | ExpectServingMetrics( |
| 7481 | FROM_HERE, nav_res1, |
| 7482 | {.prefetch_status = PrefetchStatus::kPrefetchNotFinishedInTime, |
| 7483 | .prefetch_header_latency = std::nullopt, |
| 7484 | .required_private_prefetch_proxy = true}); |
| 7485 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7486 | EXPECT_FALSE(nav_res2->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7487 | |
| 7488 | histogram_tester.ExpectUniqueSample( |
| 7489 | "PrefetchProxy.AfterClick.RedirectChainSize", 1, 1); |
| 7490 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 7491 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
| 7492 | "SpeculationRule_" |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 7493 | "Immediate2", |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7494 | true, 2); |
Taiyo Mizuhashi | a009caf | 2025-08-05 07:34:22 | [diff] [blame] | 7495 | // Call `PrefetchContainer` dtor to record the UMA. |
| 7496 | PrefetchDocumentManager::DeleteForCurrentDocument(main_rfh()); |
| 7497 | histogram_tester.ExpectUniqueSample( |
| 7498 | "Prefetch.PrefetchContainer.ServedCount.SpeculationRule_Immediate2", 1, |
| 7499 | 1); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7500 | } |
| 7501 | |
| 7502 | // Scenario: |
| 7503 | // |
| 7504 | // - Prefetch A started. |
| 7505 | // - Navigation X started, which matches to A. Blocked by A. |
| 7506 | // - Navigation Y started, which matches to A. Blocked by A. |
| 7507 | // - Cookies of domain of A changed. |
| 7508 | // - A received non-redirect header. Unblocks them as fail. |
| 7509 | // |
| 7510 | // This test checks that it is safe to call |
kenoss | 8fb8285 | 2025-03-11 02:20:42 | [diff] [blame] | 7511 | // `PrefetchContainer::OnDetectedCookiesChange()` multiple times. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7512 | TEST_P(PrefetchServiceTest, |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7513 | DISABLED_CHROMEOS( |
| 7514 | MultipleConcurrentNavigationBlockUntilHeadThenCookiesChanged)) { |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7515 | base::HistogramTester histogram_tester; |
| 7516 | |
| 7517 | MakePrefetchService( |
| 7518 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7519 | |
| 7520 | MakePrefetchOnMainFrame( |
| 7521 | GURL("https://example.com"), |
| 7522 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7523 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7524 | blink::mojom::SpeculationEagerness::kImmediate)); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7525 | task_environment()->RunUntilIdle(); |
| 7526 | |
| 7527 | VerifyCommonRequestState(GURL("https://example.com"), |
| 7528 | {.use_prefetch_proxy = true}); |
| 7529 | |
| 7530 | std::unique_ptr<NavigationResult> nav_res1 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7531 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7532 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7533 | std::unique_ptr<NavigationResult> nav_res2 = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7534 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7535 | /*is_nav_prerender=*/false); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7536 | task_environment()->RunUntilIdle(); |
| 7537 | |
| 7538 | ASSERT_TRUE(SetCookie(GURL("https://example.com"), "testing")); |
| 7539 | |
| 7540 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 7541 | /*use_prefetch_proxy=*/true, |
| 7542 | {{"X-Testing", "Hello World"}}, |
| 7543 | std::size(kHTMLBody)); |
| 7544 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 7545 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 7546 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7547 | EXPECT_FALSE(nav_res1->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7548 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7549 | EXPECT_FALSE(nav_res2->serving_handle_future.Take()); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7550 | |
| 7551 | histogram_tester.ExpectTotalCount( |
| 7552 | "PrefetchProxy.AfterClick.RedirectChainSize", 0); |
| 7553 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 7554 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
| 7555 | "SpeculationRule_" |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 7556 | "Immediate2", |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7557 | true, 2); |
Taiyo Mizuhashi | a009caf | 2025-08-05 07:34:22 | [diff] [blame] | 7558 | // Call `PrefetchContainer` dtor to record the UMA. |
| 7559 | PrefetchDocumentManager::DeleteForCurrentDocument(main_rfh()); |
| 7560 | histogram_tester.ExpectUniqueSample( |
| 7561 | "Prefetch.PrefetchContainer.ServedCount.SpeculationRule_Immediate2", 0, |
| 7562 | 1); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 7563 | } |
| 7564 | |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7565 | // Scenario: |
| 7566 | // |
| 7567 | // - Prefetch ahead of prerender A started. The eligibility check is not done |
| 7568 | // yet. |
| 7569 | // - Navigation X started, which is potentially matches and eventually matches |
| 7570 | // to A. Blocked by A. (Regard X as prerender, while we don't assume that in |
| 7571 | // this test actually.) |
| 7572 | // - The eligibility check of A scceeds. Matching process proceeds and ends as |
| 7573 | // success. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7574 | TEST_P(PrefetchServiceTest, |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7575 | DISABLED_CHROMEOS(PrefetchAheadOfPrerenderSuccess)) { |
| 7576 | base::test::ScopedFeatureList scoped_feature_list; |
| 7577 | scoped_feature_list.InitWithFeatures( |
| 7578 | {features::kPrerender2FallbackPrefetchSpecRules}, {}); |
| 7579 | |
| 7580 | base::HistogramTester histogram_tester; |
| 7581 | |
| 7582 | MakePrefetchService( |
| 7583 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7584 | |
| 7585 | base::test::TestFuture<base::OnceClosure> eligibility_check_callback_future; |
| 7586 | auto& prefetch_service = *PrefetchService::GetFromFrameTreeNodeId( |
| 7587 | web_contents()->GetPrimaryMainFrame()->GetFrameTreeNodeId()); |
| 7588 | prefetch_service.SetDelayEligibilityCheckForTesting(base::BindRepeating( |
| 7589 | [](base::test::TestFuture<base::OnceClosure>* |
| 7590 | eligibility_check_callback_future, |
| 7591 | base::OnceClosure callback) { |
| 7592 | eligibility_check_callback_future->SetValue(std::move(callback)); |
| 7593 | }, |
| 7594 | base::Unretained(&eligibility_check_callback_future))); |
| 7595 | |
| 7596 | MakePrefetchOnMainFrame( |
| 7597 | GURL("https://example.com"), |
| 7598 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7599 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7600 | blink::mojom::SpeculationEagerness::kImmediate), |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7601 | blink::mojom::Referrer(), network::mojom::NoVarySearchPtr(), |
| 7602 | /*planned_max_preloading_type=*/PreloadingType::kPrerender); |
| 7603 | task_environment()->RunUntilIdle(); |
| 7604 | |
| 7605 | std::unique_ptr<NavigationResult> nav_res = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7606 | GURL("https://example.com"), /*is_renderer_initiated=*/true, |
| 7607 | /*is_nav_prerender=*/true); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7608 | task_environment()->RunUntilIdle(); |
| 7609 | |
| 7610 | // The prefetch is a match candidate, but eligibility check is not done yet. |
| 7611 | // Matching process is in progress. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7612 | ASSERT_FALSE(nav_res->serving_handle_future.IsReady()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7613 | |
| 7614 | // Proceed to the eligibility check. |
| 7615 | eligibility_check_callback_future.Take().Run(); |
| 7616 | |
David Risney | a1dd2bf | 2025-03-06 03:40:42 | [diff] [blame] | 7617 | VerifyCommonRequestState( |
| 7618 | GURL("https://example.com"), |
| 7619 | { |
| 7620 | .use_prefetch_proxy = false, |
| 7621 | .sec_purpose_header_value = |
| 7622 | blink::kSecPurposePrefetchPrerenderHeaderValue, |
| 7623 | }); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7624 | |
| 7625 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 7626 | /*use_prefetch_proxy=*/true, |
| 7627 | {{"X-Testing", "Hello World"}}, |
| 7628 | std::size(kHTMLBody)); |
| 7629 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 7630 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 7631 | |
| 7632 | ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody), |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7633 | blink::mojom::SpeculationEagerness::kImmediate, |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7634 | /*is_accurate=*/true); |
| 7635 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7636 | ExpectServingReaderSuccess(FROM_HERE, nav_res->serving_handle_future.Take()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7637 | // TODO(crbug.com/356540465): See the bug. Make PrefetchServingMetrics |
| 7638 | // available for multiple concurrent navigations. |
| 7639 | ExpectServingMetrics( |
| 7640 | FROM_HERE, nav_res, |
| 7641 | {.prefetch_status = PrefetchStatus::kPrefetchSuccessful, |
| 7642 | .prefetch_header_latency = base::Milliseconds(kHeaderLatency), |
| 7643 | .required_private_prefetch_proxy = false}); |
| 7644 | |
| 7645 | histogram_tester.ExpectUniqueSample( |
| 7646 | "PrefetchProxy.AfterClick.RedirectChainSize", 1, 1); |
| 7647 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 7648 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
| 7649 | "SpeculationRule_" |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 7650 | "Immediate2", |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7651 | true, 1); |
kenoss | 14462ae | 2025-03-21 02:39:51 | [diff] [blame] | 7652 | |
| 7653 | prefetch_service.SetDelayEligibilityCheckForTesting(base::NullCallback()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7654 | } |
| 7655 | |
| 7656 | // Scenario: |
| 7657 | // |
| 7658 | // - Prefetch ahead of prerender A started. The eligibility check is not done |
| 7659 | // yet. |
| 7660 | // - Navigation X started, which is potentially matches to A. Blocked by A. |
| 7661 | // (Regard X as prerender, while we don't assume that in this test actually.) |
| 7662 | // - The eligibility check of A failed (due to non https). Matching process ends |
| 7663 | // with no prefetch. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7664 | TEST_P(PrefetchServiceTest, |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7665 | DISABLED_CHROMEOS(PrefetchAheadOfPrerenderIneligible)) { |
| 7666 | base::test::ScopedFeatureList scoped_feature_list; |
| 7667 | scoped_feature_list.InitWithFeatures( |
| 7668 | {features::kPrerender2FallbackPrefetchSpecRules}, {}); |
| 7669 | |
| 7670 | base::HistogramTester histogram_tester; |
| 7671 | |
| 7672 | MakePrefetchService( |
| 7673 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 7674 | |
| 7675 | base::test::TestFuture<base::OnceClosure> eligibility_check_callback_future; |
| 7676 | auto& prefetch_service = *PrefetchService::GetFromFrameTreeNodeId( |
| 7677 | web_contents()->GetPrimaryMainFrame()->GetFrameTreeNodeId()); |
| 7678 | prefetch_service.SetDelayEligibilityCheckForTesting(base::BindRepeating( |
| 7679 | [](base::test::TestFuture<base::OnceClosure>* |
| 7680 | eligibility_check_callback_future, |
| 7681 | base::OnceClosure callback) { |
| 7682 | eligibility_check_callback_future->SetValue(std::move(callback)); |
| 7683 | }, |
| 7684 | base::Unretained(&eligibility_check_callback_future))); |
| 7685 | |
| 7686 | MakePrefetchOnMainFrame( |
| 7687 | GURL("http://example.com"), |
| 7688 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7689 | /*use_prefetch_proxy=*/false, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7690 | blink::mojom::SpeculationEagerness::kImmediate), |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7691 | blink::mojom::Referrer(), network::mojom::NoVarySearchPtr(), |
| 7692 | /*planned_max_preloading_type=*/PreloadingType::kPrerender); |
| 7693 | task_environment()->RunUntilIdle(); |
| 7694 | |
| 7695 | std::unique_ptr<NavigationResult> nav_res = SimulatePartOfNavigation( |
kenoss | 804a72dc | 2024-10-11 12:43:49 | [diff] [blame] | 7696 | GURL("http://example.com"), /*is_renderer_initiated=*/true, |
| 7697 | /*is_nav_prerender=*/true); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7698 | task_environment()->RunUntilIdle(); |
| 7699 | |
| 7700 | // The prefetch is a match candidate, but eligibility check is not done yet. |
| 7701 | // Matching process is in progress. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7702 | ASSERT_FALSE(nav_res->serving_handle_future.IsReady()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7703 | |
| 7704 | // Proceed to the eligibility check. |
| 7705 | eligibility_check_callback_future.Take().Run(); |
| 7706 | |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 7707 | ASSERT_FALSE(nav_res->serving_handle_future.Take()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7708 | |
| 7709 | EXPECT_EQ(RequestCount(), 0); |
| 7710 | ExpectPrefetchNotEligible(histogram_tester, |
| 7711 | PreloadingEligibility::kSchemeIsNotHttps, |
| 7712 | /*is_accurate=*/true); |
| 7713 | |
| 7714 | // Note that serving metrics is not recorded for the prefetch because |
| 7715 | // `HasPrefetchStatus()` doesn't hold in |
| 7716 | // `PrefetchContainer::UpdateServingPageMetrics()`. |
kenoss | 14462ae | 2025-03-21 02:39:51 | [diff] [blame] | 7717 | |
| 7718 | prefetch_service.SetDelayEligibilityCheckForTesting(base::NullCallback()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7719 | } |
| 7720 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7721 | TEST_P(PrefetchServiceTest, |
Wayne Jackson Jr. | 0118d2a | 2025-02-21 10:53:46 | [diff] [blame] | 7722 | DISABLED_CHROMEOS(IsPrefetchDuplicateSameNoVarySearchHint)) { |
Wayne Jackson Jr. | 0118d2a | 2025-02-21 10:53:46 | [diff] [blame] | 7723 | base::HistogramTester histogram_tester; |
| 7724 | MakePrefetchService( |
| 7725 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 7726 | /*num_on_prefetch_likely_calls=*/std::nullopt)); |
| 7727 | |
| 7728 | std::unique_ptr<ProbePrefetchRequestStatusListener> probe_listener = |
| 7729 | std::make_unique<ProbePrefetchRequestStatusListener>(); |
| 7730 | |
| 7731 | std::unique_ptr<content::PrefetchRequestStatusListener> |
| 7732 | request_status_listener = |
| 7733 | std::make_unique<TestablePrefetchRequestStatusListener>( |
| 7734 | probe_listener->GetWeakPtr()); |
| 7735 | |
| 7736 | std::vector<std::string> no_vary_params = {"ts"}; |
| 7737 | net::HttpNoVarySearchData nvs_hint = |
| 7738 | net::HttpNoVarySearchData::CreateFromNoVaryParams(no_vary_params, false); |
| 7739 | GURL pf_one_url("https://example.com/search?q=ai&ts=1000"); |
| 7740 | std::unique_ptr<content::PrefetchHandle> handle = |
| 7741 | MakePrefetchFromBrowserContext(pf_one_url, nvs_hint, {}, |
| 7742 | std::move(request_status_listener)); |
| 7743 | task_environment()->RunUntilIdle(); |
| 7744 | |
| 7745 | // Test with the "no-vary" param value changed. |
| 7746 | GURL pf_two_url("https://example.com/search?q=ai&ts=1001"); |
| 7747 | EXPECT_TRUE(browser_context()->IsPrefetchDuplicate(pf_two_url, nvs_hint)); |
| 7748 | |
| 7749 | // Test with an additional query parameter. |
| 7750 | GURL pf_three_url("https://example.com/search?q=ai&ts=1000&qsubts=1000"); |
| 7751 | EXPECT_FALSE(browser_context()->IsPrefetchDuplicate(pf_three_url, nvs_hint)); |
| 7752 | |
| 7753 | // Test with the same params with different values. |
| 7754 | GURL pf_four_url("https://example.com/search?q=dogs&ts=1002"); |
| 7755 | EXPECT_FALSE(browser_context()->IsPrefetchDuplicate(pf_four_url, nvs_hint)); |
| 7756 | } |
| 7757 | |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7758 | // These tests check the behavior of |
| 7759 | // `PrefetchService::AddPrefetchContainerWithoutStartingPrefetch()` if an old |
| 7760 | // prefetch is registered and yet another new prefetch for the same key is |
| 7761 | // added. |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7762 | class PrefetchServiceAddPrefetchContainerTest |
| 7763 | : public PrefetchServiceTestBase, |
| 7764 | public WithPrefetchServiceRearchParam, |
| 7765 | public ::testing::WithParamInterface<PrefetchServiceRearchParam::Arg> { |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7766 | public: |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7767 | PrefetchServiceAddPrefetchContainerTest() |
| 7768 | : WithPrefetchServiceRearchParam(GetParam()) {} |
| 7769 | |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7770 | void InitScopedFeatureList() override { |
kenoss | 557d409 | 2025-04-01 05:01:15 | [diff] [blame] | 7771 | InitBaseParams(); |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7772 | InitRearchFeatures(); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7773 | scoped_feature_list_for_prerender2_fallback_.InitWithFeatures( |
| 7774 | {features::kPrerender2FallbackPrefetchSpecRules}, {}); |
| 7775 | } |
| 7776 | |
| 7777 | PrefetchService& GetPrefetchService() { |
| 7778 | return *PrefetchService::GetFromFrameTreeNodeId( |
| 7779 | web_contents()->GetPrimaryMainFrame()->GetFrameTreeNodeId()); |
| 7780 | } |
| 7781 | |
| 7782 | std::unique_ptr<PrefetchContainer> CreateSpeculationRulesPrefetchContainer( |
| 7783 | const blink::DocumentToken& document_token, |
| 7784 | const GURL& prefetch_url, |
| 7785 | PreloadingType planned_max_preloading_type) { |
| 7786 | auto prefetch_type = |
| 7787 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 7788 | /*use_prefetch_proxy=*/true, |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 7789 | blink::mojom::SpeculationEagerness::kImmediate); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7790 | |
| 7791 | auto* preloading_data = |
| 7792 | PreloadingData::GetOrCreateForWebContents(web_contents()); |
| 7793 | PreloadingURLMatchCallback matcher = |
| 7794 | PreloadingDataImpl::GetPrefetchServiceMatcher( |
| 7795 | GetPrefetchService(), |
| 7796 | PrefetchContainer::Key(document_token, prefetch_url)); |
| 7797 | |
| 7798 | auto* attempt = static_cast<PreloadingAttemptImpl*>( |
| 7799 | preloading_data->AddPreloadingAttempt( |
| 7800 | GetPredictorForPreloadingTriggerType(prefetch_type.trigger_type()), |
| 7801 | PreloadingType::kPrefetch, std::move(matcher), |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7802 | web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId())); |
| 7803 | |
| 7804 | attempt->SetSpeculationEagerness(prefetch_type.GetEagerness()); |
| 7805 | |
| 7806 | return std::make_unique<PrefetchContainer>( |
| 7807 | static_cast<content::RenderFrameHostImpl&>(*main_rfh()), document_token, |
| 7808 | prefetch_url, std::move(prefetch_type), blink::mojom::Referrer(), |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 7809 | std::make_optional(SpeculationRulesTags()), |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 7810 | /*no_vary_search_hint=*/std::nullopt, |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 7811 | /*priority=*/std::nullopt, |
kenoss | 3bd73b8 | 2024-10-10 20:33:49 | [diff] [blame] | 7812 | /*prefetch_document_manager=*/nullptr, |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 7813 | PreloadPipelineInfo::Create(planned_max_preloading_type), |
kenoss | 8644f6bf | 2025-02-10 05:51:44 | [diff] [blame] | 7814 | attempt->GetWeakPtr()); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7815 | } |
| 7816 | |
| 7817 | void AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7818 | std::unique_ptr<PrefetchContainer> prefetch_container) { |
| 7819 | // GetPrefetchService().AddPrefetchContainerWithoutStartingPrefetch(std::move(prefetch_container)); |
| 7820 | GetPrefetchService().AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7821 | std::move(prefetch_container)); |
| 7822 | } |
| 7823 | |
| 7824 | private: |
| 7825 | base::test::ScopedFeatureList scoped_feature_list_for_prerender2_fallback_; |
| 7826 | }; |
| 7827 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7828 | INSTANTIATE_TEST_SUITE_P( |
| 7829 | ParametrizedTests, |
| 7830 | PrefetchServiceAddPrefetchContainerTest, |
| 7831 | testing::ValuesIn(PrefetchServiceRearchParam::Params())); |
| 7832 | |
| 7833 | TEST_P(PrefetchServiceAddPrefetchContainerTest, ReplacesOldWithNewByDefault) { |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7834 | blink::DocumentToken document_token; |
| 7835 | |
| 7836 | std::unique_ptr<PrefetchContainer> prefetch_container1 = |
| 7837 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7838 | GURL("https://example.com"), |
| 7839 | PreloadingType::kPrefetch); |
Hiroshige Hayashizaki | 64802cf1 | 2025-01-16 23:18:46 | [diff] [blame] | 7840 | prefetch_container1->SimulatePrefetchEligibleForTest(); |
| 7841 | prefetch_container1->SimulatePrefetchStartedForTest(); |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7842 | base::WeakPtr<PreloadingAttempt> attempt1 = |
| 7843 | prefetch_container1->preloading_attempt(); |
| 7844 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7845 | std::move(prefetch_container1)); |
| 7846 | |
| 7847 | std::unique_ptr<PrefetchContainer> prefetch_container2 = |
| 7848 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7849 | GURL("https://example.com"), |
| 7850 | PreloadingType::kPrefetch); |
| 7851 | base::WeakPtr<PreloadingAttempt> attempt2 = |
| 7852 | prefetch_container2->preloading_attempt(); |
| 7853 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7854 | std::move(prefetch_container2)); |
| 7855 | |
| 7856 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7857 | GetPrefetchService().GetAllForUrlWithoutRefAndQueryForTesting( |
| 7858 | PrefetchContainer::Key(document_token, GURL("https://example.com"))); |
| 7859 | ASSERT_EQ(1u, prefetches.size()); |
| 7860 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7861 | |
| 7862 | ASSERT_EQ(attempt2.get(), prefetch_container->preloading_attempt().get()); |
| 7863 | } |
| 7864 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7865 | TEST_P(PrefetchServiceAddPrefetchContainerTest, |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7866 | PreservesOldIfOldIsAheadOfPrerender) { |
| 7867 | blink::DocumentToken document_token; |
| 7868 | |
| 7869 | std::unique_ptr<PrefetchContainer> prefetch_container1 = |
| 7870 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7871 | GURL("https://example.com"), |
| 7872 | PreloadingType::kPrerender); |
| 7873 | base::WeakPtr<PreloadingAttempt> attempt1 = |
| 7874 | prefetch_container1->preloading_attempt(); |
| 7875 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7876 | std::move(prefetch_container1)); |
| 7877 | |
| 7878 | std::unique_ptr<PrefetchContainer> prefetch_container2 = |
| 7879 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7880 | GURL("https://example.com"), |
| 7881 | PreloadingType::kPrefetch); |
| 7882 | base::WeakPtr<PreloadingAttempt> attempt2 = |
| 7883 | prefetch_container2->preloading_attempt(); |
| 7884 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7885 | std::move(prefetch_container2)); |
| 7886 | |
| 7887 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7888 | GetPrefetchService().GetAllForUrlWithoutRefAndQueryForTesting( |
| 7889 | PrefetchContainer::Key(document_token, GURL("https://example.com"))); |
| 7890 | ASSERT_EQ(1u, prefetches.size()); |
| 7891 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7892 | |
| 7893 | ASSERT_EQ(attempt1.get(), prefetch_container->preloading_attempt().get()); |
| 7894 | } |
| 7895 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7896 | TEST_P(PrefetchServiceAddPrefetchContainerTest, |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7897 | ReplacesOldWithNewIfOldIsAheadOfPrerenderAndNotServable) { |
| 7898 | blink::DocumentToken document_token; |
| 7899 | |
| 7900 | std::unique_ptr<PrefetchContainer> prefetch_container1 = |
| 7901 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7902 | GURL("https://example.com"), |
| 7903 | PreloadingType::kPrerender); |
Hiroshige Hayashizaki | 64802cf1 | 2025-01-16 23:18:46 | [diff] [blame] | 7904 | prefetch_container1->SimulatePrefetchFailedIneligibleForTest( |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7905 | PreloadingEligibility::kDataSaverEnabled); |
| 7906 | base::WeakPtr<PreloadingAttempt> attempt1 = |
| 7907 | prefetch_container1->preloading_attempt(); |
| 7908 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7909 | std::move(prefetch_container1)); |
| 7910 | |
| 7911 | std::unique_ptr<PrefetchContainer> prefetch_container2 = |
| 7912 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7913 | GURL("https://example.com"), |
| 7914 | PreloadingType::kPrefetch); |
| 7915 | base::WeakPtr<PreloadingAttempt> attempt2 = |
| 7916 | prefetch_container2->preloading_attempt(); |
| 7917 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7918 | std::move(prefetch_container2)); |
| 7919 | |
| 7920 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7921 | GetPrefetchService().GetAllForUrlWithoutRefAndQueryForTesting( |
| 7922 | PrefetchContainer::Key(document_token, GURL("https://example.com"))); |
| 7923 | ASSERT_EQ(1u, prefetches.size()); |
| 7924 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7925 | |
| 7926 | ASSERT_EQ(attempt2.get(), prefetch_container->preloading_attempt().get()); |
| 7927 | } |
| 7928 | |
kenoss | bd9a3fc | 2025-03-28 05:15:57 | [diff] [blame] | 7929 | TEST_P(PrefetchServiceAddPrefetchContainerTest, |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 7930 | TakesOldWithAttributeMigrationIfNewIsAheadOfPrerender) { |
| 7931 | blink::DocumentToken document_token; |
| 7932 | |
| 7933 | std::unique_ptr<PrefetchContainer> prefetch_container1 = |
| 7934 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7935 | GURL("https://example.com"), |
| 7936 | PreloadingType::kPrefetch); |
| 7937 | base::WeakPtr<PreloadingAttempt> attempt1 = |
| 7938 | prefetch_container1->preloading_attempt(); |
| 7939 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7940 | std::move(prefetch_container1)); |
| 7941 | |
| 7942 | std::unique_ptr<PrefetchContainer> prefetch_container2 = |
| 7943 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7944 | GURL("https://example.com"), |
| 7945 | PreloadingType::kPrerender); |
| 7946 | base::WeakPtr<PreloadingAttempt> attempt2 = |
| 7947 | prefetch_container2->preloading_attempt(); |
| 7948 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7949 | std::move(prefetch_container2)); |
| 7950 | |
| 7951 | { |
| 7952 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7953 | GetPrefetchService().GetAllForUrlWithoutRefAndQueryForTesting( |
| 7954 | PrefetchContainer::Key(document_token, |
| 7955 | GURL("https://example.com"))); |
| 7956 | ASSERT_EQ(1u, prefetches.size()); |
| 7957 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7958 | |
| 7959 | ASSERT_EQ(attempt1.get(), prefetch_container->preloading_attempt().get()); |
| 7960 | ASSERT_TRUE(prefetch_container->IsLikelyAheadOfPrerender()); |
| 7961 | } |
| 7962 | |
| 7963 | // `prefetch_container1` now inherits a property `IsLikelyAheadOfPrerender()`. |
| 7964 | // So, it wins when yet another one is about to be added. |
| 7965 | |
| 7966 | std::unique_ptr<PrefetchContainer> prefetch_container3 = |
| 7967 | CreateSpeculationRulesPrefetchContainer(document_token, |
| 7968 | GURL("https://example.com"), |
| 7969 | PreloadingType::kPrefetch); |
| 7970 | AddPrefetchContainerWithoutStartingPrefetchForTesting( |
| 7971 | std::move(prefetch_container3)); |
| 7972 | |
| 7973 | { |
| 7974 | std::vector<std::pair<GURL, base::WeakPtr<PrefetchContainer>>> prefetches = |
| 7975 | GetPrefetchService().GetAllForUrlWithoutRefAndQueryForTesting( |
| 7976 | PrefetchContainer::Key(document_token, |
| 7977 | GURL("https://example.com"))); |
| 7978 | ASSERT_EQ(1u, prefetches.size()); |
| 7979 | base::WeakPtr<PrefetchContainer> prefetch_container = prefetches[0].second; |
| 7980 | |
| 7981 | ASSERT_EQ(attempt1.get(), prefetch_container->preloading_attempt().get()); |
| 7982 | } |
| 7983 | } |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 7984 | |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 7985 | // Tests behavior of concurrent prefetches. |
| 7986 | // |
| 7987 | // Scenario: |
| 7988 | // |
| 7989 | // - Three prefetch are triggered. |
| 7990 | // - `PrefetchScheduler` starts the two of them. |
| 7991 | // - The second one ended. |
| 7992 | // - `PrefetchScheduler` starts the last one. |
| 7993 | TEST_P(PrefetchServiceTest, PrefetchScheduler_RunsTwoConcurrentPrefetches) { |
| 7994 | if (!UsePrefetchScheduler()) { |
| 7995 | GTEST_SKIP() << "Assume PrefetchScheduler"; |
| 7996 | } |
| 7997 | |
| 7998 | base::test::ScopedFeatureList scoped_feature_list; |
| 7999 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 8000 | {{features::kPrefetchSchedulerTesting, |
| 8001 | {{"kPrefetchSchedulerTestingActiveSetSizeLimitForBase", "2"}, |
| 8002 | {"kPrefetchSchedulerTestingActiveSetSizeLimitForBurst", "2"}}}}, |
| 8003 | {}); |
| 8004 | |
| 8005 | NavigateAndCommit(GURL("https://example.com")); |
| 8006 | MakePrefetchService( |
| 8007 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8008 | /*num_on_prefetch_likely_calls=*/0)); |
| 8009 | PrefetchService* prefetch_service = |
| 8010 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 8011 | |
| 8012 | const auto url_1 = GURL("https://example.com/one"); |
| 8013 | const auto url_2 = GURL("https://example.com/two"); |
| 8014 | const auto url_3 = GURL("https://example.com/three"); |
| 8015 | auto handle_1 = |
| 8016 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 8017 | auto handle_2 = |
| 8018 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
| 8019 | auto handle_3 = |
| 8020 | MakePrefetchFromBrowserContext(url_3, std::nullopt, {}, nullptr); |
| 8021 | task_environment()->RunUntilIdle(); |
| 8022 | |
| 8023 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2, |
| 8024 | prefetch_container3; |
| 8025 | std::tie(std::ignore, prefetch_container1) = |
| 8026 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8027 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 8028 | std::tie(std::ignore, prefetch_container2) = |
| 8029 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8030 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 8031 | std::tie(std::ignore, prefetch_container3) = |
| 8032 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8033 | PrefetchContainer::Key(std::nullopt, url_3))[0]; |
| 8034 | |
| 8035 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8036 | PrefetchContainer::LoadState::kStarted); |
| 8037 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8038 | PrefetchContainer::LoadState::kStarted); |
| 8039 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8040 | PrefetchContainer::LoadState::kEligible); |
| 8041 | |
| 8042 | handle_2.reset(); |
| 8043 | EXPECT_FALSE(prefetch_container2); |
| 8044 | // Resolve `PrefetchScheduler::ProgressAsync()`. |
| 8045 | task_environment()->RunUntilIdle(); |
| 8046 | |
| 8047 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8048 | PrefetchContainer::LoadState::kStarted); |
| 8049 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8050 | PrefetchContainer::LoadState::kStarted); |
| 8051 | } |
| 8052 | |
| 8053 | // Tests prioritizing behavior. |
| 8054 | // |
| 8055 | // Scenario: |
| 8056 | // |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8057 | // - Two prefetches are triggered. |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8058 | // - A prefetch is triggered with high priority. |
| 8059 | // - `PrefetchScheduler` starts the later one. |
| 8060 | TEST_P(PrefetchServiceTest, PrefetchScheduler_Prioritize) { |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8061 | if (!(UsePrefetchScheduler() && |
| 8062 | features::kPrefetchSchedulerProgressSyncBestEffort.Get())) { |
| 8063 | GTEST_SKIP() << "Assume PrefetchScheduler and " |
| 8064 | "PrefetchSchedulerProgressSyncBestEffort"; |
| 8065 | } |
| 8066 | |
| 8067 | base::test::ScopedFeatureList scoped_feature_list; |
| 8068 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 8069 | {{features::kPrefetchSchedulerTesting, |
| 8070 | {{"kPrefetchSchedulerTestingActiveSetSizeLimitForBase", "1"}, |
| 8071 | {"kPrefetchSchedulerTestingActiveSetSizeLimitForBurst", "1"}}}}, |
| 8072 | {}); |
| 8073 | |
| 8074 | NavigateAndCommit(GURL("https://example.com")); |
| 8075 | MakePrefetchService( |
| 8076 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8077 | /*num_on_prefetch_likely_calls=*/0)); |
| 8078 | PrefetchService* prefetch_service = |
| 8079 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 8080 | |
| 8081 | prefetch_service->GetPrefetchSchedulerForTesting() |
| 8082 | .SetCalculatePriorityForTesting( |
| 8083 | base::BindRepeating([](const PrefetchContainer& prefetch_container) { |
| 8084 | if (prefetch_container.GetURL().possibly_invalid_spec().ends_with( |
| 8085 | "?prioritize=1")) { |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8086 | return PrefetchSchedulerPriority::kHighTest; |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8087 | } |
| 8088 | |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8089 | return PrefetchSchedulerPriority::kBase; |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8090 | })); |
| 8091 | |
| 8092 | const auto url_1 = GURL("https://example.com/one"); |
| 8093 | const auto url_2 = GURL("https://example.com/two"); |
| 8094 | const auto url_3 = GURL("https://example.com/two?prioritize=1"); |
| 8095 | auto handle_1 = |
| 8096 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 8097 | auto handle_2 = |
| 8098 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
| 8099 | auto handle_3 = |
| 8100 | MakePrefetchFromBrowserContext(url_3, std::nullopt, {}, nullptr); |
| 8101 | task_environment()->RunUntilIdle(); |
| 8102 | |
| 8103 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2, |
| 8104 | prefetch_container3; |
| 8105 | std::tie(std::ignore, prefetch_container1) = |
| 8106 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8107 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 8108 | std::tie(std::ignore, prefetch_container2) = |
| 8109 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8110 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 8111 | std::tie(std::ignore, prefetch_container3) = |
| 8112 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8113 | PrefetchContainer::Key(std::nullopt, url_3))[0]; |
| 8114 | |
| 8115 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8116 | PrefetchContainer::LoadState::kStarted); |
| 8117 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8118 | PrefetchContainer::LoadState::kEligible); |
| 8119 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8120 | PrefetchContainer::LoadState::kEligible); |
| 8121 | |
| 8122 | handle_1.reset(); |
| 8123 | EXPECT_FALSE(prefetch_container1); |
| 8124 | // Resolve `PrefetchScheduler::ProgressAsync()`. |
| 8125 | task_environment()->RunUntilIdle(); |
| 8126 | |
| 8127 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8128 | PrefetchContainer::LoadState::kEligible); |
| 8129 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8130 | PrefetchContainer::LoadState::kStarted); |
| 8131 | } |
| 8132 | |
| 8133 | // Tests prioritizing behavior. |
| 8134 | // |
| 8135 | // Scenario: |
| 8136 | // |
| 8137 | // - A prefetch is triggered. |
| 8138 | // - A prefetch is triggered with high priority. |
| 8139 | // - `PrefetchScheduler` starts the later one. |
| 8140 | TEST_P(PrefetchServiceTest, PrefetchScheduler_Prioritize_Async) { |
| 8141 | if (!(UsePrefetchScheduler() && |
| 8142 | !features::kPrefetchSchedulerProgressSyncBestEffort.Get())) { |
| 8143 | GTEST_SKIP() << "Assume PrefetchScheduler and not " |
| 8144 | "PrefetchSchedulerProgressSyncBestEffort"; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8145 | } |
| 8146 | |
| 8147 | base::test::ScopedFeatureList scoped_feature_list; |
| 8148 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 8149 | {{features::kPrefetchSchedulerTesting, |
| 8150 | {{"kPrefetchSchedulerTestingActiveSetSizeLimitForBase", "1"}, |
| 8151 | {"kPrefetchSchedulerTestingActiveSetSizeLimitForBurst", "1"}}}}, |
| 8152 | {}); |
| 8153 | |
| 8154 | NavigateAndCommit(GURL("https://example.com")); |
| 8155 | MakePrefetchService( |
| 8156 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8157 | /*num_on_prefetch_likely_calls=*/0)); |
| 8158 | PrefetchService* prefetch_service = |
| 8159 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 8160 | |
| 8161 | prefetch_service->GetPrefetchSchedulerForTesting() |
| 8162 | .SetCalculatePriorityForTesting( |
| 8163 | base::BindRepeating([](const PrefetchContainer& prefetch_container) { |
| 8164 | if (prefetch_container.GetURL().possibly_invalid_spec().ends_with( |
| 8165 | "?prioritize=1")) { |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8166 | return PrefetchSchedulerPriority::kHighTest; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8167 | } |
| 8168 | |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8169 | return PrefetchSchedulerPriority::kBase; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8170 | })); |
| 8171 | |
| 8172 | const auto url_1 = GURL("https://example.com/one"); |
| 8173 | const auto url_2 = GURL("https://example.com/two?prioritize=1"); |
| 8174 | auto handle_1 = |
| 8175 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 8176 | auto handle_2 = |
| 8177 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
| 8178 | task_environment()->RunUntilIdle(); |
| 8179 | |
| 8180 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2; |
| 8181 | std::tie(std::ignore, prefetch_container1) = |
| 8182 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8183 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 8184 | std::tie(std::ignore, prefetch_container2) = |
| 8185 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8186 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 8187 | |
| 8188 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8189 | PrefetchContainer::LoadState::kEligible); |
| 8190 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8191 | PrefetchContainer::LoadState::kStarted); |
| 8192 | } |
| 8193 | |
| 8194 | // Tests bursting behavior. |
| 8195 | // |
| 8196 | // Scenario: |
| 8197 | // |
| 8198 | // - Two prefetches are triggered. |
| 8199 | // - `PrefetchScheduler` starts the first one. |
| 8200 | // - Two prefetches are triggered with burst. |
| 8201 | // - `PrefetchScheduler` starts the third one. |
| 8202 | // - The third one ended. |
| 8203 | // - `PrefetchScheduler` starts the fourth one. |
| 8204 | TEST_P(PrefetchServiceTest, PrefetchScheduler_Burst) { |
| 8205 | if (!UsePrefetchScheduler()) { |
| 8206 | GTEST_SKIP() << "Assume PrefetchScheduler"; |
| 8207 | } |
| 8208 | |
| 8209 | base::test::ScopedFeatureList scoped_feature_list; |
| 8210 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 8211 | { |
| 8212 | {features::kPrefetchSchedulerTesting, |
| 8213 | {{"kPrefetchSchedulerTestingActiveSetSizeLimitForBase", "1"}, |
| 8214 | {"kPrefetchSchedulerTestingActiveSetSizeLimitForBurst", "2"}}}, |
| 8215 | }, |
| 8216 | {}); |
| 8217 | |
| 8218 | NavigateAndCommit(GURL("https://example.com")); |
| 8219 | MakePrefetchService( |
| 8220 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8221 | /*num_on_prefetch_likely_calls=*/0)); |
| 8222 | PrefetchService* prefetch_service = |
| 8223 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 8224 | |
| 8225 | prefetch_service->GetPrefetchSchedulerForTesting() |
| 8226 | .SetCalculatePriorityForTesting( |
| 8227 | base::BindRepeating([](const PrefetchContainer& prefetch_container) { |
| 8228 | if (prefetch_container.GetURL().possibly_invalid_spec().ends_with( |
| 8229 | "?burst=1")) { |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8230 | return PrefetchSchedulerPriority::kBurstTest; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8231 | } |
| 8232 | |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8233 | return PrefetchSchedulerPriority::kBase; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8234 | })); |
| 8235 | |
| 8236 | const auto url_1 = GURL("https://example.com/one"); |
| 8237 | const auto url_2 = GURL("https://example.com/two"); |
| 8238 | const auto url_3 = GURL("https://example.com/three?burst=1"); |
| 8239 | const auto url_4 = GURL("https://example.com/four?burst=1"); |
| 8240 | auto handle_1 = |
| 8241 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 8242 | auto handle_2 = |
| 8243 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
| 8244 | task_environment()->RunUntilIdle(); |
| 8245 | |
| 8246 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2, |
| 8247 | prefetch_container3, prefetch_container4; |
| 8248 | std::tie(std::ignore, prefetch_container1) = |
| 8249 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8250 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 8251 | std::tie(std::ignore, prefetch_container2) = |
| 8252 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8253 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 8254 | |
| 8255 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8256 | PrefetchContainer::LoadState::kStarted); |
| 8257 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8258 | PrefetchContainer::LoadState::kEligible); |
| 8259 | |
| 8260 | auto handle_3 = |
| 8261 | MakePrefetchFromBrowserContext(url_3, std::nullopt, {}, nullptr); |
| 8262 | auto handle_4 = |
| 8263 | MakePrefetchFromBrowserContext(url_4, std::nullopt, {}, nullptr); |
| 8264 | task_environment()->RunUntilIdle(); |
| 8265 | |
| 8266 | std::tie(std::ignore, prefetch_container3) = |
| 8267 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8268 | PrefetchContainer::Key(std::nullopt, url_3))[0]; |
| 8269 | std::tie(std::ignore, prefetch_container4) = |
| 8270 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8271 | PrefetchContainer::Key(std::nullopt, url_4))[0]; |
| 8272 | |
| 8273 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8274 | PrefetchContainer::LoadState::kStarted); |
| 8275 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8276 | PrefetchContainer::LoadState::kEligible); |
| 8277 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8278 | PrefetchContainer::LoadState::kStarted); |
| 8279 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8280 | PrefetchContainer::LoadState::kEligible); |
| 8281 | |
| 8282 | handle_3.reset(); |
| 8283 | EXPECT_FALSE(prefetch_container3); |
| 8284 | // Resolve `PrefetchScheduler::ProgressAsync()`. |
| 8285 | task_environment()->RunUntilIdle(); |
| 8286 | |
| 8287 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8288 | PrefetchContainer::LoadState::kStarted); |
| 8289 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8290 | PrefetchContainer::LoadState::kEligible); |
| 8291 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8292 | PrefetchContainer::LoadState::kStarted); |
| 8293 | } |
| 8294 | |
| 8295 | // Tests bursting behavior. |
| 8296 | // |
| 8297 | // Scenario: |
| 8298 | // |
| 8299 | // - Two prefetches are triggered. |
| 8300 | // - Two prefetches are triggered with burst. |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8301 | // - `PrefetchScheduler` starts the first and third one. |
| 8302 | // - The third one ended. |
| 8303 | // - `PrefetchScheduler` starts the forth one. |
| 8304 | // - The first one ended. |
| 8305 | // - `PrefetchScheduler` doesn't start the second one as |
| 8306 | // `ActiveSetSizeLimitForBase` is 1. |
| 8307 | TEST_P(PrefetchServiceTest, PrefetchScheduler_BurstTakesPriority) { |
| 8308 | if (!(UsePrefetchScheduler() && |
| 8309 | features::kPrefetchSchedulerProgressSyncBestEffort.Get())) { |
| 8310 | GTEST_SKIP() << "Assume PrefetchScheduler and " |
| 8311 | "PrefetchSchedulerProgressSyncBestEffort"; |
| 8312 | } |
| 8313 | |
| 8314 | base::test::ScopedFeatureList scoped_feature_list; |
| 8315 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 8316 | { |
| 8317 | {features::kPrefetchSchedulerTesting, |
| 8318 | {{"kPrefetchSchedulerTestingActiveSetSizeLimitForBase", "1"}, |
| 8319 | {"kPrefetchSchedulerTestingActiveSetSizeLimitForBurst", "2"}}}, |
| 8320 | }, |
| 8321 | {}); |
| 8322 | |
| 8323 | NavigateAndCommit(GURL("https://example.com")); |
| 8324 | MakePrefetchService( |
| 8325 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8326 | /*num_on_prefetch_likely_calls=*/0)); |
| 8327 | PrefetchService* prefetch_service = |
| 8328 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 8329 | |
| 8330 | prefetch_service->GetPrefetchSchedulerForTesting() |
| 8331 | .SetCalculatePriorityForTesting( |
| 8332 | base::BindRepeating([](const PrefetchContainer& prefetch_container) { |
| 8333 | if (prefetch_container.GetURL().possibly_invalid_spec().ends_with( |
| 8334 | "?burst=1")) { |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8335 | return PrefetchSchedulerPriority::kBurstTest; |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8336 | } |
| 8337 | |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8338 | return PrefetchSchedulerPriority::kBase; |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8339 | })); |
| 8340 | |
| 8341 | const auto url_1 = GURL("https://example.com/one"); |
| 8342 | const auto url_2 = GURL("https://example.com/two"); |
| 8343 | const auto url_3 = GURL("https://example.com/three?burst=1"); |
| 8344 | const auto url_4 = GURL("https://example.com/four?burst=1"); |
| 8345 | auto handle_1 = |
| 8346 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 8347 | auto handle_2 = |
| 8348 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
| 8349 | auto handle_3 = |
| 8350 | MakePrefetchFromBrowserContext(url_3, std::nullopt, {}, nullptr); |
| 8351 | auto handle_4 = |
| 8352 | MakePrefetchFromBrowserContext(url_4, std::nullopt, {}, nullptr); |
| 8353 | task_environment()->RunUntilIdle(); |
| 8354 | |
| 8355 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2, |
| 8356 | prefetch_container3, prefetch_container4; |
| 8357 | std::tie(std::ignore, prefetch_container1) = |
| 8358 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8359 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 8360 | std::tie(std::ignore, prefetch_container2) = |
| 8361 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8362 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 8363 | std::tie(std::ignore, prefetch_container3) = |
| 8364 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8365 | PrefetchContainer::Key(std::nullopt, url_3))[0]; |
| 8366 | std::tie(std::ignore, prefetch_container4) = |
| 8367 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8368 | PrefetchContainer::Key(std::nullopt, url_4))[0]; |
| 8369 | |
| 8370 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8371 | PrefetchContainer::LoadState::kStarted); |
| 8372 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8373 | PrefetchContainer::LoadState::kEligible); |
| 8374 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8375 | PrefetchContainer::LoadState::kStarted); |
| 8376 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8377 | PrefetchContainer::LoadState::kEligible); |
| 8378 | |
| 8379 | handle_3.reset(); |
| 8380 | EXPECT_FALSE(prefetch_container3); |
| 8381 | // Resolve `PrefetchScheduler::ProgressAsync()`. |
| 8382 | task_environment()->RunUntilIdle(); |
| 8383 | |
| 8384 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8385 | PrefetchContainer::LoadState::kStarted); |
| 8386 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8387 | PrefetchContainer::LoadState::kEligible); |
| 8388 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8389 | PrefetchContainer::LoadState::kStarted); |
| 8390 | |
| 8391 | handle_1.reset(); |
| 8392 | EXPECT_FALSE(prefetch_container1); |
| 8393 | // Resolve `PrefetchScheduler::ProgressAsync()`. |
| 8394 | task_environment()->RunUntilIdle(); |
| 8395 | |
| 8396 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8397 | PrefetchContainer::LoadState::kEligible); |
| 8398 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8399 | PrefetchContainer::LoadState::kStarted); |
| 8400 | } |
| 8401 | |
| 8402 | // Tests bursting behavior. |
| 8403 | // |
| 8404 | // Scenario: |
| 8405 | // |
| 8406 | // - Two prefetches are triggered. |
| 8407 | // - Two prefetches are triggered with burst. |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8408 | // - `PrefetchScheduler` starts the third and fourth one. |
| 8409 | // - The third one ended. |
| 8410 | // - `PrefetchScheduler` doesn't start the first/second one as |
| 8411 | // `ActiveSetSizeLimitForBase` is 1. |
kenoss | 0a56736 | 2025-05-16 11:18:55 | [diff] [blame] | 8412 | TEST_P(PrefetchServiceTest, PrefetchScheduler_BurstTakesPriority_Async) { |
| 8413 | if (!(UsePrefetchScheduler() && |
| 8414 | !features::kPrefetchSchedulerProgressSyncBestEffort.Get())) { |
| 8415 | GTEST_SKIP() << "Assume PrefetchScheduler and not " |
| 8416 | "PrefetchSchedulerProgressSyncBestEffort"; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8417 | } |
| 8418 | |
| 8419 | base::test::ScopedFeatureList scoped_feature_list; |
| 8420 | scoped_feature_list.InitWithFeaturesAndParameters( |
| 8421 | { |
| 8422 | {features::kPrefetchSchedulerTesting, |
| 8423 | {{"kPrefetchSchedulerTestingActiveSetSizeLimitForBase", "1"}, |
| 8424 | {"kPrefetchSchedulerTestingActiveSetSizeLimitForBurst", "2"}}}, |
| 8425 | }, |
| 8426 | {}); |
| 8427 | |
| 8428 | NavigateAndCommit(GURL("https://example.com")); |
| 8429 | MakePrefetchService( |
| 8430 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8431 | /*num_on_prefetch_likely_calls=*/0)); |
| 8432 | PrefetchService* prefetch_service = |
| 8433 | BrowserContextImpl::From(browser_context())->GetPrefetchService(); |
| 8434 | |
| 8435 | prefetch_service->GetPrefetchSchedulerForTesting() |
| 8436 | .SetCalculatePriorityForTesting( |
| 8437 | base::BindRepeating([](const PrefetchContainer& prefetch_container) { |
| 8438 | if (prefetch_container.GetURL().possibly_invalid_spec().ends_with( |
| 8439 | "?burst=1")) { |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8440 | return PrefetchSchedulerPriority::kBurstTest; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8441 | } |
| 8442 | |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 8443 | return PrefetchSchedulerPriority::kBase; |
kenoss | 1b8ebc2 | 2025-04-04 00:11:35 | [diff] [blame] | 8444 | })); |
| 8445 | |
| 8446 | const auto url_1 = GURL("https://example.com/one"); |
| 8447 | const auto url_2 = GURL("https://example.com/two"); |
| 8448 | const auto url_3 = GURL("https://example.com/three?burst=1"); |
| 8449 | const auto url_4 = GURL("https://example.com/four?burst=1"); |
| 8450 | auto handle_1 = |
| 8451 | MakePrefetchFromBrowserContext(url_1, std::nullopt, {}, nullptr); |
| 8452 | auto handle_2 = |
| 8453 | MakePrefetchFromBrowserContext(url_2, std::nullopt, {}, nullptr); |
| 8454 | auto handle_3 = |
| 8455 | MakePrefetchFromBrowserContext(url_3, std::nullopt, {}, nullptr); |
| 8456 | auto handle_4 = |
| 8457 | MakePrefetchFromBrowserContext(url_4, std::nullopt, {}, nullptr); |
| 8458 | task_environment()->RunUntilIdle(); |
| 8459 | |
| 8460 | base::WeakPtr<PrefetchContainer> prefetch_container1, prefetch_container2, |
| 8461 | prefetch_container3, prefetch_container4; |
| 8462 | std::tie(std::ignore, prefetch_container1) = |
| 8463 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8464 | PrefetchContainer::Key(std::nullopt, url_1))[0]; |
| 8465 | std::tie(std::ignore, prefetch_container2) = |
| 8466 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8467 | PrefetchContainer::Key(std::nullopt, url_2))[0]; |
| 8468 | std::tie(std::ignore, prefetch_container3) = |
| 8469 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8470 | PrefetchContainer::Key(std::nullopt, url_3))[0]; |
| 8471 | std::tie(std::ignore, prefetch_container4) = |
| 8472 | prefetch_service->GetAllForUrlWithoutRefAndQueryForTesting( |
| 8473 | PrefetchContainer::Key(std::nullopt, url_4))[0]; |
| 8474 | |
| 8475 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8476 | PrefetchContainer::LoadState::kEligible); |
| 8477 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8478 | PrefetchContainer::LoadState::kEligible); |
| 8479 | ASSERT_EQ(prefetch_container3->GetLoadState(), |
| 8480 | PrefetchContainer::LoadState::kStarted); |
| 8481 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8482 | PrefetchContainer::LoadState::kStarted); |
| 8483 | |
| 8484 | handle_3.reset(); |
| 8485 | EXPECT_FALSE(prefetch_container3); |
| 8486 | // Resolve `PrefetchScheduler::ProgressAsync()`. |
| 8487 | task_environment()->RunUntilIdle(); |
| 8488 | |
| 8489 | ASSERT_EQ(prefetch_container1->GetLoadState(), |
| 8490 | PrefetchContainer::LoadState::kEligible); |
| 8491 | ASSERT_EQ(prefetch_container2->GetLoadState(), |
| 8492 | PrefetchContainer::LoadState::kEligible); |
| 8493 | ASSERT_EQ(prefetch_container4->GetLoadState(), |
| 8494 | PrefetchContainer::LoadState::kStarted); |
| 8495 | } |
| 8496 | |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8497 | TEST_P(PrefetchServiceTest, |
| 8498 | UMA_Prefetch_PrefetchContainer_AddedTo_Embedder_Success) { |
| 8499 | base::HistogramTester histogram_tester; |
| 8500 | |
| 8501 | NavigateAndCommit(GURL("https://example.com")); |
| 8502 | MakePrefetchService( |
| 8503 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8504 | /*num_on_prefetch_likely_calls=*/0)); |
| 8505 | |
| 8506 | const auto url = GURL("https://example.com/prefetched"); |
| 8507 | auto handle = MakePrefetchFromBrowserContext(url, std::nullopt, {}, nullptr); |
| 8508 | task_environment()->RunUntilIdle(); |
| 8509 | |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 8510 | task_environment()->FastForwardBy( |
| 8511 | base::Milliseconds(kAddedToURLRequestStartLatency + kHeaderLatency)); |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8512 | |
| 8513 | MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType, |
| 8514 | /*use_prefetch_proxy=*/false, |
| 8515 | {{"X-Testing", "Hello World"}}, kHTMLBody); |
| 8516 | |
| 8517 | // Call `PrefetchContainer::dtor()` to record UMAs. |
| 8518 | handle.reset(); |
| 8519 | |
| 8520 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8521 | base::StrCat( |
| 8522 | {"Prefetch.PrefetchContainer.AddedToInitialEligibility.Embedder_", |
| 8523 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8524 | 0, 1); |
| 8525 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8526 | base::StrCat( |
| 8527 | {"Prefetch.PrefetchContainer.AddedToPrefetchStarted.Embedder_", |
| 8528 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8529 | 0, 1); |
| 8530 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 8531 | base::StrCat( |
| 8532 | {"Prefetch.PrefetchContainer.AddedToURLRequestStarted.Embedder_", |
| 8533 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
| 8534 | kAddedToURLRequestStartLatency, 1); |
| 8535 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8536 | base::StrCat({"Prefetch.PrefetchContainer." |
| 8537 | "AddedToHeaderDeterminedSuccessfully.Embedder_", |
| 8538 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 8539 | kAddedToURLRequestStartLatency + kHeaderLatency, 1); |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8540 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8541 | base::StrCat({"Prefetch.PrefetchContainer." |
| 8542 | "AddedToPrefetchCompletedSuccessfully.Embedder_", |
| 8543 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 8544 | kAddedToURLRequestStartLatency + kHeaderLatency, 1); |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8545 | } |
| 8546 | |
| 8547 | TEST_P(PrefetchServiceTest, |
| 8548 | UMA_Prefetch_PrefetchContainer_AddedTo_Embedder_Fail) { |
| 8549 | base::HistogramTester histogram_tester; |
| 8550 | |
| 8551 | NavigateAndCommit(GURL("https://example.com")); |
| 8552 | MakePrefetchService( |
| 8553 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>( |
| 8554 | /*num_on_prefetch_likely_calls=*/0)); |
| 8555 | |
| 8556 | const auto url = GURL("https://example.com/prefetched"); |
| 8557 | auto handle = MakePrefetchFromBrowserContext(url, std::nullopt, {}, nullptr); |
| 8558 | task_environment()->RunUntilIdle(); |
| 8559 | |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 8560 | task_environment()->FastForwardBy( |
| 8561 | base::Milliseconds(kAddedToURLRequestStartLatency + kHeaderLatency)); |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8562 | |
| 8563 | // Call `PrefetchContainer::dtor()` to record UMAs. |
| 8564 | handle.reset(); |
| 8565 | |
| 8566 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8567 | base::StrCat( |
| 8568 | {"Prefetch.PrefetchContainer.AddedToInitialEligibility.Embedder_", |
| 8569 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8570 | 0, 1); |
| 8571 | histogram_tester.ExpectUniqueSample( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8572 | base::StrCat( |
| 8573 | {"Prefetch.PrefetchContainer.AddedToPrefetchStarted.Embedder_", |
| 8574 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8575 | 0, 1); |
| 8576 | histogram_tester.ExpectTotalCount( |
Taiyo Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 8577 | base::StrCat( |
| 8578 | {"Prefetch.PrefetchContainer.AddedToURLRequestStarted.Embedder_", |
| 8579 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
| 8580 | 0); |
| 8581 | histogram_tester.ExpectTotalCount( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8582 | base::StrCat({"Prefetch.PrefetchContainer." |
| 8583 | "AddedToHeaderDeterminedSuccesfully.Embedder_", |
| 8584 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8585 | 0); |
| 8586 | histogram_tester.ExpectTotalCount( |
Taiyo Mizuhashi | a12acc4 | 2025-04-25 23:40:36 | [diff] [blame] | 8587 | base::StrCat({"Prefetch.PrefetchContainer." |
| 8588 | "AddedToPrefetchCompletedSuccessfully.Embedder_", |
| 8589 | test::kPreloadingEmbedderHistgramSuffixForTesting}), |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 8590 | 0); |
| 8591 | } |
| 8592 | |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8593 | TEST_P( |
| 8594 | PrefetchServiceTest, |
| 8595 | UMA_Prefetch_PrefetchMatchingBlockedNavigation_And_BlockUntilHeadDuration_PrerenderOrNonPrerender) { |
| 8596 | base::HistogramTester histogram_tester; |
| 8597 | |
| 8598 | MakePrefetchService( |
| 8599 | std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); |
| 8600 | |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 8601 | const PrefetchType prefetch_type = |
| 8602 | PrefetchType(PreloadingTriggerType::kSpeculationRule, |
| 8603 | /*use_prefetch_proxy=*/true, |
| 8604 | blink::mojom::SpeculationEagerness::kImmediate); |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8605 | MakePrefetchOnMainFrame(GURL("https://example.com"), prefetch_type); |
| 8606 | task_environment()->RunUntilIdle(); |
| 8607 | |
| 8608 | // Request the prefetch from the PrefetchService. The given callback shouldn't |
| 8609 | // be called until after the head is received. |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 8610 | base::test::TestFuture<PrefetchServingHandle> future; |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8611 | GetPrefetchToServe(future, GURL("https://example.com"), MainDocumentToken()); |
| 8612 | EXPECT_FALSE(future.IsReady()); |
| 8613 | |
| 8614 | task_environment()->FastForwardBy(base::Milliseconds(kHeaderLatency)); |
| 8615 | |
| 8616 | // Sends the head of the prefetch response. This should trigger the above |
| 8617 | // callback. |
| 8618 | SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, |
| 8619 | /*use_prefetch_proxy=*/true, |
| 8620 | {{"X-Testing", "Hello World"}}, |
| 8621 | std::size(kHTMLBody)); |
Hiroshige Hayashizaki | 16b6e54f | 2025-08-12 06:56:57 | [diff] [blame] | 8622 | PrefetchServingHandle serving_handle = future.Take(); |
| 8623 | ASSERT_TRUE(serving_handle); |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8624 | |
| 8625 | // Send the body and completion status of the request, |
| 8626 | SendBodyContentOfResponseAndWait(kHTMLBody); |
| 8627 | CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); |
| 8628 | |
| 8629 | histogram_tester.ExpectUniqueSample( |
| 8630 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8631 | "SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8632 | true, 1); |
| 8633 | histogram_tester.ExpectUniqueSample( |
| 8634 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8635 | "NonPrerender.SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8636 | true, 1); |
| 8637 | histogram_tester.ExpectTotalCount( |
| 8638 | "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8639 | "Prerender.SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8640 | 0); |
| 8641 | histogram_tester.ExpectUniqueTimeSample( |
| 8642 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8643 | "SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8644 | base::Milliseconds(kHeaderLatency), 1); |
| 8645 | histogram_tester.ExpectTotalCount( |
| 8646 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8647 | "SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8648 | 0); |
| 8649 | histogram_tester.ExpectUniqueTimeSample( |
| 8650 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8651 | "Served.SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8652 | base::Milliseconds(kHeaderLatency), 1); |
| 8653 | histogram_tester.ExpectTotalCount( |
| 8654 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8655 | "NotServed.SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8656 | 0); |
| 8657 | histogram_tester.ExpectTotalCount( |
| 8658 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender.Served." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8659 | "SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8660 | 0); |
| 8661 | histogram_tester.ExpectTotalCount( |
| 8662 | "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender." |
Takashi Nakayama | c818350 | 2025-08-04 14:18:50 | [diff] [blame] | 8663 | "NotServed.SpeculationRule_Immediate2", |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 8664 | 0); |
| 8665 | } |
| 8666 | |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 8667 | } // namespace |
| 8668 | } // namespace content |