blob: e5a5610539fe3906e2c960537bee4814bb66861f [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/optimization_guide/optimization_guide_navigation_data.h"
#include <memory>
#include "base/base64.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::AnyOf;
using testing::HasSubstr;
using testing::Not;
typedef struct {
optimization_guide::proto::ClientModelFeature feature;
base::StringPiece ukm_metric_name;
float feature_value;
int expected_value;
} ClientHostModelFeaturesTestCase;
TEST(OptimizationGuideNavigationDataTest, RecordMetricsNoDataNoCommit) {
base::test::TaskEnvironment env;
base::HistogramTester histogram_tester;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.RecordMetrics(/*has_committed=*/false);
// Make sure no UMA recorded.
EXPECT_THAT(
histogram_tester.GetAllHistogramsRecorded(),
Not(AnyOf(
HasSubstr("OptimizationGuide.ApplyDecision"),
HasSubstr("OptimizationGuide.HintCache"),
HasSubstr(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch"),
HasSubstr("OptimizationGuide.Hints."),
HasSubstr("OptimizationGuide.TargetDecision"))));
// Make sure no UKM recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsNoDataHasCommit) {
base::test::TaskEnvironment env;
base::HistogramTester histogram_tester;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.RecordMetrics(/*has_committed=*/true);
// Make sure no UMA recorded.
EXPECT_THAT(histogram_tester.GetAllHistogramsRecorded(),
Not(AnyOf(HasSubstr("OptimizationGuide.Hints."),
HasSubstr("OptimizationGuide.HintCache"))));
// Make sure no UKM recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsCoveredByFetchButNoHintLoadAttempted) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_was_host_covered_by_fetch_at_navigation_start(true);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch.AtCommit",
0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HasHint.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HostMatch.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.PageMatch.AtCommit", 0);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheNoHostMatchBeforeCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(false);
data.set_was_host_covered_by_fetch_at_navigation_start(true);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", true, 1);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HasHint.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HostMatch.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.PageMatch.AtCommit", 0);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheNoHostMatchBeforeCommitAlsoNotCoveredByFetch) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(false);
data.set_was_host_covered_by_fetch_at_navigation_start(false);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", false, 1);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HasHint.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HostMatch.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.PageMatch.AtCommit", 0);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheNoHintButCoveredByFetchAtCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(false);
data.set_has_hint_after_commit(false);
data.set_was_host_covered_by_fetch_at_navigation_start(false);
data.set_was_host_covered_by_fetch_at_commit(true);
data.RecordMetrics(/*has_committed=*/true);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.AtCommit", false, 1);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HostMatch.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.PageMatch.AtCommit", 0);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheNoHintAtCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_after_commit(false);
data.RecordMetrics(/*has_committed=*/true);
// This probably wouldn't actually happen in practice but make sure optional
// check works for before commit.
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", 0);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.AtCommit", false, 1);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HostMatch.AtCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.PageMatch.AtCommit", 0);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheHasHintButNotLoadedAtCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_after_commit(true);
data.RecordMetrics(/*has_committed=*/true);
// This probably wouldn't actually happen in practice but make sure optional
// check works for before commit.
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", 0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
0);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", 0);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HostMatch.AtCommit", false, 1);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.HintCache.PageMatch.AtCommit", 0);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheHasPageHintAtCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(true);
data.set_was_host_covered_by_fetch_at_navigation_start(false);
data.set_has_hint_after_commit(true);
data.set_serialized_hint_version_string("abc");
data.set_page_hint(std::make_unique<optimization_guide::proto::PageHint>());
data.RecordMetrics(/*has_committed=*/true);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HostMatch.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.PageMatch.AtCommit", true, 1);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheHasHintButPageHintNotSetAtCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(true);
data.set_has_hint_after_commit(true);
data.set_serialized_hint_version_string("abc");
data.RecordMetrics(/*has_committed=*/true);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HostMatch.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.PageMatch.AtCommit", false, 1);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCacheHasHintButNoPageHintAtCommit) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(true);
data.set_has_hint_after_commit(true);
data.set_serialized_hint_version_string("abc");
data.set_page_hint(nullptr);
data.RecordMetrics(/*has_committed=*/true);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.BeforeCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"BeforeCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.BeforeCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.NavigationHostCoveredByFetch."
"AtCommit",
false, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.Hints.NavigationHostCoverage.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HasHint.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.HostMatch.AtCommit", true, 1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintCache.PageMatch.AtCommit", false, 1);
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsBadHintVersion) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_serialized_hint_version_string("123");
data.RecordMetrics(/*has_committed=*/false);
// Make sure no UKM recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsEmptyHintVersion) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/123);
data.set_serialized_hint_version_string("");
data.RecordMetrics(/*has_committed=*/false);
// Make sure no UKM recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsZeroTimestampOrSource) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
optimization_guide::proto::Version hint_version;
hint_version.mutable_generation_timestamp()->set_seconds(0);
hint_version.set_hint_source(optimization_guide::proto::HINT_SOURCE_UNKNOWN);
std::string hint_version_string;
hint_version.SerializeToString(&hint_version_string);
base::Base64Encode(hint_version_string, &hint_version_string);
data.set_serialized_hint_version_string(hint_version_string);
data.RecordMetrics(/*has_committed=*/false);
// Make sure UKM not recorded for all empty values.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsGoodHintVersion) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
optimization_guide::proto::Version hint_version;
hint_version.mutable_generation_timestamp()->set_seconds(234);
hint_version.set_hint_source(
optimization_guide::proto::HINT_SOURCE_OPTIMIZATION_GUIDE_SERVICE);
std::string hint_version_string;
hint_version.SerializeToString(&hint_version_string);
base::Base64Encode(hint_version_string, &hint_version_string);
data.set_serialized_hint_version_string(hint_version_string);
data.RecordMetrics(/*has_committed=*/false);
// Make sure version is serialized properly and UKM is recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kHintSourceName,
static_cast<int>(
optimization_guide::proto::HINT_SOURCE_OPTIMIZATION_GUIDE_SERVICE));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kHintGenerationTimestampName,
234);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintVersionWithUnknownSource) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
optimization_guide::proto::Version hint_version;
hint_version.mutable_generation_timestamp()->set_seconds(234);
hint_version.set_hint_source(optimization_guide::proto::HINT_SOURCE_UNKNOWN);
std::string hint_version_string;
hint_version.SerializeToString(&hint_version_string);
base::Base64Encode(hint_version_string, &hint_version_string);
data.set_serialized_hint_version_string(hint_version_string);
data.RecordMetrics(/*has_committed=*/false);
// Make sure version is serialized properly and UKM is only recorded for
// non-empty values.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_FALSE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kHintSourceName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kHintGenerationTimestampName,
234);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintVersionWithNoSource) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
optimization_guide::proto::Version hint_version;
hint_version.mutable_generation_timestamp()->set_seconds(234);
std::string hint_version_string;
hint_version.SerializeToString(&hint_version_string);
base::Base64Encode(hint_version_string, &hint_version_string);
data.set_serialized_hint_version_string(hint_version_string);
data.RecordMetrics(/*has_committed=*/false);
// Make sure version is serialized properly and UKM is recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_FALSE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kHintSourceName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kHintGenerationTimestampName,
234);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintVersionWithZeroTimestamp) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
optimization_guide::proto::Version hint_version;
hint_version.mutable_generation_timestamp()->set_seconds(0);
hint_version.set_hint_source(
optimization_guide::proto::HINT_SOURCE_OPTIMIZATION_GUIDE_SERVICE);
std::string hint_version_string;
hint_version.SerializeToString(&hint_version_string);
base::Base64Encode(hint_version_string, &hint_version_string);
data.set_serialized_hint_version_string(hint_version_string);
data.RecordMetrics(/*has_committed=*/false);
// Make sure version is serialized properly and UKM is only recorded for
// non-empty values.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_FALSE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kHintGenerationTimestampName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kHintSourceName,
static_cast<int>(
optimization_guide::proto::HINT_SOURCE_OPTIMIZATION_GUIDE_SERVICE));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintVersionWithNoTimestamp) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
optimization_guide::proto::Version hint_version;
hint_version.set_hint_source(
optimization_guide::proto::HINT_SOURCE_OPTIMIZATION_GUIDE_SERVICE);
std::string hint_version_string;
hint_version.SerializeToString(&hint_version_string);
base::Base64Encode(hint_version_string, &hint_version_string);
data.set_serialized_hint_version_string(hint_version_string);
data.RecordMetrics(/*has_committed=*/false);
// Make sure version is serialized properly and UKM is recorded.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_FALSE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kHintGenerationTimestampName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kHintSourceName,
static_cast<int>(
optimization_guide::proto::HINT_SOURCE_OPTIMIZATION_GUIDE_SERVICE));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsOptimizationTargetModelVersion) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetModelVersionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, 2);
data.RecordMetrics(/*has_committed=*/false);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry,
ukm::builders::OptimizationGuide::kPainfulPageLoadModelVersionName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kPainfulPageLoadModelVersionName,
2);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsModelVersionForOptimizationTargetHasNoCorrespondingUkm) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetModelVersionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_UNKNOWN, 2);
data.RecordMetrics(/*has_committed=*/false);
// Make sure UKM not recorded for all empty values.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsOptimizationTargetModelPredictionScore) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetModelPredictionScoreForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, 0.123);
data.RecordMetrics(/*has_committed=*/false);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::
kPainfulPageLoadModelPredictionScoreName));
ukm_recorder.ExpectEntryMetric(entry,
ukm::builders::OptimizationGuide::
kPainfulPageLoadModelPredictionScoreName,
12);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsModelPredictionScoreOptimizationTargetHasNoCorrespondingUkm) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetModelPredictionScoreForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_UNKNOWN, 0.123);
data.RecordMetrics(/*has_committed=*/false);
// Make sure UKM not recorded for all empty values.
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_TRUE(entries.empty());
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageHasHintBeforeCommitNoFetch) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(true);
data.RecordMetrics(/*has_committed=*/false);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(
optimization_guide::NavigationHostCoveredStatus::kCovered));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageHasHintAfterCommitNoFetch) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_after_commit(true);
data.RecordMetrics(/*has_committed=*/true);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(
optimization_guide::NavigationHostCoveredStatus::kCovered));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageNoHintHasFetchBeforeCommit) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(false);
data.set_was_host_covered_by_fetch_at_navigation_start(true);
data.RecordMetrics(/*has_committed=*/false);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(
optimization_guide::NavigationHostCoveredStatus::kCovered));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageNoHintHasFetchAtCommit) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_after_commit(false);
data.set_was_host_covered_by_fetch_at_commit(true);
data.RecordMetrics(/*has_committed=*/true);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(
optimization_guide::NavigationHostCoveredStatus::kCovered));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageNoHintOrFetchBeforeCommitAndNoFetchAttempted) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(false);
data.set_was_host_covered_by_fetch_at_navigation_start(false);
data.RecordMetrics(/*has_committed=*/true);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(
optimization_guide::NavigationHostCoveredStatus::kFetchNotAttempted));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageNoHintOrFetchAtCommitAndNoFetchAttempted) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_after_commit(false);
data.set_was_host_covered_by_fetch_at_commit(false);
data.RecordMetrics(/*has_committed=*/true);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(
optimization_guide::NavigationHostCoveredStatus::kFetchNotAttempted));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageNoHintOrFetchBeforeCommitButFetchAttempted) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_before_commit(false);
data.set_was_host_covered_by_fetch_at_navigation_start(false);
data.set_was_hint_for_host_attempted_to_be_fetched(true);
data.RecordMetrics(/*has_committed=*/true);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(optimization_guide::NavigationHostCoveredStatus::
kFetchNotSuccessful));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsHintCoverageNoHintOrFetchAtCommitButFetchAttempted) {
base::test::TaskEnvironment env;
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.set_has_hint_after_commit(false);
data.set_was_host_covered_by_fetch_at_commit(false);
data.set_was_hint_for_host_attempted_to_be_fetched(true);
data.RecordMetrics(/*has_committed=*/true);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName));
ukm_recorder.ExpectEntryMetric(
entry, ukm::builders::OptimizationGuide::kNavigationHostCoveredName,
static_cast<int>(optimization_guide::NavigationHostCoveredStatus::
kFetchNotSuccessful));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsMultipleOptimizationTypes) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetDecisionForOptimizationType(
optimization_guide::proto::NOSCRIPT,
optimization_guide::OptimizationTypeDecision::kAllowedByHint);
data.SetDecisionForOptimizationType(
optimization_guide::proto::DEFER_ALL_SCRIPT,
optimization_guide::OptimizationTypeDecision::
kAllowedByOptimizationFilter);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.NoScript",
static_cast<int>(
optimization_guide::OptimizationTypeDecision::kAllowedByHint),
1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.DeferAllScript",
static_cast<int>(optimization_guide::OptimizationTypeDecision::
kAllowedByOptimizationFilter),
1);
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsRecordsLatestType) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetDecisionForOptimizationType(
optimization_guide::proto::NOSCRIPT,
optimization_guide::OptimizationTypeDecision::kAllowedByHint);
data.SetDecisionForOptimizationType(
optimization_guide::proto::NOSCRIPT,
optimization_guide::OptimizationTypeDecision::
kAllowedByOptimizationFilter);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ApplyDecision.NoScript",
static_cast<int>(optimization_guide::OptimizationTypeDecision::
kAllowedByOptimizationFilter),
1);
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsMultipleOptimizationTargets) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
optimization_guide::OptimizationTargetDecision::kPageLoadMatches);
data.SetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_UNKNOWN,
optimization_guide::OptimizationTargetDecision::kPageLoadDoesNotMatch);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.TargetDecision.PainfulPageLoad",
static_cast<int>(
optimization_guide::OptimizationTargetDecision::kPageLoadMatches),
1);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.TargetDecision.Unknown",
static_cast<int>(optimization_guide::OptimizationTargetDecision::
kPageLoadDoesNotMatch),
1);
}
TEST(OptimizationGuideNavigationDataTest, RecordMetricsRecordsLatestTarget) {
base::HistogramTester histogram_tester;
OptimizationGuideNavigationData data(/*navigation_id=*/3);
data.SetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
optimization_guide::OptimizationTargetDecision::kPageLoadDoesNotMatch);
data.SetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
optimization_guide::OptimizationTargetDecision::kPageLoadMatches);
data.RecordMetrics(/*has_committed=*/false);
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.TargetDecision.PainfulPageLoad",
static_cast<int>(
optimization_guide::OptimizationTargetDecision::kPageLoadMatches),
1);
}
TEST(OptimizationGuideNavigationDataTest, DeepCopy) {
std::unique_ptr<OptimizationGuideNavigationData> data =
std::make_unique<OptimizationGuideNavigationData>(/*navigation_id=*/3);
EXPECT_EQ(3, data->navigation_id());
EXPECT_EQ(base::nullopt, data->serialized_hint_version_string());
EXPECT_EQ(base::nullopt, data->GetDecisionForOptimizationType(
optimization_guide::proto::NOSCRIPT));
EXPECT_EQ(
base::nullopt,
data->GetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
EXPECT_EQ(base::nullopt, data->has_hint_before_commit());
EXPECT_EQ(base::nullopt, data->has_hint_after_commit());
EXPECT_EQ(base::nullopt,
data->was_host_covered_by_fetch_at_navigation_start());
EXPECT_EQ(base::nullopt, data->was_host_covered_by_fetch_at_commit());
EXPECT_EQ(base::nullopt, data->was_hint_for_host_attempted_to_be_fetched());
EXPECT_FALSE(data->has_page_hint_value());
EXPECT_EQ(
base::nullopt,
data->GetModelVersionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
EXPECT_EQ(
base::nullopt,
data->GetModelPredictionScoreForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
data->set_serialized_hint_version_string("123abc");
data->SetDecisionForOptimizationType(
optimization_guide::proto::NOSCRIPT,
optimization_guide::OptimizationTypeDecision::kAllowedByHint);
data->SetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
optimization_guide::OptimizationTargetDecision::kPageLoadMatches);
data->set_serialized_hint_version_string("123abc");
data->set_has_hint_before_commit(true);
data->set_has_hint_after_commit(true);
data->set_was_host_covered_by_fetch_at_navigation_start(true);
data->set_was_host_covered_by_fetch_at_commit(true);
data->set_was_hint_for_host_attempted_to_be_fetched(true);
optimization_guide::proto::PageHint page_hint;
page_hint.set_page_pattern("pagepattern");
data->set_page_hint(
std::make_unique<optimization_guide::proto::PageHint>(page_hint));
data->SetModelVersionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, 123);
data->SetModelPredictionScoreForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, 0.12);
OptimizationGuideNavigationData data_copy(*data);
EXPECT_EQ(3, data_copy.navigation_id());
EXPECT_EQ(optimization_guide::OptimizationTypeDecision::kAllowedByHint,
*data_copy.GetDecisionForOptimizationType(
optimization_guide::proto::NOSCRIPT));
EXPECT_EQ(
optimization_guide::OptimizationTargetDecision::kPageLoadMatches,
*data_copy.GetDecisionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
EXPECT_TRUE(data_copy.has_hint_before_commit().value());
EXPECT_TRUE(data_copy.has_hint_after_commit().value());
EXPECT_TRUE(
data_copy.was_host_covered_by_fetch_at_navigation_start().value());
EXPECT_TRUE(data_copy.was_host_covered_by_fetch_at_commit().value());
EXPECT_TRUE(data_copy.was_hint_for_host_attempted_to_be_fetched().value());
EXPECT_EQ("123abc", *(data_copy.serialized_hint_version_string()));
EXPECT_TRUE(data_copy.has_page_hint_value());
EXPECT_EQ("pagepattern", data_copy.page_hint()->page_pattern());
EXPECT_EQ(
123,
*data_copy.GetModelVersionForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
EXPECT_EQ(
0.12,
*data_copy.GetModelPredictionScoreForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
}
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsPredictionModelHostModelFeatures) {
base::test::TaskEnvironment env;
ClientHostModelFeaturesTestCase test_cases[] = {
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_MEAN,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureNavigationToFCPSessionMeanName,
2.0, 2},
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_STANDARD_DEVIATION,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureNavigationToFCPSessionStdDevName,
3.0, 3},
{optimization_guide::proto::CLIENT_MODEL_FEATURE_PAGE_TRANSITION,
ukm::builders::OptimizationGuide::
kPredictionModelFeaturePageTransitionName,
20.0, 20},
{optimization_guide::proto::CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureIsSameOriginNavigationName,
1.0, 1},
{optimization_guide::proto::CLIENT_MODEL_FEATURE_SITE_ENGAGEMENT_SCORE,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureSiteEngagementScoreName,
5.5, 10},
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureEffectiveConnectionTypeName,
3.0, 3},
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_PREVIOUS_PAGE_LOAD,
ukm::builders::OptimizationGuide::
kPredictionModelFeaturePreviousPageLoadNavigationToFCPName,
200.0, 200},
};
for (const auto& test_case : test_cases) {
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/1);
data.SetValueForModelFeature(test_case.feature, test_case.feature_value);
data.RecordMetrics(/*has_committed=*/false);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(entry, test_case.ukm_metric_name));
ukm_recorder.ExpectEntryMetric(entry, test_case.ukm_metric_name,
test_case.expected_value);
}
}