• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "components/metrics/metrics_service.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/prefs/testing_pref_service.h"
12 #include "base/threading/platform_thread.h"
13 #include "components/metrics/compression_utils.h"
14 #include "components/metrics/metrics_log.h"
15 #include "components/metrics/metrics_pref_names.h"
16 #include "components/metrics/metrics_service_observer.h"
17 #include "components/metrics/metrics_state_manager.h"
18 #include "components/metrics/test_metrics_service_client.h"
19 #include "components/variations/metrics_util.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace {
23 
24 using metrics::MetricsLogManager;
25 
26 class TestMetricsService : public MetricsService {
27  public:
TestMetricsService(metrics::MetricsStateManager * state_manager,metrics::MetricsServiceClient * client,PrefService * local_state)28   TestMetricsService(metrics::MetricsStateManager* state_manager,
29                      metrics::MetricsServiceClient* client,
30                      PrefService* local_state)
31       : MetricsService(state_manager, client, local_state) {}
~TestMetricsService()32   virtual ~TestMetricsService() {}
33 
34   using MetricsService::log_manager;
35 
36  private:
37   DISALLOW_COPY_AND_ASSIGN(TestMetricsService);
38 };
39 
40 class TestMetricsLog : public MetricsLog {
41  public:
TestMetricsLog(const std::string & client_id,int session_id,metrics::MetricsServiceClient * client,PrefService * local_state)42   TestMetricsLog(const std::string& client_id,
43                  int session_id,
44                  metrics::MetricsServiceClient* client,
45                  PrefService* local_state)
46       : MetricsLog(client_id,
47                    session_id,
48                    MetricsLog::ONGOING_LOG,
49                    client,
50                    local_state) {}
51 
~TestMetricsLog()52   virtual ~TestMetricsLog() {}
53 
54  private:
55   DISALLOW_COPY_AND_ASSIGN(TestMetricsLog);
56 };
57 
58 class MetricsServiceTest : public testing::Test {
59  public:
MetricsServiceTest()60   MetricsServiceTest() : is_metrics_reporting_enabled_(false) {
61     MetricsService::RegisterPrefs(testing_local_state_.registry());
62     metrics_state_manager_ = metrics::MetricsStateManager::Create(
63         GetLocalState(),
64         base::Bind(&MetricsServiceTest::is_metrics_reporting_enabled,
65                    base::Unretained(this)));
66   }
67 
~MetricsServiceTest()68   virtual ~MetricsServiceTest() {
69     MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE,
70                                       GetLocalState());
71   }
72 
GetMetricsStateManager()73   metrics::MetricsStateManager* GetMetricsStateManager() {
74     return metrics_state_manager_.get();
75   }
76 
GetLocalState()77   PrefService* GetLocalState() { return &testing_local_state_; }
78 
79   // Sets metrics reporting as enabled for testing.
EnableMetricsReporting()80   void EnableMetricsReporting() {
81     is_metrics_reporting_enabled_ = true;
82   }
83 
84   // Waits until base::TimeTicks::Now() no longer equals |value|. This should
85   // take between 1-15ms per the documented resolution of base::TimeTicks.
WaitUntilTimeChanges(const base::TimeTicks & value)86   void WaitUntilTimeChanges(const base::TimeTicks& value) {
87     while (base::TimeTicks::Now() == value) {
88       base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
89     }
90   }
91 
92   // Returns true if there is a synthetic trial in the given vector that matches
93   // the given trial name and trial group; returns false otherwise.
HasSyntheticTrial(const std::vector<variations::ActiveGroupId> & synthetic_trials,const std::string & trial_name,const std::string & trial_group)94   bool HasSyntheticTrial(
95       const std::vector<variations::ActiveGroupId>& synthetic_trials,
96       const std::string& trial_name,
97       const std::string& trial_group) {
98     uint32 trial_name_hash = metrics::HashName(trial_name);
99     uint32 trial_group_hash = metrics::HashName(trial_group);
100     for (std::vector<variations::ActiveGroupId>::const_iterator it =
101              synthetic_trials.begin();
102          it != synthetic_trials.end(); ++it) {
103       if ((*it).name == trial_name_hash && (*it).group == trial_group_hash)
104         return true;
105     }
106     return false;
107   }
108 
109  private:
is_metrics_reporting_enabled() const110   bool is_metrics_reporting_enabled() const {
111     return is_metrics_reporting_enabled_;
112   }
113 
114   bool is_metrics_reporting_enabled_;
115   TestingPrefServiceSimple testing_local_state_;
116   scoped_ptr<metrics::MetricsStateManager> metrics_state_manager_;
117   base::MessageLoop message_loop;
118 
119   DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest);
120 };
121 
122 class TestMetricsServiceObserver : public MetricsServiceObserver {
123  public:
TestMetricsServiceObserver()124   TestMetricsServiceObserver(): observed_(0) {}
~TestMetricsServiceObserver()125   virtual ~TestMetricsServiceObserver() {}
126 
OnDidCreateMetricsLog()127   virtual void OnDidCreateMetricsLog() OVERRIDE {
128     ++observed_;
129   }
observed() const130   int observed() const { return observed_; }
131 
132  private:
133   int observed_;
134 
135   DISALLOW_COPY_AND_ASSIGN(TestMetricsServiceObserver);
136 };
137 
138 }  // namespace
139 
TEST_F(MetricsServiceTest,InitialStabilityLogAfterCleanShutDown)140 TEST_F(MetricsServiceTest, InitialStabilityLogAfterCleanShutDown) {
141   EnableMetricsReporting();
142   GetLocalState()->SetBoolean(metrics::prefs::kStabilityExitedCleanly, true);
143 
144   metrics::TestMetricsServiceClient client;
145   TestMetricsService service(
146       GetMetricsStateManager(), &client, GetLocalState());
147   service.InitializeMetricsRecordingState();
148   // No initial stability log should be generated.
149   EXPECT_FALSE(service.log_manager()->has_unsent_logs());
150   EXPECT_FALSE(service.log_manager()->has_staged_log());
151 }
152 
TEST_F(MetricsServiceTest,InitialStabilityLogAfterCrash)153 TEST_F(MetricsServiceTest, InitialStabilityLogAfterCrash) {
154   EnableMetricsReporting();
155   GetLocalState()->ClearPref(metrics::prefs::kStabilityExitedCleanly);
156 
157   // Set up prefs to simulate restarting after a crash.
158 
159   // Save an existing system profile to prefs, to correspond to what would be
160   // saved from a previous session.
161   metrics::TestMetricsServiceClient client;
162   TestMetricsLog log("client", 1, &client, GetLocalState());
163   log.RecordEnvironment(std::vector<metrics::MetricsProvider*>(),
164                         std::vector<variations::ActiveGroupId>());
165 
166   // Record stability build time and version from previous session, so that
167   // stability metrics (including exited cleanly flag) won't be cleared.
168   GetLocalState()->SetInt64(metrics::prefs::kStabilityStatsBuildTime,
169                         MetricsLog::GetBuildTime());
170   GetLocalState()->SetString(metrics::prefs::kStabilityStatsVersion,
171                          client.GetVersionString());
172 
173   GetLocalState()->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false);
174 
175   TestMetricsService service(
176       GetMetricsStateManager(), &client, GetLocalState());
177   service.InitializeMetricsRecordingState();
178 
179   // The initial stability log should be generated and persisted in unsent logs.
180   MetricsLogManager* log_manager = service.log_manager();
181   EXPECT_TRUE(log_manager->has_unsent_logs());
182   EXPECT_FALSE(log_manager->has_staged_log());
183 
184   // Stage the log and retrieve it.
185   log_manager->StageNextLogForUpload();
186   EXPECT_TRUE(log_manager->has_staged_log());
187 
188   std::string uncompressed_log;
189   EXPECT_TRUE(metrics::GzipUncompress(log_manager->staged_log(),
190                                       &uncompressed_log));
191 
192   metrics::ChromeUserMetricsExtension uma_log;
193   EXPECT_TRUE(uma_log.ParseFromString(uncompressed_log));
194 
195   EXPECT_TRUE(uma_log.has_client_id());
196   EXPECT_TRUE(uma_log.has_session_id());
197   EXPECT_TRUE(uma_log.has_system_profile());
198   EXPECT_EQ(0, uma_log.user_action_event_size());
199   EXPECT_EQ(0, uma_log.omnibox_event_size());
200   EXPECT_EQ(0, uma_log.histogram_event_size());
201   EXPECT_EQ(0, uma_log.profiler_event_size());
202   EXPECT_EQ(0, uma_log.perf_data_size());
203 
204   EXPECT_EQ(1, uma_log.system_profile().stability().crash_count());
205 }
206 
TEST_F(MetricsServiceTest,RegisterSyntheticTrial)207 TEST_F(MetricsServiceTest, RegisterSyntheticTrial) {
208   metrics::TestMetricsServiceClient client;
209   MetricsService service(GetMetricsStateManager(), &client, GetLocalState());
210 
211   // Add two synthetic trials and confirm that they show up in the list.
212   SyntheticTrialGroup trial1(metrics::HashName("TestTrial1"),
213                              metrics::HashName("Group1"));
214   service.RegisterSyntheticFieldTrial(trial1);
215 
216   SyntheticTrialGroup trial2(metrics::HashName("TestTrial2"),
217                              metrics::HashName("Group2"));
218   service.RegisterSyntheticFieldTrial(trial2);
219   // Ensure that time has advanced by at least a tick before proceeding.
220   WaitUntilTimeChanges(base::TimeTicks::Now());
221 
222   service.log_manager_.BeginLoggingWithLog(scoped_ptr<MetricsLog>(
223       new MetricsLog("clientID",
224                      1,
225                      MetricsLog::INITIAL_STABILITY_LOG,
226                      &client,
227                      GetLocalState())));
228   // Save the time when the log was started (it's okay for this to be greater
229   // than the time recorded by the above call since it's used to ensure the
230   // value changes).
231   const base::TimeTicks begin_log_time = base::TimeTicks::Now();
232 
233   std::vector<variations::ActiveGroupId> synthetic_trials;
234   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
235   EXPECT_EQ(2U, synthetic_trials.size());
236   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group1"));
237   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
238 
239   // Ensure that time has advanced by at least a tick before proceeding.
240   WaitUntilTimeChanges(begin_log_time);
241 
242   // Change the group for the first trial after the log started.
243   SyntheticTrialGroup trial3(metrics::HashName("TestTrial1"),
244                              metrics::HashName("Group2"));
245   service.RegisterSyntheticFieldTrial(trial3);
246   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
247   EXPECT_EQ(1U, synthetic_trials.size());
248   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
249 
250   // Add a new trial after the log started and confirm that it doesn't show up.
251   SyntheticTrialGroup trial4(metrics::HashName("TestTrial3"),
252                              metrics::HashName("Group3"));
253   service.RegisterSyntheticFieldTrial(trial4);
254   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
255   EXPECT_EQ(1U, synthetic_trials.size());
256   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
257 
258   // Ensure that time has advanced by at least a tick before proceeding.
259   WaitUntilTimeChanges(base::TimeTicks::Now());
260 
261   // Start a new log and ensure all three trials appear in it.
262   service.log_manager_.FinishCurrentLog();
263   service.log_manager_.BeginLoggingWithLog(
264       scoped_ptr<MetricsLog>(new MetricsLog(
265           "clientID", 1, MetricsLog::ONGOING_LOG, &client, GetLocalState())));
266   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
267   EXPECT_EQ(3U, synthetic_trials.size());
268   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2"));
269   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
270   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3"));
271   service.log_manager_.FinishCurrentLog();
272 }
273 
TEST_F(MetricsServiceTest,MetricsServiceObserver)274 TEST_F(MetricsServiceTest, MetricsServiceObserver) {
275   metrics::TestMetricsServiceClient client;
276   MetricsService service(GetMetricsStateManager(), &client, GetLocalState());
277   TestMetricsServiceObserver observer1;
278   TestMetricsServiceObserver observer2;
279 
280   service.AddObserver(&observer1);
281   EXPECT_EQ(0, observer1.observed());
282   EXPECT_EQ(0, observer2.observed());
283 
284   service.OpenNewLog();
285   EXPECT_EQ(1, observer1.observed());
286   EXPECT_EQ(0, observer2.observed());
287   service.log_manager_.FinishCurrentLog();
288 
289   service.AddObserver(&observer2);
290 
291   service.OpenNewLog();
292   EXPECT_EQ(2, observer1.observed());
293   EXPECT_EQ(1, observer2.observed());
294   service.log_manager_.FinishCurrentLog();
295 
296   service.RemoveObserver(&observer1);
297 
298   service.OpenNewLog();
299   EXPECT_EQ(2, observer1.observed());
300   EXPECT_EQ(2, observer2.observed());
301   service.log_manager_.FinishCurrentLog();
302 
303   service.RemoveObserver(&observer2);
304 }
305