| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/metrics/metrics_service.h" | 5 #include "components/metrics/metrics_service.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <string> | 11 #include <string> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/metrics/metrics_hashes.h" | 16 #include "base/metrics/metrics_hashes.h" |
| 17 #include "base/metrics/statistics_recorder.h" | 17 #include "base/metrics/statistics_recorder.h" |
| 18 #include "base/metrics/user_metrics.h" | 18 #include "base/metrics/user_metrics.h" |
| 19 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
| 20 #include "base/strings/string16.h" | 20 #include "base/strings/string16.h" |
| 21 #include "base/strings/stringprintf.h" | |
| 22 #include "base/test/scoped_feature_list.h" | 21 #include "base/test/scoped_feature_list.h" |
| 23 #include "base/test/test_simple_task_runner.h" | 22 #include "base/test/test_simple_task_runner.h" |
| 24 #include "base/threading/platform_thread.h" | 23 #include "base/threading/platform_thread.h" |
| 25 #include "base/threading/thread_task_runner_handle.h" | 24 #include "base/threading/thread_task_runner_handle.h" |
| 26 #include "components/metrics/client_info.h" | 25 #include "components/metrics/client_info.h" |
| 27 #include "components/metrics/environment_recorder.h" | 26 #include "components/metrics/environment_recorder.h" |
| 28 #include "components/metrics/metrics_log.h" | 27 #include "components/metrics/metrics_log.h" |
| 29 #include "components/metrics/metrics_pref_names.h" | 28 #include "components/metrics/metrics_pref_names.h" |
| 30 #include "components/metrics/metrics_state_manager.h" | 29 #include "components/metrics/metrics_state_manager.h" |
| 31 #include "components/metrics/metrics_upload_scheduler.h" | 30 #include "components/metrics/metrics_upload_scheduler.h" |
| 32 #include "components/metrics/test_enabled_state_provider.h" | 31 #include "components/metrics/test_enabled_state_provider.h" |
| 33 #include "components/metrics/test_metrics_provider.h" | 32 #include "components/metrics/test_metrics_provider.h" |
| 34 #include "components/metrics/test_metrics_service_client.h" | 33 #include "components/metrics/test_metrics_service_client.h" |
| 35 #include "components/prefs/testing_pref_service.h" | 34 #include "components/prefs/testing_pref_service.h" |
| 36 #include "components/variations/active_field_trials.h" | |
| 37 #include "components/variations/metrics_util.h" | |
| 38 #include "components/variations/synthetic_trials_active_group_id_provider.h" | |
| 39 #include "testing/gtest/include/gtest/gtest.h" | 35 #include "testing/gtest/include/gtest/gtest.h" |
| 40 #include "third_party/zlib/google/compression_utils.h" | 36 #include "third_party/zlib/google/compression_utils.h" |
| 41 | 37 |
| 42 namespace metrics { | 38 namespace metrics { |
| 43 | 39 |
| 44 namespace { | 40 namespace { |
| 45 | 41 |
| 46 void StoreNoClientInfoBackup(const ClientInfo& /* client_info */) { | 42 void StoreNoClientInfoBackup(const ClientInfo& /* client_info */) { |
| 47 } | 43 } |
| 48 | 44 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 } | 106 } |
| 111 | 107 |
| 112 PrefService* GetLocalState() { return &testing_local_state_; } | 108 PrefService* GetLocalState() { return &testing_local_state_; } |
| 113 | 109 |
| 114 // Sets metrics reporting as enabled for testing. | 110 // Sets metrics reporting as enabled for testing. |
| 115 void EnableMetricsReporting() { | 111 void EnableMetricsReporting() { |
| 116 enabled_state_provider_->set_consent(true); | 112 enabled_state_provider_->set_consent(true); |
| 117 enabled_state_provider_->set_enabled(true); | 113 enabled_state_provider_->set_enabled(true); |
| 118 } | 114 } |
| 119 | 115 |
| 120 // Waits until base::TimeTicks::Now() no longer equals |value|. This should | |
| 121 // take between 1-15ms per the documented resolution of base::TimeTicks. | |
| 122 void WaitUntilTimeChanges(const base::TimeTicks& value) { | |
| 123 while (base::TimeTicks::Now() == value) { | |
| 124 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 // Returns true if there is a synthetic trial in the given vector that matches | |
| 129 // the given trial name and trial group; returns false otherwise. | |
| 130 bool HasSyntheticTrial( | |
| 131 const std::vector<variations::ActiveGroupId>& synthetic_trials, | |
| 132 const std::string& trial_name, | |
| 133 const std::string& trial_group) { | |
| 134 uint32_t trial_name_hash = HashName(trial_name); | |
| 135 uint32_t trial_group_hash = HashName(trial_group); | |
| 136 for (const variations::ActiveGroupId& trial : synthetic_trials) { | |
| 137 if (trial.name == trial_name_hash && trial.group == trial_group_hash) | |
| 138 return true; | |
| 139 } | |
| 140 return false; | |
| 141 } | |
| 142 | |
| 143 // Finds a histogram with the specified |name_hash| in |histograms|. | 116 // Finds a histogram with the specified |name_hash| in |histograms|. |
| 144 const base::HistogramBase* FindHistogram( | 117 const base::HistogramBase* FindHistogram( |
| 145 const base::StatisticsRecorder::Histograms& histograms, | 118 const base::StatisticsRecorder::Histograms& histograms, |
| 146 uint64_t name_hash) { | 119 uint64_t name_hash) { |
| 147 for (const base::HistogramBase* histogram : histograms) { | 120 for (const base::HistogramBase* histogram : histograms) { |
| 148 if (name_hash == base::HashMetricName(histogram->histogram_name())) | 121 if (name_hash == base::HashMetricName(histogram->histogram_name())) |
| 149 return histogram; | 122 return histogram; |
| 150 } | 123 } |
| 151 return nullptr; | 124 return nullptr; |
| 152 } | 125 } |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 EXPECT_TRUE(uma_log.has_system_profile()); | 311 EXPECT_TRUE(uma_log.has_system_profile()); |
| 339 EXPECT_EQ(0, uma_log.user_action_event_size()); | 312 EXPECT_EQ(0, uma_log.user_action_event_size()); |
| 340 EXPECT_EQ(0, uma_log.omnibox_event_size()); | 313 EXPECT_EQ(0, uma_log.omnibox_event_size()); |
| 341 EXPECT_EQ(0, uma_log.profiler_event_size()); | 314 EXPECT_EQ(0, uma_log.profiler_event_size()); |
| 342 EXPECT_EQ(0, uma_log.perf_data_size()); | 315 EXPECT_EQ(0, uma_log.perf_data_size()); |
| 343 CheckForNonStabilityHistograms(uma_log); | 316 CheckForNonStabilityHistograms(uma_log); |
| 344 | 317 |
| 345 EXPECT_EQ(1, uma_log.system_profile().stability().crash_count()); | 318 EXPECT_EQ(1, uma_log.system_profile().stability().crash_count()); |
| 346 } | 319 } |
| 347 | 320 |
| 348 TEST_F(MetricsServiceTest, RegisterSyntheticTrial) { | |
| 349 TestMetricsServiceClient client; | |
| 350 MetricsService service(GetMetricsStateManager(), &client, GetLocalState()); | |
| 351 | |
| 352 // Add two synthetic trials and confirm that they show up in the list. | |
| 353 variations::SyntheticTrialGroup trial1(HashName("TestTrial1"), | |
| 354 HashName("Group1")); | |
| 355 service.RegisterSyntheticFieldTrial(trial1); | |
| 356 | |
| 357 variations::SyntheticTrialGroup trial2(HashName("TestTrial2"), | |
| 358 HashName("Group2")); | |
| 359 service.RegisterSyntheticFieldTrial(trial2); | |
| 360 // Ensure that time has advanced by at least a tick before proceeding. | |
| 361 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
| 362 | |
| 363 service.log_manager_.BeginLoggingWithLog(std::unique_ptr<MetricsLog>( | |
| 364 new MetricsLog("clientID", 1, MetricsLog::INITIAL_STABILITY_LOG, &client, | |
| 365 GetLocalState()))); | |
| 366 // Save the time when the log was started (it's okay for this to be greater | |
| 367 // than the time recorded by the above call since it's used to ensure the | |
| 368 // value changes). | |
| 369 const base::TimeTicks begin_log_time = base::TimeTicks::Now(); | |
| 370 | |
| 371 std::vector<variations::ActiveGroupId> synthetic_trials; | |
| 372 service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), | |
| 373 &synthetic_trials); | |
| 374 EXPECT_EQ(2U, synthetic_trials.size()); | |
| 375 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group1")); | |
| 376 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
| 377 | |
| 378 // Ensure that time has advanced by at least a tick before proceeding. | |
| 379 WaitUntilTimeChanges(begin_log_time); | |
| 380 | |
| 381 // Change the group for the first trial after the log started. | |
| 382 variations::SyntheticTrialGroup trial3(HashName("TestTrial1"), | |
| 383 HashName("Group2")); | |
| 384 service.RegisterSyntheticFieldTrial(trial3); | |
| 385 service.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials); | |
| 386 EXPECT_EQ(1U, synthetic_trials.size()); | |
| 387 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
| 388 | |
| 389 // Add a new trial after the log started and confirm that it doesn't show up. | |
| 390 variations::SyntheticTrialGroup trial4(HashName("TestTrial3"), | |
| 391 HashName("Group3")); | |
| 392 service.RegisterSyntheticFieldTrial(trial4); | |
| 393 service.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials); | |
| 394 EXPECT_EQ(1U, synthetic_trials.size()); | |
| 395 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
| 396 | |
| 397 // Ensure that time has advanced by at least a tick before proceeding. | |
| 398 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
| 399 | |
| 400 // Start a new log and ensure all three trials appear in it. | |
| 401 service.log_manager_.FinishCurrentLog(service.log_store()); | |
| 402 service.log_manager_.BeginLoggingWithLog( | |
| 403 std::unique_ptr<MetricsLog>(new MetricsLog( | |
| 404 "clientID", 1, MetricsLog::ONGOING_LOG, &client, GetLocalState()))); | |
| 405 service.GetSyntheticFieldTrialsOlderThan( | |
| 406 service.log_manager_.current_log()->creation_time(), &synthetic_trials); | |
| 407 EXPECT_EQ(3U, synthetic_trials.size()); | |
| 408 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2")); | |
| 409 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2")); | |
| 410 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3")); | |
| 411 service.log_manager_.FinishCurrentLog(service.log_store()); | |
| 412 } | |
| 413 | |
| 414 TEST_F(MetricsServiceTest, RegisterSyntheticMultiGroupFieldTrial) { | |
| 415 TestMetricsServiceClient client; | |
| 416 MetricsService service(GetMetricsStateManager(), &client, GetLocalState()); | |
| 417 | |
| 418 // Register a synthetic trial TestTrial1 with groups A and B. | |
| 419 uint32_t trial_name_hash = HashName("TestTrial1"); | |
| 420 std::vector<uint32_t> group_name_hashes = {HashName("A"), HashName("B")}; | |
| 421 service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash, | |
| 422 group_name_hashes); | |
| 423 // Ensure that time has advanced by at least a tick before proceeding. | |
| 424 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
| 425 | |
| 426 service.log_manager_.BeginLoggingWithLog(std::unique_ptr<MetricsLog>( | |
| 427 new MetricsLog("clientID", 1, MetricsLog::INITIAL_STABILITY_LOG, &client, | |
| 428 GetLocalState()))); | |
| 429 | |
| 430 std::vector<variations::ActiveGroupId> synthetic_trials; | |
| 431 service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), | |
| 432 &synthetic_trials); | |
| 433 EXPECT_EQ(2U, synthetic_trials.size()); | |
| 434 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "A")); | |
| 435 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "B")); | |
| 436 | |
| 437 // Change the group for the trial to a single group. | |
| 438 group_name_hashes = {HashName("X")}; | |
| 439 service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash, | |
| 440 group_name_hashes); | |
| 441 // Ensure that time has advanced by at least a tick before proceeding. | |
| 442 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
| 443 | |
| 444 service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), | |
| 445 &synthetic_trials); | |
| 446 EXPECT_EQ(1U, synthetic_trials.size()); | |
| 447 EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "X")); | |
| 448 | |
| 449 // Register a trial with no groups, which should effectively remove the trial. | |
| 450 group_name_hashes.clear(); | |
| 451 service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash, | |
| 452 group_name_hashes); | |
| 453 // Ensure that time has advanced by at least a tick before proceeding. | |
| 454 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
| 455 | |
| 456 service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), | |
| 457 &synthetic_trials); | |
| 458 service.log_manager_.FinishCurrentLog(service.log_store()); | |
| 459 } | |
| 460 | |
| 461 TEST_F(MetricsServiceTest, | 321 TEST_F(MetricsServiceTest, |
| 462 MetricsProviderOnRecordingDisabledCalledOnInitialStop) { | 322 MetricsProviderOnRecordingDisabledCalledOnInitialStop) { |
| 463 TestMetricsServiceClient client; | 323 TestMetricsServiceClient client; |
| 464 TestMetricsService service( | 324 TestMetricsService service( |
| 465 GetMetricsStateManager(), &client, GetLocalState()); | 325 GetMetricsStateManager(), &client, GetLocalState()); |
| 466 | 326 |
| 467 TestMetricsProvider* test_provider = new TestMetricsProvider(); | 327 TestMetricsProvider* test_provider = new TestMetricsProvider(); |
| 468 service.RegisterMetricsProvider( | 328 service.RegisterMetricsProvider( |
| 469 std::unique_ptr<MetricsProvider>(test_provider)); | 329 std::unique_ptr<MetricsProvider>(test_provider)); |
| 470 | 330 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 service.PushExternalLog("Blah"); | 391 service.PushExternalLog("Blah"); |
| 532 client.uploader()->CompleteUpload(200); | 392 client.uploader()->CompleteUpload(200); |
| 533 EXPECT_FALSE(client.uploader()->is_uploading()); | 393 EXPECT_FALSE(client.uploader()->is_uploading()); |
| 534 EXPECT_EQ(2U, task_runner_->NumPendingTasks()); | 394 EXPECT_EQ(2U, task_runner_->NumPendingTasks()); |
| 535 // Upload should start. | 395 // Upload should start. |
| 536 task_runner_->RunPendingTasks(); | 396 task_runner_->RunPendingTasks(); |
| 537 EXPECT_TRUE(client.uploader()->is_uploading()); | 397 EXPECT_TRUE(client.uploader()->is_uploading()); |
| 538 EXPECT_EQ(1U, task_runner_->NumPendingTasks()); | 398 EXPECT_EQ(1U, task_runner_->NumPendingTasks()); |
| 539 } | 399 } |
| 540 | 400 |
| 541 TEST_F(MetricsServiceTest, GetSyntheticFieldTrialActiveGroups) { | |
| 542 TestMetricsServiceClient client; | |
| 543 MetricsService service(GetMetricsStateManager(), &client, GetLocalState()); | |
| 544 | |
| 545 // Instantiate and setup the corresponding singleton observer which tracks the | |
| 546 // creation of all SyntheticTrialGroups. | |
| 547 service.AddSyntheticTrialObserver( | |
| 548 variations::SyntheticTrialsActiveGroupIdProvider::GetInstance()); | |
| 549 | |
| 550 // Add two synthetic trials and confirm that they show up in the list. | |
| 551 variations::SyntheticTrialGroup trial1(HashName("TestTrial1"), | |
| 552 HashName("Group1")); | |
| 553 service.RegisterSyntheticFieldTrial(trial1); | |
| 554 | |
| 555 variations::SyntheticTrialGroup trial2(HashName("TestTrial2"), | |
| 556 HashName("Group2")); | |
| 557 service.RegisterSyntheticFieldTrial(trial2); | |
| 558 | |
| 559 // Ensure that time has advanced by at least a tick before proceeding. | |
| 560 WaitUntilTimeChanges(base::TimeTicks::Now()); | |
| 561 | |
| 562 // Now get the list of currently active groups. | |
| 563 std::vector<std::string> output; | |
| 564 variations::GetSyntheticTrialGroupIdsAsString(&output); | |
| 565 EXPECT_EQ(2U, output.size()); | |
| 566 | |
| 567 std::string trial1_hash = | |
| 568 base::StringPrintf("%x-%x", trial1.id.name, trial1.id.group); | |
| 569 EXPECT_TRUE(base::ContainsValue(output, trial1_hash)); | |
| 570 | |
| 571 std::string trial2_hash = | |
| 572 base::StringPrintf("%x-%x", trial2.id.name, trial2.id.group); | |
| 573 EXPECT_TRUE(base::ContainsValue(output, trial2_hash)); | |
| 574 } | |
| 575 | |
| 576 } // namespace metrics | 401 } // namespace metrics |
| OLD | NEW |