• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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