// // 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 #include #include #include #include #include #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(); reporter_.metrics_lib_.reset(mock_metrics_lib_); } testing::NiceMock* 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(result), _)) .Times(2); EXPECT_CALL(*mock_metrics_lib_, SendEnumToUMA( metrics::kMetricCheckReaction, static_cast(reaction), _)) .Times(2); EXPECT_CALL(*mock_metrics_lib_, SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, static_cast(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( 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(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(attempt_result), _)) .Times(2); EXPECT_CALL(*mock_metrics_lib_, SendEnumToUMA(metrics::kMetricAttemptInternalErrorCode, static_cast(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(download_source), _)) .Times(1); EXPECT_CALL(*mock_metrics_lib_, SendSparseToUMA(metrics::kMetricAttemptDownloadErrorCode, static_cast(payload_download_error_code))) .Times(1); EXPECT_CALL(*mock_metrics_lib_, SendEnumToUMA(metrics::kMetricAttemptConnectionType, static_cast(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(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(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); } TEST_F(MetricsReporterOmahaTest, ReportEnterpriseUpdateSeenToDownloadDays) { constexpr int kDaysToUpdate = 10; constexpr int kMinBucket = 1; constexpr int kMaxBucket = 6 * 30; // approximately 6 months constexpr int kNumBuckets = 50; EXPECT_CALL(*mock_metrics_lib_, SendToUMA(metrics::kMetricSuccessfulUpdateDurationFromSeenDays, kDaysToUpdate, kMinBucket, kMaxBucket, kNumBuckets)) .Times(1); reporter_.ReportEnterpriseUpdateSeenToDownloadDays( false /* has_time_restriction_policy */, kDaysToUpdate); } TEST_F(MetricsReporterOmahaTest, ReportEnterpriseTimeRestrictedUpdateSeenToDownloadTime) { const int kDaysToUpdate = 15; constexpr int kMinBucket = 1; constexpr int kMaxBucket = 6 * 30; // approximately 6 months constexpr int kNumBuckets = 50; EXPECT_CALL( *mock_metrics_lib_, SendToUMA( metrics::kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays, kDaysToUpdate, kMinBucket, kMaxBucket, kNumBuckets)) .Times(1); reporter_.ReportEnterpriseUpdateSeenToDownloadDays( true /* has_time_restriction_policy */, kDaysToUpdate); } } // namespace chromeos_update_engine