1 //
2 // Copyright (C) 2017 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "update_engine/metrics_reporter_omaha.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include <base/time/time.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <metrics/metrics_library_mock.h>
26 
27 #include "update_engine/common/fake_clock.h"
28 #include "update_engine/common/fake_prefs.h"
29 #include "update_engine/fake_system_state.h"
30 
31 using base::TimeDelta;
32 using testing::_;
33 using testing::AnyNumber;
34 using testing::Return;
35 
36 namespace chromeos_update_engine {
37 class MetricsReporterOmahaTest : public ::testing::Test {
38  protected:
39   MetricsReporterOmahaTest() = default;
40 
41   // Reset the metrics_lib_ to a mock library.
42   void SetUp() override {
43     mock_metrics_lib_ = new testing::NiceMock<MetricsLibraryMock>();
44     reporter_.metrics_lib_.reset(mock_metrics_lib_);
45   }
46 
47   testing::NiceMock<MetricsLibraryMock>* mock_metrics_lib_;
48   MetricsReporterOmaha reporter_;
49 };
50 
51 TEST_F(MetricsReporterOmahaTest, ReportDailyMetrics) {
52   TimeDelta age = TimeDelta::FromDays(10);
53   EXPECT_CALL(*mock_metrics_lib_,
54               SendToUMA(metrics::kMetricDailyOSAgeDays, _, _, _, _))
55       .Times(1);
56 
57   reporter_.ReportDailyMetrics(age);
58 }
59 
60 TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetrics) {
61   FakeSystemState fake_system_state;
62   FakeClock fake_clock;
63   FakePrefs fake_prefs;
64 
65   // We need to execute the report twice to test the time since last report.
66   fake_system_state.set_clock(&fake_clock);
67   fake_system_state.set_prefs(&fake_prefs);
68   fake_clock.SetWallclockTime(base::Time::FromInternalValue(1000000));
69   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(1000000));
70 
71   metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
72   metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
73   metrics::DownloadErrorCode error_code =
74       metrics::DownloadErrorCode::kHttpStatus200;
75 
76   EXPECT_CALL(
77       *mock_metrics_lib_,
78       SendEnumToUMA(metrics::kMetricCheckResult, static_cast<int>(result), _))
79       .Times(2);
80   EXPECT_CALL(*mock_metrics_lib_,
81               SendEnumToUMA(
82                   metrics::kMetricCheckReaction, static_cast<int>(reaction), _))
83       .Times(2);
84   EXPECT_CALL(*mock_metrics_lib_,
85               SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode,
86                               static_cast<int>(error_code)))
87       .Times(2);
88 
89   // Not pinned nor rollback
90   EXPECT_CALL(*mock_metrics_lib_,
91               SendSparseToUMA(metrics::kMetricCheckTargetVersion, _))
92       .Times(0);
93   EXPECT_CALL(*mock_metrics_lib_,
94               SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
95       .Times(0);
96 
97   EXPECT_CALL(
98       *mock_metrics_lib_,
99       SendToUMA(metrics::kMetricCheckTimeSinceLastCheckMinutes, 1, _, _, _))
100       .Times(1);
101   EXPECT_CALL(
102       *mock_metrics_lib_,
103       SendToUMA(
104           metrics::kMetricCheckTimeSinceLastCheckUptimeMinutes, 1, _, _, _))
105       .Times(1);
106 
107   reporter_.ReportUpdateCheckMetrics(
108       &fake_system_state, result, reaction, error_code);
109 
110   // Advance the clock by 1 minute and report the same metrics again.
111   fake_clock.SetWallclockTime(base::Time::FromInternalValue(61000000));
112   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(61000000));
113   // Allow rollback
114   reporter_.ReportUpdateCheckMetrics(
115       &fake_system_state, result, reaction, error_code);
116 }
117 
118 TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsPinned) {
119   FakeSystemState fake_system_state;
120 
121   OmahaRequestParams params(&fake_system_state);
122   params.set_target_version_prefix("10575.");
123   params.set_rollback_allowed(false);
124   fake_system_state.set_request_params(&params);
125 
126   metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
127   metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
128   metrics::DownloadErrorCode error_code =
129       metrics::DownloadErrorCode::kHttpStatus200;
130 
131   EXPECT_CALL(*mock_metrics_lib_,
132               SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
133   // Target version set, but not a rollback.
134   EXPECT_CALL(*mock_metrics_lib_,
135               SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
136       .Times(1);
137   EXPECT_CALL(*mock_metrics_lib_,
138               SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
139       .Times(0);
140 
141   reporter_.ReportUpdateCheckMetrics(
142       &fake_system_state, result, reaction, error_code);
143 }
144 
145 TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsRollback) {
146   FakeSystemState fake_system_state;
147 
148   OmahaRequestParams params(&fake_system_state);
149   params.set_target_version_prefix("10575.");
150   params.set_rollback_allowed(true);
151   fake_system_state.set_request_params(&params);
152 
153   metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
154   metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
155   metrics::DownloadErrorCode error_code =
156       metrics::DownloadErrorCode::kHttpStatus200;
157 
158   EXPECT_CALL(*mock_metrics_lib_,
159               SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
160   // Rollback.
161   EXPECT_CALL(*mock_metrics_lib_,
162               SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
163       .Times(1);
164   EXPECT_CALL(
165       *mock_metrics_lib_,
166       SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, 10575))
167       .Times(1);
168 
169   reporter_.ReportUpdateCheckMetrics(
170       &fake_system_state, result, reaction, error_code);
171 }
172 
173 TEST_F(MetricsReporterOmahaTest,
174        ReportAbnormallyTerminatedUpdateAttemptMetrics) {
175   EXPECT_CALL(*mock_metrics_lib_,
176               SendEnumToUMA(metrics::kMetricAttemptResult,
177                             static_cast<int>(
178                                 metrics::AttemptResult::kAbnormalTermination),
179                             _))
180       .Times(1);
181 
182   reporter_.ReportAbnormallyTerminatedUpdateAttemptMetrics();
183 }
184 
185 TEST_F(MetricsReporterOmahaTest, ReportUpdateAttemptMetrics) {
186   FakeSystemState fake_system_state;
187   FakeClock fake_clock;
188   FakePrefs fake_prefs;
189 
190   fake_system_state.set_clock(&fake_clock);
191   fake_system_state.set_prefs(&fake_prefs);
192   fake_clock.SetWallclockTime(base::Time::FromInternalValue(1000000));
193   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(1000000));
194 
195   int attempt_number = 1;
196   PayloadType payload_type = kPayloadTypeFull;
197   TimeDelta duration = TimeDelta::FromMinutes(1000);
198   TimeDelta duration_uptime = TimeDelta::FromMinutes(1000);
199 
200   int64_t payload_size = 100 * kNumBytesInOneMiB;
201 
202   metrics::AttemptResult attempt_result =
203       metrics::AttemptResult::kInternalError;
204   ErrorCode internal_error_code = ErrorCode::kDownloadInvalidMetadataSignature;
205 
206   EXPECT_CALL(*mock_metrics_lib_,
207               SendToUMA(metrics::kMetricAttemptNumber, attempt_number, _, _, _))
208       .Times(2);
209   EXPECT_CALL(*mock_metrics_lib_,
210               SendEnumToUMA(metrics::kMetricAttemptPayloadType,
211                             static_cast<int>(payload_type),
212                             _))
213       .Times(2);
214   EXPECT_CALL(*mock_metrics_lib_,
215               SendToUMA(metrics::kMetricAttemptDurationMinutes,
216                         duration.InMinutes(),
217                         _,
218                         _,
219                         _))
220       .Times(2);
221   EXPECT_CALL(*mock_metrics_lib_,
222               SendToUMA(metrics::kMetricAttemptDurationUptimeMinutes,
223                         duration_uptime.InMinutes(),
224                         _,
225                         _,
226                         _))
227       .Times(2);
228 
229   // Check the report of attempt result.
230   EXPECT_CALL(
231       *mock_metrics_lib_,
232       SendEnumToUMA(
233           metrics::kMetricAttemptResult, static_cast<int>(attempt_result), _))
234       .Times(2);
235   EXPECT_CALL(*mock_metrics_lib_,
236               SendEnumToUMA(metrics::kMetricAttemptInternalErrorCode,
237                             static_cast<int>(internal_error_code),
238                             _))
239       .Times(2);
240   EXPECT_CALL(*mock_metrics_lib_,
241               SendToUMA(metrics::kMetricAttemptPayloadSizeMiB, 100, _, _, _))
242       .Times(2);
243 
244   // Check the duration between two reports.
245   EXPECT_CALL(
246       *mock_metrics_lib_,
247       SendToUMA(metrics::kMetricAttemptTimeSinceLastAttemptMinutes, 1, _, _, _))
248       .Times(1);
249   EXPECT_CALL(
250       *mock_metrics_lib_,
251       SendToUMA(
252           metrics::kMetricAttemptTimeSinceLastAttemptUptimeMinutes, 1, _, _, _))
253       .Times(1);
254 
255   reporter_.ReportUpdateAttemptMetrics(&fake_system_state,
256                                        attempt_number,
257                                        payload_type,
258                                        duration,
259                                        duration_uptime,
260                                        payload_size,
261                                        attempt_result,
262                                        internal_error_code);
263 
264   // Advance the clock by 1 minute and report the same metrics again.
265   fake_clock.SetWallclockTime(base::Time::FromInternalValue(61000000));
266   fake_clock.SetMonotonicTime(base::Time::FromInternalValue(61000000));
267   reporter_.ReportUpdateAttemptMetrics(&fake_system_state,
268                                        attempt_number,
269                                        payload_type,
270                                        duration,
271                                        duration_uptime,
272                                        payload_size,
273                                        attempt_result,
274                                        internal_error_code);
275 }
276 
277 TEST_F(MetricsReporterOmahaTest, ReportUpdateAttemptDownloadMetrics) {
278   int64_t payload_bytes_downloaded = 200 * kNumBytesInOneMiB;
279   int64_t payload_download_speed_bps = 100 * 1000;
280   DownloadSource download_source = kDownloadSourceHttpServer;
281   metrics::DownloadErrorCode payload_download_error_code =
282       metrics::DownloadErrorCode::kDownloadError;
283   metrics::ConnectionType connection_type = metrics::ConnectionType::kCellular;
284 
285   EXPECT_CALL(
286       *mock_metrics_lib_,
287       SendToUMA(metrics::kMetricAttemptPayloadBytesDownloadedMiB, 200, _, _, _))
288       .Times(1);
289   EXPECT_CALL(
290       *mock_metrics_lib_,
291       SendToUMA(metrics::kMetricAttemptPayloadDownloadSpeedKBps, 100, _, _, _))
292       .Times(1);
293   EXPECT_CALL(*mock_metrics_lib_,
294               SendEnumToUMA(metrics::kMetricAttemptDownloadSource,
295                             static_cast<int>(download_source),
296                             _))
297       .Times(1);
298   EXPECT_CALL(*mock_metrics_lib_,
299               SendSparseToUMA(metrics::kMetricAttemptDownloadErrorCode,
300                               static_cast<int>(payload_download_error_code)))
301       .Times(1);
302   EXPECT_CALL(*mock_metrics_lib_,
303               SendEnumToUMA(metrics::kMetricAttemptConnectionType,
304                             static_cast<int>(connection_type),
305                             _))
306       .Times(1);
307 
308   reporter_.ReportUpdateAttemptDownloadMetrics(payload_bytes_downloaded,
309                                                payload_download_speed_bps,
310                                                download_source,
311                                                payload_download_error_code,
312                                                connection_type);
313 }
314 
315 TEST_F(MetricsReporterOmahaTest, ReportSuccessfulUpdateMetrics) {
316   int attempt_count = 3;
317   int updates_abandoned_count = 2;
318   PayloadType payload_type = kPayloadTypeDelta;
319   int64_t payload_size = 200 * kNumBytesInOneMiB;
320   int64_t num_bytes_downloaded[kNumDownloadSources] = {};
321   // 200MiB payload downloaded from HttpsServer.
322   num_bytes_downloaded[0] = 200 * kNumBytesInOneMiB;
323   int download_overhead_percentage = 20;
324   TimeDelta total_duration = TimeDelta::FromMinutes(30);
325   TimeDelta total_duration_uptime = TimeDelta::FromMinutes(20);
326   int reboot_count = 2;
327   int url_switch_count = 2;
328 
329   EXPECT_CALL(
330       *mock_metrics_lib_,
331       SendToUMA(metrics::kMetricSuccessfulUpdatePayloadSizeMiB, 200, _, _, _))
332       .Times(1);
333 
334   // Check the report to both BytesDownloadedMiBHttpsServer and
335   // BytesDownloadedMiB
336   std::string DownloadedMiBMetric =
337       metrics::kMetricSuccessfulUpdateBytesDownloadedMiB;
338   DownloadedMiBMetric += "HttpsServer";
339   EXPECT_CALL(*mock_metrics_lib_, SendToUMA(DownloadedMiBMetric, 200, _, _, _))
340       .Times(1);
341   EXPECT_CALL(
342       *mock_metrics_lib_,
343       SendToUMA(
344           metrics::kMetricSuccessfulUpdateBytesDownloadedMiB, 200, _, _, _))
345       .Times(1);
346 
347   EXPECT_CALL(
348       *mock_metrics_lib_,
349       SendToUMA(
350           metrics::kMetricSuccessfulUpdateDownloadSourcesUsed, 1, _, _, _))
351       .Times(1);
352   EXPECT_CALL(
353       *mock_metrics_lib_,
354       SendToUMA(metrics::kMetricSuccessfulUpdateDownloadOverheadPercentage,
355                 20,
356                 _,
357                 _,
358                 _));
359 
360   EXPECT_CALL(*mock_metrics_lib_,
361               SendToUMA(metrics::kMetricSuccessfulUpdateUrlSwitchCount,
362                         url_switch_count,
363                         _,
364                         _,
365                         _))
366       .Times(1);
367   EXPECT_CALL(
368       *mock_metrics_lib_,
369       SendToUMA(
370           metrics::kMetricSuccessfulUpdateTotalDurationMinutes, 30, _, _, _))
371       .Times(1);
372   EXPECT_CALL(
373       *mock_metrics_lib_,
374       SendToUMA(metrics::kMetricSuccessfulUpdateTotalDurationUptimeMinutes,
375                 20,
376                 _,
377                 _,
378                 _))
379       .Times(1);
380   EXPECT_CALL(
381       *mock_metrics_lib_,
382       SendToUMA(
383           metrics::kMetricSuccessfulUpdateRebootCount, reboot_count, _, _, _))
384       .Times(1);
385   EXPECT_CALL(*mock_metrics_lib_,
386               SendEnumToUMA(
387                   metrics::kMetricSuccessfulUpdatePayloadType, payload_type, _))
388       .Times(1);
389   EXPECT_CALL(
390       *mock_metrics_lib_,
391       SendToUMA(
392           metrics::kMetricSuccessfulUpdateAttemptCount, attempt_count, _, _, _))
393       .Times(1);
394   EXPECT_CALL(*mock_metrics_lib_,
395               SendToUMA(metrics::kMetricSuccessfulUpdateUpdatesAbandonedCount,
396                         updates_abandoned_count,
397                         _,
398                         _,
399                         _))
400       .Times(1);
401 
402   reporter_.ReportSuccessfulUpdateMetrics(attempt_count,
403                                           updates_abandoned_count,
404                                           payload_type,
405                                           payload_size,
406                                           num_bytes_downloaded,
407                                           download_overhead_percentage,
408                                           total_duration,
409                                           total_duration_uptime,
410                                           reboot_count,
411                                           url_switch_count);
412 }
413 
414 TEST_F(MetricsReporterOmahaTest, ReportRollbackMetrics) {
415   metrics::RollbackResult result = metrics::RollbackResult::kSuccess;
416   EXPECT_CALL(*mock_metrics_lib_,
417               SendEnumToUMA(
418                   metrics::kMetricRollbackResult, static_cast<int>(result), _))
419       .Times(1);
420 
421   reporter_.ReportRollbackMetrics(result);
422 }
423 
424 TEST_F(MetricsReporterOmahaTest, ReportEnterpriseRollbackMetrics) {
425   EXPECT_CALL(*mock_metrics_lib_,
426               SendSparseToUMA(metrics::kMetricEnterpriseRollbackSuccess, 10575))
427       .Times(1);
428   EXPECT_CALL(*mock_metrics_lib_,
429               SendSparseToUMA(metrics::kMetricEnterpriseRollbackFailure, 10323))
430       .Times(1);
431 
432   reporter_.ReportEnterpriseRollbackMetrics(/*success=*/true, "10575.39.2");
433   reporter_.ReportEnterpriseRollbackMetrics(/*success=*/false, "10323.67.7");
434 }
435 
436 TEST_F(MetricsReporterOmahaTest, ReportCertificateCheckMetrics) {
437   ServerToCheck server_to_check = ServerToCheck::kUpdate;
438   CertificateCheckResult result = CertificateCheckResult::kValid;
439   EXPECT_CALL(*mock_metrics_lib_,
440               SendEnumToUMA(metrics::kMetricCertificateCheckUpdateCheck,
441                             static_cast<int>(result),
442                             _))
443       .Times(1);
444 
445   reporter_.ReportCertificateCheckMetrics(server_to_check, result);
446 }
447 
448 TEST_F(MetricsReporterOmahaTest, ReportFailedUpdateCount) {
449   int target_attempt = 3;
450   EXPECT_CALL(
451       *mock_metrics_lib_,
452       SendToUMA(metrics::kMetricFailedUpdateCount, target_attempt, _, _, _))
453       .Times(1);
454 
455   reporter_.ReportFailedUpdateCount(target_attempt);
456 }
457 
458 TEST_F(MetricsReporterOmahaTest, ReportTimeToReboot) {
459   int time_to_reboot_minutes = 1000;
460   EXPECT_CALL(
461       *mock_metrics_lib_,
462       SendToUMA(
463           metrics::kMetricTimeToRebootMinutes, time_to_reboot_minutes, _, _, _))
464       .Times(1);
465 
466   reporter_.ReportTimeToReboot(time_to_reboot_minutes);
467 }
468 
469 TEST_F(MetricsReporterOmahaTest, ReportInstallDateProvisioningSource) {
470   int source = 2;
471   int max = 5;
472   EXPECT_CALL(
473       *mock_metrics_lib_,
474       SendEnumToUMA(metrics::kMetricInstallDateProvisioningSource, source, max))
475       .Times(1);
476 
477   reporter_.ReportInstallDateProvisioningSource(source, max);
478 }
479 
480 TEST_F(MetricsReporterOmahaTest, ReportKeyVersionMetrics) {
481   int kernel_min_version = 0x00040002;
482   int kernel_max_rollforward_version = 0xfffffffe;
483   bool kernel_max_rollforward_success = true;
484   EXPECT_CALL(
485       *mock_metrics_lib_,
486       SendSparseToUMA(metrics::kMetricKernelMinVersion, kernel_min_version))
487       .Times(1);
488   EXPECT_CALL(*mock_metrics_lib_,
489               SendSparseToUMA(metrics::kMetricKernelMaxRollforwardVersion,
490                               kernel_max_rollforward_version))
491       .Times(1);
492   EXPECT_CALL(*mock_metrics_lib_,
493               SendBoolToUMA(metrics::kMetricKernelMaxRollforwardSetSuccess,
494                             kernel_max_rollforward_success))
495       .Times(1);
496 
497   reporter_.ReportKeyVersionMetrics(kernel_min_version,
498                                     kernel_max_rollforward_version,
499                                     kernel_max_rollforward_success);
500 }
501 
502 TEST_F(MetricsReporterOmahaTest, ReportEnterpriseUpdateSeenToDownloadDays) {
503   constexpr int kDaysToUpdate = 10;
504   constexpr int kMinBucket = 1;
505   constexpr int kMaxBucket = 6 * 30;  // approximately 6 months
506   constexpr int kNumBuckets = 50;
507 
508   EXPECT_CALL(*mock_metrics_lib_,
509               SendToUMA(metrics::kMetricSuccessfulUpdateDurationFromSeenDays,
510                         kDaysToUpdate,
511                         kMinBucket,
512                         kMaxBucket,
513                         kNumBuckets))
514       .Times(1);
515 
516   reporter_.ReportEnterpriseUpdateSeenToDownloadDays(
517       false /* has_time_restriction_policy */, kDaysToUpdate);
518 }
519 
520 TEST_F(MetricsReporterOmahaTest,
521        ReportEnterpriseTimeRestrictedUpdateSeenToDownloadTime) {
522   const int kDaysToUpdate = 15;
523   constexpr int kMinBucket = 1;
524   constexpr int kMaxBucket = 6 * 30;  // approximately 6 months
525   constexpr int kNumBuckets = 50;
526 
527   EXPECT_CALL(
528       *mock_metrics_lib_,
529       SendToUMA(
530           metrics::kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays,
531           kDaysToUpdate,
532           kMinBucket,
533           kMaxBucket,
534           kNumBuckets))
535       .Times(1);
536 
537   reporter_.ReportEnterpriseUpdateSeenToDownloadDays(
538       true /* has_time_restriction_policy */, kDaysToUpdate);
539 }
540 
541 }  // namespace chromeos_update_engine
542