1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <stddef.h>
6 
7 #include <vector>
8 
9 #include "base/bind.h"
10 #include "base/json/json_reader.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/metrics/statistics_recorder.h"
15 #include "base/values.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace base {
19 
20 class StatisticsRecorderTest : public testing::Test {
21  protected:
SetUp()22   void SetUp() override {
23     // Each test will have a clean state (no Histogram / BucketRanges
24     // registered).
25     InitializeStatisticsRecorder();
26   }
27 
TearDown()28   void TearDown() override { UninitializeStatisticsRecorder(); }
29 
InitializeStatisticsRecorder()30   void InitializeStatisticsRecorder() {
31     statistics_recorder_ = new StatisticsRecorder();
32   }
33 
UninitializeStatisticsRecorder()34   void UninitializeStatisticsRecorder() {
35     delete statistics_recorder_;
36     statistics_recorder_ = NULL;
37   }
38 
CreateHistogram(const std::string & name,HistogramBase::Sample min,HistogramBase::Sample max,size_t bucket_count)39   Histogram* CreateHistogram(const std::string& name,
40                              HistogramBase::Sample min,
41                              HistogramBase::Sample max,
42                              size_t bucket_count) {
43     BucketRanges* ranges = new BucketRanges(bucket_count + 1);
44     Histogram::InitializeBucketRanges(min, max, ranges);
45     const BucketRanges* registered_ranges =
46         StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
47     return new Histogram(name, min, max, registered_ranges);
48   }
49 
DeleteHistogram(HistogramBase * histogram)50   void DeleteHistogram(HistogramBase* histogram) {
51     delete histogram;
52   }
53 
54   StatisticsRecorder* statistics_recorder_;
55 };
56 
TEST_F(StatisticsRecorderTest,NotInitialized)57 TEST_F(StatisticsRecorderTest, NotInitialized) {
58   UninitializeStatisticsRecorder();
59 
60   ASSERT_FALSE(StatisticsRecorder::IsActive());
61 
62   StatisticsRecorder::Histograms registered_histograms;
63   std::vector<const BucketRanges*> registered_ranges;
64 
65   StatisticsRecorder::GetHistograms(&registered_histograms);
66   EXPECT_EQ(0u, registered_histograms.size());
67 
68   Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
69 
70   // When StatisticsRecorder is not initialized, register is a noop.
71   EXPECT_EQ(histogram,
72             StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
73   // Manually delete histogram that was not registered.
74   DeleteHistogram(histogram);
75 
76   // RegisterOrDeleteDuplicateRanges is a no-op.
77   BucketRanges* ranges = new BucketRanges(3);
78   ranges->ResetChecksum();
79   EXPECT_EQ(ranges,
80             StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
81   StatisticsRecorder::GetBucketRanges(&registered_ranges);
82   EXPECT_EQ(0u, registered_ranges.size());
83 }
84 
TEST_F(StatisticsRecorderTest,RegisterBucketRanges)85 TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
86   std::vector<const BucketRanges*> registered_ranges;
87 
88   BucketRanges* ranges1 = new BucketRanges(3);
89   ranges1->ResetChecksum();
90   BucketRanges* ranges2 = new BucketRanges(4);
91   ranges2->ResetChecksum();
92 
93   // Register new ranges.
94   EXPECT_EQ(ranges1,
95             StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
96   EXPECT_EQ(ranges2,
97             StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2));
98   StatisticsRecorder::GetBucketRanges(&registered_ranges);
99   ASSERT_EQ(2u, registered_ranges.size());
100 
101   // Register some ranges again.
102   EXPECT_EQ(ranges1,
103             StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
104   registered_ranges.clear();
105   StatisticsRecorder::GetBucketRanges(&registered_ranges);
106   ASSERT_EQ(2u, registered_ranges.size());
107   // Make sure the ranges is still the one we know.
108   ASSERT_EQ(3u, ranges1->size());
109   EXPECT_EQ(0, ranges1->range(0));
110   EXPECT_EQ(0, ranges1->range(1));
111   EXPECT_EQ(0, ranges1->range(2));
112 
113   // Register ranges with same values.
114   BucketRanges* ranges3 = new BucketRanges(3);
115   ranges3->ResetChecksum();
116   EXPECT_EQ(ranges1,  // returning ranges1
117             StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
118   registered_ranges.clear();
119   StatisticsRecorder::GetBucketRanges(&registered_ranges);
120   ASSERT_EQ(2u, registered_ranges.size());
121 }
122 
TEST_F(StatisticsRecorderTest,RegisterHistogram)123 TEST_F(StatisticsRecorderTest, RegisterHistogram) {
124   // Create a Histogram that was not registered.
125   Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
126 
127   StatisticsRecorder::Histograms registered_histograms;
128   StatisticsRecorder::GetHistograms(&registered_histograms);
129   EXPECT_EQ(0u, registered_histograms.size());
130 
131   // Register the Histogram.
132   EXPECT_EQ(histogram,
133             StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
134   StatisticsRecorder::GetHistograms(&registered_histograms);
135   EXPECT_EQ(1u, registered_histograms.size());
136 
137   // Register the same Histogram again.
138   EXPECT_EQ(histogram,
139             StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
140   registered_histograms.clear();
141   StatisticsRecorder::GetHistograms(&registered_histograms);
142   EXPECT_EQ(1u, registered_histograms.size());
143 }
144 
TEST_F(StatisticsRecorderTest,FindHistogram)145 TEST_F(StatisticsRecorderTest, FindHistogram) {
146   HistogramBase* histogram1 = Histogram::FactoryGet(
147       "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags);
148   HistogramBase* histogram2 = Histogram::FactoryGet(
149       "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags);
150 
151   EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
152   EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
153   EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram") == NULL);
154 }
155 
TEST_F(StatisticsRecorderTest,GetSnapshot)156 TEST_F(StatisticsRecorderTest, GetSnapshot) {
157   Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
158   Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
159   Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
160 
161   StatisticsRecorder::Histograms snapshot;
162   StatisticsRecorder::GetSnapshot("Test", &snapshot);
163   EXPECT_EQ(3u, snapshot.size());
164 
165   snapshot.clear();
166   StatisticsRecorder::GetSnapshot("1", &snapshot);
167   EXPECT_EQ(1u, snapshot.size());
168 
169   snapshot.clear();
170   StatisticsRecorder::GetSnapshot("hello", &snapshot);
171   EXPECT_EQ(0u, snapshot.size());
172 }
173 
TEST_F(StatisticsRecorderTest,RegisterHistogramWithFactoryGet)174 TEST_F(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
175   StatisticsRecorder::Histograms registered_histograms;
176 
177   StatisticsRecorder::GetHistograms(&registered_histograms);
178   ASSERT_EQ(0u, registered_histograms.size());
179 
180   // Create a histogram.
181   HistogramBase* histogram = Histogram::FactoryGet(
182       "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
183   registered_histograms.clear();
184   StatisticsRecorder::GetHistograms(&registered_histograms);
185   EXPECT_EQ(1u, registered_histograms.size());
186 
187   // Get an existing histogram.
188   HistogramBase* histogram2 = Histogram::FactoryGet(
189       "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
190   registered_histograms.clear();
191   StatisticsRecorder::GetHistograms(&registered_histograms);
192   EXPECT_EQ(1u, registered_histograms.size());
193   EXPECT_EQ(histogram, histogram2);
194 
195   // Create a LinearHistogram.
196   histogram = LinearHistogram::FactoryGet(
197       "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
198   registered_histograms.clear();
199   StatisticsRecorder::GetHistograms(&registered_histograms);
200   EXPECT_EQ(2u, registered_histograms.size());
201 
202   // Create a BooleanHistogram.
203   histogram = BooleanHistogram::FactoryGet(
204       "TestBooleanHistogram", HistogramBase::kNoFlags);
205   registered_histograms.clear();
206   StatisticsRecorder::GetHistograms(&registered_histograms);
207   EXPECT_EQ(3u, registered_histograms.size());
208 
209   // Create a CustomHistogram.
210   std::vector<int> custom_ranges;
211   custom_ranges.push_back(1);
212   custom_ranges.push_back(5);
213   histogram = CustomHistogram::FactoryGet(
214       "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
215   registered_histograms.clear();
216   StatisticsRecorder::GetHistograms(&registered_histograms);
217   EXPECT_EQ(4u, registered_histograms.size());
218 }
219 
TEST_F(StatisticsRecorderTest,RegisterHistogramWithMacros)220 TEST_F(StatisticsRecorderTest, RegisterHistogramWithMacros) {
221   StatisticsRecorder::Histograms registered_histograms;
222 
223   HistogramBase* histogram = Histogram::FactoryGet(
224       "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags);
225 
226   // The histogram we got from macro is the same as from FactoryGet.
227   LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30);
228   registered_histograms.clear();
229   StatisticsRecorder::GetHistograms(&registered_histograms);
230   ASSERT_EQ(1u, registered_histograms.size());
231   EXPECT_EQ(histogram, registered_histograms[0]);
232 
233   LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1));
234   LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
235 
236   registered_histograms.clear();
237   StatisticsRecorder::GetHistograms(&registered_histograms);
238   EXPECT_EQ(3u, registered_histograms.size());
239 }
240 
TEST_F(StatisticsRecorderTest,BucketRangesSharing)241 TEST_F(StatisticsRecorderTest, BucketRangesSharing) {
242   std::vector<const BucketRanges*> ranges;
243   StatisticsRecorder::GetBucketRanges(&ranges);
244   EXPECT_EQ(0u, ranges.size());
245 
246   Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags);
247   Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags);
248 
249   StatisticsRecorder::GetBucketRanges(&ranges);
250   EXPECT_EQ(1u, ranges.size());
251 
252   Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags);
253 
254   ranges.clear();
255   StatisticsRecorder::GetBucketRanges(&ranges);
256   EXPECT_EQ(2u, ranges.size());
257 }
258 
TEST_F(StatisticsRecorderTest,ToJSON)259 TEST_F(StatisticsRecorderTest, ToJSON) {
260   LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 30);
261   LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 40);
262   LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 30);
263   LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 40);
264 
265   std::string json(StatisticsRecorder::ToJSON(std::string()));
266 
267   // Check for valid JSON.
268   scoped_ptr<Value> root = JSONReader::Read(json);
269   ASSERT_TRUE(root.get());
270 
271   DictionaryValue* root_dict = NULL;
272   ASSERT_TRUE(root->GetAsDictionary(&root_dict));
273 
274   // No query should be set.
275   ASSERT_FALSE(root_dict->HasKey("query"));
276 
277   ListValue* histogram_list = NULL;
278   ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
279   ASSERT_EQ(2u, histogram_list->GetSize());
280 
281   // Examine the first histogram.
282   DictionaryValue* histogram_dict = NULL;
283   ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
284 
285   int sample_count;
286   ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count));
287   EXPECT_EQ(2, sample_count);
288 
289   // Test the query filter.
290   std::string query("TestHistogram2");
291   json = StatisticsRecorder::ToJSON(query);
292 
293   root = JSONReader::Read(json);
294   ASSERT_TRUE(root.get());
295   ASSERT_TRUE(root->GetAsDictionary(&root_dict));
296 
297   std::string query_value;
298   ASSERT_TRUE(root_dict->GetString("query", &query_value));
299   EXPECT_EQ(query, query_value);
300 
301   ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
302   ASSERT_EQ(1u, histogram_list->GetSize());
303 
304   ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
305 
306   std::string histogram_name;
307   ASSERT_TRUE(histogram_dict->GetString("name", &histogram_name));
308   EXPECT_EQ("TestHistogram2", histogram_name);
309 
310   json.clear();
311   UninitializeStatisticsRecorder();
312 
313   // No data should be returned.
314   json = StatisticsRecorder::ToJSON(query);
315   EXPECT_TRUE(json.empty());
316 }
317 
318 namespace {
319 
320 // CallbackCheckWrapper is simply a convenient way to check and store that
321 // a callback was actually run.
322 struct CallbackCheckWrapper {
CallbackCheckWrapperbase::__anon3d7c4c580111::CallbackCheckWrapper323   CallbackCheckWrapper() : called(false), last_histogram_value(0) {}
324 
OnHistogramChangedbase::__anon3d7c4c580111::CallbackCheckWrapper325   void OnHistogramChanged(base::HistogramBase::Sample histogram_value) {
326     called = true;
327     last_histogram_value = histogram_value;
328   }
329 
330   bool called;
331   base::HistogramBase::Sample last_histogram_value;
332 };
333 
334 }  // namespace
335 
336 // Check that you can't overwrite the callback with another.
TEST_F(StatisticsRecorderTest,SetCallbackFailsWithoutHistogramTest)337 TEST_F(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
338   CallbackCheckWrapper callback_wrapper;
339 
340   bool result = base::StatisticsRecorder::SetCallback(
341       "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
342                                   base::Unretained(&callback_wrapper)));
343   EXPECT_TRUE(result);
344 
345   result = base::StatisticsRecorder::SetCallback(
346       "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
347                                   base::Unretained(&callback_wrapper)));
348   EXPECT_FALSE(result);
349 }
350 
351 // Check that you can't overwrite the callback with another.
TEST_F(StatisticsRecorderTest,SetCallbackFailsWithHistogramTest)352 TEST_F(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
353   HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
354                                                    HistogramBase::kNoFlags);
355   EXPECT_TRUE(histogram);
356 
357   CallbackCheckWrapper callback_wrapper;
358 
359   bool result = base::StatisticsRecorder::SetCallback(
360       "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
361                                   base::Unretained(&callback_wrapper)));
362   EXPECT_TRUE(result);
363   EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
364             base::HistogramBase::kCallbackExists);
365 
366   result = base::StatisticsRecorder::SetCallback(
367       "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
368                                   base::Unretained(&callback_wrapper)));
369   EXPECT_FALSE(result);
370   EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
371             base::HistogramBase::kCallbackExists);
372 
373   histogram->Add(1);
374 
375   EXPECT_TRUE(callback_wrapper.called);
376 }
377 
378 // Check that you can't overwrite the callback with another.
TEST_F(StatisticsRecorderTest,ClearCallbackSuceedsWithHistogramTest)379 TEST_F(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
380   HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
381                                                    HistogramBase::kNoFlags);
382   EXPECT_TRUE(histogram);
383 
384   CallbackCheckWrapper callback_wrapper;
385 
386   bool result = base::StatisticsRecorder::SetCallback(
387       "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
388                                   base::Unretained(&callback_wrapper)));
389   EXPECT_TRUE(result);
390   EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
391             base::HistogramBase::kCallbackExists);
392 
393   base::StatisticsRecorder::ClearCallback("TestHistogram");
394   EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0);
395 
396   histogram->Add(1);
397 
398   EXPECT_FALSE(callback_wrapper.called);
399 }
400 
401 // Check that callback is used.
TEST_F(StatisticsRecorderTest,CallbackUsedTest)402 TEST_F(StatisticsRecorderTest, CallbackUsedTest) {
403   {
404     HistogramBase* histogram = Histogram::FactoryGet(
405         "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
406     EXPECT_TRUE(histogram);
407 
408     CallbackCheckWrapper callback_wrapper;
409 
410     base::StatisticsRecorder::SetCallback(
411         "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
412                                     base::Unretained(&callback_wrapper)));
413 
414     histogram->Add(1);
415 
416     EXPECT_TRUE(callback_wrapper.called);
417     EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
418   }
419 
420   {
421     HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
422         "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
423 
424     CallbackCheckWrapper callback_wrapper;
425 
426     base::StatisticsRecorder::SetCallback(
427         "TestLinearHistogram",
428         base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
429                    base::Unretained(&callback_wrapper)));
430 
431     linear_histogram->Add(1);
432 
433     EXPECT_TRUE(callback_wrapper.called);
434     EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
435   }
436 
437   {
438     std::vector<int> custom_ranges;
439     custom_ranges.push_back(1);
440     custom_ranges.push_back(5);
441     HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
442         "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
443 
444     CallbackCheckWrapper callback_wrapper;
445 
446     base::StatisticsRecorder::SetCallback(
447         "TestCustomHistogram",
448         base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
449                    base::Unretained(&callback_wrapper)));
450 
451     custom_histogram->Add(1);
452 
453     EXPECT_TRUE(callback_wrapper.called);
454     EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
455   }
456 
457   {
458     HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
459         "TestSparseHistogram", HistogramBase::kNoFlags);
460 
461     CallbackCheckWrapper callback_wrapper;
462 
463     base::StatisticsRecorder::SetCallback(
464         "TestSparseHistogram",
465         base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
466                    base::Unretained(&callback_wrapper)));
467 
468     custom_histogram->Add(1);
469 
470     EXPECT_TRUE(callback_wrapper.called);
471     EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
472   }
473 }
474 
475 // Check that setting a callback before the histogram exists works.
TEST_F(StatisticsRecorderTest,CallbackUsedBeforeHistogramCreatedTest)476 TEST_F(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
477   CallbackCheckWrapper callback_wrapper;
478 
479   base::StatisticsRecorder::SetCallback(
480       "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
481                                   base::Unretained(&callback_wrapper)));
482 
483   HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
484                                                    HistogramBase::kNoFlags);
485   EXPECT_TRUE(histogram);
486   histogram->Add(1);
487 
488   EXPECT_TRUE(callback_wrapper.called);
489   EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
490 }
491 
492 }  // namespace base
493