| // | 
 | // Copyright (C) 2017 The Android Open Source Project | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 | // | 
 |  | 
 | #include "update_engine/metrics_reporter_omaha.h" | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include <base/time/time.h> | 
 | #include <gmock/gmock.h> | 
 | #include <gtest/gtest.h> | 
 | #include <metrics/metrics_library_mock.h> | 
 |  | 
 | #include "update_engine/common/fake_clock.h" | 
 | #include "update_engine/common/fake_prefs.h" | 
 | #include "update_engine/fake_system_state.h" | 
 |  | 
 | using base::TimeDelta; | 
 | using testing::_; | 
 | using testing::AnyNumber; | 
 | using testing::Return; | 
 |  | 
 | namespace chromeos_update_engine { | 
 | class MetricsReporterOmahaTest : public ::testing::Test { | 
 |  protected: | 
 |   MetricsReporterOmahaTest() = default; | 
 |  | 
 |   // Reset the metrics_lib_ to a mock library. | 
 |   void SetUp() override { | 
 |     mock_metrics_lib_ = new testing::NiceMock<MetricsLibraryMock>(); | 
 |     reporter_.metrics_lib_.reset(mock_metrics_lib_); | 
 |   } | 
 |  | 
 |   testing::NiceMock<MetricsLibraryMock>* mock_metrics_lib_; | 
 |   MetricsReporterOmaha reporter_; | 
 | }; | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportDailyMetrics) { | 
 |   TimeDelta age = TimeDelta::FromDays(10); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricDailyOSAgeDays, _, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportDailyMetrics(age); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetrics) { | 
 |   FakeSystemState fake_system_state; | 
 |   FakeClock fake_clock; | 
 |   FakePrefs fake_prefs; | 
 |  | 
 |   // We need to execute the report twice to test the time since last report. | 
 |   fake_system_state.set_clock(&fake_clock); | 
 |   fake_system_state.set_prefs(&fake_prefs); | 
 |   fake_clock.SetWallclockTime(base::Time::FromInternalValue(1000000)); | 
 |   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(1000000)); | 
 |  | 
 |   metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable; | 
 |   metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored; | 
 |   metrics::DownloadErrorCode error_code = | 
 |       metrics::DownloadErrorCode::kHttpStatus200; | 
 |  | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendEnumToUMA(metrics::kMetricCheckResult, static_cast<int>(result), _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA( | 
 |                   metrics::kMetricCheckReaction, static_cast<int>(reaction), _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, | 
 |                               static_cast<int>(error_code))) | 
 |       .Times(2); | 
 |  | 
 |   // Not pinned nor rollback | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckTargetVersion, _)) | 
 |       .Times(0); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _)) | 
 |       .Times(0); | 
 |  | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricCheckTimeSinceLastCheckMinutes, 1, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricCheckTimeSinceLastCheckUptimeMinutes, 1, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportUpdateCheckMetrics( | 
 |       &fake_system_state, result, reaction, error_code); | 
 |  | 
 |   // Advance the clock by 1 minute and report the same metrics again. | 
 |   fake_clock.SetWallclockTime(base::Time::FromInternalValue(61000000)); | 
 |   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(61000000)); | 
 |   // Allow rollback | 
 |   reporter_.ReportUpdateCheckMetrics( | 
 |       &fake_system_state, result, reaction, error_code); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsPinned) { | 
 |   FakeSystemState fake_system_state; | 
 |  | 
 |   OmahaRequestParams params(&fake_system_state); | 
 |   params.set_target_version_prefix("10575."); | 
 |   params.set_rollback_allowed(false); | 
 |   fake_system_state.set_request_params(¶ms); | 
 |  | 
 |   metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable; | 
 |   metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored; | 
 |   metrics::DownloadErrorCode error_code = | 
 |       metrics::DownloadErrorCode::kHttpStatus200; | 
 |  | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _)); | 
 |   // Target version set, but not a rollback. | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _)) | 
 |       .Times(0); | 
 |  | 
 |   reporter_.ReportUpdateCheckMetrics( | 
 |       &fake_system_state, result, reaction, error_code); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsRollback) { | 
 |   FakeSystemState fake_system_state; | 
 |  | 
 |   OmahaRequestParams params(&fake_system_state); | 
 |   params.set_target_version_prefix("10575."); | 
 |   params.set_rollback_allowed(true); | 
 |   fake_system_state.set_request_params(¶ms); | 
 |  | 
 |   metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable; | 
 |   metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored; | 
 |   metrics::DownloadErrorCode error_code = | 
 |       metrics::DownloadErrorCode::kHttpStatus200; | 
 |  | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _)); | 
 |   // Rollback. | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, 10575)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportUpdateCheckMetrics( | 
 |       &fake_system_state, result, reaction, error_code); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, | 
 |        ReportAbnormallyTerminatedUpdateAttemptMetrics) { | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA(metrics::kMetricAttemptResult, | 
 |                             static_cast<int>( | 
 |                                 metrics::AttemptResult::kAbnormalTermination), | 
 |                             _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportAbnormallyTerminatedUpdateAttemptMetrics(); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportUpdateAttemptMetrics) { | 
 |   FakeSystemState fake_system_state; | 
 |   FakeClock fake_clock; | 
 |   FakePrefs fake_prefs; | 
 |  | 
 |   fake_system_state.set_clock(&fake_clock); | 
 |   fake_system_state.set_prefs(&fake_prefs); | 
 |   fake_clock.SetWallclockTime(base::Time::FromInternalValue(1000000)); | 
 |   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(1000000)); | 
 |  | 
 |   int attempt_number = 1; | 
 |   PayloadType payload_type = kPayloadTypeFull; | 
 |   TimeDelta duration = TimeDelta::FromMinutes(1000); | 
 |   TimeDelta duration_uptime = TimeDelta::FromMinutes(1000); | 
 |  | 
 |   int64_t payload_size = 100 * kNumBytesInOneMiB; | 
 |  | 
 |   metrics::AttemptResult attempt_result = | 
 |       metrics::AttemptResult::kInternalError; | 
 |   ErrorCode internal_error_code = ErrorCode::kDownloadInvalidMetadataSignature; | 
 |  | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricAttemptNumber, attempt_number, _, _, _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA(metrics::kMetricAttemptPayloadType, | 
 |                             static_cast<int>(payload_type), | 
 |                             _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricAttemptDurationMinutes, | 
 |                         duration.InMinutes(), | 
 |                         _, | 
 |                         _, | 
 |                         _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricAttemptDurationUptimeMinutes, | 
 |                         duration_uptime.InMinutes(), | 
 |                         _, | 
 |                         _, | 
 |                         _)) | 
 |       .Times(2); | 
 |  | 
 |  | 
 |   // Check the report of attempt result. | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendEnumToUMA( | 
 |           metrics::kMetricAttemptResult, static_cast<int>(attempt_result), _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA(metrics::kMetricAttemptInternalErrorCode, | 
 |                             static_cast<int>(internal_error_code), | 
 |                             _)) | 
 |       .Times(2); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricAttemptPayloadSizeMiB, 100, _, _, _)) | 
 |       .Times(2); | 
 |  | 
 |   // Check the duration between two reports. | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricAttemptTimeSinceLastAttemptMinutes, 1, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricAttemptTimeSinceLastAttemptUptimeMinutes, 1, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportUpdateAttemptMetrics(&fake_system_state, | 
 |                                        attempt_number, | 
 |                                        payload_type, | 
 |                                        duration, | 
 |                                        duration_uptime, | 
 |                                        payload_size, | 
 |                                        attempt_result, | 
 |                                        internal_error_code); | 
 |  | 
 |   // Advance the clock by 1 minute and report the same metrics again. | 
 |   fake_clock.SetWallclockTime(base::Time::FromInternalValue(61000000)); | 
 |   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(61000000)); | 
 |   reporter_.ReportUpdateAttemptMetrics(&fake_system_state, | 
 |                                        attempt_number, | 
 |                                        payload_type, | 
 |                                        duration, | 
 |                                        duration_uptime, | 
 |                                        payload_size, | 
 |                                        attempt_result, | 
 |                                        internal_error_code); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportUpdateAttemptDownloadMetrics) { | 
 |   int64_t payload_bytes_downloaded = 200 * kNumBytesInOneMiB; | 
 |   int64_t payload_download_speed_bps = 100 * 1000; | 
 |   DownloadSource download_source = kDownloadSourceHttpServer; | 
 |   metrics::DownloadErrorCode payload_download_error_code = | 
 |       metrics::DownloadErrorCode::kDownloadError; | 
 |   metrics::ConnectionType connection_type = metrics::ConnectionType::kCellular; | 
 |  | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricAttemptPayloadBytesDownloadedMiB, 200, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricAttemptPayloadDownloadSpeedKBps, 100, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA(metrics::kMetricAttemptDownloadSource, | 
 |                             static_cast<int>(download_source), | 
 |                             _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricAttemptDownloadErrorCode, | 
 |                               static_cast<int>(payload_download_error_code))) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA(metrics::kMetricAttemptConnectionType, | 
 |                             static_cast<int>(connection_type), | 
 |                             _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportUpdateAttemptDownloadMetrics(payload_bytes_downloaded, | 
 |                                                payload_download_speed_bps, | 
 |                                                download_source, | 
 |                                                payload_download_error_code, | 
 |                                                connection_type); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportSuccessfulUpdateMetrics) { | 
 |   int attempt_count = 3; | 
 |   int updates_abandoned_count = 2; | 
 |   PayloadType payload_type = kPayloadTypeDelta; | 
 |   int64_t payload_size = 200 * kNumBytesInOneMiB; | 
 |   int64_t num_bytes_downloaded[kNumDownloadSources] = {}; | 
 |   // 200MiB payload downloaded from HttpsServer. | 
 |   num_bytes_downloaded[0] = 200 * kNumBytesInOneMiB; | 
 |   int download_overhead_percentage = 20; | 
 |   TimeDelta total_duration = TimeDelta::FromMinutes(30); | 
 |   TimeDelta total_duration_uptime = TimeDelta::FromMinutes(20); | 
 |   int reboot_count = 2; | 
 |   int url_switch_count = 2; | 
 |  | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricSuccessfulUpdatePayloadSizeMiB, 200, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   // Check the report to both BytesDownloadedMiBHttpsServer and | 
 |   // BytesDownloadedMiB | 
 |   std::string DownloadedMiBMetric = | 
 |       metrics::kMetricSuccessfulUpdateBytesDownloadedMiB; | 
 |   DownloadedMiBMetric += "HttpsServer"; | 
 |   EXPECT_CALL(*mock_metrics_lib_, SendToUMA(DownloadedMiBMetric, 200, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricSuccessfulUpdateBytesDownloadedMiB, 200, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricSuccessfulUpdateDownloadSourcesUsed, 1, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricSuccessfulUpdateDownloadOverheadPercentage, | 
 |                 20, | 
 |                 _, | 
 |                 _, | 
 |                 _)); | 
 |  | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricSuccessfulUpdateUrlSwitchCount, | 
 |                         url_switch_count, | 
 |                         _, | 
 |                         _, | 
 |                         _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricSuccessfulUpdateTotalDurationMinutes, 30, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricSuccessfulUpdateTotalDurationUptimeMinutes, | 
 |                 20, | 
 |                 _, | 
 |                 _, | 
 |                 _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricSuccessfulUpdateRebootCount, reboot_count, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA( | 
 |                   metrics::kMetricSuccessfulUpdatePayloadType, payload_type, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricSuccessfulUpdateAttemptCount, attempt_count, _, _, _)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendToUMA(metrics::kMetricSuccessfulUpdateUpdatesAbandonedCount, | 
 |                         updates_abandoned_count, | 
 |                         _, | 
 |                         _, | 
 |                         _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportSuccessfulUpdateMetrics(attempt_count, | 
 |                                           updates_abandoned_count, | 
 |                                           payload_type, | 
 |                                           payload_size, | 
 |                                           num_bytes_downloaded, | 
 |                                           download_overhead_percentage, | 
 |                                           total_duration, | 
 |                                           total_duration_uptime, | 
 |                                           reboot_count, | 
 |                                           url_switch_count); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportRollbackMetrics) { | 
 |   metrics::RollbackResult result = metrics::RollbackResult::kSuccess; | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA( | 
 |                   metrics::kMetricRollbackResult, static_cast<int>(result), _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportRollbackMetrics(result); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportEnterpriseRollbackMetrics) { | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricEnterpriseRollbackSuccess, 10575)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricEnterpriseRollbackFailure, 10323)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportEnterpriseRollbackMetrics(/*success=*/true, "10575.39.2"); | 
 |   reporter_.ReportEnterpriseRollbackMetrics(/*success=*/false, "10323.67.7"); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportCertificateCheckMetrics) { | 
 |   ServerToCheck server_to_check = ServerToCheck::kUpdate; | 
 |   CertificateCheckResult result = CertificateCheckResult::kValid; | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendEnumToUMA(metrics::kMetricCertificateCheckUpdateCheck, | 
 |                             static_cast<int>(result), | 
 |                             _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportCertificateCheckMetrics(server_to_check, result); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportFailedUpdateCount) { | 
 |   int target_attempt = 3; | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA(metrics::kMetricFailedUpdateCount, target_attempt, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportFailedUpdateCount(target_attempt); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportTimeToReboot) { | 
 |   int time_to_reboot_minutes = 1000; | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendToUMA( | 
 |           metrics::kMetricTimeToRebootMinutes, time_to_reboot_minutes, _, _, _)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportTimeToReboot(time_to_reboot_minutes); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportInstallDateProvisioningSource) { | 
 |   int source = 2; | 
 |   int max = 5; | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendEnumToUMA(metrics::kMetricInstallDateProvisioningSource, source, max)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportInstallDateProvisioningSource(source, max); | 
 | } | 
 |  | 
 | TEST_F(MetricsReporterOmahaTest, ReportKeyVersionMetrics) { | 
 |   int kernel_min_version = 0x00040002; | 
 |   int kernel_max_rollforward_version = 0xfffffffe; | 
 |   bool kernel_max_rollforward_success = true; | 
 |   EXPECT_CALL( | 
 |       *mock_metrics_lib_, | 
 |       SendSparseToUMA(metrics::kMetricKernelMinVersion, kernel_min_version)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendSparseToUMA(metrics::kMetricKernelMaxRollforwardVersion, | 
 |                               kernel_max_rollforward_version)) | 
 |       .Times(1); | 
 |   EXPECT_CALL(*mock_metrics_lib_, | 
 |               SendBoolToUMA(metrics::kMetricKernelMaxRollforwardSetSuccess, | 
 |                             kernel_max_rollforward_success)) | 
 |       .Times(1); | 
 |  | 
 |   reporter_.ReportKeyVersionMetrics(kernel_min_version, | 
 |                                     kernel_max_rollforward_version, | 
 |                                     kernel_max_rollforward_success); | 
 | } | 
 |  | 
 | }  // namespace chromeos_update_engine |