
This is step 1 of https://crbug.com/375330756#comment2 This CL disables `Prerender2FallbackPrefetchSpecRules` in `ScopedPrerenderFeatureList` and `PrerenderTestHelper` so that we can land fieldtrial testing config and then fix affected tests one by one. Also, this CL updates preloading_decider_browsertest.cc and ignores the UKM corresponding to prefetch ahead of prerender. Bug: 375119160, 375330756 Change-Id: I7ae1ef445eabbf43bc3a61fce4b9364631f01156 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5961438 Commit-Queue: Ken Okada <kenoss@chromium.org> Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org> Cr-Commit-Position: refs/heads/main@{#1373744}
476 lines
20 KiB
C++
476 lines
20 KiB
C++
// Copyright 2023 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "content/browser/preloading/preloading_decider.h"
|
|
|
|
#include "base/test/scoped_feature_list.h"
|
|
#include "base/timer/elapsed_timer.h"
|
|
#include "components/ukm/test_ukm_recorder.h"
|
|
#include "content/browser/preloading/preloading.h"
|
|
#include "content/browser/preloading/preloading_data_impl.h"
|
|
#include "content/browser/preloading/prerender/prerender_features.h"
|
|
#include "content/public/browser/render_frame_host.h"
|
|
#include "content/public/test/browser_test.h"
|
|
#include "content/public/test/browser_test_utils.h"
|
|
#include "content/public/test/content_browser_test.h"
|
|
#include "content/public/test/content_browser_test_utils.h"
|
|
#include "content/public/test/preloading_test_util.h"
|
|
#include "content/public/test/test_navigation_observer.h"
|
|
#include "content/shell/browser/shell.h"
|
|
#include "net/dns/mock_host_resolver.h"
|
|
#include "services/metrics/public/cpp/ukm_builders.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/blink/public/common/features.h"
|
|
#include "third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom.h"
|
|
|
|
namespace content {
|
|
|
|
class PreloadingDeciderBrowserTest : public ContentBrowserTest {
|
|
public:
|
|
PreloadingDeciderBrowserTest() = default;
|
|
~PreloadingDeciderBrowserTest() override = default;
|
|
|
|
void SetUp() override {
|
|
feature_list_.InitWithFeaturesAndParameters(
|
|
{
|
|
{blink::features::kPreloadingHeuristicsMLModel,
|
|
{{"enact_candidates", "true"}}},
|
|
{blink::features::kPrerender2InNewTab, {}},
|
|
},
|
|
{
|
|
// Disable the memory requirement of Prerender2 so the test can run
|
|
// on any bot.
|
|
{blink::features::kPrerender2MemoryControls},
|
|
});
|
|
|
|
ContentBrowserTest::SetUp();
|
|
}
|
|
|
|
void SetUpOnMainThread() override {
|
|
ContentBrowserTest::SetUpOnMainThread();
|
|
host_resolver()->AddRule("*", "127.0.0.1");
|
|
https_server_ = std::make_unique<net::EmbeddedTestServer>(
|
|
net::EmbeddedTestServer::TYPE_HTTPS);
|
|
https_server_->AddDefaultHandlers(GetTestDataFilePath());
|
|
|
|
ASSERT_TRUE(https_server_->Start());
|
|
}
|
|
|
|
WebContents* web_contents() { return shell()->web_contents(); }
|
|
|
|
const GURL GetTestURL(const char* file) const {
|
|
return https_server_->GetURL(file);
|
|
}
|
|
|
|
void ExpectCandidatesReceived() {
|
|
// The renderer queues updates and waits for style to be clean.
|
|
EXPECT_EQ(true, EvalJsAfterLifecycleUpdate(web_contents(), "", "true"));
|
|
EXPECT_EQ(true, EvalJsAfterLifecycleUpdate(web_contents(), "", "true"));
|
|
|
|
auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
|
|
web_contents()->GetPrimaryMainFrame());
|
|
ASSERT_TRUE(preloading_decider);
|
|
EXPECT_TRUE(preloading_decider->HasCandidatesForTesting());
|
|
}
|
|
|
|
private:
|
|
content::test::PreloadingConfigOverride preloading_config_override_;
|
|
base::test::ScopedFeatureList feature_list_;
|
|
std::unique_ptr<net::EmbeddedTestServer> https_server_;
|
|
};
|
|
|
|
IN_PROC_BROWSER_TEST_F(PreloadingDeciderBrowserTest,
|
|
SetIsNavigationInDomainCallback) {
|
|
base::HistogramTester histogram_tester;
|
|
ASSERT_TRUE(NavigateToURL(shell(),
|
|
GetTestURL("/preloading/preloading_decider.html")));
|
|
ExpectCandidatesReceived();
|
|
|
|
// Now navigate to another page
|
|
TestNavigationObserver nav_observer(web_contents());
|
|
EXPECT_TRUE(ExecJs(web_contents(), "document.getElementById('bar').click()"));
|
|
nav_observer.Wait();
|
|
|
|
histogram_tester.ExpectBucketCount(
|
|
"Preloading.Predictor.SpeculationRules.Recall",
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
histogram_tester.ExpectBucketCount(
|
|
"Preloading.Predictor.UrlPointerDownOnAnchor.Recall",
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
histogram_tester.ExpectBucketCount(
|
|
"Preloading.Predictor.UrlPointerHoverOnAnchor.Recall",
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
histogram_tester.ExpectBucketCount(
|
|
"Preloading.Predictor.PreloadingHeuristicsMLModel.Recall",
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
}
|
|
|
|
class PreloadingDeciderNonEagerBrowserTest
|
|
: public PreloadingDeciderBrowserTest,
|
|
public ::testing::WithParamInterface<
|
|
::testing::tuple<PreloadingPredictor, PreloadingType>> {
|
|
public:
|
|
static std::string DescribeParams(
|
|
const testing::TestParamInfo<ParamType>& info) {
|
|
const auto& [predictor, type] = info.param;
|
|
return base::StringPrintf(
|
|
"%s_%s", std::string(predictor.name()).c_str(),
|
|
std::string(PreloadingTypeToString(type)).c_str());
|
|
}
|
|
|
|
static constexpr PreloadingPredictor kNonEagerPredictors[] = {
|
|
preloading_predictor::kUrlPointerDownOnAnchor,
|
|
preloading_predictor::kUrlPointerHoverOnAnchor,
|
|
preloading_predictor::kPreloadingHeuristicsMLModel,
|
|
};
|
|
|
|
static constexpr PreloadingType kPreloadingTypes[] = {
|
|
PreloadingType::kPrefetch,
|
|
PreloadingType::kPrerender,
|
|
};
|
|
|
|
PreloadingPredictor predictor() const {
|
|
return ::testing::get<0>(GetParam());
|
|
}
|
|
|
|
PreloadingType type() const { return ::testing::get<1>(GetParam()); }
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
All,
|
|
PreloadingDeciderNonEagerBrowserTest,
|
|
::testing::Combine(
|
|
::testing::ValuesIn(
|
|
PreloadingDeciderNonEagerBrowserTest::kNonEagerPredictors),
|
|
::testing::ValuesIn(
|
|
PreloadingDeciderNonEagerBrowserTest::kPreloadingTypes)),
|
|
PreloadingDeciderNonEagerBrowserTest::DescribeParams);
|
|
|
|
IN_PROC_BROWSER_TEST_P(PreloadingDeciderNonEagerBrowserTest,
|
|
EnactModerateCandidate) {
|
|
base::ScopedMockElapsedTimersForTest mock_elapsed_timer;
|
|
base::HistogramTester histogram_tester;
|
|
ukm::TestAutoSetUkmRecorder ukm_recorder;
|
|
|
|
ASSERT_TRUE(NavigateToURL(
|
|
shell(), GetTestURL("/preloading/preloading_decider_moderate.html")));
|
|
ExpectCandidatesReceived();
|
|
|
|
std::string next_page_id;
|
|
GURL next_page_url;
|
|
switch (type()) {
|
|
case PreloadingType::kPrefetch:
|
|
next_page_id = "b";
|
|
next_page_url = GetTestURL("/title1.html?b");
|
|
break;
|
|
case PreloadingType::kPrerender:
|
|
next_page_id = "c";
|
|
next_page_url = GetTestURL("/title1.html?c");
|
|
break;
|
|
default:
|
|
FAIL();
|
|
}
|
|
|
|
// Trigger the non-eager predictor.
|
|
auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
|
|
web_contents()->GetPrimaryMainFrame());
|
|
ASSERT_TRUE(preloading_decider);
|
|
if (predictor() == preloading_predictor::kUrlPointerDownOnAnchor) {
|
|
preloading_decider->OnPointerDown(next_page_url);
|
|
} else if (predictor() == preloading_predictor::kUrlPointerHoverOnAnchor) {
|
|
preloading_decider->OnPointerHover(
|
|
next_page_url,
|
|
blink::mojom::AnchorElementPointerData::New(true, 0.0, 0.0));
|
|
} else if (predictor() ==
|
|
preloading_predictor::kPreloadingHeuristicsMLModel) {
|
|
preloading_decider->OnPreloadingHeuristicsModelDone(next_page_url,
|
|
/*score=*/1.0);
|
|
} else {
|
|
FAIL();
|
|
}
|
|
|
|
TestNavigationObserver nav_observer(web_contents());
|
|
EXPECT_TRUE(
|
|
ExecJs(web_contents(),
|
|
JsReplace("document.getElementById($1).click()", next_page_id)));
|
|
nav_observer.Wait();
|
|
|
|
const ukm::SourceId source_id = nav_observer.next_page_ukm_source_id();
|
|
|
|
const std::string type_str{PreloadingTypeToString(type())};
|
|
const char* type_cstr = type_str.c_str();
|
|
|
|
// For non-eager predictors, there are two PreloadingPredictors that
|
|
// contribute to a preloading attempt. One creates a candidate, but does not
|
|
// start the preloading attempt. The other starts the attempt. We assert below
|
|
// that both predictors have appropriate attribution in the recorded metrics.
|
|
{
|
|
const std::string rule_predictor_str{
|
|
content_preloading_predictor::kSpeculationRules.name()};
|
|
const char* rule_predictor_cstr = rule_predictor_str.c_str();
|
|
|
|
// We intentionally don't record a prediction for non-eager speculation
|
|
// rules. They aren't predictions per se, but a declaration to the browser
|
|
// that preloading would be safe.
|
|
histogram_tester.ExpectTotalCount(
|
|
base::StringPrintf("Preloading.Predictor.%s.Precision",
|
|
rule_predictor_cstr),
|
|
0);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Recall",
|
|
rule_predictor_cstr),
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.%s.Attempt.%s.Precision", type_cstr,
|
|
rule_predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.%s.Attempt.%s.Recall", type_cstr,
|
|
rule_predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.%s.Attempt.%s.TriggeringOutcome",
|
|
type_cstr, rule_predictor_cstr),
|
|
PreloadingTriggeringOutcome::kSuccess, 1);
|
|
|
|
test::PreloadingAttemptUkmEntryBuilder attempt_entry_builder(
|
|
content_preloading_predictor::kSpeculationRules);
|
|
ukm::TestUkmRecorder::HumanReadableUkmEntry expected_attempt_entry =
|
|
attempt_entry_builder.BuildEntry(
|
|
source_id, type(), PreloadingEligibility::kEligible,
|
|
PreloadingHoldbackStatus::kAllowed,
|
|
PreloadingTriggeringOutcome::kSuccess,
|
|
PreloadingFailureReason::kUnspecified, /*accurate=*/true,
|
|
base::ScopedMockElapsedTimersForTest::kMockElapsedTime,
|
|
blink::mojom::SpeculationEagerness::kModerate);
|
|
std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> attempts =
|
|
ukm_recorder.GetEntries(ukm::builders::Preloading_Attempt::kEntryName,
|
|
test::kPreloadingAttemptUkmMetrics);
|
|
std::erase_if(attempts, [&](const auto& entry) {
|
|
return entry.metrics.at(
|
|
ukm::builders::Preloading_Attempt::kPreloadingPredictorName) !=
|
|
content_preloading_predictor::kSpeculationRules.ukm_value();
|
|
});
|
|
if (base::FeatureList::IsEnabled(
|
|
features::kPrerender2FallbackPrefetchSpecRules) &&
|
|
type() == PreloadingType::kPrerender) {
|
|
// If type is prerender, `PrerendererImpl` triggers prefetch ahead
|
|
// prerender. Ignore the corresponding UKM as it is checkid in
|
|
// prerenderer_impl_browsertest.cc.
|
|
ASSERT_EQ(attempts.size(), 2u);
|
|
EXPECT_EQ(attempts[1], expected_attempt_entry)
|
|
<< test::ActualVsExpectedUkmEntryToString(attempts[1],
|
|
expected_attempt_entry);
|
|
} else {
|
|
ASSERT_EQ(attempts.size(), 1u);
|
|
EXPECT_EQ(attempts[0], expected_attempt_entry)
|
|
<< test::ActualVsExpectedUkmEntryToString(attempts[0],
|
|
expected_attempt_entry);
|
|
}
|
|
|
|
std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> predictions =
|
|
ukm_recorder.GetEntries(
|
|
ukm::builders::Preloading_Prediction::kEntryName,
|
|
test::kPreloadingPredictionUkmMetrics);
|
|
std::erase_if(predictions, [&](const auto& entry) {
|
|
return entry.metrics.at(ukm::builders::Preloading_Prediction::
|
|
kPreloadingPredictorName) !=
|
|
content_preloading_predictor::kSpeculationRules.ukm_value();
|
|
});
|
|
EXPECT_TRUE(predictions.empty());
|
|
}
|
|
|
|
{
|
|
const std::string predictor_str{predictor().name()};
|
|
const char* predictor_cstr = predictor_str.c_str();
|
|
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Precision", predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Recall", predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.%s.Attempt.%s.Precision", type_cstr,
|
|
predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.%s.Attempt.%s.Recall", type_cstr,
|
|
predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.%s.Attempt.%s.TriggeringOutcome",
|
|
type_cstr, predictor_cstr),
|
|
PreloadingTriggeringOutcome::kSuccess, 1);
|
|
|
|
constexpr bool accurate = true;
|
|
constexpr int confidence = 100;
|
|
|
|
test::PreloadingAttemptUkmEntryBuilder attempt_entry_builder(predictor());
|
|
ukm::TestUkmRecorder::HumanReadableUkmEntry expected_attempt_entry =
|
|
attempt_entry_builder.BuildEntry(
|
|
source_id, type(), PreloadingEligibility::kEligible,
|
|
PreloadingHoldbackStatus::kAllowed,
|
|
PreloadingTriggeringOutcome::kSuccess,
|
|
PreloadingFailureReason::kUnspecified, accurate,
|
|
base::ScopedMockElapsedTimersForTest::kMockElapsedTime,
|
|
blink::mojom::SpeculationEagerness::kModerate);
|
|
std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> attempts =
|
|
ukm_recorder.GetEntries(ukm::builders::Preloading_Attempt::kEntryName,
|
|
test::kPreloadingAttemptUkmMetrics);
|
|
std::erase_if(attempts, [&](const auto& entry) {
|
|
return entry.metrics.at(
|
|
ukm::builders::Preloading_Attempt::kPreloadingPredictorName) !=
|
|
predictor().ukm_value();
|
|
});
|
|
if (base::FeatureList::IsEnabled(
|
|
features::kPrerender2FallbackPrefetchSpecRules) &&
|
|
type() == PreloadingType::kPrerender) {
|
|
// If type is prerender, `PrerendererImpl` triggers prefetch ahead
|
|
// prerender. Ignore the corresponding UKM as it is checkid in
|
|
// prerenderer_impl_browsertest.cc.
|
|
ASSERT_EQ(attempts.size(), 2u);
|
|
EXPECT_EQ(attempts[1], expected_attempt_entry)
|
|
<< test::ActualVsExpectedUkmEntryToString(attempts[1],
|
|
expected_attempt_entry);
|
|
} else {
|
|
ASSERT_EQ(attempts.size(), 1u);
|
|
EXPECT_EQ(attempts[0], expected_attempt_entry)
|
|
<< test::ActualVsExpectedUkmEntryToString(attempts[0],
|
|
expected_attempt_entry);
|
|
}
|
|
|
|
test::PreloadingPredictionUkmEntryBuilder prediction_entry_builder(
|
|
predictor());
|
|
ukm::TestUkmRecorder::HumanReadableUkmEntry expected_prediction_entry =
|
|
prediction_entry_builder.BuildEntry(source_id, confidence, accurate);
|
|
std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> predictions =
|
|
ukm_recorder.GetEntries(
|
|
ukm::builders::Preloading_Prediction::kEntryName,
|
|
test::kPreloadingPredictionUkmMetrics);
|
|
std::erase_if(predictions, [&](const auto& entry) {
|
|
return entry.metrics.at(ukm::builders::Preloading_Prediction::
|
|
kPreloadingPredictorName) !=
|
|
predictor().ukm_value();
|
|
});
|
|
ASSERT_EQ(predictions.size(), 1u);
|
|
EXPECT_EQ(predictions[0], expected_prediction_entry)
|
|
<< test::ActualVsExpectedUkmEntryToString(predictions[0],
|
|
expected_prediction_entry);
|
|
}
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PreloadingDeciderBrowserTest,
|
|
EnactModerateNewTabPrerender) {
|
|
base::HistogramTester histogram_tester;
|
|
ASSERT_TRUE(NavigateToURL(
|
|
shell(), GetTestURL("/preloading/preloading_decider_moderate.html")));
|
|
ExpectCandidatesReceived();
|
|
|
|
const GURL new_tab_url = GetTestURL("/title1.html?d");
|
|
|
|
auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
|
|
web_contents()->GetPrimaryMainFrame());
|
|
ASSERT_TRUE(preloading_decider);
|
|
|
|
TestNavigationObserver nav_observer(new_tab_url);
|
|
nav_observer.StartWatchingNewWebContents();
|
|
|
|
preloading_decider->OnPointerDown(new_tab_url);
|
|
|
|
EXPECT_TRUE(ExecJs(web_contents(), "document.getElementById('d').click()"));
|
|
nav_observer.Wait();
|
|
|
|
// Also navigate the current tab away, so any of its metrics are flushed.
|
|
ASSERT_TRUE(NavigateToURL(shell(), GetTestURL("/title2.html")));
|
|
|
|
{
|
|
const std::string rule_predictor_str{
|
|
content_preloading_predictor::kSpeculationRules.name()};
|
|
const char* rule_predictor_cstr = rule_predictor_str.c_str();
|
|
|
|
// We intentionally don't record a prediction for non-eager speculation
|
|
// rules. They aren't predictions per se, but a declaration to the browser
|
|
// that preloading would be safe.
|
|
histogram_tester.ExpectTotalCount(
|
|
base::StringPrintf("Preloading.Predictor.%s.Precision",
|
|
rule_predictor_cstr),
|
|
0);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Recall",
|
|
rule_predictor_cstr),
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Prerender.Attempt.%s.Precision",
|
|
rule_predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Prerender.Attempt.%s.Recall",
|
|
rule_predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
}
|
|
|
|
{
|
|
const std::string predictor_str{
|
|
preloading_predictor::kUrlPointerDownOnAnchor.name()};
|
|
const char* predictor_cstr = predictor_str.c_str();
|
|
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Precision", predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Recall", predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Prerender.Attempt.%s.Precision",
|
|
predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Prerender.Attempt.%s.Recall",
|
|
predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
}
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PreloadingDeciderBrowserTest, PredictionWithoutAttempt) {
|
|
base::HistogramTester histogram_tester;
|
|
ASSERT_TRUE(NavigateToURL(
|
|
shell(), GetTestURL("/preloading/preloading_decider_moderate.html")));
|
|
ExpectCandidatesReceived();
|
|
|
|
auto* preloading_decider = PreloadingDecider::GetOrCreateForCurrentDocument(
|
|
web_contents()->GetPrimaryMainFrame());
|
|
ASSERT_TRUE(preloading_decider);
|
|
|
|
TestNavigationObserver nav_observer(web_contents());
|
|
preloading_decider->OnPointerDown(GetTestURL("/title1.html?a"));
|
|
EXPECT_TRUE(ExecJs(web_contents(), "document.getElementById('a').click()"));
|
|
nav_observer.Wait();
|
|
|
|
{
|
|
const std::string predictor_str{
|
|
preloading_predictor::kUrlPointerDownOnAnchor.name()};
|
|
const char* predictor_cstr = predictor_str.c_str();
|
|
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Precision", predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Predictor.%s.Recall", predictor_cstr),
|
|
PredictorConfusionMatrix::kTruePositive, 1);
|
|
histogram_tester.ExpectTotalCount(
|
|
base::StringPrintf("Preloading.Prerender.Attempt.%s.Precision",
|
|
predictor_cstr),
|
|
0);
|
|
histogram_tester.ExpectUniqueSample(
|
|
base::StringPrintf("Preloading.Prerender.Attempt.%s.Recall",
|
|
predictor_cstr),
|
|
PredictorConfusionMatrix::kFalseNegative, 1);
|
|
}
|
|
}
|
|
|
|
} // namespace content
|