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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_histograms);
129 EXPECT_EQ(0u, registered_histograms.size());
130
131 // Register the Histogram.
132 EXPECT_EQ(histogram,
133 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
134 StatisticsRecorder::GetHistograms(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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