[go: nahoru, domu]

blob: ac7bbf38e6a8f352d30f503ce61d131c94155707 [file] [log] [blame]
Avi Drissman3a215d1e2022-09-07 19:43:091// Copyright 2021 The Chromium Authors
Kenneth Albanowski0745f0662021-08-27 02:34:342// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/metrics/stylus_metrics_recorder.h"
6
7#include <memory>
8#include <set>
9#include <string>
10
11#include "ash/system/power/peripheral_battery_listener.h"
12#include "ash/system/power/peripheral_battery_tests.h"
13#include "ash/test/ash_test_base.h"
14#include "base/containers/contains.h"
15#include "base/strings/string_piece.h"
16#include "base/strings/string_util.h"
17#include "base/strings/utf_string_conversions.h"
18#include "base/test/metrics/histogram_tester.h"
19#include "testing/gmock/include/gmock/gmock.h"
20
21using BatteryInfo = ash::PeripheralBatteryListener::BatteryInfo;
22
23namespace ash {
24namespace {
25
26const char kHistogramGarageSessionMetric[] =
27 "ChromeOS.FeatureUsage.StylusDetachedFromGarageSession";
28const char kHistogramGarageSessionUsetimeMetric[] =
29 "ChromeOS.FeatureUsage.StylusDetachedFromGarageSession.Usetime";
30const char kHistogramDockSessionMetric[] =
31 "ChromeOS.FeatureUsage.StylusDetachedFromDockSession";
32const char kHistogramDockSessionUsetimeMetric[] =
33 "ChromeOS.FeatureUsage.StylusDetachedFromDockSession.Usetime";
34const char kHistogramGarageOrDockSessionMetric[] =
35 "ChromeOS.FeatureUsage.StylusDetachedFromGarageOrDockSession";
36const char kHistogramGarageOrDockSessionUsetimeMetric[] =
37 "ChromeOS.FeatureUsage.StylusDetachedFromGarageOrDockSession.Usetime";
38
39enum class StylusChargingStyle { kDock, kGarage };
40
41std::string BatteryKey(StylusChargingStyle style) {
42 return (style == StylusChargingStyle::kGarage) ? "garaged-stylus-charger"
43 : "docked-stylus-charger";
44}
45
46// Test fixture for the StylusMetricsRecorder class.
47class StylusMetricsRecorderTest : public AshTestBase {
48 public:
49 StylusMetricsRecorderTest()
50 : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
51 StylusMetricsRecorderTest(const StylusMetricsRecorderTest&) = delete;
52 StylusMetricsRecorderTest& operator=(const StylusMetricsRecorderTest&) =
53 delete;
54 ~StylusMetricsRecorderTest() override = default;
55
56 // AshTestBase:
57
58 void SetUp() override {
59 AshTestBase::SetUp();
60 stylus_metrics_recorder_ = std::make_unique<ash::StylusMetricsRecorder>();
61 histogram_tester_ = std::make_unique<base::HistogramTester>();
62 }
63
64 void TearDown() override {
65 stylus_metrics_recorder_.reset();
66 AshTestBase::TearDown();
67 }
68
69 base::TimeTicks NowTicks() { return task_environment()->NowTicks(); }
70
71 void AdvanceClock(base::TimeDelta delta) {
72 task_environment()->AdvanceClock(delta);
73 }
74
75 BatteryInfo ConstructBatteryInfo(
76 StylusChargingStyle style,
77 BatteryInfo::ChargeStatus charge_status,
78 bool battery_report_eligible = true,
79 BatteryInfo::PeripheralType type =
80 BatteryInfo::PeripheralType::kStylusViaCharger) {
81 const std::string key = BatteryKey(style);
82 const int level = 50;
83 const std::u16string name = base::ASCIIToUTF16("name:" + key);
84 const std::string btaddr = "";
85
86 return BatteryInfo(key, name, level, battery_report_eligible, NowTicks(),
87 type, charge_status, btaddr);
88 }
89
90 void SetChargerState(StylusChargingStyle style,
91 BatteryInfo::ChargeStatus charge_status,
92 bool battery_report_eligible = true,
93 BatteryInfo::PeripheralType type =
94 BatteryInfo::PeripheralType::kStylusViaCharger) {
95 const BatteryInfo info = ConstructBatteryInfo(
96 style, charge_status, battery_report_eligible, type);
97 if (!base::Contains(known_batteries_, info.key)) {
98 stylus_metrics_recorder_->OnAddingBattery(info);
99 known_batteries_.insert(info.key);
100 }
101 stylus_metrics_recorder_->OnUpdatedBatteryLevel(info);
102 }
103
104 void RemoveCharger(StylusChargingStyle style,
105 BatteryInfo::ChargeStatus charge_status,
106 bool battery_report_eligible = true,
107 BatteryInfo::PeripheralType type =
108 BatteryInfo::PeripheralType::kStylusViaCharger) {
109 const BatteryInfo info = ConstructBatteryInfo(
110 style, charge_status, battery_report_eligible, type);
111 if (base::Contains(known_batteries_, info.key)) {
112 stylus_metrics_recorder_->OnRemovingBattery(info);
113 known_batteries_.erase(info.key);
114 }
115 }
116
117 protected:
118 // The test target.
119 std::unique_ptr<StylusMetricsRecorder> stylus_metrics_recorder_;
120
121 // Used to verify recorded data.
122 std::unique_ptr<base::HistogramTester> histogram_tester_;
123
124 // Track whether batteries are known or need to be added.
125 std::set<std::string> known_batteries_;
126};
127
128} // namespace
129
130// Verifies that histogram is not recorded when no events are received.
131TEST_F(StylusMetricsRecorderTest, Baseline) {
132 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionMetric, 0);
133 histogram_tester_->ExpectTotalCount(kHistogramDockSessionMetric, 0);
134 histogram_tester_->ExpectTotalCount(
135 kHistogramGarageOrDockSessionUsetimeMetric, 0);
136 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionUsetimeMetric, 0);
137 histogram_tester_->ExpectTotalCount(kHistogramDockSessionUsetimeMetric, 0);
138 histogram_tester_->ExpectTotalCount(
139 kHistogramGarageOrDockSessionUsetimeMetric, 0);
140}
141
142TEST_F(StylusMetricsRecorderTest, BaselineStayInGarage) {
Peter Kastinge5a38ed2021-10-02 03:06:35143 const base::TimeDelta kTimeSpentCharging = base::Minutes(5);
Kenneth Albanowski0745f0662021-08-27 02:34:34144
145 SetChargerState(StylusChargingStyle::kGarage,
146 BatteryInfo::ChargeStatus::kCharging);
147 AdvanceClock(kTimeSpentCharging);
148 // By removing the battery, we force the stylus_metrics_recorder to close out
149 // the session.
150 RemoveCharger(StylusChargingStyle::kGarage,
151 BatteryInfo::ChargeStatus::kCharging);
152
153 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionMetric, 0);
154 histogram_tester_->ExpectTotalCount(kHistogramDockSessionMetric, 0);
155 histogram_tester_->ExpectTotalCount(kHistogramGarageOrDockSessionMetric, 0);
156
157 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionUsetimeMetric, 0);
158 histogram_tester_->ExpectTotalCount(kHistogramDockSessionUsetimeMetric, 0);
159 histogram_tester_->ExpectTotalCount(
160 kHistogramGarageOrDockSessionUsetimeMetric, 0);
161}
162
163TEST_F(StylusMetricsRecorderTest, BaselineStayInDock) {
Peter Kastinge5a38ed2021-10-02 03:06:35164 const base::TimeDelta kTimeSpentCharging = base::Minutes(5);
Kenneth Albanowski0745f0662021-08-27 02:34:34165
166 SetChargerState(StylusChargingStyle::kDock,
167 BatteryInfo::ChargeStatus::kCharging);
168 AdvanceClock(kTimeSpentCharging);
169 // By removing the battery, we force the stylus_metrics_recorder to close out
170 // the session.
171 RemoveCharger(StylusChargingStyle::kDock,
172 BatteryInfo::ChargeStatus::kCharging);
173
174 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionMetric, 0);
175 histogram_tester_->ExpectTotalCount(kHistogramDockSessionMetric, 0);
176 histogram_tester_->ExpectTotalCount(kHistogramGarageOrDockSessionMetric, 0);
177
178 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionUsetimeMetric, 0);
179 histogram_tester_->ExpectTotalCount(kHistogramDockSessionUsetimeMetric, 0);
180 histogram_tester_->ExpectTotalCount(
181 kHistogramGarageOrDockSessionUsetimeMetric, 0);
182}
183
184TEST_F(StylusMetricsRecorderTest, RemovedFromGarage) {
Peter Kastinge5a38ed2021-10-02 03:06:35185 const base::TimeDelta kTimeSpentInUse = base::Minutes(5);
186 const base::TimeDelta kTimeSpentCharging = base::Minutes(1);
Kenneth Albanowski0745f0662021-08-27 02:34:34187
188 SetChargerState(StylusChargingStyle::kGarage,
189 BatteryInfo::ChargeStatus::kDischarging);
190 AdvanceClock(kTimeSpentInUse);
191 // By removing the battery, we force the stylus_metrics_recorder to close out
192 // the session.
193 SetChargerState(StylusChargingStyle::kGarage,
194 BatteryInfo::ChargeStatus::kCharging);
195 // Step time further when we're back on charge, to make sure this time is not
196 // counted
197 AdvanceClock(kTimeSpentCharging);
198 RemoveCharger(StylusChargingStyle::kGarage,
199 BatteryInfo::ChargeStatus::kCharging);
200
201 histogram_tester_->ExpectTotalCount(kHistogramDockSessionMetric, 0);
202
203 histogram_tester_->ExpectBucketCount(
204 kHistogramGarageSessionMetric,
205 static_cast<int>(
206 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
207 1);
208 histogram_tester_->ExpectBucketCount(
209 kHistogramGarageSessionMetric,
210 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEnabled), 1);
211 histogram_tester_->ExpectBucketCount(
212 kHistogramGarageSessionMetric,
213 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEligible),
214 1);
215
216 histogram_tester_->ExpectBucketCount(
217 kHistogramGarageOrDockSessionMetric,
218 static_cast<int>(
219 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
220 1);
221 histogram_tester_->ExpectBucketCount(
222 kHistogramGarageOrDockSessionMetric,
223 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEnabled), 1);
224 histogram_tester_->ExpectBucketCount(
225 kHistogramGarageOrDockSessionMetric,
226 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEligible),
227 1);
228
229 histogram_tester_->ExpectTimeBucketCount(kHistogramGarageSessionUsetimeMetric,
230 kTimeSpentInUse, 1);
231 histogram_tester_->ExpectTimeBucketCount(
232 kHistogramGarageOrDockSessionUsetimeMetric, kTimeSpentInUse, 1);
233}
234
235TEST_F(StylusMetricsRecorderTest, RemovedFromDock) {
Peter Kastinge5a38ed2021-10-02 03:06:35236 const base::TimeDelta kTimeSpentInUse = base::Minutes(5);
237 const base::TimeDelta kTimeSpentCharging = base::Minutes(1);
Kenneth Albanowski0745f0662021-08-27 02:34:34238
239 SetChargerState(StylusChargingStyle::kDock,
240 BatteryInfo::ChargeStatus::kDischarging);
241 AdvanceClock(kTimeSpentInUse);
242 // By removing the battery, we force the stylus_metrics_recorder to close out
243 // the session.
244 SetChargerState(StylusChargingStyle::kDock,
245 BatteryInfo::ChargeStatus::kCharging);
246 // Step time further when we're back on charge, to make sure this time is not
247 // counted
248 AdvanceClock(kTimeSpentCharging);
249 RemoveCharger(StylusChargingStyle::kDock,
250 BatteryInfo::ChargeStatus::kCharging);
251
252 histogram_tester_->ExpectTotalCount(kHistogramGarageSessionMetric, 0);
253
254 histogram_tester_->ExpectBucketCount(
255 kHistogramDockSessionMetric,
256 static_cast<int>(
257 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
258 1);
259 histogram_tester_->ExpectBucketCount(
260 kHistogramDockSessionMetric,
261 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEnabled), 1);
262 histogram_tester_->ExpectBucketCount(
263 kHistogramDockSessionMetric,
264 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEligible),
265 1);
266
267 histogram_tester_->ExpectBucketCount(
268 kHistogramGarageOrDockSessionMetric,
269 static_cast<int>(
270 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
271 1);
272 histogram_tester_->ExpectBucketCount(
273 kHistogramGarageOrDockSessionMetric,
274 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEnabled), 1);
275 histogram_tester_->ExpectBucketCount(
276 kHistogramGarageOrDockSessionMetric,
277 static_cast<int>(feature_usage::FeatureUsageMetrics::Event::kEligible),
278 1);
279
280 histogram_tester_->ExpectTimeBucketCount(kHistogramDockSessionUsetimeMetric,
281 kTimeSpentInUse, 1);
282 histogram_tester_->ExpectTimeBucketCount(
283 kHistogramGarageOrDockSessionUsetimeMetric, kTimeSpentInUse, 1);
284}
285
286TEST_F(StylusMetricsRecorderTest, ShutdownWhileStylusRemoved) {
Peter Kastinge5a38ed2021-10-02 03:06:35287 const base::TimeDelta kTimeSpentInUse = base::Minutes(5);
Kenneth Albanowski0745f0662021-08-27 02:34:34288
289 SetChargerState(StylusChargingStyle::kGarage,
290 BatteryInfo::ChargeStatus::kDischarging);
291 AdvanceClock(kTimeSpentInUse);
292 // By removing the battery, we force the stylus_metrics_recorder to close out
293 // the session.
294 SetChargerState(StylusChargingStyle::kGarage,
295 BatteryInfo::ChargeStatus::kCharging);
296 // Just destroy the recorder, without replacing the stylus; we should still
297 // see the time recorded
298 stylus_metrics_recorder_.reset();
299
300 histogram_tester_->ExpectBucketCount(
301 kHistogramGarageSessionMetric,
302 static_cast<int>(
303 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
304 1);
305
306 histogram_tester_->ExpectTimeBucketCount(kHistogramGarageSessionUsetimeMetric,
307 kTimeSpentInUse, 1);
308}
309
310TEST_F(StylusMetricsRecorderTest, StylusUsageOverMultipleDays) {
Peter Kastinge5a38ed2021-10-02 03:06:35311 const base::TimeDelta kTimeSpentInUse = base::Hours(48);
Kenneth Albanowski0745f0662021-08-27 02:34:34312
313 SetChargerState(StylusChargingStyle::kGarage,
314 BatteryInfo::ChargeStatus::kDischarging);
315 AdvanceClock(kTimeSpentInUse);
316 RemoveCharger(StylusChargingStyle::kGarage,
317 BatteryInfo::ChargeStatus::kCharging);
318
319 histogram_tester_->ExpectBucketCount(
320 kHistogramGarageSessionMetric,
321 static_cast<int>(
322 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
323 1);
324
325 histogram_tester_->ExpectTimeBucketCount(kHistogramGarageSessionUsetimeMetric,
326 kTimeSpentInUse, 1);
327}
328
329TEST_F(StylusMetricsRecorderTest, StylusChargeSequencing) {
Peter Kastinge5a38ed2021-10-02 03:06:35330 const base::TimeDelta kTimeSpentTrickleCharging = base::Minutes(1);
331 const base::TimeDelta kTimeSpentCharging = base::Minutes(60);
332 const base::TimeDelta kTimeSpentFull = base::Minutes(5);
333 const base::TimeDelta kTimeSpentDischarging = base::Minutes(60);
Kenneth Albanowski0745f0662021-08-27 02:34:34334 const int kCycles = 2;
335
336 // Initial state, stylus is garage, charging, not in use
337 SetChargerState(StylusChargingStyle::kGarage,
338 BatteryInfo::ChargeStatus::kCharging);
339
340 for (int cycle = 0; cycle < kCycles; cycle++) {
341 SetChargerState(StylusChargingStyle::kGarage,
342 BatteryInfo::ChargeStatus::kCharging);
343 AdvanceClock(kTimeSpentTrickleCharging);
344 SetChargerState(StylusChargingStyle::kGarage,
345 BatteryInfo::ChargeStatus::kCharging);
346 AdvanceClock(kTimeSpentCharging);
347 SetChargerState(StylusChargingStyle::kGarage,
348 BatteryInfo::ChargeStatus::kFull);
349 AdvanceClock(kTimeSpentFull);
350 // Stylus is removed from garage when it starts discharging
351 SetChargerState(StylusChargingStyle::kGarage,
352 BatteryInfo::ChargeStatus::kDischarging);
353 AdvanceClock(kTimeSpentDischarging);
354 }
355
356 // Final state, same as initial
357 SetChargerState(StylusChargingStyle::kGarage,
358 BatteryInfo::ChargeStatus::kCharging);
359
360 histogram_tester_->ExpectBucketCount(
361 kHistogramGarageSessionMetric,
362 static_cast<int>(
363 feature_usage::FeatureUsageMetrics::Event::kUsedWithSuccess),
364 kCycles);
365
366 histogram_tester_->ExpectTimeBucketCount(kHistogramGarageSessionUsetimeMetric,
367 kTimeSpentDischarging, kCycles);
368}
369
370} // namespace ash