Home | History | Annotate | Download | only in metrics_private
      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 <map>
      6 
      7 #include "base/metrics/field_trial.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/metrics/statistics_recorder.h"
     10 #include "base/metrics/user_metrics.h"
     11 #include "chrome/browser/extensions/extension_apitest.h"
     12 #include "components/variations/variations_associated_data.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;
     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;
     32   base::HistogramType type;
     33   int min;
     34   int max;
     35   size_t buckets;
     36   int count;
     37 } g_histograms[] = {
     38       {"test.h.1", base::HISTOGRAM, 1, 100, 50, 1},          // custom
     39       {"test.h.2", base::LINEAR_HISTOGRAM, 1, 200, 50, 1},   // custom
     40       {"test.h.3", base::LINEAR_HISTOGRAM, 1, 101, 102, 2},  // percentage
     41       {"test.sparse.1", base::SPARSE_HISTOGRAM, 0, 0, 0, 1},
     42       {"test.sparse.2", base::SPARSE_HISTOGRAM, 0, 0, 0, 2},
     43       {"test.sparse.3", base::SPARSE_HISTOGRAM, 0, 0, 0, 6},
     44       {"test.time", base::HISTOGRAM, 1, 10000, 50, 1},
     45       {"test.medium.time", base::HISTOGRAM, 1, 180000, 50, 1},
     46       {"test.long.time", base::HISTOGRAM, 1, 3600000, 50, 1},
     47       {"test.count", base::HISTOGRAM, 1, 1000000, 50, 1},
     48       {"test.medium.count", base::HISTOGRAM, 1, 10000, 50, 1},
     49       {"test.small.count", base::HISTOGRAM, 1, 100, 50, 1},
     50       {"test.bucketchange.linear", base::LINEAR_HISTOGRAM, 1, 100, 10, 2},
     51       {"test.bucketchange.log", base::HISTOGRAM, 1, 100, 10, 2}, };
     52 
     53 // Represents a bucket in a sparse histogram.
     54 struct Bucket {
     55   int histogram_value;
     56   int count;
     57 };
     58 
     59 // We expect the following sparse histograms.
     60 struct SparseHistogram {
     61   const char* name;
     62   int bucket_count;
     63   Bucket buckets[10];
     64 } g_sparse_histograms[] = {
     65   {"test.sparse.1", 1, {{42, 1}}},
     66   {"test.sparse.2", 1, {{24, 2}}},
     67   {"test.sparse.3", 3, {{1, 1}, {2, 2}, {3, 3}}}};
     68 
     69 // This class observes and collects user action notifications that are sent
     70 // by the tests, so that they can be examined afterwards for correctness.
     71 class UserActionObserver {
     72  public:
     73   UserActionObserver();
     74   ~UserActionObserver();
     75 
     76   void ValidateUserActions(const RecordedUserAction* recorded, int count);
     77 
     78  private:
     79   typedef std::map<std::string, int> UserActionCountMap;
     80 
     81   void OnUserAction(const std::string& action);
     82 
     83   int num_metrics() const {
     84     return count_map_.size();
     85   }
     86 
     87   int GetMetricCount(const std::string& name) const {
     88     UserActionCountMap::const_iterator i = count_map_.find(name);
     89     return i == count_map_.end() ? -1 : i->second;
     90   }
     91 
     92   UserActionCountMap count_map_;
     93 
     94   base::ActionCallback action_callback_;
     95 
     96   DISALLOW_COPY_AND_ASSIGN(UserActionObserver);
     97 };
     98 
     99 UserActionObserver::UserActionObserver()
    100     : action_callback_(base::Bind(&UserActionObserver::OnUserAction,
    101                                   base::Unretained(this))) {
    102   base::AddActionCallback(action_callback_);
    103 }
    104 
    105 UserActionObserver::~UserActionObserver() {
    106   base::RemoveActionCallback(action_callback_);
    107 }
    108 
    109 void UserActionObserver::OnUserAction(const std::string& action) {
    110   ++(count_map_[action]);
    111 }
    112 
    113 void UserActionObserver::ValidateUserActions(const RecordedUserAction* recorded,
    114                                              int count) {
    115   for (int i = 0; i < count; ++i) {
    116     const RecordedUserAction& ua = recorded[i];
    117     EXPECT_EQ(ua.count, GetMetricCount(ua.name));
    118   }
    119 }
    120 
    121 void ValidateSparseHistogramSamples(
    122     const std::string& name,
    123     const base::HistogramSamples& samples) {
    124   for (unsigned int i = 0; i < arraysize(g_sparse_histograms); ++i) {
    125     const SparseHistogram& sparse_histogram = g_sparse_histograms[i];
    126     if (std::string(name) == sparse_histogram.name) {
    127       for (int j = 0; j < sparse_histogram.bucket_count; ++j) {
    128         const Bucket& bucket = sparse_histogram.buckets[j];
    129         EXPECT_EQ(bucket.count, samples.GetCount(bucket.histogram_value));
    130       }
    131     }
    132   }
    133 }
    134 
    135 void ValidateHistograms(const RecordedHistogram* recorded,
    136                         int count) {
    137   base::StatisticsRecorder::Histograms histograms;
    138   base::StatisticsRecorder::GetHistograms(&histograms);
    139 
    140   // Code other than the tests tun here will record some histogram values, but
    141   // we will ignore those. This function validates that all the histogram we
    142   // expect to see are present in the list, and that their basic info is
    143   // correct.
    144   for (int i = 0; i < count; ++i) {
    145     const RecordedHistogram& r = recorded[i];
    146     size_t j = 0;
    147     for (j = 0; j < histograms.size(); ++j) {
    148       base::HistogramBase* histogram(histograms[j]);
    149       if (r.name == histogram->histogram_name()) {
    150         scoped_ptr<base::HistogramSamples> snapshot =
    151             histogram->SnapshotSamples();
    152         base::HistogramBase::Count sample_count = snapshot->TotalCount();
    153         EXPECT_EQ(r.count, sample_count);
    154 
    155         EXPECT_EQ(r.type, histogram->GetHistogramType());
    156         if (r.type == base::SPARSE_HISTOGRAM) {
    157           ValidateSparseHistogramSamples(r.name, *snapshot);
    158         } else {
    159           EXPECT_TRUE(
    160               histogram->HasConstructionArguments(r.min, r.max, r.buckets));
    161         }
    162         break;
    163       }
    164     }
    165     EXPECT_LT(j, histograms.size());
    166   }
    167 }
    168 
    169 }  // anonymous namespace
    170 
    171 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) {
    172   UserActionObserver observer;
    173 
    174   base::FieldTrialList::CreateFieldTrial("apitestfieldtrial2", "group1");
    175 
    176   std::map<std::string, std::string> params;
    177   params["a"] = "aa";
    178   params["b"] = "bb";
    179   ASSERT_TRUE(chrome_variations::AssociateVariationParams(
    180       "apitestfieldtrial2", "group1", params));
    181 
    182   ASSERT_TRUE(RunComponentExtensionTest("metrics")) << message_;
    183 
    184   observer.ValidateUserActions(g_user_actions, arraysize(g_user_actions));
    185   ValidateHistograms(g_histograms, arraysize(g_histograms));
    186 }
    187