blob: 3e03482330e1602186f48d6836820900e04f56c6 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/test/preloading_test_util.h"
#include "base/strings/stringprintf.h"
#include "content/browser/preloading/preloading_attempt_impl.h"
#include "content/browser/preloading/preloading_config.h"
#include "content/browser/preloading/preloading_data_impl.h"
#include "preloading_test_util.h"
#include "services/metrics/public/cpp/metrics_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content::test {
using UkmEntry = ukm::TestUkmRecorder::HumanReadableUkmEntry;
using Preloading_Attempt = ukm::builders::Preloading_Attempt;
using Preloading_Prediction = ukm::builders::Preloading_Prediction;
const std::vector<std::string> kPreloadingAttemptUkmMetrics{
Preloading_Attempt::kPreloadingTypeName,
Preloading_Attempt::kPreloadingPredictorName,
Preloading_Attempt::kEligibilityName,
Preloading_Attempt::kHoldbackStatusName,
Preloading_Attempt::kTriggeringOutcomeName,
Preloading_Attempt::kFailureReasonName,
Preloading_Attempt::kAccurateTriggeringName,
Preloading_Attempt::kReadyTimeName,
Preloading_Attempt::kTimeToNextNavigationName,
Preloading_Attempt::kSpeculationEagernessName,
};
const std::vector<std::string> kPreloadingPredictionUkmMetrics{
Preloading_Prediction::kPreloadingPredictorName,
Preloading_Prediction::kConfidenceName,
Preloading_Prediction::kAccuratePredictionName,
Preloading_Prediction::kTimeToNextNavigationName,
};
PreloadingAttemptUkmEntryBuilder::PreloadingAttemptUkmEntryBuilder(
PreloadingPredictor predictor)
: predictor_(predictor) {}
UkmEntry PreloadingAttemptUkmEntryBuilder::BuildEntry(
ukm::SourceId source_id,
PreloadingType preloading_type,
PreloadingEligibility eligibility,
PreloadingHoldbackStatus holdback_status,
PreloadingTriggeringOutcome triggering_outcome,
PreloadingFailureReason failure_reason,
bool accurate,
std::optional<base::TimeDelta> ready_time,
std::optional<blink::mojom::SpeculationEagerness> eagerness) const {
std::map<std::string, int64_t> metrics = {
{Preloading_Attempt::kPreloadingTypeName,
static_cast<int64_t>(preloading_type)},
{Preloading_Attempt::kPreloadingPredictorName, predictor_.ukm_value()},
{Preloading_Attempt::kEligibilityName, static_cast<int64_t>(eligibility)},
{Preloading_Attempt::kHoldbackStatusName,
static_cast<int64_t>(holdback_status)},
{Preloading_Attempt::kTriggeringOutcomeName,
static_cast<int64_t>(triggering_outcome)},
{Preloading_Attempt::kFailureReasonName,
static_cast<int64_t>(failure_reason)},
{Preloading_Attempt::kAccurateTriggeringName, accurate ? 1 : 0},
{Preloading_Attempt::kTimeToNextNavigationName,
ukm::GetExponentialBucketMinForCounts1000(
base::ScopedMockElapsedTimersForTest::kMockElapsedTime
.InMilliseconds())}};
if (ready_time) {
metrics.insert({Preloading_Attempt::kReadyTimeName,
ukm::GetExponentialBucketMinForCounts1000(
ready_time->InMilliseconds())});
}
if (eagerness) {
metrics.insert({Preloading_Attempt::kSpeculationEagernessName,
static_cast<int64_t>(eagerness.value())});
}
return UkmEntry{source_id, std::move(metrics)};
}
PreloadingPredictionUkmEntryBuilder::PreloadingPredictionUkmEntryBuilder(
PreloadingPredictor predictor)
: predictor_(predictor) {}
UkmEntry PreloadingPredictionUkmEntryBuilder::BuildEntry(
ukm::SourceId source_id,
int64_t confidence,
bool accurate_prediction) const {
return UkmEntry{source_id,
{{Preloading_Prediction::kPreloadingPredictorName,
predictor_.ukm_value()},
{Preloading_Prediction::kConfidenceName, confidence},
{Preloading_Prediction::kAccuratePredictionName,
accurate_prediction ? 1 : 0},
{Preloading_Prediction::kTimeToNextNavigationName,
ukm::GetExponentialBucketMinForCounts1000(
base::ScopedMockElapsedTimersForTest::kMockElapsedTime
.InMilliseconds())}}};
}
void ExpectPreloadingAttemptUkm(
const ukm::TestAutoSetUkmRecorder& ukm_recorder,
const std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>&
expected_attempt_entries) {
auto attempt_entries = ukm_recorder.GetEntries(
Preloading_Attempt::kEntryName, test::kPreloadingAttemptUkmMetrics);
EXPECT_EQ(attempt_entries.size(), expected_attempt_entries.size());
EXPECT_THAT(attempt_entries,
testing::UnorderedElementsAreArray(expected_attempt_entries))
<< test::ActualVsExpectedUkmEntriesToString(attempt_entries,
expected_attempt_entries);
}
void ExpectPreloadingPredictionUkm(
const ukm::TestAutoSetUkmRecorder& ukm_recorder,
const std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>&
expected_prediction_entries) {
auto prediction_entries = ukm_recorder.GetEntries(
Preloading_Prediction::kEntryName, test::kPreloadingPredictionUkmMetrics);
EXPECT_EQ(prediction_entries.size(), expected_prediction_entries.size());
EXPECT_THAT(prediction_entries,
testing::UnorderedElementsAreArray(expected_prediction_entries))
<< test::ActualVsExpectedUkmEntriesToString(prediction_entries,
expected_prediction_entries);
}
std::string UkmEntryToString(const UkmEntry& entry) {
std::string result;
result +=
base::StringPrintf("Source ID: %d\n", static_cast<int>(entry.source_id));
for (const auto& metric : entry.metrics) {
result += base::StringPrintf("Metric '%s' = %d\n", metric.first.c_str(),
static_cast<int>(metric.second));
}
result += "\n";
return result;
}
std::string ActualVsExpectedUkmEntryToString(const UkmEntry& actual,
const UkmEntry& expected) {
std::string result = "Actual UKM entry:\n";
result += UkmEntryToString(actual);
result += "Expected UKM entry:\n";
result += UkmEntryToString(expected);
return result;
}
std::string ActualVsExpectedUkmEntriesToString(
const std::vector<UkmEntry>& actual,
const std::vector<UkmEntry>& expected) {
std::string result = "Actual UKM entries:\n";
for (auto entry : actual) {
result += UkmEntryToString(entry);
}
result += "Expected UKM entries:\n";
for (auto entry : expected) {
result += UkmEntryToString(entry);
}
return result;
}
PreloadingAttemptAccessor::PreloadingAttemptAccessor(
PreloadingAttempt* preloading_attempt)
: preloading_attempt_(preloading_attempt) {}
PreloadingTriggeringOutcome PreloadingAttemptAccessor::GetTriggeringOutcome() {
return static_cast<PreloadingAttemptImpl*>(preloading_attempt_)
->triggering_outcome_;
}
PreloadingFailureReason PreloadingAttemptAccessor::GetFailureReason() {
return static_cast<PreloadingAttemptImpl*>(preloading_attempt_)
->failure_reason_;
}
PreloadingConfigOverride::PreloadingConfigOverride() {
preloading_config_ = std::make_unique<PreloadingConfig>();
overridden_config_ =
PreloadingConfig::OverrideForTesting(preloading_config_.get());
}
PreloadingConfigOverride::~PreloadingConfigOverride() {
raw_ptr<PreloadingConfig> uninstalled_override =
PreloadingConfig::OverrideForTesting(overridden_config_);
// Make sure the override we uninstalled is the one we installed in the
// constructor.
CHECK_EQ(uninstalled_override.get(), preloading_config_.get());
}
void PreloadingConfigOverride::SetHoldback(PreloadingType preloading_type,
PreloadingPredictor predictor,
bool holdback) {
preloading_config_->SetHoldbackForTesting(preloading_type, predictor,
holdback);
}
void PreloadingConfigOverride::SetHoldback(std::string_view preloading_type,
std::string_view predictor,
bool holdback) {
preloading_config_->SetHoldbackForTesting(preloading_type, predictor,
holdback);
}
void SetHasSpeculationRulesPrerender(PreloadingData* preloading_data) {
static_cast<PreloadingDataImpl*>(preloading_data)
->SetHasSpeculationRulesPrerender();
}
} // namespace content::test