1 // Copyright (c) 2011 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 <map> 6 7 #include "base/metrics/histogram.h" 8 #include "chrome/browser/extensions/extension_apitest.h" 9 #include "chrome/common/chrome_switches.h" 10 #include "chrome/common/extensions/extension.h" 11 #include "content/common/notification_registrar.h" 12 #include "content/common/notification_service.h" 13 14 namespace { 15 16 // The tests that are run by this extension are expected to record the following 17 // user actions, with the specified counts. If the tests in test.js are 18 // modified, this array may need to be updated. 19 struct RecordedUserAction { 20 const char* name; // base name of metric without extension id. 21 int count; // number of times the metric was recorded. 22 } g_user_actions[] = { 23 {"test.ua.1", 1}, 24 {"test.ua.2", 2}, 25 }; 26 27 // The tests that are run by this extension are expected to record the following 28 // histograms. If the tests in test.js are modified, this array may need to be 29 // updated. 30 struct RecordedHistogram { 31 const char* name; // base name of metric without extension id. 32 base::Histogram::ClassType type; 33 int min; 34 int max; 35 size_t buckets; 36 } g_histograms[] = { 37 {"test.h.1", base::Histogram::HISTOGRAM, 1, 100, 50}, // custom 38 {"test.h.2", base::Histogram::LINEAR_HISTOGRAM, 1, 200, 50}, // custom 39 {"test.h.3", base::Histogram::LINEAR_HISTOGRAM, 1, 101, 102}, // percentage 40 {"test.time", base::Histogram::HISTOGRAM, 1, 10000, 50}, 41 {"test.medium.time", base::Histogram::HISTOGRAM, 1, 180000, 50}, 42 {"test.long.time", base::Histogram::HISTOGRAM, 1, 3600000, 50}, 43 {"test.count", base::Histogram::HISTOGRAM, 1, 1000000, 50}, 44 {"test.medium.count", base::Histogram::HISTOGRAM, 1, 10000, 50}, 45 {"test.small.count", base::Histogram::HISTOGRAM, 1, 100, 50}, 46 }; 47 48 // Build the full name of a metrics for the given extension. Each metric 49 // is made up of the unique name within the extension followed by the 50 // extension's id. 51 std::string BuildFullName(const std::string& name, const Extension* extension) { 52 std::string full_name(name); 53 full_name += extension->id(); 54 return full_name; 55 } 56 57 // This class observes and collects user action notifications that are sent 58 // by the tests, so that they can be examined afterwards for correctness. 59 class UserActionObserver : public NotificationObserver { 60 public: 61 UserActionObserver(); 62 63 void ValidateUserActions(const Extension* extension, 64 const RecordedUserAction* recorded, 65 int count); 66 67 virtual void Observe(NotificationType type, 68 const NotificationSource& source, 69 const NotificationDetails& details); 70 71 private: 72 typedef std::map<std::string, int> UserActionCountMap; 73 74 int num_metrics() const { 75 return count_map_.size(); 76 } 77 78 int GetMetricCount(const std::string& name) const { 79 UserActionCountMap::const_iterator i = count_map_.find(name); 80 return i == count_map_.end() ? -1 : i->second; 81 } 82 83 NotificationRegistrar registrar_; 84 UserActionCountMap count_map_; 85 }; 86 87 UserActionObserver::UserActionObserver() { 88 registrar_.Add(this, NotificationType::USER_ACTION, 89 NotificationService::AllSources()); 90 } 91 92 void UserActionObserver::Observe(NotificationType type, 93 const NotificationSource& source, 94 const NotificationDetails& details) { 95 const char* name = *Details<const char*>(details).ptr(); 96 ++(count_map_[name]); 97 } 98 99 void UserActionObserver::ValidateUserActions(const Extension* extension, 100 const RecordedUserAction* recorded, 101 int count) { 102 EXPECT_EQ(count, num_metrics()); 103 104 for (int i = 0; i < count; ++i) { 105 const RecordedUserAction& ua = recorded[i]; 106 EXPECT_EQ(ua.count, GetMetricCount(BuildFullName(ua.name, extension))); 107 } 108 } 109 110 void ValidateHistograms(const Extension* extension, 111 const RecordedHistogram* recorded, 112 int count) { 113 base::StatisticsRecorder::Histograms histograms; 114 base::StatisticsRecorder::GetHistograms(&histograms); 115 116 // Code other than the tests tun here will record some histogram values, but 117 // we will ignore those. This function validates that all the histogram we 118 // expect to see are present in the list, and that their basic info is 119 // correct. 120 for (int i = 0; i < count; ++i) { 121 const RecordedHistogram& r = recorded[i]; 122 std::string name(BuildFullName(r.name, extension)); 123 124 size_t j = 0; 125 for (j = 0; j < histograms.size(); ++j) { 126 base::Histogram* histogram(histograms[j]); 127 128 if (name == histogram->histogram_name()) { 129 EXPECT_EQ(r.type, histogram->histogram_type()); 130 EXPECT_EQ(r.min, histogram->declared_min()); 131 EXPECT_EQ(r.max, histogram->declared_max()); 132 EXPECT_EQ(r.buckets, histogram->bucket_count()); 133 break; 134 } 135 } 136 EXPECT_LT(j, histograms.size()); 137 } 138 } 139 140 } // anonymous namespace 141 142 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) { 143 CommandLine::ForCurrentProcess()->AppendSwitch( 144 switches::kEnableExperimentalExtensionApis); 145 146 UserActionObserver observer; 147 148 ASSERT_TRUE(RunExtensionTest("metrics")) << message_; 149 const Extension* extension = GetSingleLoadedExtension(); 150 ASSERT_TRUE(extension); 151 152 observer.ValidateUserActions(extension, 153 g_user_actions, 154 arraysize(g_user_actions)); 155 ValidateHistograms(extension, g_histograms, arraysize(g_histograms)); 156 } 157