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