Home | History | Annotate | Download | only in metrics
      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 "chrome/browser/metrics/metrics_service.h"
      6 
      7 #include <ctype.h>
      8 #include <string>
      9 
     10 #include "base/command_line.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "chrome/common/chrome_switches.h"
     13 #include "chrome/common/pref_names.h"
     14 #include "chrome/test/base/scoped_testing_local_state.h"
     15 #include "chrome/test/base/testing_browser_process.h"
     16 #include "components/variations/metrics_util.h"
     17 #include "content/public/common/process_type.h"
     18 #include "content/public/common/webplugininfo.h"
     19 #include "content/public/test/test_browser_thread.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "ui/gfx/size.h"
     22 
     23 #if defined(OS_CHROMEOS)
     24 #include "chromeos/dbus/fake_bluetooth_adapter_client.h"
     25 #include "chromeos/dbus/fake_bluetooth_device_client.h"
     26 #include "chromeos/dbus/fake_bluetooth_input_client.h"
     27 #include "chromeos/dbus/fake_dbus_thread_manager.h"
     28 #endif  // OS_CHROMEOS
     29 
     30 namespace {
     31 
     32 class TestMetricsService : public MetricsService {
     33  public:
     34   TestMetricsService() {}
     35   virtual ~TestMetricsService() {}
     36 
     37   MetricsLogManager* log_manager() {
     38     return &log_manager_;
     39   }
     40 
     41  private:
     42   DISALLOW_COPY_AND_ASSIGN(TestMetricsService);
     43 };
     44 
     45 class TestMetricsLog : public MetricsLog {
     46  public:
     47   TestMetricsLog(const std::string& client_id, int session_id)
     48       : MetricsLog(client_id, session_id) {}
     49   virtual ~TestMetricsLog() {}
     50 
     51  private:
     52   virtual gfx::Size GetScreenSize() const OVERRIDE {
     53     return gfx::Size(1024, 768);
     54   }
     55 
     56   virtual float GetScreenDeviceScaleFactor() const OVERRIDE {
     57     return 1.0f;
     58   }
     59 
     60   virtual int GetScreenCount() const OVERRIDE {
     61     return 1;
     62   }
     63 
     64   DISALLOW_COPY_AND_ASSIGN(TestMetricsLog);
     65 };
     66 
     67 class MetricsServiceTest : public testing::Test {
     68  public:
     69   MetricsServiceTest()
     70       : ui_thread_(content::BrowserThread::UI, &message_loop_),
     71         testing_local_state_(TestingBrowserProcess::GetGlobal()) {
     72 #if defined(OS_CHROMEOS)
     73     chromeos::FakeDBusThreadManager* fake_dbus_thread_manager =
     74         new chromeos::FakeDBusThreadManager;
     75     fake_dbus_thread_manager->SetBluetoothAdapterClient(
     76         scoped_ptr<chromeos::BluetoothAdapterClient>(
     77             new chromeos::FakeBluetoothAdapterClient));
     78     fake_dbus_thread_manager->SetBluetoothDeviceClient(
     79         scoped_ptr<chromeos::BluetoothDeviceClient>(
     80             new chromeos::FakeBluetoothDeviceClient));
     81     fake_dbus_thread_manager->SetBluetoothInputClient(
     82         scoped_ptr<chromeos::BluetoothInputClient>(
     83             new chromeos::FakeBluetoothInputClient));
     84     chromeos::DBusThreadManager::InitializeForTesting(fake_dbus_thread_manager);
     85 #endif  // OS_CHROMEOS
     86   }
     87 
     88   virtual ~MetricsServiceTest() {
     89 #if defined(OS_CHROMEOS)
     90     chromeos::DBusThreadManager::Shutdown();
     91 #endif  // OS_CHROMEOS
     92     MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE);
     93   }
     94 
     95   PrefService* GetLocalState() {
     96     return testing_local_state_.Get();
     97   }
     98 
     99   // Returns true if there is a synthetic trial in the given vector that matches
    100   // the given trial name and trial group; returns false otherwise.
    101   bool HasSyntheticTrial(
    102       const std::vector<chrome_variations::ActiveGroupId>& synthetic_trials,
    103       const std::string& trial_name,
    104       const std::string& trial_group) {
    105     uint32 trial_name_hash = metrics::HashName(trial_name);
    106     uint32 trial_group_hash = metrics::HashName(trial_group);
    107     for (std::vector<chrome_variations::ActiveGroupId>::const_iterator it =
    108              synthetic_trials.begin();
    109          it != synthetic_trials.end(); ++it) {
    110       if ((*it).name == trial_name_hash && (*it).group == trial_group_hash)
    111         return true;
    112     }
    113     return false;
    114   }
    115 
    116  private:
    117   base::MessageLoopForUI message_loop_;
    118   content::TestBrowserThread ui_thread_;
    119   ScopedTestingLocalState testing_local_state_;
    120 
    121   DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest);
    122 };
    123 
    124 }  // namespace
    125 
    126 // Ensure the ClientId is formatted as expected.
    127 TEST_F(MetricsServiceTest, ClientIdCorrectlyFormatted) {
    128   std::string clientid = MetricsService::GenerateClientID();
    129   EXPECT_EQ(36U, clientid.length());
    130 
    131   for (size_t i = 0; i < clientid.length(); ++i) {
    132     char current = clientid[i];
    133     if (i == 8 || i == 13 || i == 18 || i == 23)
    134       EXPECT_EQ('-', current);
    135     else
    136       EXPECT_TRUE(isxdigit(current));
    137   }
    138 }
    139 
    140 TEST_F(MetricsServiceTest, IsPluginProcess) {
    141   EXPECT_TRUE(
    142       MetricsService::IsPluginProcess(content::PROCESS_TYPE_PLUGIN));
    143   EXPECT_TRUE(
    144       MetricsService::IsPluginProcess(content::PROCESS_TYPE_PPAPI_PLUGIN));
    145   EXPECT_FALSE(
    146       MetricsService::IsPluginProcess(content::PROCESS_TYPE_GPU));
    147 }
    148 
    149 TEST_F(MetricsServiceTest, LowEntropySource0NotReset) {
    150   MetricsService service;
    151 
    152   // Get the low entropy source once, to initialize it.
    153   service.GetLowEntropySource();
    154 
    155   // Now, set it to 0 and ensure it doesn't get reset.
    156   service.low_entropy_source_ = 0;
    157   EXPECT_EQ(0, service.GetLowEntropySource());
    158   // Call it another time, just to make sure.
    159   EXPECT_EQ(0, service.GetLowEntropySource());
    160 }
    161 
    162 TEST_F(MetricsServiceTest, PermutedEntropyCacheClearedWhenLowEntropyReset) {
    163   const PrefService::Preference* low_entropy_pref =
    164       GetLocalState()->FindPreference(prefs::kMetricsLowEntropySource);
    165   const char* kCachePrefName = prefs::kMetricsPermutedEntropyCache;
    166   int low_entropy_value = -1;
    167 
    168   // First, generate an initial low entropy source value.
    169   {
    170     EXPECT_TRUE(low_entropy_pref->IsDefaultValue());
    171 
    172     MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE);
    173     MetricsService service;
    174     service.GetLowEntropySource();
    175 
    176     EXPECT_FALSE(low_entropy_pref->IsDefaultValue());
    177     EXPECT_TRUE(low_entropy_pref->GetValue()->GetAsInteger(&low_entropy_value));
    178   }
    179 
    180   // Now, set a dummy value in the permuted entropy cache pref and verify that
    181   // another call to GetLowEntropySource() doesn't clobber it when
    182   // --reset-variation-state wasn't specified.
    183   {
    184     GetLocalState()->SetString(kCachePrefName, "test");
    185 
    186     MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE);
    187     MetricsService service;
    188     service.GetLowEntropySource();
    189 
    190     EXPECT_EQ("test", GetLocalState()->GetString(kCachePrefName));
    191     EXPECT_EQ(low_entropy_value,
    192               GetLocalState()->GetInteger(prefs::kMetricsLowEntropySource));
    193   }
    194 
    195   // Verify that the cache does get reset if --reset-variations-state is passed.
    196   {
    197     CommandLine::ForCurrentProcess()->AppendSwitch(
    198         switches::kResetVariationState);
    199 
    200     MetricsService::SetExecutionPhase(MetricsService::UNINITIALIZED_PHASE);
    201     MetricsService service;
    202     service.GetLowEntropySource();
    203 
    204     EXPECT_TRUE(GetLocalState()->GetString(kCachePrefName).empty());
    205   }
    206 }
    207 
    208 TEST_F(MetricsServiceTest, InitialStabilityLogAfterCleanShutDown) {
    209   base::FieldTrialList field_trial_list(NULL);
    210   base::FieldTrialList::CreateFieldTrial("UMAStability", "SeparateLog");
    211 
    212   GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly, true);
    213 
    214   TestMetricsService service;
    215   service.InitializeMetricsRecordingState(MetricsService::REPORTING_ENABLED);
    216   // No initial stability log should be generated.
    217   EXPECT_FALSE(service.log_manager()->has_unsent_logs());
    218   EXPECT_FALSE(service.log_manager()->has_staged_log());
    219 }
    220 
    221 TEST_F(MetricsServiceTest, InitialStabilityLogAfterCrash) {
    222   base::FieldTrialList field_trial_list(NULL);
    223   base::FieldTrialList::CreateFieldTrial("UMAStability", "SeparateLog");
    224 
    225   GetLocalState()->ClearPref(prefs::kStabilityExitedCleanly);
    226 
    227   // Set up prefs to simulate restarting after a crash.
    228 
    229   // Save an existing system profile to prefs, to correspond to what would be
    230   // saved from a previous session.
    231   TestMetricsLog log("client", 1);
    232   log.RecordEnvironment(std::vector<content::WebPluginInfo>(),
    233                         GoogleUpdateMetrics(),
    234                         std::vector<chrome_variations::ActiveGroupId>());
    235 
    236   // Record stability build time and version from previous session, so that
    237   // stability metrics (including exited cleanly flag) won't be cleared.
    238   GetLocalState()->SetInt64(prefs::kStabilityStatsBuildTime,
    239                             MetricsLog::GetBuildTime());
    240   GetLocalState()->SetString(prefs::kStabilityStatsVersion,
    241                              MetricsLog::GetVersionString());
    242 
    243   GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly, false);
    244 
    245   TestMetricsService service;
    246   service.InitializeMetricsRecordingState(MetricsService::REPORTING_ENABLED);
    247 
    248   // The initial stability log should be generated and persisted in unsent logs.
    249   MetricsLogManager* log_manager = service.log_manager();
    250   EXPECT_TRUE(log_manager->has_unsent_logs());
    251   EXPECT_FALSE(log_manager->has_staged_log());
    252 
    253   // Stage the log and retrieve it.
    254   log_manager->StageNextLogForUpload();
    255   EXPECT_TRUE(log_manager->has_staged_log());
    256 
    257   metrics::ChromeUserMetricsExtension uma_log;
    258   EXPECT_TRUE(uma_log.ParseFromString(log_manager->staged_log_text()));
    259 
    260   EXPECT_TRUE(uma_log.has_client_id());
    261   EXPECT_TRUE(uma_log.has_session_id());
    262   EXPECT_TRUE(uma_log.has_system_profile());
    263   EXPECT_EQ(0, uma_log.user_action_event_size());
    264   EXPECT_EQ(0, uma_log.omnibox_event_size());
    265   EXPECT_EQ(0, uma_log.histogram_event_size());
    266   EXPECT_EQ(0, uma_log.profiler_event_size());
    267   EXPECT_EQ(0, uma_log.perf_data_size());
    268 
    269   EXPECT_EQ(1, uma_log.system_profile().stability().crash_count());
    270 }
    271 
    272 // Crashes on at least Mac and Linux.  http://crbug.com/320433
    273 TEST_F(MetricsServiceTest, DISABLED_RegisterSyntheticTrial) {
    274   MetricsService service;
    275 
    276   // Add two synthetic trials and confirm that they show up in the list.
    277   SyntheticTrialGroup trial1(metrics::HashName("TestTrial1"),
    278                              metrics::HashName("Group1"),
    279                              base::TimeTicks::Now());
    280   service.RegisterSyntheticFieldTrial(trial1);
    281 
    282   SyntheticTrialGroup trial2(metrics::HashName("TestTrial2"),
    283                              metrics::HashName("Group2"),
    284                              base::TimeTicks::Now());
    285   service.RegisterSyntheticFieldTrial(trial2);
    286 
    287   service.log_manager_.BeginLoggingWithLog(new MetricsLog("clientID", 1),
    288                                            MetricsLog::INITIAL_LOG);
    289 
    290   std::vector<chrome_variations::ActiveGroupId> synthetic_trials;
    291   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
    292   EXPECT_EQ(2U, synthetic_trials.size());
    293   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group1"));
    294   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
    295 
    296   // Change the group for the first trial after the log started.
    297   SyntheticTrialGroup trial3(metrics::HashName("TestTrial1"),
    298                              metrics::HashName("Group2"),
    299                              base::TimeTicks::Now());
    300   service.RegisterSyntheticFieldTrial(trial3);
    301   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
    302   EXPECT_EQ(1U, synthetic_trials.size());
    303   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
    304 
    305   // Add a new trial after the log started and confirm that it doesn't show up.
    306   SyntheticTrialGroup trial4(metrics::HashName("TestTrial3"),
    307                              metrics::HashName("Group3"),
    308                              base::TimeTicks::Now());
    309   service.RegisterSyntheticFieldTrial(trial4);
    310   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
    311   EXPECT_EQ(1U, synthetic_trials.size());
    312   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
    313 
    314   // Start a new log.
    315   service.log_manager_.FinishCurrentLog();
    316   service.log_manager_.BeginLoggingWithLog(new MetricsLog("clientID", 1),
    317                                            MetricsLog::ONGOING_LOG);
    318   service.GetCurrentSyntheticFieldTrials(&synthetic_trials);
    319   EXPECT_EQ(3U, synthetic_trials.size());
    320   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2"));
    321   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
    322   EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3"));
    323   service.log_manager_.FinishCurrentLog();
    324 }
    325