From 07637b015c74b180c1163f38c1458ec41647644e Mon Sep 17 00:00:00 2001 From: holte Date: Mon, 22 Sep 2014 12:15:02 -0700 Subject: [PATCH] Add a mechanism for collecting Rappor samples on a daily interval. BUG=400927 Review URL: https://codereview.chromium.org/511623002 Cr-Commit-Position: refs/heads/master@{#296025} --- chrome/browser/chrome_browser_main.cc | 1 - .../activity_log/ad_injection_unittest.cc | 7 +- .../metrics/metrics_services_manager.cc | 2 +- components/components_tests.gyp | 1 + components/metrics.gypi | 2 + components/metrics/BUILD.gn | 2 + components/metrics/daily_event.cc | 106 ++++++++++++++++++ components/metrics/daily_event.h | 92 +++++++++++++++ components/metrics/daily_event_unittest.cc | 96 ++++++++++++++++ components/rappor/rappor_pref_names.cc | 3 + components/rappor/rappor_pref_names.h | 1 + components/rappor/rappor_service.cc | 39 +++++-- components/rappor/rappor_service.h | 42 ++++--- components/rappor/rappor_service_unittest.cc | 24 +++- tools/metrics/histograms/histograms.xml | 11 ++ 15 files changed, 396 insertions(+), 33 deletions(-) create mode 100644 components/metrics/daily_event.cc create mode 100644 components/metrics/daily_event.h create mode 100644 components/metrics/daily_event_unittest.cc diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 14990cffcca8..2a261b94cbc9 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -656,7 +656,6 @@ void ChromeBrowserMainParts::StartMetricsRecording() { // TODO(asvitkine): Since this function is not run on Android, RAPPOR is // currently disabled there. http://crbug.com/370041 browser_process_->rappor_service()->Start( - browser_process_->local_state(), browser_process_->system_request_context(), metrics_enabled); } diff --git a/chrome/browser/extensions/activity_log/ad_injection_unittest.cc b/chrome/browser/extensions/activity_log/ad_injection_unittest.cc index be2e6c4ad5e6..d723efc0fbae 100644 --- a/chrome/browser/extensions/activity_log/ad_injection_unittest.cc +++ b/chrome/browser/extensions/activity_log/ad_injection_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/prefs/testing_pref_service.h" #include "base/time/time.h" #include "chrome/browser/extensions/activity_log/activity_actions.h" #include "components/rappor/byte_vector_utils.h" @@ -42,9 +43,13 @@ class TestRapporService : public rappor::RapporService { // be from the last time GetReports() was called (not from the beginning of // the test). rappor::RapporReports GetReports(); + + protected: + TestingPrefServiceSimple prefs_; }; -TestRapporService::TestRapporService() { +TestRapporService::TestRapporService() + : rappor::RapporService(&prefs_) { // Initialize the RapporService for testing. SetCohortForTesting(0); SetSecretForTesting(rappor::HmacByteVectorGenerator::GenerateEntropyInput()); diff --git a/chrome/browser/metrics/metrics_services_manager.cc b/chrome/browser/metrics/metrics_services_manager.cc index 186bfde7c3fd..15cae1294696 100644 --- a/chrome/browser/metrics/metrics_services_manager.cc +++ b/chrome/browser/metrics/metrics_services_manager.cc @@ -38,7 +38,7 @@ metrics::MetricsService* MetricsServicesManager::GetMetricsService() { rappor::RapporService* MetricsServicesManager::GetRapporService() { DCHECK(thread_checker_.CalledOnValidThread()); if (!rappor_service_) - rappor_service_.reset(new rappor::RapporService); + rappor_service_.reset(new rappor::RapporService(local_state_)); return rappor_service_.get(); } diff --git a/components/components_tests.gyp b/components/components_tests.gyp index e7733eb01adf..b7336490c919 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -144,6 +144,7 @@ 'language_usage_metrics/language_usage_metrics_unittest.cc', 'leveldb_proto/proto_database_impl_unittest.cc', 'metrics/compression_utils_unittest.cc', + 'metrics/daily_event_unittest.cc', 'metrics/machine_id_provider_win_unittest.cc', 'metrics/metrics_hashes_unittest.cc', 'metrics/metrics_log_manager_unittest.cc', diff --git a/components/metrics.gypi b/components/metrics.gypi index c16c1911d211..1e41f86f39b4 100644 --- a/components/metrics.gypi +++ b/components/metrics.gypi @@ -26,6 +26,8 @@ 'metrics/cloned_install_detector.h', 'metrics/compression_utils.cc', 'metrics/compression_utils.h', + 'metrics/daily_event.cc', + 'metrics/daily_event.h', 'metrics/machine_id_provider.h', 'metrics/machine_id_provider_stub.cc', 'metrics/machine_id_provider_win.cc', diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index 89bedd83c9c4..685788c6b017 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn @@ -13,6 +13,8 @@ source_set("metrics") { "cloned_install_detector.h", "compression_utils.cc", "compression_utils.h", + "daily_event.cc", + "daily_event.h", "machine_id_provider.h", "machine_id_provider_stub.cc", "machine_id_provider_win.cc", diff --git a/components/metrics/daily_event.cc b/components/metrics/daily_event.cc new file mode 100644 index 000000000000..34c34265a3bb --- /dev/null +++ b/components/metrics/daily_event.cc @@ -0,0 +1,106 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/metrics/daily_event.h" + +#include "base/i18n/time_formatting.h" +#include "base/metrics/histogram.h" +#include "base/prefs/pref_registry_simple.h" +#include "base/prefs/pref_service.h" + +namespace metrics { + +namespace { + +enum IntervalType { + FIRST_RUN, + DAY_ELAPSED, + CLOCK_CHANGED, + NUM_INTERVAL_TYPES +}; + +void RecordIntervalTypeHistogram(const std::string& histogram_name, + IntervalType type) { + base::Histogram::FactoryGet( + histogram_name, + 1, + NUM_INTERVAL_TYPES, + NUM_INTERVAL_TYPES + 1, + base::HistogramBase::kUmaTargetedHistogramFlag)->Add(type); +} + +} // namespace + +DailyEvent::Observer::Observer() { +} + +DailyEvent::Observer::~Observer() { +} + +DailyEvent::DailyEvent(PrefService* pref_service, + const char* pref_name, + const std::string& histogram_name) + : pref_service_(pref_service), + pref_name_(pref_name), + histogram_name_(histogram_name) { +} + +DailyEvent::~DailyEvent() { +} + +// static +void DailyEvent::RegisterPref(PrefRegistrySimple* registry, + const char* pref_name) { + registry->RegisterInt64Pref(pref_name, base::Time().ToInternalValue()); +} + +void DailyEvent::AddObserver(scoped_ptr observer) { + DVLOG(2) << "DailyEvent observer added."; + DCHECK(last_fired_.is_null()); + observers_.push_back(observer.release()); +} + +void DailyEvent::CheckInterval() { + base::Time now = base::Time::Now(); + if (last_fired_.is_null()) { + // The first time we call CheckInterval, we read the time stored in prefs. + last_fired_ = base::Time::FromInternalValue( + pref_service_->GetInt64(pref_name_)); + DVLOG(1) << "DailyEvent time loaded: " + << base::TimeFormatShortDateAndTime(last_fired_); + if (last_fired_.is_null()) { + DVLOG(1) << "DailyEvent first run."; + RecordIntervalTypeHistogram(pref_name_, FIRST_RUN); + OnInterval(now); + return; + } + } + int days_elapsed = (now - last_fired_).InDays(); + if (days_elapsed >= 1) { + DVLOG(1) << "DailyEvent day elapsed."; + RecordIntervalTypeHistogram(pref_name_, DAY_ELAPSED); + OnInterval(now); + } else if (days_elapsed <= -1) { + // The "last fired" time is more than a day in the future, so the clock + // must have been changed. + DVLOG(1) << "DailyEvent clock change detected."; + RecordIntervalTypeHistogram(pref_name_, CLOCK_CHANGED); + OnInterval(now); + } +} + +void DailyEvent::OnInterval(base::Time now) { + DCHECK(!now.is_null()); + last_fired_ = now; + pref_service_->SetInt64(pref_name_, last_fired_.ToInternalValue()); + + // Notify all observers + for (ScopedVector::iterator it = observers_.begin(); + it != observers_.end(); + ++it) { + (*it)->OnDailyEvent(); + } +} + +} // namespace metrics diff --git a/components/metrics/daily_event.h b/components/metrics/daily_event.h new file mode 100644 index 000000000000..24b31dc58eaf --- /dev/null +++ b/components/metrics/daily_event.h @@ -0,0 +1,92 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_METRICS_DAILY_EVENT_H_ +#define COMPONENTS_METRICS_DAILY_EVENT_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/time/time.h" + +class PrefRegistrySimple; +class PrefService; + +namespace metrics { + +// DailyEvent is used for throttling an event to about once per day, even if +// the program is restarted more frequently. It is based on local machine +// time, so it could be fired more often if the clock is changed. +// +// The service using the DailyEvent should first provide all of the Observers +// for the interval, and then arrange for CheckInterval() to be called +// periodically to test if the event should be fired. +class DailyEvent { + public: + // Observer receives notifications from a DailyEvent. + // Observers must be added before the DailyEvent begins checking time, + // and will be owned by the DailyEvent. + class Observer { + public: + Observer(); + virtual ~Observer(); + + // Called when the daily event is fired. + virtual void OnDailyEvent() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Observer); + }; + + // Constructs DailyEvent monitor which stores the time it last fired in the + // preference |pref_name|. |pref_name| should be registered by calling + // RegisterPref before using this object. + // Caller is responsible for ensuring that |pref_service| and |pref_name| + // outlive the DailyEvent. + // |histogram_name| is the name of the UMA metric which record when this + // interval fires, and should be registered in histograms.xml + DailyEvent(PrefService* pref_service, + const char* pref_name, + const std::string& histogram_name); + ~DailyEvent(); + + // Adds a observer to be notified when a day elapses. All observers should + // be registered before the the DailyEvent starts checking time. + void AddObserver(scoped_ptr observer); + + // Checks if a day has elapsed. If it has, OnDailyEvent will be called on + // all observers. + void CheckInterval(); + + // Registers the preference used by this interval. + static void RegisterPref(PrefRegistrySimple* registry, const char* pref_name); + + private: + // Handles an interval elapsing. + void OnInterval(base::Time now); + + // A weak pointer to the PrefService object to read and write preferences + // from. Calling code should ensure this object continues to exist for the + // lifetime of the DailyEvent object. + PrefService* pref_service_; + + // The name of the preference to store the last fired time in. + // Calling code should ensure this outlives the DailyEvent. + const char* pref_name_; + + // The name of the histogram to record intervals. + std::string histogram_name_; + + // A list of observers. + ScopedVector observers_; + + // The time that the daily event was last fired. + base::Time last_fired_; + + DISALLOW_COPY_AND_ASSIGN(DailyEvent); +}; + +} // namespace metrics + +#endif // COMPONENTS_METRICS_DAILY_EVENT_H_ diff --git a/components/metrics/daily_event_unittest.cc b/components/metrics/daily_event_unittest.cc new file mode 100644 index 000000000000..4253c1304539 --- /dev/null +++ b/components/metrics/daily_event_unittest.cc @@ -0,0 +1,96 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/metrics/daily_event.h" + +#include "base/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace metrics { + +namespace { + +const char kTestPrefName[] = "TestPref"; +const char kTestMetricName[] = "TestMetric"; + +class TestDailyObserver : public DailyEvent::Observer { + public: + TestDailyObserver() : fired_(false) {} + + bool fired() const { return fired_; } + + virtual void OnDailyEvent() OVERRIDE { + fired_ = true; + } + + void Reset() { + fired_ = false; + } + + private: + // True if this event has been observed. + bool fired_; + + DISALLOW_COPY_AND_ASSIGN(TestDailyObserver); +}; + +class DailyEventTest : public testing::Test { + public: + DailyEventTest() : event_(&prefs_, kTestPrefName, kTestMetricName) { + DailyEvent::RegisterPref(prefs_.registry(), kTestPrefName); + observer_ = new TestDailyObserver(); + scoped_ptr p(observer_); + event_.AddObserver(p.Pass()); + } + + protected: + TestingPrefServiceSimple prefs_; + TestDailyObserver* observer_; + DailyEvent event_; + + private: + DISALLOW_COPY_AND_ASSIGN(DailyEventTest); +}; + +} // namespace + +// The event should fire if the preference is not available. +TEST_F(DailyEventTest, TestNewFires) { + event_.CheckInterval(); + EXPECT_TRUE(observer_->fired()); +} + +// The event should fire if the preference is more than a day old. +TEST_F(DailyEventTest, TestOldFires) { + base::Time last_time = base::Time::Now() - base::TimeDelta::FromHours(25); + prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue()); + event_.CheckInterval(); + EXPECT_TRUE(observer_->fired()); +} + +// The event should fire if the preference is more than a day in the future. +TEST_F(DailyEventTest, TestFutureFires) { + base::Time last_time = base::Time::Now() + base::TimeDelta::FromHours(25); + prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue()); + event_.CheckInterval(); + EXPECT_TRUE(observer_->fired()); +} + +// The event should not fire if the preference is more recent than a day. +TEST_F(DailyEventTest, TestRecentNotFired) { + base::Time last_time = base::Time::Now() - base::TimeDelta::FromMinutes(2); + prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue()); + event_.CheckInterval(); + EXPECT_FALSE(observer_->fired()); +} + +// The event should not fire if the preference is less than a day in the future. +TEST_F(DailyEventTest, TestSoonNotFired) { + base::Time last_time = base::Time::Now() + base::TimeDelta::FromMinutes(2); + prefs_.SetInt64(kTestPrefName, last_time.ToInternalValue()); + event_.CheckInterval(); + EXPECT_FALSE(observer_->fired()); +} + +} // namespace metrics diff --git a/components/rappor/rappor_pref_names.cc b/components/rappor/rappor_pref_names.cc index ff444efd2ba1..b879c4bd2b3a 100644 --- a/components/rappor/rappor_pref_names.cc +++ b/components/rappor/rappor_pref_names.cc @@ -13,6 +13,9 @@ const char kRapporCohortDeprecated[] = "rappor.cohort"; // A randomly generated number, which determines cohorts data is reported for. const char kRapporCohortSeed[] = "rappor.cohort_seed"; +// Timestamp of the last time we sampled daily metrics. +const char kRapporLastDailySample[] = "rappor.last_daily_sample"; + // A base-64 encoded, randomly generated byte string, which is used as a seed // for redacting collected data. // Important: This value should remain secret at the client, and never be diff --git a/components/rappor/rappor_pref_names.h b/components/rappor/rappor_pref_names.h index 9cb60cab7266..06ea8d5293cc 100644 --- a/components/rappor/rappor_pref_names.h +++ b/components/rappor/rappor_pref_names.h @@ -12,6 +12,7 @@ namespace prefs { // component. Keep alphabetized, and document each in the .cc file. extern const char kRapporCohortDeprecated[]; extern const char kRapporCohortSeed[]; +extern const char kRapporLastDailySample[]; extern const char kRapporSecret[]; } // namespace prefs diff --git a/components/rappor/rappor_service.cc b/components/rappor/rappor_service.cc index 6ca64b70f94b..11419f5baaf5 100644 --- a/components/rappor/rappor_service.cc +++ b/components/rappor/rappor_service.cc @@ -29,6 +29,8 @@ const int kLogIntervalSeconds = 30 * 60; const char kMimeType[] = "application/vnd.chrome.rappor"; +const char kRapporDailyEventHistogram[] = "Rappor.DailyEvent.IntervalType"; + // Constants for the RAPPOR rollout field trial. const char kRapporRolloutFieldTrialName[] = "RapporRollout"; @@ -69,14 +71,24 @@ const RapporParameters kRapporParametersForType[NUM_RAPPOR_TYPES] = { } // namespace -RapporService::RapporService() : cohort_(-1) {} +RapporService::RapporService(PrefService* pref_service) + : pref_service_(pref_service), + cohort_(-1), + daily_event_(pref_service, + prefs::kRapporLastDailySample, + kRapporDailyEventHistogram) { +} RapporService::~RapporService() { STLDeleteValues(&metrics_map_); } -void RapporService::Start(PrefService* pref_service, - net::URLRequestContextGetter* request_context, +void RapporService::AddDailyObserver( + scoped_ptr observer) { + daily_event_.AddObserver(observer.Pass()); +} + +void RapporService::Start(net::URLRequestContextGetter* request_context, bool metrics_enabled) { const GURL server_url = GetServerUrl(metrics_enabled); if (!server_url.is_valid()) { @@ -86,8 +98,8 @@ void RapporService::Start(PrefService* pref_service, } DVLOG(1) << "RapporService started. Reporting to " << server_url.spec(); DCHECK(!uploader_); - LoadSecret(pref_service); - LoadCohort(pref_service); + LoadSecret(); + LoadCohort(); uploader_.reset(new LogUploader(server_url, kMimeType, request_context)); log_rotation_timer_.Start( FROM_HERE, @@ -99,6 +111,7 @@ void RapporService::Start(PrefService* pref_service, void RapporService::OnLogInterval() { DCHECK(uploader_); DVLOG(2) << "RapporService::OnLogInterval"; + daily_event_.CheckInterval(); RapporReports reports; if (ExportMetrics(&reports)) { std::string log_text; @@ -119,14 +132,16 @@ void RapporService::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterStringPref(prefs::kRapporSecret, std::string()); registry->RegisterIntegerPref(prefs::kRapporCohortDeprecated, -1); registry->RegisterIntegerPref(prefs::kRapporCohortSeed, -1); + metrics::DailyEvent::RegisterPref(registry, + prefs::kRapporLastDailySample); } -void RapporService::LoadCohort(PrefService* pref_service) { +void RapporService::LoadCohort() { DCHECK(!IsInitialized()); // Ignore and delete old cohort parameter. - pref_service->ClearPref(prefs::kRapporCohortDeprecated); + pref_service_->ClearPref(prefs::kRapporCohortDeprecated); - cohort_ = pref_service->GetInteger(prefs::kRapporCohortSeed); + cohort_ = pref_service_->GetInteger(prefs::kRapporCohortSeed); // If the user is already assigned to a valid cohort, we're done. if (cohort_ >= 0 && cohort_ < RapporParameters::kMaxCohorts) return; @@ -135,12 +150,12 @@ void RapporService::LoadCohort(PrefService* pref_service) { // preferences were corrupted). Randomly assign them to a cohort. cohort_ = base::RandGenerator(RapporParameters::kMaxCohorts); DVLOG(2) << "Selected a new Rappor cohort: " << cohort_; - pref_service->SetInteger(prefs::kRapporCohortSeed, cohort_); + pref_service_->SetInteger(prefs::kRapporCohortSeed, cohort_); } -void RapporService::LoadSecret(PrefService* pref_service) { +void RapporService::LoadSecret() { DCHECK(secret_.empty()); - std::string secret_base64 = pref_service->GetString(prefs::kRapporSecret); + std::string secret_base64 = pref_service_->GetString(prefs::kRapporSecret); if (!secret_base64.empty()) { bool decoded = base::Base64Decode(secret_base64, &secret_); if (decoded && secret_.size() == HmacByteVectorGenerator::kEntropyInputSize) @@ -153,7 +168,7 @@ void RapporService::LoadSecret(PrefService* pref_service) { DVLOG(2) << "Generated a new Rappor secret."; secret_ = HmacByteVectorGenerator::GenerateEntropyInput(); base::Base64Encode(secret_, &secret_base64); - pref_service->SetString(prefs::kRapporSecret, secret_base64); + pref_service_->SetString(prefs::kRapporSecret, secret_base64); } bool RapporService::ExportMetrics(RapporReports* reports) { diff --git a/components/rappor/rappor_service.h b/components/rappor/rappor_service.h index f02a85a3fe65..b48c31c4453c 100644 --- a/components/rappor/rappor_service.h +++ b/components/rappor/rappor_service.h @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/timer/timer.h" +#include "components/metrics/daily_event.h" class PrefRegistrySimple; class PrefService; @@ -38,12 +39,17 @@ enum RapporType { // and periodically generates and uploads reports based on the collected data. class RapporService { public: - RapporService(); + // Constructs a RapporService. + // Calling code is responsible for ensuring that the lifetime of + // |pref_service| is longer than the lifetime of RapporService. + explicit RapporService(PrefService* pref_service); virtual ~RapporService(); + // Add an observer for collecting daily metrics. + void AddDailyObserver(scoped_ptr observer); + // Starts the periodic generation of reports and upload attempts. - void Start(PrefService* pref_service, - net::URLRequestContextGetter* context, + void Start(net::URLRequestContextGetter* context, bool metrics_enabled); // Records a sample of the rappor metric specified by |metric_name|. @@ -52,10 +58,10 @@ class RapporService { RapporType type, const std::string& sample); - // Sets the cohort value. For use by tests only. + // Sets the cohort value. For use by tests only. void SetCohortForTesting(uint32_t cohort) { cohort_ = cohort; } - // Sets the secret value. For use by tests only. + // Sets the secret value. For use by tests only. void SetSecretForTesting(const std::string& secret) { secret_ = secret; } // Registers the names of all of the preferences used by RapporService in the @@ -63,8 +69,17 @@ class RapporService { static void RegisterPrefs(PrefRegistrySimple* registry); protected: + // Retrieves the cohort number this client was assigned to, generating it if + // doesn't already exist. The cohort should be persistent. + void LoadCohort(); + + // Retrieves the value for secret_ from preferences, generating it if doesn't + // already exist. The secret should be persistent, so that additional bits + // from the client do not get exposed over time. + void LoadSecret(); + // Logs all of the collected metrics to the reports proto message and clears - // the internal map. Exposed for tests. Returns true if any metrics were + // the internal map. Exposed for tests. Returns true if any metrics were // recorded. bool ExportMetrics(RapporReports* reports); @@ -79,15 +94,6 @@ class RapporService { // Check if the service has been started successfully. bool IsInitialized() const; - // Retrieves the cohort number this client was assigned to, generating it if - // doesn't already exist. The cohort should be persistent. - void LoadCohort(PrefService* pref_service); - - // Retrieves the value for secret_ from preferences, generating it if doesn't - // already exist. The secret should be persistent, so that additional bits - // from the client do not get exposed over time. - void LoadSecret(PrefService* pref_service); - // Called whenever the logging interval elapses to generate a new log of // reports and pass it to the uploader. void OnLogInterval(); @@ -97,6 +103,9 @@ class RapporService { RapporMetric* LookUpMetric(const std::string& metric_name, const RapporParameters& parameters); + // A weak pointer to the PrefService used to read and write preferences. + PrefService* pref_service_; + // Client-side secret used to generate fake bits. std::string secret_; @@ -106,6 +115,9 @@ class RapporService { // Timer which schedules calls to OnLogInterval(). base::OneShotTimer log_rotation_timer_; + // A daily event for collecting metrics once a day. + metrics::DailyEvent daily_event_; + // A private LogUploader instance for sending reports to the server. scoped_ptr uploader_; diff --git a/components/rappor/rappor_service_unittest.cc b/components/rappor/rappor_service_unittest.cc index a91db8c03221..4430ee3eb982 100644 --- a/components/rappor/rappor_service_unittest.cc +++ b/components/rappor/rappor_service_unittest.cc @@ -4,23 +4,44 @@ #include "components/rappor/rappor_service.h" +#include "base/base64.h" +#include "base/prefs/testing_pref_service.h" #include "components/rappor/byte_vector_utils.h" #include "components/rappor/proto/rappor_metric.pb.h" #include "components/rappor/rappor_parameters.h" +#include "components/rappor/rappor_pref_names.h" #include "testing/gtest/include/gtest/gtest.h" namespace rappor { class TestRapporService : public RapporService { public: + TestRapporService() : RapporService(&prefs_) { + RegisterPrefs(prefs_.registry()); + prefs_.SetInteger(prefs::kRapporCohortSeed, 0); + std::string secret = HmacByteVectorGenerator::GenerateEntropyInput(); + std::string secret_base64; + base::Base64Encode(secret, &secret_base64); + prefs_.SetString(prefs::kRapporSecret, secret_base64); + LoadCohort(); + LoadSecret(); + } + void GetReports(RapporReports* reports) { ExportMetrics(reports); } + void TestRecordSample(const std::string& metric_name, const RapporParameters& parameters, const std::string& sample) { RecordSampleInternal(metric_name, parameters, sample); } + + protected: + TestingPrefServiceSimple prefs_; + + private: + DISALLOW_COPY_AND_ASSIGN(TestRapporService); }; TEST(RapporServiceTest, RecordAndExportMetrics) { @@ -34,9 +55,6 @@ TEST(RapporServiceTest, RecordAndExportMetrics) { PROBABILITY_50 /* Zero coin probability */}; TestRapporService rappor_service; - rappor_service.SetCohortForTesting(0); - rappor_service.SetSecretForTesting( - HmacByteVectorGenerator::GenerateEntropyInput()); rappor_service.TestRecordSample("MyMetric", kTestRapporParameters, "foo"); rappor_service.TestRecordSample("MyMetric", kTestRapporParameters, "bar"); diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b3b3c0ec1505..ec7c7a3e74c2 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -26389,6 +26389,11 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + holte@chromium.org + Counts how often daily interval events were fired. + + holte@chromium.org @@ -39465,6 +39470,12 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + + + + +