blob: 439e1fe0162641a042f15c270e9669025d211807 [file] [log] [blame]
Iman Saboorieda025c72023-05-12 18:55:291// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/preloading/preloading_decider.h"
6
Lei Zhangab09dd842025-05-17 08:06:487#include "base/strings/stringprintf.h"
Iman Saboorieda025c72023-05-12 18:55:298#include "base/test/scoped_feature_list.h"
Kevin McNee98e068a2024-04-09 20:12:349#include "base/timer/elapsed_timer.h"
Iman Saboorieda025c72023-05-12 18:55:2910#include "components/ukm/test_ukm_recorder.h"
Kevin McNee98e068a2024-04-09 20:12:3411#include "content/browser/preloading/preloading.h"
Kevin McNee031e28c2024-03-21 20:55:0012#include "content/browser/preloading/preloading_data_impl.h"
kenossc3814a42024-10-25 06:03:0213#include "content/browser/preloading/prerender/prerender_features.h"
Kevin McNee031e28c2024-03-21 20:55:0014#include "content/public/browser/render_frame_host.h"
Iman Saboorieda025c72023-05-12 18:55:2915#include "content/public/test/browser_test.h"
16#include "content/public/test/browser_test_utils.h"
17#include "content/public/test/content_browser_test.h"
18#include "content/public/test/content_browser_test_utils.h"
Kevin McNee031e28c2024-03-21 20:55:0019#include "content/public/test/preloading_test_util.h"
20#include "content/public/test/test_navigation_observer.h"
Iman Saboorieda025c72023-05-12 18:55:2921#include "content/shell/browser/shell.h"
22#include "net/dns/mock_host_resolver.h"
Kevin McNee98e068a2024-04-09 20:12:3423#include "services/metrics/public/cpp/ukm_builders.h"
Iman Saboorieda025c72023-05-12 18:55:2924#include "testing/gtest/include/gtest/gtest.h"
25#include "third_party/blink/public/common/features.h"
Kevin McNee98e068a2024-04-09 20:12:3426#include "third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom.h"
Iman Saboorieda025c72023-05-12 18:55:2927
28namespace content {
29
30class PreloadingDeciderBrowserTest : public ContentBrowserTest {
31 public:
32 PreloadingDeciderBrowserTest() = default;
33 ~PreloadingDeciderBrowserTest() override = default;
34
35 void SetUp() override {
36 feature_list_.InitWithFeaturesAndParameters(
37 {
Kevin McNee842eb0a2024-04-11 20:14:1638 {blink::features::kPreloadingHeuristicsMLModel,
39 {{"enact_candidates", "true"}}},
Kevin McNee98e068a2024-04-09 20:12:3440 {blink::features::kPrerender2InNewTab, {}},
Iman Saboorieda025c72023-05-12 18:55:2941 },
Kevin McNee98e068a2024-04-09 20:12:3442 {
43 // Disable the memory requirement of Prerender2 so the test can run
44 // on any bot.
45 {blink::features::kPrerender2MemoryControls},
46 });
Iman Saboorieda025c72023-05-12 18:55:2947
48 ContentBrowserTest::SetUp();
49 }
50
51 void SetUpOnMainThread() override {
52 ContentBrowserTest::SetUpOnMainThread();
53 host_resolver()->AddRule("*", "127.0.0.1");
54 https_server_ = std::make_unique<net::EmbeddedTestServer>(
55 net::EmbeddedTestServer::TYPE_HTTPS);
56 https_server_->AddDefaultHandlers(GetTestDataFilePath());
57
58 ASSERT_TRUE(https_server_->Start());
Iman Saboorieda025c72023-05-12 18:55:2959 }
60
61 WebContents* web_contents() { return shell()->web_contents(); }
Iman Saboorieda025c72023-05-12 18:55:2962
63 const GURL GetTestURL(const char* file) const {
64 return https_server_->GetURL(file);
65 }
Iman Saboorieda025c72023-05-12 18:55:2966
Kevin McNee031e28c2024-03-21 20:55:0067 void ExpectCandidatesReceived() {
Kevin McNee98e068a2024-04-09 20:12:3468 // The renderer queues updates and waits for style to be clean.
Kevin McNee031e28c2024-03-21 20:55:0069 EXPECT_EQ(true, EvalJsAfterLifecycleUpdate(web_contents(), "", "true"));
Kevin McNee98e068a2024-04-09 20:12:3470 EXPECT_EQ(true, EvalJsAfterLifecycleUpdate(web_contents(), "", "true"));
71
Kevin McNee031e28c2024-03-21 20:55:0072 auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
73 web_contents()->GetPrimaryMainFrame());
74 ASSERT_TRUE(preloading_decider);
75 EXPECT_TRUE(preloading_decider->HasCandidatesForTesting());
Iman Saboorieda025c72023-05-12 18:55:2976 }
77
78 private:
Domenic Denicolae2d56682024-06-05 07:18:4579 content::test::PreloadingConfigOverride preloading_config_override_;
Iman Saboorieda025c72023-05-12 18:55:2980 base::test::ScopedFeatureList feature_list_;
81 std::unique_ptr<net::EmbeddedTestServer> https_server_;
Iman Saboorieda025c72023-05-12 18:55:2982};
83
84IN_PROC_BROWSER_TEST_F(PreloadingDeciderBrowserTest,
85 SetIsNavigationInDomainCallback) {
86 base::HistogramTester histogram_tester;
Kevin McNee031e28c2024-03-21 20:55:0087 ASSERT_TRUE(NavigateToURL(shell(),
88 GetTestURL("/preloading/preloading_decider.html")));
89 ExpectCandidatesReceived();
Iman Saboorieda025c72023-05-12 18:55:2990
91 // Now navigate to another page
Kevin McNee031e28c2024-03-21 20:55:0092 TestNavigationObserver nav_observer(web_contents());
93 EXPECT_TRUE(ExecJs(web_contents(), "document.getElementById('bar').click()"));
94 nav_observer.Wait();
95
Iman Saboorieda025c72023-05-12 18:55:2996 histogram_tester.ExpectBucketCount(
97 "Preloading.Predictor.SpeculationRules.Recall",
Kevin McNee031e28c2024-03-21 20:55:0098 PredictorConfusionMatrix::kFalseNegative, 1);
Iman Saboorieda025c72023-05-12 18:55:2999 histogram_tester.ExpectBucketCount(
100 "Preloading.Predictor.UrlPointerDownOnAnchor.Recall",
Kevin McNee031e28c2024-03-21 20:55:00101 PredictorConfusionMatrix::kFalseNegative, 1);
Iman Saboorieda025c72023-05-12 18:55:29102 histogram_tester.ExpectBucketCount(
103 "Preloading.Predictor.UrlPointerHoverOnAnchor.Recall",
Kevin McNee031e28c2024-03-21 20:55:00104 PredictorConfusionMatrix::kFalseNegative, 1);
Kevin McNee842eb0a2024-04-11 20:14:16105 histogram_tester.ExpectBucketCount(
106 "Preloading.Predictor.PreloadingHeuristicsMLModel.Recall",
107 PredictorConfusionMatrix::kFalseNegative, 1);
Iman Saboorieda025c72023-05-12 18:55:29108}
109
Takashi Nakayama978f0a152025-06-17 08:26:25110class PreloadingDeciderNonImmediateBrowserTest
Kevin McNee98e068a2024-04-09 20:12:34111 : public PreloadingDeciderBrowserTest,
112 public ::testing::WithParamInterface<
113 ::testing::tuple<PreloadingPredictor, PreloadingType>> {
114 public:
115 static std::string DescribeParams(
116 const testing::TestParamInfo<ParamType>& info) {
117 const auto& [predictor, type] = info.param;
118 return base::StringPrintf(
119 "%s_%s", std::string(predictor.name()).c_str(),
120 std::string(PreloadingTypeToString(type)).c_str());
121 }
122
Takashi Nakayama978f0a152025-06-17 08:26:25123 static constexpr PreloadingPredictor kNonImmediatePredictors[] = {
Kevin McNee98e068a2024-04-09 20:12:34124 preloading_predictor::kUrlPointerDownOnAnchor,
125 preloading_predictor::kUrlPointerHoverOnAnchor,
Kevin McNee842eb0a2024-04-11 20:14:16126 preloading_predictor::kPreloadingHeuristicsMLModel,
Kevin McNee98e068a2024-04-09 20:12:34127 };
128
129 static constexpr PreloadingType kPreloadingTypes[] = {
130 PreloadingType::kPrefetch,
131 PreloadingType::kPrerender,
132 };
133
134 PreloadingPredictor predictor() const {
135 return ::testing::get<0>(GetParam());
136 }
137
138 PreloadingType type() const { return ::testing::get<1>(GetParam()); }
139};
140
141INSTANTIATE_TEST_SUITE_P(
142 All,
Takashi Nakayama978f0a152025-06-17 08:26:25143 PreloadingDeciderNonImmediateBrowserTest,
Kevin McNee98e068a2024-04-09 20:12:34144 ::testing::Combine(
145 ::testing::ValuesIn(
Takashi Nakayama978f0a152025-06-17 08:26:25146 PreloadingDeciderNonImmediateBrowserTest::kNonImmediatePredictors),
Kevin McNee98e068a2024-04-09 20:12:34147 ::testing::ValuesIn(
Takashi Nakayama978f0a152025-06-17 08:26:25148 PreloadingDeciderNonImmediateBrowserTest::kPreloadingTypes)),
149 PreloadingDeciderNonImmediateBrowserTest::DescribeParams);
Kevin McNee98e068a2024-04-09 20:12:34150
Takashi Nakayama978f0a152025-06-17 08:26:25151IN_PROC_BROWSER_TEST_P(PreloadingDeciderNonImmediateBrowserTest,
Kevin McNee98e068a2024-04-09 20:12:34152 EnactModerateCandidate) {
153 base::ScopedMockElapsedTimersForTest mock_elapsed_timer;
154 base::HistogramTester histogram_tester;
155 ukm::TestAutoSetUkmRecorder ukm_recorder;
156
157 ASSERT_TRUE(NavigateToURL(
158 shell(), GetTestURL("/preloading/preloading_decider_moderate.html")));
159 ExpectCandidatesReceived();
160
161 std::string next_page_id;
162 GURL next_page_url;
163 switch (type()) {
164 case PreloadingType::kPrefetch:
165 next_page_id = "b";
166 next_page_url = GetTestURL("/title1.html?b");
167 break;
168 case PreloadingType::kPrerender:
169 next_page_id = "c";
170 next_page_url = GetTestURL("/title1.html?c");
171 break;
172 default:
173 FAIL();
174 }
175
Takashi Nakayama978f0a152025-06-17 08:26:25176 // Trigger the non-immediate predictor.
Kevin McNee98e068a2024-04-09 20:12:34177 auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
178 web_contents()->GetPrimaryMainFrame());
179 ASSERT_TRUE(preloading_decider);
180 if (predictor() == preloading_predictor::kUrlPointerDownOnAnchor) {
181 preloading_decider->OnPointerDown(next_page_url);
182 } else if (predictor() == preloading_predictor::kUrlPointerHoverOnAnchor) {
183 preloading_decider->OnPointerHover(
184 next_page_url,
Takashi Nakayamae234c492025-08-04 03:16:48185 blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0),
186 blink::mojom::SpeculationEagerness::kModerate);
Kevin McNee842eb0a2024-04-11 20:14:16187 } else if (predictor() ==
188 preloading_predictor::kPreloadingHeuristicsMLModel) {
189 preloading_decider->OnPreloadingHeuristicsModelDone(next_page_url,
190 /*score=*/1.0);
Kevin McNee98e068a2024-04-09 20:12:34191 } else {
192 FAIL();
193 }
194
195 TestNavigationObserver nav_observer(web_contents());
196 EXPECT_TRUE(
197 ExecJs(web_contents(),
198 JsReplace("document.getElementById($1).click()", next_page_id)));
199 nav_observer.Wait();
200
201 const ukm::SourceId source_id = nav_observer.next_page_ukm_source_id();
202
203 const std::string type_str{PreloadingTypeToString(type())};
204 const char* type_cstr = type_str.c_str();
205
Takashi Nakayama978f0a152025-06-17 08:26:25206 // For non-immediate predictors, there are two PreloadingPredictors that
Kevin McNee98e068a2024-04-09 20:12:34207 // contribute to a preloading attempt. One creates a candidate, but does not
208 // start the preloading attempt. The other starts the attempt. We assert below
209 // that both predictors have appropriate attribution in the recorded metrics.
210 {
211 const std::string rule_predictor_str{
212 content_preloading_predictor::kSpeculationRules.name()};
213 const char* rule_predictor_cstr = rule_predictor_str.c_str();
214
Takashi Nakayama978f0a152025-06-17 08:26:25215 // We intentionally don't record a prediction for non-immediate speculation
Kevin McNee98e068a2024-04-09 20:12:34216 // rules. They aren't predictions per se, but a declaration to the browser
217 // that preloading would be safe.
218 histogram_tester.ExpectTotalCount(
219 base::StringPrintf("Preloading.Predictor.%s.Precision",
220 rule_predictor_cstr),
221 0);
222 histogram_tester.ExpectUniqueSample(
223 base::StringPrintf("Preloading.Predictor.%s.Recall",
224 rule_predictor_cstr),
225 PredictorConfusionMatrix::kFalseNegative, 1);
226
227 histogram_tester.ExpectUniqueSample(
228 base::StringPrintf("Preloading.%s.Attempt.%s.Precision", type_cstr,
229 rule_predictor_cstr),
230 PredictorConfusionMatrix::kTruePositive, 1);
231 histogram_tester.ExpectUniqueSample(
232 base::StringPrintf("Preloading.%s.Attempt.%s.Recall", type_cstr,
233 rule_predictor_cstr),
234 PredictorConfusionMatrix::kTruePositive, 1);
235 histogram_tester.ExpectUniqueSample(
236 base::StringPrintf("Preloading.%s.Attempt.%s.TriggeringOutcome",
237 type_cstr, rule_predictor_cstr),
238 PreloadingTriggeringOutcome::kSuccess, 1);
239
240 test::PreloadingAttemptUkmEntryBuilder attempt_entry_builder(
241 content_preloading_predictor::kSpeculationRules);
242 ukm::TestUkmRecorder::HumanReadableUkmEntry expected_attempt_entry =
243 attempt_entry_builder.BuildEntry(
244 source_id, type(), PreloadingEligibility::kEligible,
245 PreloadingHoldbackStatus::kAllowed,
246 PreloadingTriggeringOutcome::kSuccess,
247 PreloadingFailureReason::kUnspecified, /*accurate=*/true,
248 base::ScopedMockElapsedTimersForTest::kMockElapsedTime,
249 blink::mojom::SpeculationEagerness::kModerate);
250 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> attempts =
251 ukm_recorder.GetEntries(ukm::builders::Preloading_Attempt::kEntryName,
252 test::kPreloadingAttemptUkmMetrics);
253 std::erase_if(attempts, [&](const auto& entry) {
254 return entry.metrics.at(
255 ukm::builders::Preloading_Attempt::kPreloadingPredictorName) !=
256 content_preloading_predictor::kSpeculationRules.ukm_value();
257 });
kenossc3814a42024-10-25 06:03:02258 if (base::FeatureList::IsEnabled(
259 features::kPrerender2FallbackPrefetchSpecRules) &&
260 type() == PreloadingType::kPrerender) {
261 // If type is prerender, `PrerendererImpl` triggers prefetch ahead
262 // prerender. Ignore the corresponding UKM as it is checkid in
263 // prerenderer_impl_browsertest.cc.
264 ASSERT_EQ(attempts.size(), 2u);
265 EXPECT_EQ(attempts[1], expected_attempt_entry)
266 << test::ActualVsExpectedUkmEntryToString(attempts[1],
267 expected_attempt_entry);
268 } else {
269 ASSERT_EQ(attempts.size(), 1u);
270 EXPECT_EQ(attempts[0], expected_attempt_entry)
271 << test::ActualVsExpectedUkmEntryToString(attempts[0],
272 expected_attempt_entry);
273 }
Kevin McNee98e068a2024-04-09 20:12:34274
275 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> predictions =
276 ukm_recorder.GetEntries(
277 ukm::builders::Preloading_Prediction::kEntryName,
278 test::kPreloadingPredictionUkmMetrics);
279 std::erase_if(predictions, [&](const auto& entry) {
280 return entry.metrics.at(ukm::builders::Preloading_Prediction::
281 kPreloadingPredictorName) !=
282 content_preloading_predictor::kSpeculationRules.ukm_value();
283 });
284 EXPECT_TRUE(predictions.empty());
285 }
286
287 {
288 const std::string predictor_str{predictor().name()};
289 const char* predictor_cstr = predictor_str.c_str();
290
291 histogram_tester.ExpectUniqueSample(
292 base::StringPrintf("Preloading.Predictor.%s.Precision", predictor_cstr),
293 PredictorConfusionMatrix::kTruePositive, 1);
294 histogram_tester.ExpectUniqueSample(
295 base::StringPrintf("Preloading.Predictor.%s.Recall", predictor_cstr),
296 PredictorConfusionMatrix::kTruePositive, 1);
297 histogram_tester.ExpectUniqueSample(
298 base::StringPrintf("Preloading.%s.Attempt.%s.Precision", type_cstr,
299 predictor_cstr),
300 PredictorConfusionMatrix::kTruePositive, 1);
301 histogram_tester.ExpectUniqueSample(
302 base::StringPrintf("Preloading.%s.Attempt.%s.Recall", type_cstr,
303 predictor_cstr),
304 PredictorConfusionMatrix::kTruePositive, 1);
305 histogram_tester.ExpectUniqueSample(
306 base::StringPrintf("Preloading.%s.Attempt.%s.TriggeringOutcome",
307 type_cstr, predictor_cstr),
308 PreloadingTriggeringOutcome::kSuccess, 1);
309
310 constexpr bool accurate = true;
311 constexpr int confidence = 100;
312
313 test::PreloadingAttemptUkmEntryBuilder attempt_entry_builder(predictor());
314 ukm::TestUkmRecorder::HumanReadableUkmEntry expected_attempt_entry =
315 attempt_entry_builder.BuildEntry(
316 source_id, type(), PreloadingEligibility::kEligible,
317 PreloadingHoldbackStatus::kAllowed,
318 PreloadingTriggeringOutcome::kSuccess,
319 PreloadingFailureReason::kUnspecified, accurate,
320 base::ScopedMockElapsedTimersForTest::kMockElapsedTime,
321 blink::mojom::SpeculationEagerness::kModerate);
322 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> attempts =
323 ukm_recorder.GetEntries(ukm::builders::Preloading_Attempt::kEntryName,
324 test::kPreloadingAttemptUkmMetrics);
325 std::erase_if(attempts, [&](const auto& entry) {
326 return entry.metrics.at(
327 ukm::builders::Preloading_Attempt::kPreloadingPredictorName) !=
328 predictor().ukm_value();
329 });
kenossc3814a42024-10-25 06:03:02330 if (base::FeatureList::IsEnabled(
331 features::kPrerender2FallbackPrefetchSpecRules) &&
332 type() == PreloadingType::kPrerender) {
333 // If type is prerender, `PrerendererImpl` triggers prefetch ahead
334 // prerender. Ignore the corresponding UKM as it is checkid in
335 // prerenderer_impl_browsertest.cc.
336 ASSERT_EQ(attempts.size(), 2u);
337 EXPECT_EQ(attempts[1], expected_attempt_entry)
338 << test::ActualVsExpectedUkmEntryToString(attempts[1],
339 expected_attempt_entry);
340 } else {
341 ASSERT_EQ(attempts.size(), 1u);
342 EXPECT_EQ(attempts[0], expected_attempt_entry)
343 << test::ActualVsExpectedUkmEntryToString(attempts[0],
344 expected_attempt_entry);
345 }
Kevin McNee98e068a2024-04-09 20:12:34346
347 test::PreloadingPredictionUkmEntryBuilder prediction_entry_builder(
348 predictor());
349 ukm::TestUkmRecorder::HumanReadableUkmEntry expected_prediction_entry =
350 prediction_entry_builder.BuildEntry(source_id, confidence, accurate);
351 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> predictions =
352 ukm_recorder.GetEntries(
353 ukm::builders::Preloading_Prediction::kEntryName,
354 test::kPreloadingPredictionUkmMetrics);
355 std::erase_if(predictions, [&](const auto& entry) {
356 return entry.metrics.at(ukm::builders::Preloading_Prediction::
357 kPreloadingPredictorName) !=
358 predictor().ukm_value();
359 });
360 ASSERT_EQ(predictions.size(), 1u);
361 EXPECT_EQ(predictions[0], expected_prediction_entry)
362 << test::ActualVsExpectedUkmEntryToString(predictions[0],
363 expected_prediction_entry);
364 }
365}
366
367IN_PROC_BROWSER_TEST_F(PreloadingDeciderBrowserTest,
368 EnactModerateNewTabPrerender) {
369 base::HistogramTester histogram_tester;
370 ASSERT_TRUE(NavigateToURL(
371 shell(), GetTestURL("/preloading/preloading_decider_moderate.html")));
372 ExpectCandidatesReceived();
373
374 const GURL new_tab_url = GetTestURL("/title1.html?d");
375
376 auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
377 web_contents()->GetPrimaryMainFrame());
378 ASSERT_TRUE(preloading_decider);
379
380 TestNavigationObserver nav_observer(new_tab_url);
381 nav_observer.StartWatchingNewWebContents();
382
383 preloading_decider->OnPointerDown(new_tab_url);
384
385 EXPECT_TRUE(ExecJs(web_contents(), "document.getElementById('d').click()"));
386 nav_observer.Wait();
387
388 // Also navigate the current tab away, so any of its metrics are flushed.
389 ASSERT_TRUE(NavigateToURL(shell(), GetTestURL("/title2.html")));
390
391 {
392 const std::string rule_predictor_str{
393 content_preloading_predictor::kSpeculationRules.name()};
394 const char* rule_predictor_cstr = rule_predictor_str.c_str();
395
Takashi Nakayama978f0a152025-06-17 08:26:25396 // We intentionally don't record a prediction for non-immediate speculation
Kevin McNee98e068a2024-04-09 20:12:34397 // rules. They aren't predictions per se, but a declaration to the browser
398 // that preloading would be safe.
399 histogram_tester.ExpectTotalCount(
400 base::StringPrintf("Preloading.Predictor.%s.Precision",
401 rule_predictor_cstr),
402 0);
403 histogram_tester.ExpectUniqueSample(
404 base::StringPrintf("Preloading.Predictor.%s.Recall",
405 rule_predictor_cstr),
406 PredictorConfusionMatrix::kFalseNegative, 1);
407
408 histogram_tester.ExpectUniqueSample(
409 base::StringPrintf("Preloading.Prerender.Attempt.%s.Precision",
410 rule_predictor_cstr),
411 PredictorConfusionMatrix::kTruePositive, 1);
412 histogram_tester.ExpectUniqueSample(
413 base::StringPrintf("Preloading.Prerender.Attempt.%s.Recall",
414 rule_predictor_cstr),
415 PredictorConfusionMatrix::kTruePositive, 1);
416 }
417
418 {
419 const std::string predictor_str{
420 preloading_predictor::kUrlPointerDownOnAnchor.name()};
421 const char* predictor_cstr = predictor_str.c_str();
422
423 histogram_tester.ExpectUniqueSample(
424 base::StringPrintf("Preloading.Predictor.%s.Precision", predictor_cstr),
425 PredictorConfusionMatrix::kTruePositive, 1);
426 histogram_tester.ExpectUniqueSample(
427 base::StringPrintf("Preloading.Predictor.%s.Recall", predictor_cstr),
428 PredictorConfusionMatrix::kTruePositive, 1);
429 histogram_tester.ExpectUniqueSample(
430 base::StringPrintf("Preloading.Prerender.Attempt.%s.Precision",
431 predictor_cstr),
432 PredictorConfusionMatrix::kTruePositive, 1);
433 histogram_tester.ExpectUniqueSample(
434 base::StringPrintf("Preloading.Prerender.Attempt.%s.Recall",
435 predictor_cstr),
436 PredictorConfusionMatrix::kTruePositive, 1);
437 }
438}
439
440IN_PROC_BROWSER_TEST_F(PreloadingDeciderBrowserTest, PredictionWithoutAttempt) {
441 base::HistogramTester histogram_tester;
442 ASSERT_TRUE(NavigateToURL(
443 shell(), GetTestURL("/preloading/preloading_decider_moderate.html")));
444 ExpectCandidatesReceived();
445
446 auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
447 web_contents()->GetPrimaryMainFrame());
448 ASSERT_TRUE(preloading_decider);
449
450 TestNavigationObserver nav_observer(web_contents());
451 preloading_decider->OnPointerDown(GetTestURL("/title1.html?a"));
452 EXPECT_TRUE(ExecJs(web_contents(), "document.getElementById('a').click()"));
453 nav_observer.Wait();
454
455 {
456 const std::string predictor_str{
457 preloading_predictor::kUrlPointerDownOnAnchor.name()};
458 const char* predictor_cstr = predictor_str.c_str();
459
460 histogram_tester.ExpectUniqueSample(
461 base::StringPrintf("Preloading.Predictor.%s.Precision", predictor_cstr),
462 PredictorConfusionMatrix::kTruePositive, 1);
463 histogram_tester.ExpectUniqueSample(
464 base::StringPrintf("Preloading.Predictor.%s.Recall", predictor_cstr),
465 PredictorConfusionMatrix::kTruePositive, 1);
466 histogram_tester.ExpectTotalCount(
467 base::StringPrintf("Preloading.Prerender.Attempt.%s.Precision",
468 predictor_cstr),
469 0);
470 histogram_tester.ExpectUniqueSample(
471 base::StringPrintf("Preloading.Prerender.Attempt.%s.Recall",
472 predictor_cstr),
473 PredictorConfusionMatrix::kFalseNegative, 1);
474 }
475}
476
Iman Saboorieda025c72023-05-12 18:55:29477} // namespace content