blob: 80027f230359f563f372e25406f148d295c938c0 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/base/web_feature_histogram_tester.h"
#include <utility>
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace {
using blink::mojom::WebFeature;
using testing::_;
using testing::Each;
using testing::Ge;
using testing::Pair;
constexpr char kFeatureHistogramName[] = "Blink.UseCounter.Features";
void FetchCounts() {
content::FetchHistogramsFromChildProcesses();
metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
}
// Returns the list of keys in the given map.
std::vector<WebFeature> Keys(const std::map<WebFeature, int>& counts) {
std::vector<WebFeature> keys;
for (const auto& entry : counts) {
keys.push_back(entry.first);
}
return keys;
}
bool AllCountsAreLessThanOrEqual(const std::map<WebFeature, int>& lhs,
const std::map<WebFeature, int>& rhs) {
// Prints both sets of keys in case of mismatch, for debugging.
EXPECT_EQ(Keys(lhs), Keys(rhs));
for (const auto& entry : lhs) {
WebFeature feature = entry.first;
int lhs_count = entry.second;
const auto it = rhs.find(feature);
if (it == rhs.end()) {
return false;
}
int rhs_count = it->second;
if (lhs_count > rhs_count) {
return false;
}
}
return true;
}
} // namespace
std::map<WebFeature, int> AllZeroFeatureCounts(
const std::vector<WebFeature>& features) {
std::map<WebFeature, int> result;
for (WebFeature feature : features) {
result.emplace(feature, 0);
}
return result;
}
std::map<WebFeature, int> AddFeatureCounts(
const std::map<WebFeature, int>& lhs,
const std::map<WebFeature, int>& rhs) {
std::map<WebFeature, int> result = lhs;
for (const auto& entry : rhs) {
result[entry.first] += entry.second;
}
return result;
}
WebFeatureHistogramTester::WebFeatureHistogramTester() = default;
WebFeatureHistogramTester::~WebFeatureHistogramTester() = default;
int WebFeatureHistogramTester::GetCountInternal(WebFeature feature) const {
return histogram_tester_.GetBucketCount(kFeatureHistogramName, feature);
}
int WebFeatureHistogramTester::GetCount(WebFeature feature) const {
FetchCounts();
return GetCountInternal(feature);
}
std::map<WebFeature, int> WebFeatureHistogramTester::GetCounts(
const std::vector<WebFeature>& features) const {
FetchCounts();
return GetCountsInternal(features, true);
}
std::map<WebFeature, int> WebFeatureHistogramTester::GetNonZeroCounts(
const std::vector<WebFeature>& features) const {
FetchCounts();
return GetCountsInternal(features, false);
}
std::map<WebFeature, int> WebFeatureHistogramTester::GetCountsInternal(
const std::vector<WebFeature>& features,
bool include_zeroes) const {
std::map<WebFeature, int> counts;
for (WebFeature feature : features) {
int count = GetCountInternal(feature);
if (count == 0 && !include_zeroes) {
continue;
}
counts.emplace(feature, count);
}
return counts;
}
std::map<WebFeature, int> WebFeatureHistogramTester::WaitForCountsAtLeast(
const std::map<WebFeature, int>& expected) const {
EXPECT_THAT(expected, Each(Pair(_, Ge(0))))
<< "All counts must be non-negative.";
std::vector<WebFeature> features = Keys(expected);
std::map<WebFeature, int> counts;
while (true) {
counts = GetCounts(features);
if (!AllCountsAreLessThanOrEqual(counts, expected) || counts == expected) {
break;
}
base::PlatformThread::Sleep(base::Milliseconds(5));
}
return expected;
}
void WebFeatureHistogramTester::ExpectCounts(
const std::map<WebFeature, int>& expected) const {
EXPECT_EQ(WaitForCountsAtLeast(expected), expected);
}