Commit 8d67b4f2 authored by Bryan McQuade's avatar Bryan McQuade Committed by Commit Bot

[page load metrics] Generalize UKM test infrastructure.

We're in the process of adding new PLMObservers that log UKM
metrics, so need to generalize our UKM test infra.

This change introduces the UkmTester test harness class, which
makes it easier to test logging of UKM metrics, and updates the
UKM observer to use this new class.

Other PLMObservers that will use this test infra can be seen
in https://codereview.chromium.org/2924673004

Bug: 738921
Change-Id: I84d61aca66453bcaca21f003f5e5dbfd9b6ac51c
Reviewed-on: https://chromium-review.googlesource.com/558945
Commit-Queue: Bryan McQuade <bmcquade@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#484796}
parent be8dfafe
......@@ -6,11 +6,13 @@
#include <memory>
#include <string>
#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
......@@ -52,12 +54,13 @@ class TestPageLoadMetricsEmbedderInterface
} // namespace
PageLoadMetricsObserverTestHarness::PageLoadMetricsObserverTestHarness()
: ChromeRenderViewHostTestHarness() {}
: ChromeRenderViewHostTestHarness(), ukm_tester_(&test_ukm_recorder_) {}
PageLoadMetricsObserverTestHarness::~PageLoadMetricsObserverTestHarness() {}
void PageLoadMetricsObserverTestHarness::SetUp() {
ChromeRenderViewHostTestHarness::SetUp();
TestingBrowserProcess::GetGlobal()->SetUkmRecorder(&test_ukm_recorder_);
SetContents(CreateTestWebContents());
NavigateAndCommit(GURL("http://www.google.com"));
observer_ = MetricsWebContentsObserver::CreateForWebContents(
......
......@@ -9,10 +9,12 @@
#include "base/test/histogram_tester.h"
#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
#include "chrome/browser/page_load_metrics/page_load_tracker.h"
#include "chrome/browser/page_load_metrics/test/ukm_tester.h"
#include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h"
#include "chrome/common/page_load_metrics/test/weak_mock_timer.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/test/web_contents_tester.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
......@@ -86,8 +88,14 @@ class PageLoadMetricsObserverTestHarness
// Gets the PageLoadExtraInfo for the committed_load_ in observer_.
const PageLoadExtraInfo GetPageLoadExtraInfoForCommittedLoad();
const page_load_metrics::test::UkmTester& ukm_tester() const {
return ukm_tester_;
}
private:
base::HistogramTester histogram_tester_;
ukm::TestUkmRecorder test_ukm_recorder_;
page_load_metrics::test::UkmTester ukm_tester_;
MetricsWebContentsObserver* observer_;
DISALLOW_COPY_AND_ASSIGN(PageLoadMetricsObserverTestHarness);
......
// Copyright 2017 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/page_load_metrics/test/ukm_tester.h"
#include <algorithm>
#include <iterator>
#include "base/metrics/metrics_hashes.h"
#include "components/ukm/ukm_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Provides a single merged ukm::mojom::UkmEntry 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::mojom::UkmEntryPtr GetMergedEntry(
const std::vector<const ukm::mojom::UkmEntry*>& entries) {
EXPECT_FALSE(entries.empty());
ukm::mojom::UkmEntryPtr merged_entry = ukm::mojom::UkmEntry::New();
for (const auto* entry : entries) {
if (merged_entry->event_hash) {
EXPECT_EQ(merged_entry->source_id, entry->source_id);
EXPECT_EQ(merged_entry->event_hash, entry->event_hash);
} else {
merged_entry->event_hash = entry->event_hash;
merged_entry->source_id = entry->source_id;
}
for (const auto& metric : entry->metrics) {
merged_entry->metrics.emplace_back(metric->Clone());
}
}
return merged_entry;
}
std::vector<int64_t> GetValuesForMetric(const ukm::mojom::UkmEntry* entry,
const char* metric_name) {
std::vector<int64_t> values;
const uint64_t metric_hash = base::HashMetricName(metric_name);
for (const auto& metric : entry->metrics) {
if (metric->metric_hash == metric_hash)
values.push_back(metric->value);
}
return values;
}
} // namespace
namespace page_load_metrics {
namespace test {
UkmTester::UkmTester(ukm::TestUkmRecorder* test_ukm_recorder)
: test_ukm_recorder_(test_ukm_recorder) {}
const ukm::UkmSource* UkmTester::GetSourceForUrl(const char* url) const {
std::vector<const ukm::UkmSource*> matching_sources = GetSourcesForUrl(url);
EXPECT_LE(1ul, matching_sources.size());
return matching_sources.empty() ? nullptr : matching_sources.back();
}
std::vector<const ukm::UkmSource*> UkmTester::GetSourcesForUrl(
const char* url) const {
std::vector<const ukm::UkmSource*> matching_sources;
for (const auto& candidate : test_ukm_recorder_->GetSources()) {
if (candidate.second->url() == url)
matching_sources.push_back(candidate.second.get());
}
return matching_sources;
}
std::vector<const ukm::mojom::UkmEntry*> UkmTester::GetEntriesForSourceID(
ukm::SourceId source_id,
const char* event_name) const {
const uint64_t event_hash = base::HashMetricName(event_name);
std::vector<const ukm::mojom::UkmEntry*> entries;
for (size_t i = 0; i < entries_count(); ++i) {
const ukm::mojom::UkmEntry* entry = test_ukm_recorder_->GetEntry(i);
if (entry->source_id == source_id && entry->event_hash == event_hash) {
entries.push_back(entry);
}
}
return entries;
}
ukm::mojom::UkmEntryPtr UkmTester::GetMergedEntryForSourceID(
ukm::SourceId source_id,
const char* event_name) const {
ukm::mojom::UkmEntryPtr entry =
GetMergedEntry(GetEntriesForSourceID(source_id, event_name));
EXPECT_EQ(source_id, entry->source_id);
EXPECT_EQ(base::HashMetricName(event_name), entry->event_hash);
return entry;
}
bool UkmTester::HasEntry(const ukm::UkmSource& source,
const char* event_name) const {
return CountEntries(source, event_name) > 0;
}
int UkmTester::CountEntries(const ukm::UkmSource& source,
const char* event_name) const {
return GetEntriesForSourceID(source.id(), event_name).size();
}
void UkmTester::ExpectEntry(const ukm::UkmSource& source,
const char* event_name,
const std::vector<std::pair<const char*, int64_t>>&
expected_metrics) const {
// Produce a sorted view of the expected metrics, since order is not
// significant.
std::vector<std::pair<uint64_t, int64_t>> sorted_expected_metrics;
std::transform(expected_metrics.begin(), expected_metrics.end(),
std::back_inserter(sorted_expected_metrics),
[](const std::pair<const char*, int64_t>& metric) {
return std::make_pair(base::HashMetricName(metric.first),
metric.second);
});
std::sort(sorted_expected_metrics.begin(), sorted_expected_metrics.end());
std::vector<const ukm::mojom::UkmEntry*> candidate_entries =
GetEntriesForSourceID(source.id(), event_name);
// Produce a view of each matching entry's metrics that can be compared with
// sorted_expected_metrics.
std::vector<std::vector<std::pair<uint64_t, int64_t>>> candidate_metrics;
std::transform(candidate_entries.begin(), candidate_entries.end(),
std::back_inserter(candidate_metrics),
[](const ukm::mojom::UkmEntry* candidate_entry) {
std::vector<std::pair<uint64_t, int64_t>> metrics;
std::transform(candidate_entry->metrics.begin(),
candidate_entry->metrics.end(),
std::back_inserter(metrics),
[](const ukm::mojom::UkmMetricPtr& metric) {
return std::make_pair(metric->metric_hash,
metric->value);
});
std::sort(metrics.begin(), metrics.end());
return metrics;
});
if (std::find(candidate_metrics.begin(), candidate_metrics.end(),
sorted_expected_metrics) == candidate_metrics.end()) {
FAIL() << "Failed to find metrics for event: " << event_name;
}
}
int UkmTester::CountMetricsForEventName(const ukm::UkmSource& source,
const char* event_name) const {
ukm::mojom::UkmEntryPtr entry =
GetMergedEntryForSourceID(source.id(), event_name);
return entry.get() ? entry->metrics.size() : 0;
}
bool UkmTester::HasMetric(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name) const {
return CountMetrics(source, event_name, metric_name) > 0;
}
int UkmTester::CountMetrics(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name) const {
ukm::mojom::UkmEntryPtr entry =
GetMergedEntryForSourceID(source.id(), event_name);
return GetValuesForMetric(entry.get(), metric_name).size();
}
void UkmTester::ExpectMetric(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name,
int64_t expected_value) const {
ExpectMetrics(source, event_name, metric_name, {expected_value});
}
void UkmTester::ExpectMetrics(
const ukm::UkmSource& source,
const char* event_name,
const char* metric_name,
const std::vector<int64_t>& expected_values) const {
ukm::mojom::UkmEntryPtr entry =
GetMergedEntryForSourceID(source.id(), event_name);
// Make sure both vectors are sorted before comparing, since order is not
// significant.
std::vector<int64_t> sorted_expected_values(expected_values);
std::sort(sorted_expected_values.begin(), sorted_expected_values.end());
std::vector<int64_t> actual_values =
GetValuesForMetric(entry.get(), metric_name);
std::sort(actual_values.begin(), actual_values.end());
EXPECT_EQ(actual_values, sorted_expected_values)
<< "Failed to find expected_values for metric: " << metric_name;
}
} // namespace test
} // namespace page_load_metrics
// Copyright 2017 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.
#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_TEST_UKM_TESTER_H_
#define CHROME_BROWSER_PAGE_LOAD_METRICS_TEST_UKM_TESTER_H_
#include <utility>
#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "components/ukm/test_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
namespace ukm {
class UkmSource;
} // namespace ukm
namespace page_load_metrics {
namespace test {
// UkmTester provides utilities for testing the logging of UKM sources, events,
// and metrics.
class UkmTester {
public:
explicit UkmTester(ukm::TestUkmRecorder* test_ukm_recorder);
// Number of UKM sources recorded.
size_t sources_count() const { return test_ukm_recorder_->sources_count(); }
// Number of UKM entries recorded.
size_t entries_count() const { return test_ukm_recorder_->entries_count(); }
const ukm::UkmSource* GetSourceForUrl(const char* url) const;
std::vector<const ukm::UkmSource*> GetSourcesForUrl(const char* url) const;
// Returns whether the given UKM |source| has an entry with the given
// |event_name|.
bool HasEntry(const ukm::UkmSource& source,
const char* event_name) const WARN_UNUSED_RESULT;
// Returns the number of metrics recorded for the given UKM |source| and
// |event_name|.
int CountMetricsForEventName(const ukm::UkmSource& source,
const char* event_name) const;
// Returns whether a metric with the given |metric_name| was recorded for the
// given UKM |source| and |event_name|.
bool HasMetric(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name) const WARN_UNUSED_RESULT;
// Returns the number of metrics recorded with the given |metric_name|, for
// the given UKM |source| and |event_name|.
int CountMetrics(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name) const WARN_UNUSED_RESULT;
// Expects that a single metric was recorded with the given |expected_value|,
// for the given |source| and |event_name|. This is shorthand for calling
// ExpectMetrics with a single value in the expected values vector.
void ExpectMetric(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name,
int64_t expected_value) const;
// Expects that metrics were recorded with the given |expected_values|, for
// the given |source| and |event_name|. The order of |expected_values| is not
// significant.
void ExpectMetrics(const ukm::UkmSource& source,
const char* event_name,
const char* metric_name,
const std::vector<int64_t>& expected_values) const;
// UKM entries that may be recorded multiple times for a single source may
// need to verify that an expected number of UKM entries were logged. The
// utility methods below can be used to verify expected entries. UKM entries
// that aren't recorded multiple times per source should prefer using
// HasMetric/CountMetrics/ExpectMetric(s) above.
// Returns the number of entries recorded with the given |event_name|, for the
// given UKM |source|.
int CountEntries(const ukm::UkmSource& source, const char* event_name) const;
// Expects that an entry with the given |expected_metrics| was recorded, for
// the given |source| and |event_name|. The order of |expected_metrics| is not
// significant. |expected_metrics| contains (metric name,metric value) pairs.
void ExpectEntry(const ukm::UkmSource& source,
const char* event_name,
const std::vector<std::pair<const char*, int64_t>>&
expected_metrics) const;
private:
ukm::mojom::UkmEntryPtr GetMergedEntryForSourceID(
ukm::SourceId source_id,
const char* event_name) const;
std::vector<const ukm::mojom::UkmEntry*> GetEntriesForSourceID(
ukm::SourceId source_id,
const char* event_name) const;
const ukm::TestUkmRecorder* test_ukm_recorder_;
DISALLOW_COPY_AND_ASSIGN(UkmTester);
};
} // namespace test
} // namespace page_load_metrics
#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_TEST_UKM_TESTER_H_
......@@ -3201,6 +3201,8 @@ test("unit_tests") {
"../browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc",
"../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
"../browser/page_load_metrics/page_load_metrics_util_unittest.cc",
"../browser/page_load_metrics/test/ukm_tester.cc",
"../browser/page_load_metrics/test/ukm_tester.h",
"../browser/page_load_metrics/user_input_tracker_unittest.cc",
"../browser/password_manager/chrome_password_manager_client_unittest.cc",
"../browser/password_manager/password_manager_internals_service_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment