1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/single_sample_metrics_factory_impl.h"
6
7 #include "base/functional/bind.h"
8 #include "base/memory/raw_ptr.h"
9 #include "base/metrics/dummy_histogram.h"
10 #include "base/run_loop.h"
11 #include "base/test/gtest_util.h"
12 #include "base/test/metrics/histogram_tester.h"
13 #include "base/test/task_environment.h"
14 #include "base/threading/thread.h"
15 #include "components/metrics/single_sample_metrics.h"
16 #include "mojo/public/cpp/bindings/pending_receiver.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace metrics {
20
21 namespace {
22
23 const base::HistogramBase::Sample kMin = 1;
24 const base::HistogramBase::Sample kMax = 10;
25 const uint32_t kBucketCount = 10;
26 const char kMetricName[] = "Single.Sample.Metric";
27
28 class SingleSampleMetricsFactoryImplTest : public testing::Test {
29 public:
SingleSampleMetricsFactoryImplTest()30 SingleSampleMetricsFactoryImplTest() : thread_("TestThread") {
31 InitializeSingleSampleMetricsFactory(
32 base::BindRepeating(&SingleSampleMetricsFactoryImplTest::CreateProvider,
33 base::Unretained(this)));
34 factory_ = static_cast<SingleSampleMetricsFactoryImpl*>(
35 base::SingleSampleMetricsFactory::Get());
36 }
37
38 SingleSampleMetricsFactoryImplTest(
39 const SingleSampleMetricsFactoryImplTest&) = delete;
40 SingleSampleMetricsFactoryImplTest& operator=(
41 const SingleSampleMetricsFactoryImplTest&) = delete;
42
~SingleSampleMetricsFactoryImplTest()43 ~SingleSampleMetricsFactoryImplTest() override {
44 factory_->DestroyProviderForTesting();
45 factory_ = nullptr;
46 if (thread_.IsRunning())
47 ShutdownThread();
48 base::SingleSampleMetricsFactory::DeleteFactoryForTesting();
49 }
50
51 protected:
StartThread()52 void StartThread() { ASSERT_TRUE(thread_.Start()); }
53
ShutdownThread()54 void ShutdownThread() {
55 thread_.task_runner()->PostTask(
56 FROM_HERE,
57 base::BindOnce(
58 &SingleSampleMetricsFactoryImpl::DestroyProviderForTesting,
59 base::Unretained(factory_)));
60 thread_.Stop();
61 }
62
CreateProvider(mojo::PendingReceiver<mojom::SingleSampleMetricsProvider> receiver)63 void CreateProvider(
64 mojo::PendingReceiver<mojom::SingleSampleMetricsProvider> receiver) {
65 CreateSingleSampleMetricsProvider(std::move(receiver));
66 provider_count_++;
67 }
68
CreateMetricOnThread()69 std::unique_ptr<base::SingleSampleMetric> CreateMetricOnThread() {
70 std::unique_ptr<base::SingleSampleMetric> metric;
71 base::RunLoop run_loop;
72 thread_.task_runner()->PostTaskAndReply(
73 FROM_HERE,
74 base::BindOnce(
75 &SingleSampleMetricsFactoryImplTest::CreateAndStoreMetric,
76 base::Unretained(this), &metric),
77 run_loop.QuitClosure());
78 run_loop.Run();
79 return metric;
80 }
81
CreateAndStoreMetric(std::unique_ptr<base::SingleSampleMetric> * metric)82 void CreateAndStoreMetric(std::unique_ptr<base::SingleSampleMetric>* metric) {
83 *metric = factory_->CreateCustomCountsMetric(kMetricName, kMin, kMax,
84 kBucketCount);
85 }
86
87 base::test::SingleThreadTaskEnvironment task_environment_;
88 raw_ptr<SingleSampleMetricsFactoryImpl> factory_;
89 base::Thread thread_;
90 size_t provider_count_ = 0;
91 };
92
93 } // namespace
94
TEST_F(SingleSampleMetricsFactoryImplTest,SingleProvider)95 TEST_F(SingleSampleMetricsFactoryImplTest, SingleProvider) {
96 std::unique_ptr<base::SingleSampleMetric> metric1 =
97 factory_->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount);
98
99 std::unique_ptr<base::SingleSampleMetric> metric2 =
100 factory_->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount);
101
102 // Verify that only a single provider is created for multiple metrics.
103 base::RunLoop().RunUntilIdle();
104 EXPECT_EQ(1u, provider_count_);
105 }
106
TEST_F(SingleSampleMetricsFactoryImplTest,DoesNothing)107 TEST_F(SingleSampleMetricsFactoryImplTest, DoesNothing) {
108 base::HistogramTester tester;
109
110 std::unique_ptr<base::SingleSampleMetric> metric =
111 factory_->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount);
112 metric.reset();
113
114 // Verify that no sample is recorded if SetSample() is never called.
115 base::RunLoop().RunUntilIdle();
116 tester.ExpectTotalCount(kMetricName, 0);
117 }
118
TEST_F(SingleSampleMetricsFactoryImplTest,DefaultSingleSampleMetricWithValue)119 TEST_F(SingleSampleMetricsFactoryImplTest, DefaultSingleSampleMetricWithValue) {
120 base::HistogramTester tester;
121 std::unique_ptr<base::SingleSampleMetric> metric =
122 factory_->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount);
123
124 const base::HistogramBase::Sample kLastSample = 9;
125 metric->SetSample(1);
126 metric->SetSample(3);
127 metric->SetSample(5);
128 metric->SetSample(kLastSample);
129 metric.reset();
130
131 // Verify only the last sample sent to SetSample() is recorded.
132 base::RunLoop().RunUntilIdle();
133 tester.ExpectUniqueSample(kMetricName, kLastSample, 1);
134
135 // Verify construction implicitly by requesting a histogram with the same
136 // parameters; this test relies on the fact that histogram objects are unique
137 // per name. Different parameters will result in a Dummy histogram returned.
138 EXPECT_EQ(base::DummyHistogram::GetInstance(),
139 base::Histogram::FactoryGet(kMetricName, 1, 3, 3,
140 base::HistogramBase::kNoFlags));
141 EXPECT_NE(base::DummyHistogram::GetInstance(),
142 base::Histogram::FactoryGet(
143 kMetricName, kMin, kMax, kBucketCount,
144 base::HistogramBase::kUmaTargetedHistogramFlag));
145 }
146
TEST_F(SingleSampleMetricsFactoryImplTest,MultithreadedMetrics)147 TEST_F(SingleSampleMetricsFactoryImplTest, MultithreadedMetrics) {
148 // Allow EXPECT_DCHECK_DEATH for multiple threads.
149 // https://github.com/google/googletest/blob/main/docs/advanced.md#death-tests-and-threads
150 testing::FLAGS_gtest_death_test_style = "threadsafe";
151
152 base::HistogramTester tester;
153 std::unique_ptr<base::SingleSampleMetric> metric =
154 factory_->CreateCustomCountsMetric(kMetricName, kMin, kMax, kBucketCount);
155 EXPECT_EQ(1u, provider_count_);
156
157 StartThread();
158
159 std::unique_ptr<base::SingleSampleMetric> threaded_metric =
160 CreateMetricOnThread();
161 ASSERT_TRUE(threaded_metric);
162
163 // A second provider should be created to handle requests on our new thread.
164 EXPECT_EQ(2u, provider_count_);
165
166 // Calls from the wrong thread should DCHECK.
167 EXPECT_DCHECK_DEATH(threaded_metric->SetSample(5));
168 EXPECT_DCHECK_DEATH(threaded_metric.reset());
169
170 // Test that samples are set on each thread correctly.
171 const base::HistogramBase::Sample kSample = 7;
172
173 {
174 metric->SetSample(kSample);
175
176 base::RunLoop run_loop;
177 thread_.task_runner()->PostTaskAndReply(
178 FROM_HERE,
179 base::BindOnce(&base::SingleSampleMetric::SetSample,
180 base::Unretained(threaded_metric.get()), kSample),
181 run_loop.QuitClosure());
182 run_loop.Run();
183 }
184
185 // Release metrics and shutdown thread to ensure destruction completes.
186 thread_.task_runner()->DeleteSoon(FROM_HERE, threaded_metric.release());
187 ShutdownThread();
188
189 metric.reset();
190 base::RunLoop().RunUntilIdle();
191
192 tester.ExpectUniqueSample(kMetricName, kSample, 2);
193 }
194
195 } // namespace metrics
196