xref: /aosp_15_r20/external/cronet/base/power_monitor/battery_state_sampler_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/power_monitor/battery_state_sampler.h"
6 
7 #include <queue>
8 #include <utility>
9 
10 #include "base/power_monitor/power_monitor_buildflags.h"
11 #include "base/power_monitor/sampling_event_source.h"
12 #include "base/run_loop.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/test/bind.h"
15 #include "base/test/gtest_util.h"
16 #include "base/test/power_monitor_test_utils.h"
17 #include "base/test/task_environment.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 
20 namespace base {
21 
22 class TestBatteryLevelProvider : public BatteryLevelProvider {
23  public:
24   TestBatteryLevelProvider() = default;
25   ~TestBatteryLevelProvider() override = default;
26 
GetBatteryState(OnceCallback<void (const std::optional<BatteryState> &)> callback)27   void GetBatteryState(OnceCallback<void(const std::optional<BatteryState>&)>
28                            callback) override {
29     DCHECK(!battery_states_.empty());
30 
31     auto next_battery_state = std::move(battery_states_.front());
32     battery_states_.pop();
33 
34     std::move(callback).Run(next_battery_state);
35   }
36 
PushBatteryState(const std::optional<BatteryState> & battery_state)37   void PushBatteryState(const std::optional<BatteryState>& battery_state) {
38     battery_states_.push(battery_state);
39   }
40 
41  protected:
42   std::queue<std::optional<BatteryState>> battery_states_;
43 };
44 
45 class TestBatteryLevelProviderAsync : public TestBatteryLevelProvider {
46  public:
47   TestBatteryLevelProviderAsync() = default;
48   ~TestBatteryLevelProviderAsync() override = default;
49 
GetBatteryState(OnceCallback<void (const std::optional<BatteryState> &)> callback)50   void GetBatteryState(OnceCallback<void(const std::optional<BatteryState>&)>
51                            callback) override {
52     DCHECK(!battery_states_.empty());
53 
54     auto next_battery_state = std::move(battery_states_.front());
55     battery_states_.pop();
56 
57     SequencedTaskRunner::GetCurrentDefault()->PostTask(
58         FROM_HERE,
59         BindLambdaForTesting([callback = std::move(callback),
60                               battery_state = next_battery_state]() mutable {
61           std::move(callback).Run(battery_state);
62         }));
63   }
64 };
65 
66 // A test observer that exposes the last battery state received.
67 class TestObserver : public BatteryStateSampler::Observer {
68  public:
69   TestObserver() = default;
70   ~TestObserver() override = default;
71 
OnBatteryStateSampled(const std::optional<BatteryLevelProvider::BatteryState> & battery_state)72   void OnBatteryStateSampled(
73       const std::optional<BatteryLevelProvider::BatteryState>& battery_state)
74       override {
75     battery_state_ = battery_state;
76   }
77 
battery_state() const78   std::optional<BatteryLevelProvider::BatteryState> battery_state() const {
79     return battery_state_;
80   }
81 
82  private:
83   std::optional<BatteryLevelProvider::BatteryState> battery_state_;
84 };
85 
86 // Those test battery states just need to be different. The actual values don't
87 // matter.
88 const std::optional<BatteryLevelProvider::BatteryState> kTestBatteryState1 =
89     BatteryLevelProvider::BatteryState{
90         .battery_count = 1,
91         .is_external_power_connected = false,
92         .current_capacity = 10000,
93         .full_charged_capacity = 10000,
94         .charge_unit = BatteryLevelProvider::BatteryLevelUnit::kMWh};
95 const std::optional<BatteryLevelProvider::BatteryState> kTestBatteryState2 =
96     BatteryLevelProvider::BatteryState{
97         .battery_count = 1,
98         .is_external_power_connected = false,
99         .current_capacity = 5000,
100         .full_charged_capacity = 10000,
101         .charge_unit = BatteryLevelProvider::BatteryLevelUnit::kMWh};
102 const std::optional<BatteryLevelProvider::BatteryState> kTestBatteryState3 =
103     BatteryLevelProvider::BatteryState{
104         .battery_count = 1,
105         .is_external_power_connected = true,
106         .current_capacity = 2000,
107         .full_charged_capacity = 10000,
108         .charge_unit = BatteryLevelProvider::BatteryLevelUnit::kMWh};
109 
operator ==(const BatteryLevelProvider::BatteryState & lhs,const BatteryLevelProvider::BatteryState & rhs)110 bool operator==(const BatteryLevelProvider::BatteryState& lhs,
111                 const BatteryLevelProvider::BatteryState& rhs) {
112   return std::tie(lhs.battery_count, lhs.is_external_power_connected,
113                   lhs.current_capacity, lhs.full_charged_capacity,
114                   lhs.charge_unit) ==
115          std::tie(rhs.battery_count, rhs.is_external_power_connected,
116                   rhs.current_capacity, rhs.full_charged_capacity,
117                   rhs.charge_unit);
118 }
119 
operator !=(const BatteryLevelProvider::BatteryState & lhs,const BatteryLevelProvider::BatteryState & rhs)120 bool operator!=(const BatteryLevelProvider::BatteryState& lhs,
121                 const BatteryLevelProvider::BatteryState& rhs) {
122   return !(lhs == rhs);
123 }
124 
TEST(BatteryStateSamplerTest,GlobalInstance)125 TEST(BatteryStateSamplerTest, GlobalInstance) {
126 #if BUILDFLAG(HAS_BATTERY_LEVEL_PROVIDER_IMPL) || BUILDFLAG(IS_CHROMEOS_ASH)
127   // Get() DCHECKs on platforms with a battery level provider if it's called
128   // without being initialized. ChromeOS behaves the same because it has a
129   // `BatteryLevelProvider`, but it doesn't live in base so it doesn't exist in
130   // this test.
131   EXPECT_DCHECK_DEATH(BatteryStateSampler::Get());
132 #else
133   // Get() returns null if the sampler doesn't exist on platforms without a
134   // battery level provider.
135   EXPECT_FALSE(BatteryStateSampler::Get());
136 #endif
137 
138   auto battery_level_provider = std::make_unique<TestBatteryLevelProvider>();
139   battery_level_provider->PushBatteryState(kTestBatteryState1);
140 
141   // Create the sampler.
142   auto battery_state_sampler = std::make_unique<BatteryStateSampler>(
143       std::make_unique<test::TestSamplingEventSource>(),
144       std::move(battery_level_provider));
145 
146   // Now the getter works.
147   EXPECT_TRUE(BatteryStateSampler::Get());
148 
149   // Can't create a second sampler.
150   EXPECT_DCHECK_DEATH({
151     BatteryStateSampler another_battery_state_sampler(
152         std::make_unique<test::TestSamplingEventSource>(),
153         std::make_unique<TestBatteryLevelProvider>());
154   });
155 
156   battery_state_sampler.reset();
157 
158   // The sampler no longer exists.
159 #if BUILDFLAG(HAS_BATTERY_LEVEL_PROVIDER_IMPL) || BUILDFLAG(IS_CHROMEOS_ASH)
160   EXPECT_DCHECK_DEATH(BatteryStateSampler::Get());
161 #else
162   EXPECT_FALSE(BatteryStateSampler::Get());
163 #endif
164 }
165 
TEST(BatteryStateSamplerTest,InitialSample)166 TEST(BatteryStateSamplerTest, InitialSample) {
167   auto sampling_event_source =
168       std::make_unique<test::TestSamplingEventSource>();
169 
170   auto battery_level_provider = std::make_unique<TestBatteryLevelProvider>();
171   // Push the initial battery state that will be queried by the sampler.
172   battery_level_provider->PushBatteryState(kTestBatteryState1);
173 
174   BatteryStateSampler battery_state_sampler(std::move(sampling_event_source),
175                                             std::move(battery_level_provider));
176 
177   TestObserver observer;
178   battery_state_sampler.AddObserver(&observer);
179 
180   EXPECT_EQ(observer.battery_state(), kTestBatteryState1);
181 }
182 
TEST(BatteryStateSamplerTest,MultipleSamples)183 TEST(BatteryStateSamplerTest, MultipleSamples) {
184   auto battery_level_provider = std::make_unique<TestBatteryLevelProvider>();
185   // Push the initial battery state and the first 3 samples after it.
186   battery_level_provider->PushBatteryState(kTestBatteryState1);
187   battery_level_provider->PushBatteryState(kTestBatteryState2);
188   battery_level_provider->PushBatteryState(kTestBatteryState3);
189   battery_level_provider->PushBatteryState(kTestBatteryState1);
190 
191   auto sampling_event_source =
192       std::make_unique<test::TestSamplingEventSource>();
193   auto* sampling_event_source_ptr = sampling_event_source.get();
194 
195   BatteryStateSampler battery_state_sampler(std::move(sampling_event_source),
196                                             std::move(battery_level_provider));
197 
198   TestObserver observer;
199   battery_state_sampler.AddObserver(&observer);
200   EXPECT_EQ(observer.battery_state(), kTestBatteryState1);
201 
202   // Simulate 2 events to trigger 2 more samples.
203   sampling_event_source_ptr->SimulateEvent();
204   EXPECT_EQ(observer.battery_state(), kTestBatteryState2);
205   sampling_event_source_ptr->SimulateEvent();
206   EXPECT_EQ(observer.battery_state(), kTestBatteryState3);
207 
208   battery_state_sampler.RemoveObserver(&observer);
209 
210   // Simulate 1 event and ensure the observer does not receive the new state.
211   sampling_event_source_ptr->SimulateEvent();
212   EXPECT_NE(observer.battery_state(), kTestBatteryState1);
213 }
214 
TEST(BatteryStateSamplerTest,MultipleObservers)215 TEST(BatteryStateSamplerTest, MultipleObservers) {
216   auto battery_level_provider = std::make_unique<TestBatteryLevelProvider>();
217   // Push the initial battery state and the first sample after it.
218   battery_level_provider->PushBatteryState(kTestBatteryState1);
219   battery_level_provider->PushBatteryState(kTestBatteryState2);
220 
221   auto sampling_event_source =
222       std::make_unique<test::TestSamplingEventSource>();
223   auto* sampling_event_source_ptr = sampling_event_source.get();
224 
225   BatteryStateSampler battery_state_sampler(std::move(sampling_event_source),
226                                             std::move(battery_level_provider));
227 
228   // Add 2 observers.
229   TestObserver observer1;
230   battery_state_sampler.AddObserver(&observer1);
231   EXPECT_EQ(observer1.battery_state(), kTestBatteryState1);
232   TestObserver observer2;
233   battery_state_sampler.AddObserver(&observer2);
234   EXPECT_EQ(observer2.battery_state(), kTestBatteryState1);
235 
236   // Simulate an event to get another sample.
237   sampling_event_source_ptr->SimulateEvent();
238   EXPECT_EQ(observer1.battery_state(), kTestBatteryState2);
239   EXPECT_EQ(observer2.battery_state(), kTestBatteryState2);
240 }
241 
242 // Tests that if sampling the battery state is asynchronous (like it is on
243 // Windows), the sampler will correctly notify new observers when the first
244 // sample arrives.
TEST(BatteryStateSamplerTest,InitialSample_Async)245 TEST(BatteryStateSamplerTest, InitialSample_Async) {
246   test::SingleThreadTaskEnvironment task_environment;
247 
248   auto battery_level_provider =
249       std::make_unique<TestBatteryLevelProviderAsync>();
250   // Push the initial battery state.
251   battery_level_provider->PushBatteryState(kTestBatteryState1);
252 
253   auto sampling_event_source =
254       std::make_unique<test::TestSamplingEventSource>();
255 
256   // Creating the sampler starts the first async sample.
257   BatteryStateSampler battery_state_sampler(std::move(sampling_event_source),
258                                             std::move(battery_level_provider));
259 
260   TestObserver observer;
261   battery_state_sampler.AddObserver(&observer);
262   EXPECT_EQ(observer.battery_state(), std::nullopt);
263 
264   RunLoop().RunUntilIdle();
265   EXPECT_EQ(observer.battery_state(), kTestBatteryState1);
266 }
267 
268 }  // namespace base
269