stylus_metrics_recorder_unittest.cc 15 KB

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