Index: chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc |
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc |
index 7f0a754e75bfe0e47230aa7fc4978e1854b70d6e..e5bf87d86105f263d3d4c366d057e3f0fa5365d6 100644 |
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc |
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc |
@@ -51,9 +51,49 @@ class UkmPageLoadMetricsObserverTest |
return ukm_service_test_harness_.test_ukm_service()->GetEntry(entry_index); |
} |
+ std::vector<const ukm::UkmEntry*> GetUkmEntriesForSourceID( |
+ int32_t source_id) { |
+ std::vector<const ukm::UkmEntry*> entries; |
+ for (size_t i = 0; i < ukm_entry_count(); ++i) { |
+ const ukm::UkmEntry* entry = GetUkmEntry(i); |
+ if (entry->source_id() == source_id) |
+ entries.push_back(entry); |
+ } |
+ return entries; |
+ } |
+ |
+ // Provides a single merged ukm::Entry proto that contains all metrics from |
+ // the given |entries|. |entries| must be non-empty, and all |entries| must |
+ // have the same |source_id| and |event_hash|. |
+ ukm::Entry GetMergedEntryProto( |
+ const std::vector<const ukm::UkmEntry*>& entries) { |
+ EXPECT_FALSE(entries.empty()); |
+ ukm::Entry merged_entry; |
+ for (auto* entry : entries) { |
+ ukm::Entry entry_proto; |
+ entry->PopulateProto(&entry_proto); |
+ EXPECT_TRUE(entry_proto.has_source_id()); |
+ EXPECT_TRUE(entry_proto.has_event_hash()); |
+ if (merged_entry.has_source_id()) { |
+ EXPECT_EQ(merged_entry.source_id(), entry_proto.source_id()); |
+ EXPECT_EQ(merged_entry.event_hash(), entry_proto.event_hash()); |
+ } |
+ merged_entry.MergeFrom(entry_proto); |
+ } |
+ return merged_entry; |
+ } |
+ |
+ ukm::Entry GetMergedEntryProtoForSourceID(int32_t source_id) { |
+ ukm::Entry entry = GetMergedEntryProto(GetUkmEntriesForSourceID(source_id)); |
+ EXPECT_EQ(source_id, entry.source_id()); |
+ EXPECT_TRUE(entry.has_event_hash()); |
+ return entry; |
+ } |
+ |
static const ukm::Entry_Metric* FindMetric( |
const char* name, |
- const google::protobuf::RepeatedPtrField<ukm::Entry_Metric>& metrics) { |
+ const google::protobuf::RepeatedPtrField<ukm::Entry_Metric>& metrics) |
+ WARN_UNUSED_RESULT { |
for (const auto& metric : metrics) { |
if (metric.metric_hash() == base::HashMetricName(name)) |
return &metric; |
@@ -63,7 +103,8 @@ class UkmPageLoadMetricsObserverTest |
static bool HasMetric( |
const char* name, |
- const google::protobuf::RepeatedPtrField<ukm::Entry_Metric>& metrics) { |
+ const google::protobuf::RepeatedPtrField<ukm::Entry_Metric>& metrics) |
+ WARN_UNUSED_RESULT { |
return FindMetric(name, metrics) != nullptr; |
} |
@@ -85,10 +126,18 @@ TEST_F(UkmPageLoadMetricsObserverTest, NoMetrics) { |
EXPECT_EQ(0ul, ukm_entry_count()); |
} |
-TEST_F(UkmPageLoadMetricsObserverTest, FirstContentfulPaint) { |
+TEST_F(UkmPageLoadMetricsObserverTest, Basic) { |
+ // PageLoadTiming with all recorded metrics other than FMP. This allows us to |
+ // verify both that all metrics are logged, and that we don't log metrics that |
+ // aren't present in the PageLoadTiming struct. Logging of FMP is verified in |
+ // the FirstMeaningfulPaint test below. |
page_load_metrics::PageLoadTiming timing; |
timing.navigation_start = base::Time::FromDoubleT(1); |
+ timing.parse_start = base::TimeDelta::FromMilliseconds(100); |
+ timing.dom_content_loaded_event_start = |
+ base::TimeDelta::FromMilliseconds(200); |
timing.first_contentful_paint = base::TimeDelta::FromMilliseconds(300); |
+ timing.load_event_start = base::TimeDelta::FromMilliseconds(500); |
PopulateRequiredTimingFields(&timing); |
NavigateAndCommit(GURL(kTestUrl1)); |
@@ -101,18 +150,49 @@ TEST_F(UkmPageLoadMetricsObserverTest, FirstContentfulPaint) { |
const ukm::UkmSource* source = GetUkmSource(0); |
EXPECT_EQ(GURL(kTestUrl1), source->url()); |
- EXPECT_EQ(1ul, ukm_entry_count()); |
- const ukm::UkmEntry* entry = GetUkmEntry(0); |
- EXPECT_EQ(entry->source_id(), source->id()); |
- |
- ukm::Entry entry_proto; |
- entry->PopulateProto(&entry_proto); |
+ EXPECT_GE(ukm_entry_count(), 1ul); |
+ ukm::Entry entry_proto = GetMergedEntryProtoForSourceID(source->id()); |
EXPECT_EQ(entry_proto.source_id(), source->id()); |
EXPECT_EQ(entry_proto.event_hash(), |
base::HashMetricName(internal::kUkmPageLoadEventName)); |
- EXPECT_GE(entry_proto.metrics_size(), 1); |
+ EXPECT_FALSE(entry_proto.metrics().empty()); |
+ ExpectMetric(internal::kUkmParseStartName, 100, entry_proto.metrics()); |
+ ExpectMetric(internal::kUkmDomContentLoadedName, 200, entry_proto.metrics()); |
ExpectMetric(internal::kUkmFirstContentfulPaintName, 300, |
entry_proto.metrics()); |
+ ExpectMetric(internal::kUkmLoadEventName, 500, entry_proto.metrics()); |
+ EXPECT_FALSE( |
+ HasMetric(internal::kUkmFirstMeaningfulPaintName, entry_proto.metrics())); |
+ EXPECT_TRUE( |
+ HasMetric(internal::kUkmForegroundDurationName, entry_proto.metrics())); |
+} |
+ |
+TEST_F(UkmPageLoadMetricsObserverTest, FirstMeaningfulPaint) { |
+ page_load_metrics::PageLoadTiming timing; |
+ timing.navigation_start = base::Time::FromDoubleT(1); |
+ timing.first_meaningful_paint = base::TimeDelta::FromMilliseconds(600); |
+ PopulateRequiredTimingFields(&timing); |
+ |
+ NavigateAndCommit(GURL(kTestUrl1)); |
+ SimulateTimingUpdate(timing); |
+ |
+ // Simulate closing the tab. |
+ DeleteContents(); |
+ |
+ EXPECT_EQ(1ul, ukm_source_count()); |
+ const ukm::UkmSource* source = GetUkmSource(0); |
+ EXPECT_EQ(GURL(kTestUrl1), source->url()); |
+ |
+ EXPECT_GE(ukm_entry_count(), 1ul); |
+ ukm::Entry entry_proto = GetMergedEntryProtoForSourceID(source->id()); |
+ EXPECT_EQ(entry_proto.source_id(), source->id()); |
+ EXPECT_EQ(entry_proto.event_hash(), |
+ base::HashMetricName(internal::kUkmPageLoadEventName)); |
+ EXPECT_FALSE(entry_proto.metrics().empty()); |
+ ExpectMetric(internal::kUkmFirstMeaningfulPaintName, 600, |
+ entry_proto.metrics()); |
+ EXPECT_TRUE( |
+ HasMetric(internal::kUkmForegroundDurationName, entry_proto.metrics())); |
} |
TEST_F(UkmPageLoadMetricsObserverTest, MultiplePageLoads) { |
@@ -124,7 +204,6 @@ TEST_F(UkmPageLoadMetricsObserverTest, MultiplePageLoads) { |
// Second navigation reports no timing metrics. |
page_load_metrics::PageLoadTiming timing2; |
timing2.navigation_start = base::Time::FromDoubleT(1); |
- timing2.first_contentful_paint = base::TimeDelta::FromMilliseconds(300); |
PopulateRequiredTimingFields(&timing2); |
NavigateAndCommit(GURL(kTestUrl1)); |
@@ -143,30 +222,31 @@ TEST_F(UkmPageLoadMetricsObserverTest, MultiplePageLoads) { |
EXPECT_EQ(GURL(kTestUrl2), source2->url()); |
EXPECT_NE(source1->id(), source2->id()); |
- EXPECT_EQ(2ul, ukm_entry_count()); |
- const ukm::UkmEntry* entry1 = GetUkmEntry(0); |
- const ukm::UkmEntry* entry2 = GetUkmEntry(1); |
- EXPECT_EQ(entry1->source_id(), source1->id()); |
- EXPECT_EQ(entry2->source_id(), source2->id()); |
- EXPECT_NE(entry1->source_id(), entry2->source_id()); |
- |
- ukm::Entry entry1_proto; |
- entry1->PopulateProto(&entry1_proto); |
- ukm::Entry entry2_proto; |
- entry2->PopulateProto(&entry2_proto); |
+ EXPECT_GE(ukm_entry_count(), 2ul); |
+ ukm::Entry entry1_proto = GetMergedEntryProtoForSourceID(source1->id()); |
+ ukm::Entry entry2_proto = GetMergedEntryProtoForSourceID(source2->id()); |
EXPECT_NE(entry1_proto.source_id(), entry2_proto.source_id()); |
EXPECT_EQ(entry1_proto.source_id(), source1->id()); |
EXPECT_EQ(entry1_proto.event_hash(), |
base::HashMetricName(internal::kUkmPageLoadEventName)); |
- EXPECT_GE(entry1_proto.metrics_size(), 1); |
+ EXPECT_FALSE(entry1_proto.metrics().empty()); |
ExpectMetric(internal::kUkmFirstContentfulPaintName, 200, |
entry1_proto.metrics()); |
+ EXPECT_FALSE(HasMetric(internal::kUkmFirstMeaningfulPaintName, |
+ entry2_proto.metrics())); |
+ EXPECT_TRUE( |
+ HasMetric(internal::kUkmForegroundDurationName, entry1_proto.metrics())); |
EXPECT_EQ(entry2_proto.source_id(), source2->id()); |
EXPECT_EQ(entry2_proto.event_hash(), |
base::HashMetricName(internal::kUkmPageLoadEventName)); |
- EXPECT_GE(entry2_proto.metrics_size(), 1); |
- ExpectMetric(internal::kUkmFirstContentfulPaintName, 300, |
- entry2_proto.metrics()); |
+ EXPECT_FALSE(entry2_proto.metrics().empty()); |
+ EXPECT_FALSE(HasMetric(internal::kUkmParseStartName, entry2_proto.metrics())); |
+ EXPECT_FALSE(HasMetric(internal::kUkmFirstContentfulPaintName, |
+ entry2_proto.metrics())); |
+ EXPECT_FALSE(HasMetric(internal::kUkmFirstMeaningfulPaintName, |
+ entry2_proto.metrics())); |
+ EXPECT_TRUE( |
+ HasMetric(internal::kUkmForegroundDurationName, entry2_proto.metrics())); |
} |