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: 22 void SetUp() override { 23 // Each test will have a clean state (no Histogram / BucketRanges 24 // registered). 25 InitializeStatisticsRecorder(); 26 } 27 28 void TearDown() override { UninitializeStatisticsRecorder(); } 29 30 void InitializeStatisticsRecorder() { 31 statistics_recorder_ = new StatisticsRecorder(); 32 } 33 34 void UninitializeStatisticsRecorder() { 35 delete statistics_recorder_; 36 statistics_recorder_ = NULL; 37 } 38 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 50 void DeleteHistogram(HistogramBase* histogram) { 51 delete histogram; 52 } 53 54 StatisticsRecorder* statistics_recorder_; 55 }; 56 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 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 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 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 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 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 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 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 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 { 323 CallbackCheckWrapper() : called(false), last_histogram_value(0) {} 324 325 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. 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. 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. 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. 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. 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