blob: d9fae83d7fdc46dbb1c7c74a98056f9ffdabd3e9 [file] [log] [blame]
// 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_attempt_impl.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/browser/preloading/preloading.h"
#include "content/browser/preloading/preloading_config.h"
#include "content/public/browser/preloading.h"
#include "content/public/common/content_features.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/gtest/include/gtest/gtest-param-test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
const PreloadingPredictor kPredictors[] = {
preloading_predictor::kUnspecified,
preloading_predictor::kUrlPointerDownOnAnchor,
preloading_predictor::kUrlPointerHoverOnAnchor,
preloading_predictor::kLinkRel,
content_preloading_predictor::kSpeculationRules,
};
const PreloadingType kTypes[] = {
PreloadingType::kUnspecified, PreloadingType::kPreconnect,
PreloadingType::kPrefetch, PreloadingType::kPrerender,
PreloadingType::kNoStatePrefetch,
};
const char* kUmaTriggerOutcome = "Preloading.%s.Attempt.%s.TriggeringOutcome";
} // namespace
using PreloadingAttemptImplRecordUMATest = ::testing::TestWithParam<
::testing::tuple<PreloadingPredictor, PreloadingType>>;
TEST_P(PreloadingAttemptImplRecordUMATest, TestHistogramRecordedCorrectly) {
const auto& test_param = GetParam();
const auto predictor = ::testing::get<0>(test_param);
const auto preloading_type = ::testing::get<1>(test_param);
auto attempt = std::make_unique<PreloadingAttemptImpl>(
predictor, preloading_type, /*triggered_primary_page_source_id=*/0,
/*url_match_predicate=*/
PreloadingData::GetSameURLMatcher(GURL("http://example.com/")),
/*sampling_seed=*/1ul);
{
base::HistogramTester histogram_tester;
// Use `ukm::kInvalidSourceId` so we skip the UKM recording.
attempt->RecordPreloadingAttemptMetrics(ukm::kInvalidSourceId);
histogram_tester.ExpectUniqueSample(
base::StringPrintf(kUmaTriggerOutcome,
PreloadingTypeToString(preloading_type).data(),
predictor.name().data()),
PreloadingTriggeringOutcome::kUnspecified, 1);
}
{
attempt->SetEligibility(PreloadingEligibility::kEligible);
attempt->SetHoldbackStatus(PreloadingHoldbackStatus::kAllowed);
attempt->SetTriggeringOutcome(PreloadingTriggeringOutcome::kRunning);
base::HistogramTester histogram_tester;
attempt->RecordPreloadingAttemptMetrics(ukm::kInvalidSourceId);
histogram_tester.ExpectUniqueSample(
base::StringPrintf(kUmaTriggerOutcome,
PreloadingTypeToString(preloading_type).data(),
predictor.name().data()),
PreloadingTriggeringOutcome::kRunning, 1);
}
}
INSTANTIATE_TEST_SUITE_P(PreloadingAttemptImplRecordUMATests,
PreloadingAttemptImplRecordUMATest,
::testing::Combine(::testing::ValuesIn(kPredictors),
::testing::ValuesIn(kTypes)));
class PreloadingAttemptUKMTest : public ::testing::Test {
public:
PreloadingAttemptUKMTest() = default;
void SetUp() override {
ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
}
void TearDown() override { ukm_recorder_.reset(); }
ukm::TestUkmRecorder* ukm_recorder() { return ukm_recorder_.get(); }
private:
base::test::SingleThreadTaskEnvironment task_environment_;
std::unique_ptr<ukm::TestUkmRecorder> ukm_recorder_;
};
TEST_F(PreloadingAttemptUKMTest, NoSampling) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(features::kPreloadingConfig,
{{"preloading_config", R"(
[{
"preloading_type": "Preconnect",
"preloading_predictor": "UrlPointerDownOnAnchor",
"sampling_likelihood": 1.0
}]
)"}});
PreloadingConfig& config = PreloadingConfig::GetInstance();
config.ParseConfig();
PreloadingAttemptImpl attempt(
preloading_predictor::kUrlPointerDownOnAnchor,
PreloadingType::kPreconnect, ukm::AssignNewSourceId(),
PreloadingData::GetSameURLMatcher(GURL("http://example.com/")),
/*sampling_seed=*/1ul);
attempt.RecordPreloadingAttemptMetrics(ukm::AssignNewSourceId());
const char* entry_name =
ukm::builders::Preloading_Attempt_PreviousPrimaryPage::kEntryName;
// Make sure the attempt is recorded, with a sampling_likelihood of 1,000,000.
EXPECT_EQ(ukm_recorder()->GetEntriesByName(entry_name).size(), 1ul);
auto* entry = ukm_recorder()->GetEntriesByName(entry_name)[0];
ukm_recorder()->EntryHasMetric(
entry, ukm::builders::Preloading_Attempt_PreviousPrimaryPage::
kSamplingLikelihoodName);
ukm_recorder()->ExpectEntryMetric(
entry,
ukm::builders::Preloading_Attempt_PreviousPrimaryPage::
kSamplingLikelihoodName,
1'000'000);
}
TEST_F(PreloadingAttemptUKMTest, SampledOut) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeatureWithParameters(features::kPreloadingConfig,
{{"preloading_config", R"(
[{
"preloading_type": "Preconnect",
"preloading_predictor": "UrlPointerDownOnAnchor",
"sampling_likelihood": 0.0
}]
)"}});
PreloadingConfig& config = PreloadingConfig::GetInstance();
config.ParseConfig();
PreloadingAttemptImpl attempt(
preloading_predictor::kUrlPointerDownOnAnchor,
PreloadingType::kPreconnect, ukm::AssignNewSourceId(),
PreloadingData::GetSameURLMatcher(GURL("http://example.com/")),
/*sampling_seed=*/1ul);
attempt.RecordPreloadingAttemptMetrics(ukm::AssignNewSourceId());
const char* entry_name =
ukm::builders::Preloading_Attempt_PreviousPrimaryPage::kEntryName;
// Make sure the attempt is not recorded.
EXPECT_EQ(ukm_recorder()->GetEntriesByName(entry_name).size(), 0ul);
}
} // namespace content