Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 1 | // 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_data_impl.h" |
| 6 | |
Kevin McNee | 8efb8f7 | 2024-05-27 19:58:24 | [diff] [blame] | 7 | #include <algorithm> |
| 8 | |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 9 | #include "base/strings/strcat.h" |
Lei Zhang | 0a85e65a | 2025-05-23 19:22:06 | [diff] [blame] | 10 | #include "base/strings/string_number_conversions.h" |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 11 | #include "base/test/metrics/histogram_tester.h" |
Kevin McNee | 8efb8f7 | 2024-05-27 19:58:24 | [diff] [blame] | 12 | #include "components/ukm/test_ukm_recorder.h" |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 13 | #include "content/browser/preloading/preloading.h" |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 14 | #include "content/browser/preloading/preloading_confidence.h" |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 15 | #include "content/public/browser/navigation_handle.h" |
| 16 | #include "content/public/test/mock_navigation_handle.h" |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 17 | #include "content/public/test/navigation_simulator.h" |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 18 | #include "content/public/test/test_browser_context.h" |
| 19 | #include "content/public/test/test_renderer_host.h" |
| 20 | #include "content/test/test_web_contents.h" |
Kevin McNee | 8efb8f7 | 2024-05-27 19:58:24 | [diff] [blame] | 21 | #include "services/metrics/public/cpp/metrics_utils.h" |
| 22 | #include "services/metrics/public/cpp/ukm_builders.h" |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 23 | |
| 24 | namespace content { |
| 25 | |
| 26 | class PreloadingDataImplTest : public RenderViewHostTestHarness { |
| 27 | public: |
| 28 | PreloadingDataImplTest() = default; |
| 29 | |
| 30 | PreloadingDataImplTest(const PreloadingDataImplTest&) = delete; |
| 31 | PreloadingDataImplTest& operator=(const PreloadingDataImplTest&) = delete; |
| 32 | |
| 33 | void SetUp() override { |
| 34 | RenderViewHostTestHarness::SetUp(); |
| 35 | |
| 36 | browser_context_ = std::make_unique<TestBrowserContext>(); |
| 37 | web_contents_ = TestWebContents::Create( |
| 38 | browser_context_.get(), |
| 39 | SiteInstanceImpl::Create(browser_context_.get())); |
| 40 | } |
| 41 | |
| 42 | void TearDown() override { |
| 43 | web_contents_.reset(); |
| 44 | browser_context_.reset(); |
| 45 | RenderViewHostTestHarness::TearDown(); |
| 46 | } |
| 47 | |
| 48 | WebContents* GetWebContents() { return web_contents_.get(); } |
| 49 | |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 50 | std::string UmaPredictorPrecision(const PreloadingPredictor& predictor) { |
| 51 | return base::StrCat( |
| 52 | {"Preloading.Predictor.", predictor.name(), ".Precision"}); |
| 53 | } |
| 54 | |
| 55 | std::string UmaPredictorRecall(const PreloadingPredictor& predictor) { |
| 56 | return base::StrCat({"Preloading.Predictor.", predictor.name(), ".Recall"}); |
| 57 | } |
| 58 | |
| 59 | std::string UmaAttemptPrecision(const PreloadingPredictor& predictor, |
| 60 | PreloadingType preloading_type) { |
| 61 | return base::StrCat({"Preloading.", PreloadingTypeToString(preloading_type), |
| 62 | ".Attempt.", predictor.name(), ".Precision"}); |
| 63 | } |
| 64 | |
| 65 | std::string UmaAttemptRecall(const PreloadingPredictor& predictor, |
| 66 | PreloadingType preloading_type) { |
| 67 | return base::StrCat({"Preloading.", PreloadingTypeToString(preloading_type), |
| 68 | ".Attempt.", predictor.name(), ".Recall"}); |
| 69 | } |
| 70 | |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 71 | private: |
| 72 | std::unique_ptr<TestBrowserContext> browser_context_; |
| 73 | std::unique_ptr<TestWebContents> web_contents_; |
| 74 | }; |
| 75 | |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 76 | TEST_F(PreloadingDataImplTest, PredictorPrecisionAndRecall) { |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 77 | base::HistogramTester histogram_tester; |
| 78 | auto* preloading_data = |
| 79 | PreloadingDataImpl::GetOrCreateForWebContents(GetWebContents()); |
| 80 | |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 81 | preloading_data->SetIsNavigationInDomainCallback( |
| 82 | preloading_predictor::kUrlPointerDownOnAnchor, |
| 83 | base::BindRepeating( |
| 84 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 85 | preloading_data->SetIsNavigationInDomainCallback( |
| 86 | preloading_predictor::kUrlPointerHoverOnAnchor, |
| 87 | base::BindRepeating( |
| 88 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 89 | preloading_data->SetIsNavigationInDomainCallback( |
| 90 | preloading_predictor::kLinkRel, |
| 91 | base::BindRepeating( |
| 92 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 93 | |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 94 | // Add preloading predictions. |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 95 | GURL url_1{"https://www.example.com/page1.html"}; |
| 96 | GURL url_2{"https://www.example.com/page2.html"}; |
| 97 | GURL url_3{"https://www.example.com/page3.html"}; |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 98 | const auto target = url_1; |
| 99 | PreloadingPredictor predictor_1{ |
| 100 | preloading_predictor::kUrlPointerDownOnAnchor}; |
| 101 | PreloadingPredictor predictor_2{ |
| 102 | preloading_predictor::kUrlPointerHoverOnAnchor}; |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 103 | PreloadingPredictor predictor_3{preloading_predictor::kLinkRel}; |
HuanPo Lin | 12ce3b5fb4 | 2024-03-04 09:01:14 | [diff] [blame] | 104 | ukm::SourceId triggered_primary_page_source_id = |
| 105 | GetWebContents()->GetPrimaryMainFrame()->GetPageUkmSourceId(); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 106 | preloading_data->AddPreloadingPrediction( |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 107 | predictor_1, PreloadingConfidence{100}, |
| 108 | PreloadingData::GetSameURLMatcher(url_1), |
HuanPo Lin | 12ce3b5fb4 | 2024-03-04 09:01:14 | [diff] [blame] | 109 | triggered_primary_page_source_id); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 110 | preloading_data->AddPreloadingPrediction( |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 111 | predictor_1, PreloadingConfidence{100}, |
| 112 | PreloadingData::GetSameURLMatcher(url_1), |
HuanPo Lin | 12ce3b5fb4 | 2024-03-04 09:01:14 | [diff] [blame] | 113 | triggered_primary_page_source_id); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 114 | preloading_data->AddPreloadingPrediction( |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 115 | predictor_1, PreloadingConfidence{100}, |
| 116 | PreloadingData::GetSameURLMatcher(url_2), |
HuanPo Lin | 12ce3b5fb4 | 2024-03-04 09:01:14 | [diff] [blame] | 117 | triggered_primary_page_source_id); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 118 | |
| 119 | preloading_data->AddPreloadingPrediction( |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 120 | predictor_2, PreloadingConfidence{100}, |
| 121 | PreloadingData::GetSameURLMatcher(url_2), |
HuanPo Lin | 12ce3b5fb4 | 2024-03-04 09:01:14 | [diff] [blame] | 122 | triggered_primary_page_source_id); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 123 | preloading_data->AddPreloadingPrediction( |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 124 | predictor_2, PreloadingConfidence{100}, |
| 125 | PreloadingData::GetSameURLMatcher(url_3), |
HuanPo Lin | 12ce3b5fb4 | 2024-03-04 09:01:14 | [diff] [blame] | 126 | triggered_primary_page_source_id); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 127 | |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 128 | NavigationSimulator::NavigateAndCommitFromBrowser(GetWebContents(), target); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 129 | |
| 130 | // Check precision UKM records. |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 131 | // Since, we added the predictor twice, it should count the true positives |
| 132 | // twice as well. |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 133 | histogram_tester.ExpectBucketCount(UmaPredictorPrecision(predictor_1), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 134 | PredictorConfusionMatrix::kTruePositive, |
| 135 | 2); |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 136 | histogram_tester.ExpectBucketCount(UmaPredictorPrecision(predictor_1), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 137 | PredictorConfusionMatrix::kFalsePositive, |
| 138 | 1); |
| 139 | |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 140 | histogram_tester.ExpectBucketCount(UmaPredictorPrecision(predictor_2), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 141 | PredictorConfusionMatrix::kTruePositive, |
| 142 | 0); |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 143 | histogram_tester.ExpectBucketCount(UmaPredictorPrecision(predictor_2), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 144 | PredictorConfusionMatrix::kFalsePositive, |
| 145 | 2); |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 146 | |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 147 | histogram_tester.ExpectTotalCount(UmaPredictorPrecision(predictor_3), 0); |
| 148 | |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 149 | // Check recall UKM records. |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 150 | // It should only record 1 TP and not 2, and also no FN. |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 151 | histogram_tester.ExpectBucketCount(UmaPredictorRecall(predictor_1), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 152 | PredictorConfusionMatrix::kTruePositive, |
| 153 | 1); |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 154 | histogram_tester.ExpectBucketCount(UmaPredictorRecall(predictor_1), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 155 | PredictorConfusionMatrix::kFalseNegative, |
| 156 | 0); |
| 157 | // It should only record 1 FN. |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 158 | histogram_tester.ExpectBucketCount(UmaPredictorRecall(predictor_2), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 159 | PredictorConfusionMatrix::kTruePositive, |
| 160 | 0); |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 161 | histogram_tester.ExpectBucketCount(UmaPredictorRecall(predictor_2), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 162 | PredictorConfusionMatrix::kFalseNegative, |
| 163 | 1); |
| 164 | // For the missing predictor we should record 1 FN. |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 165 | histogram_tester.ExpectBucketCount(UmaPredictorRecall(predictor_3), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 166 | PredictorConfusionMatrix::kTruePositive, |
| 167 | 0); |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 168 | histogram_tester.ExpectBucketCount(UmaPredictorRecall(predictor_3), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 169 | PredictorConfusionMatrix::kFalseNegative, |
| 170 | 1); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 171 | } |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 172 | |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 173 | TEST_F(PreloadingDataImplTest, PageLoadWithoutAttemptIsFalseNegative) { |
| 174 | base::HistogramTester histogram_tester; |
| 175 | auto* preloading_data = |
| 176 | PreloadingDataImpl::GetOrCreateForWebContents(GetWebContents()); |
| 177 | |
| 178 | const PreloadingPredictor predictor{ |
| 179 | preloading_predictor::kUrlPointerDownOnAnchor}; |
| 180 | preloading_data->SetIsNavigationInDomainCallback( |
| 181 | predictor, |
| 182 | base::BindRepeating( |
| 183 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 184 | |
| 185 | const GURL target{"https://www.example.com/page1.html"}; |
| 186 | |
| 187 | NavigationSimulator::NavigateAndCommitFromBrowser(GetWebContents(), target); |
| 188 | |
| 189 | // The lack of an attempt represents a false negative. |
| 190 | histogram_tester.ExpectUniqueSample( |
| 191 | UmaAttemptRecall(predictor, PreloadingType::kPrefetch), |
| 192 | PredictorConfusionMatrix::kFalseNegative, 1); |
| 193 | histogram_tester.ExpectUniqueSample( |
| 194 | UmaAttemptRecall(predictor, PreloadingType::kPrerender), |
| 195 | PredictorConfusionMatrix::kFalseNegative, 1); |
| 196 | } |
| 197 | |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 198 | TEST_F(PreloadingDataImplTest, PreloadingAttemptPrecisionAndRecall) { |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 199 | base::HistogramTester histogram_tester; |
| 200 | auto* preloading_data = |
| 201 | PreloadingDataImpl::GetOrCreateForWebContents(GetWebContents()); |
| 202 | |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 203 | preloading_data->SetIsNavigationInDomainCallback( |
| 204 | preloading_predictor::kUrlPointerDownOnAnchor, |
| 205 | base::BindRepeating( |
| 206 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 207 | preloading_data->SetIsNavigationInDomainCallback( |
| 208 | preloading_predictor::kUrlPointerHoverOnAnchor, |
| 209 | base::BindRepeating( |
| 210 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 211 | preloading_data->SetIsNavigationInDomainCallback( |
| 212 | preloading_predictor::kLinkRel, |
| 213 | base::BindRepeating( |
| 214 | [](NavigationHandle* /*navigation_handle*/) { return false; })); |
| 215 | |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 216 | // Add preloading predictions. |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 217 | GURL url_1{"https://www.example.com/page1.html"}; |
| 218 | GURL url_2{"https://www.example.com/page2.html"}; |
| 219 | GURL url_3{"https://www.example.com/page3.html"}; |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 220 | const auto target = url_1; |
| 221 | PreloadingPredictor predictor_1{ |
| 222 | preloading_predictor::kUrlPointerDownOnAnchor}; |
| 223 | PreloadingPredictor predictor_2{ |
| 224 | preloading_predictor::kUrlPointerHoverOnAnchor}; |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 225 | PreloadingPredictor predictor_3{preloading_predictor::kLinkRel}; |
| 226 | |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 227 | std::vector<std::tuple<PreloadingPredictor, PreloadingType, GURL>> attempts{ |
| 228 | {predictor_1, PreloadingType::kPrerender, url_1}, |
| 229 | {predictor_2, PreloadingType::kPrefetch, url_2}, |
| 230 | {predictor_2, PreloadingType::kPrerender, url_1}, |
| 231 | {predictor_2, PreloadingType::kPrerender, url_2}, |
| 232 | {predictor_2, PreloadingType::kPrerender, url_3}, |
| 233 | }; |
| 234 | |
| 235 | for (const auto& [predictor, preloading_type, url] : attempts) { |
| 236 | preloading_data->AddPreloadingAttempt( |
Hiroki Nakagawa | f93776b | 2023-09-12 22:04:27 | [diff] [blame] | 237 | predictor, preloading_type, PreloadingData::GetSameURLMatcher(url), |
| 238 | GetWebContents()->GetPrimaryMainFrame()->GetPageUkmSourceId()); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 239 | } |
| 240 | |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 241 | NavigationSimulator::NavigateAndCommitFromBrowser(GetWebContents(), target); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 242 | |
| 243 | // Check precision UKM records. |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 244 | // There should be no UMA records for predictor_1, prefetch attempt. |
| 245 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 246 | UmaAttemptPrecision(predictor_1, PreloadingType::kPrefetch), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 247 | PredictorConfusionMatrix::kTruePositive, 0); |
| 248 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 249 | UmaAttemptPrecision(predictor_1, PreloadingType::kPrefetch), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 250 | PredictorConfusionMatrix::kFalsePositive, 0); |
| 251 | // There should 1 TP and 0 FP for predictor_1, prerender attempt. |
| 252 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 253 | UmaAttemptPrecision(predictor_1, PreloadingType::kPrerender), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 254 | PredictorConfusionMatrix::kTruePositive, 1); |
| 255 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 256 | UmaAttemptPrecision(predictor_1, PreloadingType::kPrerender), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 257 | PredictorConfusionMatrix::kFalsePositive, 0); |
| 258 | // There should 0 TP and 1 FP for predictor_2, prefetch attempt. |
| 259 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 260 | UmaAttemptPrecision(predictor_2, PreloadingType::kPrefetch), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 261 | PredictorConfusionMatrix::kTruePositive, 0); |
| 262 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 263 | UmaAttemptPrecision(predictor_2, PreloadingType::kPrefetch), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 264 | PredictorConfusionMatrix::kFalsePositive, 1); |
| 265 | // There should 1 TP and 2 FP for predictor_2, prerender attempt. |
| 266 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 267 | UmaAttemptPrecision(predictor_2, PreloadingType::kPrerender), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 268 | PredictorConfusionMatrix::kTruePositive, 1); |
| 269 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 270 | UmaAttemptPrecision(predictor_2, PreloadingType::kPrerender), |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 271 | PredictorConfusionMatrix::kFalsePositive, 2); |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 272 | |
| 273 | // Check recall UKM records. |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 274 | // predictor_1, prerender should be TP |
| 275 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 276 | UmaAttemptRecall(predictor_1, PreloadingType::kPrerender), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 277 | PredictorConfusionMatrix::kTruePositive, 1); |
| 278 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 279 | UmaAttemptRecall(predictor_1, PreloadingType::kPrerender), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 280 | PredictorConfusionMatrix::kFalseNegative, 0); |
| 281 | // predictor_1, prefetch should be FN |
| 282 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 283 | UmaAttemptRecall(predictor_1, PreloadingType::kPrefetch), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 284 | PredictorConfusionMatrix::kTruePositive, 0); |
| 285 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 286 | UmaAttemptRecall(predictor_1, PreloadingType::kPrefetch), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 287 | PredictorConfusionMatrix::kFalseNegative, 1); |
| 288 | // predictor_2, prerender should be TP |
| 289 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 290 | UmaAttemptRecall(predictor_2, PreloadingType::kPrerender), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 291 | PredictorConfusionMatrix::kTruePositive, 1); |
| 292 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 293 | UmaAttemptRecall(predictor_2, PreloadingType::kPrerender), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 294 | PredictorConfusionMatrix::kFalseNegative, 0); |
| 295 | // predictor_2, prefetch should be FN |
| 296 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 297 | UmaAttemptRecall(predictor_2, PreloadingType::kPrefetch), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 298 | PredictorConfusionMatrix::kTruePositive, 0); |
| 299 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 300 | UmaAttemptRecall(predictor_2, PreloadingType::kPrefetch), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 301 | PredictorConfusionMatrix::kFalseNegative, 1); |
| 302 | // 'page_in_domain_check' returns false for predictor_3: TP=0, FN=0. |
| 303 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 304 | UmaAttemptRecall(predictor_3, PreloadingType::kPrerender), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 305 | PredictorConfusionMatrix::kTruePositive, 0); |
| 306 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 307 | UmaAttemptRecall(predictor_3, PreloadingType::kPrerender), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 308 | PredictorConfusionMatrix::kFalseNegative, 0); |
| 309 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 310 | UmaAttemptRecall(predictor_3, PreloadingType::kPrefetch), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 311 | PredictorConfusionMatrix::kTruePositive, 0); |
| 312 | histogram_tester.ExpectBucketCount( |
Kevin McNee | 806cf67a | 2023-04-03 21:29:48 | [diff] [blame] | 313 | UmaAttemptRecall(predictor_3, PreloadingType::kPrefetch), |
Iman Saboori | 41d9b35 | 2023-03-09 20:52:11 | [diff] [blame] | 314 | PredictorConfusionMatrix::kFalseNegative, 0); |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 315 | } |
| 316 | |
Kevin McNee | 8efb8f7 | 2024-05-27 19:58:24 | [diff] [blame] | 317 | namespace { |
| 318 | void RunSamplingTest(WebContents* web_contents, |
| 319 | int num_predictions, |
| 320 | int expected_sampling_amount_bucket) { |
| 321 | using Preloading_Prediction = ukm::builders::Preloading_Prediction; |
| 322 | |
| 323 | ukm::TestAutoSetUkmRecorder test_ukm_recorder; |
| 324 | ukm::SourceId triggered_primary_page_source_id = |
| 325 | web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId(); |
| 326 | |
| 327 | auto* preloading_data = |
| 328 | PreloadingDataImpl::GetOrCreateForWebContents(web_contents); |
| 329 | preloading_data->SetIsNavigationInDomainCallback( |
| 330 | preloading_predictor::kUrlPointerHoverOnAnchor, |
| 331 | base::BindRepeating( |
| 332 | [](NavigationHandle* /*navigation_handle*/) { return true; })); |
| 333 | |
| 334 | // Add a number of predictions. If they're beyond the limit, we should only |
| 335 | // keep a random sample to stay within the limit. |
| 336 | preloading_data->SetMaxPredictionsToTenForTesting(); |
| 337 | const size_t expected_predictions_size = std::min(10, num_predictions); |
| 338 | for (int i = 0; i < num_predictions; ++i) { |
| 339 | preloading_data->AddPreloadingPrediction( |
| 340 | preloading_predictor::kUrlPointerHoverOnAnchor, |
| 341 | PreloadingConfidence{100}, |
| 342 | PreloadingData::GetSameURLMatcher( |
| 343 | GURL(base::StrCat({"https://www.example.com/page", |
| 344 | base::NumberToString(i), ".html"}))), |
| 345 | triggered_primary_page_source_id); |
| 346 | } |
| 347 | EXPECT_EQ(expected_predictions_size, |
| 348 | preloading_data->GetPredictionsSizeForTesting()); |
| 349 | |
| 350 | NavigationSimulator::NavigateAndCommitFromBrowser( |
| 351 | web_contents, GURL("https://www.example.com/somewhere_else.html")); |
| 352 | |
| 353 | std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> actual_ukm_entries = |
| 354 | test_ukm_recorder.GetEntries( |
| 355 | Preloading_Prediction::kEntryName, |
| 356 | {Preloading_Prediction::kSamplingAmountName}); |
| 357 | EXPECT_EQ(expected_predictions_size, actual_ukm_entries.size()); |
| 358 | for (const auto& entry : actual_ukm_entries) { |
| 359 | EXPECT_EQ(expected_sampling_amount_bucket, |
| 360 | entry.metrics.at(Preloading_Prediction::kSamplingAmountName)); |
| 361 | } |
| 362 | } |
| 363 | } // namespace |
| 364 | |
| 365 | TEST_F(PreloadingDataImplTest, MaxPredictions) { |
| 366 | constexpr double kBucketSpacing = 1.3; |
| 367 | RunSamplingTest(GetWebContents(), /*num_predictions=*/20, |
| 368 | /*expected_sampling_amount_bucket=*/ |
| 369 | ukm::GetExponentialBucketMin(500'000, kBucketSpacing)); |
| 370 | } |
| 371 | |
| 372 | TEST_F(PreloadingDataImplTest, NoSamplingUnderMaxPredictions) { |
| 373 | RunSamplingTest(GetWebContents(), /*num_predictions=*/5, |
| 374 | /*expected_sampling_amount_bucket=*/0); |
| 375 | } |
| 376 | |
Iman Saboori | 6a245ec | 2023-02-22 20:03:20 | [diff] [blame] | 377 | } // namespace content |