1 // Copyright 2016 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
5 #include "chromeos/dbus/power/power_manager_client.h"
6
7 #include <map>
8 #include <memory>
9 #include <string>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/location.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/run_loop.h"
18 #include "base/test/bind.h"
19 #include "base/test/power_monitor_test_base.h"
20 #include "base/test/task_environment.h"
21 #include "base/unguessable_token.h"
22 #include "chromeos/dbus/power_manager/suspend.pb.h"
23 #include "chromeos/dbus/power_manager/thermal.pb.h"
24 #include "dbus/mock_bus.h"
25 #include "dbus/mock_object_proxy.h"
26 #include "dbus/object_path.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "third_party/cros_system_api/dbus/service_constants.h"
30
31 using ::testing::_;
32 using ::testing::Return;
33 using ::testing::SaveArg;
34
35 namespace chromeos {
36
37 namespace {
38
39 // Shorthand for a few commonly-used constants.
40 const char* kInterface = power_manager::kPowerManagerInterface;
41 const char* kSuspendImminent = power_manager::kSuspendImminentSignal;
42 const char* kDarkSuspendImminent = power_manager::kDarkSuspendImminentSignal;
43 const char* kHandleSuspendReadiness =
44 power_manager::kHandleSuspendReadinessMethod;
45 const char* kHandleDarkSuspendReadiness =
46 power_manager::kHandleDarkSuspendReadinessMethod;
47
48 // Matcher that verifies that a dbus::Message has member |name|.
49 MATCHER_P(HasMember, name, "") {
50 if (arg->GetMember() != name) {
51 *result_listener << "has member " << arg->GetMember();
52 return false;
53 }
54 return true;
55 }
56
57 // Matcher that verifies that a dbus::MethodCall has member |method_name| and
58 // contains a SuspendReadinessInfo protobuf referring to |suspend_id| and
59 // |delay_id|.
60 MATCHER_P3(IsSuspendReadiness, method_name, suspend_id, delay_id, "") {
61 if (arg->GetMember() != method_name) {
62 *result_listener << "has member " << arg->GetMember();
63 return false;
64 }
65 power_manager::SuspendReadinessInfo proto;
66 if (!dbus::MessageReader(arg).PopArrayOfBytesAsProto(&proto)) {
67 *result_listener << "does not contain SuspendReadinessInfo protobuf";
68 return false;
69 }
70 if (proto.suspend_id() != suspend_id) {
71 *result_listener << "suspend ID is " << proto.suspend_id();
72 return false;
73 }
74 if (proto.delay_id() != delay_id) {
75 *result_listener << "delay ID is " << proto.delay_id();
76 return false;
77 }
78 return true;
79 }
80
81 // Runs |callback| with |response|. Needed due to ResponseCallback expecting a
82 // bare pointer rather than an std::unique_ptr.
RunResponseCallback(dbus::ObjectProxy::ResponseCallback callback,std::unique_ptr<dbus::Response> response)83 void RunResponseCallback(dbus::ObjectProxy::ResponseCallback callback,
84 std::unique_ptr<dbus::Response> response) {
85 std::move(callback).Run(response.get());
86 }
87
88 // Stub implementation of PowerManagerClient::Observer.
89 class TestObserver : public PowerManagerClient::Observer {
90 public:
TestObserver(PowerManagerClient * client)91 explicit TestObserver(PowerManagerClient* client) : client_(client) {
92 client_->AddObserver(this);
93 }
~TestObserver()94 ~TestObserver() override { client_->RemoveObserver(this); }
95
num_suspend_imminent() const96 int num_suspend_imminent() const { return num_suspend_imminent_; }
num_suspend_done() const97 int num_suspend_done() const { return num_suspend_done_; }
num_dark_suspend_imminent() const98 int num_dark_suspend_imminent() const { return num_dark_suspend_imminent_; }
block_suspend_token() const99 const base::UnguessableToken& block_suspend_token() const {
100 return block_suspend_token_;
101 }
ambient_color_temperature() const102 int32_t ambient_color_temperature() const {
103 return ambient_color_temperature_;
104 }
105
set_should_block_suspend(bool take_callback)106 void set_should_block_suspend(bool take_callback) {
107 should_block_suspend_ = take_callback;
108 }
set_run_unblock_suspend_immediately(bool run)109 void set_run_unblock_suspend_immediately(bool run) {
110 run_unblock_suspend_immediately_ = run;
111 }
112
113 // Runs |block_suspend_token_|.
UnblockSuspend()114 bool UnblockSuspend() WARN_UNUSED_RESULT {
115 if (block_suspend_token_.is_empty())
116 return false;
117
118 client_->UnblockSuspend(block_suspend_token_);
119 return true;
120 }
121
122 // PowerManagerClient::Observer:
SuspendImminent(power_manager::SuspendImminent::Reason reason)123 void SuspendImminent(power_manager::SuspendImminent::Reason reason) override {
124 num_suspend_imminent_++;
125 if (should_block_suspend_) {
126 block_suspend_token_ = base::UnguessableToken::Create();
127 client_->BlockSuspend(block_suspend_token_, FROM_HERE.ToString());
128 }
129 if (run_unblock_suspend_immediately_)
130 CHECK(UnblockSuspend());
131 }
SuspendDone(const base::TimeDelta & sleep_duration)132 void SuspendDone(const base::TimeDelta& sleep_duration) override {
133 num_suspend_done_++;
134 }
DarkSuspendImminent()135 void DarkSuspendImminent() override {
136 num_dark_suspend_imminent_++;
137 if (should_block_suspend_) {
138 block_suspend_token_ = base::UnguessableToken::Create();
139 client_->BlockSuspend(block_suspend_token_, FROM_HERE.ToString());
140 }
141 if (run_unblock_suspend_immediately_)
142 CHECK(UnblockSuspend());
143 }
AmbientColorChanged(const int32_t color_temperature)144 void AmbientColorChanged(const int32_t color_temperature) override {
145 ambient_color_temperature_ = color_temperature;
146 }
147
148 private:
149 PowerManagerClient* client_; // Not owned.
150
151 // Number of times SuspendImminent(), SuspendDone(), and DarkSuspendImminent()
152 // have been called.
153 int num_suspend_imminent_ = 0;
154 int num_suspend_done_ = 0;
155 int num_dark_suspend_imminent_ = 0;
156
157 // Should SuspendImminent() and DarkSuspendImminent() call |client_|'s
158 // BlockSuspend() method?
159 bool should_block_suspend_ = false;
160
161 // Should SuspendImminent() and DarkSuspendImminent() unblock the suspend
162 // synchronously after blocking itit? Only has an effect if
163 // |should_block_suspend_| is true.
164 bool run_unblock_suspend_immediately_ = false;
165
166 // When non-empty, the token for the outstanding block-suspend registration.
167 base::UnguessableToken block_suspend_token_;
168
169 // Ambient color temperature
170 int32_t ambient_color_temperature_ = 0;
171 DISALLOW_COPY_AND_ASSIGN(TestObserver);
172 };
173
174 // Stub implementation of PowerManagerClient::RenderProcessManagerDelegate.
175 class TestDelegate : public PowerManagerClient::RenderProcessManagerDelegate {
176 public:
TestDelegate(PowerManagerClient * client)177 explicit TestDelegate(PowerManagerClient* client) {
178 client->SetRenderProcessManagerDelegate(weak_ptr_factory_.GetWeakPtr());
179 }
180 ~TestDelegate() override = default;
181
num_suspend_imminent() const182 int num_suspend_imminent() const { return num_suspend_imminent_; }
num_suspend_done() const183 int num_suspend_done() const { return num_suspend_done_; }
184
185 // PowerManagerClient::RenderProcessManagerDelegate:
SuspendImminent()186 void SuspendImminent() override { num_suspend_imminent_++; }
SuspendDone()187 void SuspendDone() override { num_suspend_done_++; }
188
189 private:
190 // Number of times SuspendImminent() and SuspendDone() have been called.
191 int num_suspend_imminent_ = 0;
192 int num_suspend_done_ = 0;
193
194 base::WeakPtrFactory<TestDelegate> weak_ptr_factory_{this};
195
196 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
197 };
198
199 // Local implementation of base::PowerMonitorTestObserver to add callback to
200 // OnThermalStateChange.
201 class PowerMonitorTestObserverLocal : public base::PowerMonitorTestObserver {
202 public:
203 using base::PowerMonitorTestObserver::PowerMonitorTestObserver;
204
OnThermalStateChange(PowerObserver::DeviceThermalState new_state)205 void OnThermalStateChange(
206 PowerObserver::DeviceThermalState new_state) override {
207 ASSERT_TRUE(cb);
208 base::PowerMonitorTestObserver::OnThermalStateChange(new_state);
209 std::move(cb).Run();
210 }
211
set_cb_for_testing(base::OnceCallback<void ()> cb)212 void set_cb_for_testing(base::OnceCallback<void()> cb) {
213 this->cb = std::move(cb);
214 }
215
216 private:
217 base::OnceCallback<void()> cb;
218
219 DISALLOW_COPY_AND_ASSIGN(PowerMonitorTestObserverLocal);
220 };
221
222 } // namespace
223
224 class PowerManagerClientTest : public testing::Test {
225 public:
226 PowerManagerClientTest() = default;
227 ~PowerManagerClientTest() override = default;
228
SetUp()229 void SetUp() override {
230 dbus::Bus::Options options;
231 options.bus_type = dbus::Bus::SYSTEM;
232 bus_ = new dbus::MockBus(options);
233
234 proxy_ = new dbus::MockObjectProxy(
235 bus_.get(), power_manager::kPowerManagerServiceName,
236 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
237
238 // |client_|'s Init() method should request a proxy for communicating with
239 // powerd.
240 EXPECT_CALL(*bus_,
241 GetObjectProxy(
242 power_manager::kPowerManagerServiceName,
243 dbus::ObjectPath(power_manager::kPowerManagerServicePath)))
244 .WillRepeatedly(Return(proxy_.get()));
245
246 EXPECT_CALL(*bus_, GetDBusTaskRunner())
247 .WillRepeatedly(
248 Return(task_environment_.GetMainThreadTaskRunner().get()));
249 EXPECT_CALL(*bus_, GetOriginTaskRunner())
250 .WillRepeatedly(
251 Return(task_environment_.GetMainThreadTaskRunner().get()));
252
253 // Save |client_|'s signal and name-owner-changed callbacks.
254 EXPECT_CALL(*proxy_, DoConnectToSignal(kInterface, _, _, _))
255 .WillRepeatedly(Invoke(this, &PowerManagerClientTest::ConnectToSignal));
256 EXPECT_CALL(*proxy_, SetNameOwnerChangedCallback(_))
257 .WillRepeatedly(SaveArg<0>(&name_owner_changed_callback_));
258
259 // |client_|'s Init() method should register regular and dark suspend
260 // delays.
261 EXPECT_CALL(
262 *proxy_,
263 DoCallMethod(HasMember(power_manager::kRegisterSuspendDelayMethod), _,
264 _))
265 .WillRepeatedly(
266 Invoke(this, &PowerManagerClientTest::RegisterSuspendDelay));
267 EXPECT_CALL(
268 *proxy_,
269 DoCallMethod(HasMember(power_manager::kRegisterDarkSuspendDelayMethod),
270 _, _))
271 .WillRepeatedly(
272 Invoke(this, &PowerManagerClientTest::RegisterSuspendDelay));
273 // Init should also request a fresh power status.
274 EXPECT_CALL(
275 *proxy_,
276 DoCallMethod(HasMember(power_manager::kGetPowerSupplyPropertiesMethod),
277 _, _));
278 // Init will test for the presence of an ambient light sensor.
279 EXPECT_CALL(
280 *proxy_,
281 DoCallMethod(HasMember(power_manager::kHasAmbientColorDeviceMethod), _,
282 _));
283
284 PowerManagerClient::Initialize(bus_.get());
285 client_ = PowerManagerClient::Get();
286
287 // Execute callbacks posted by Init().
288 base::RunLoop().RunUntilIdle();
289 }
290
TearDown()291 void TearDown() override { PowerManagerClient::Shutdown(); }
292
293 protected:
294 // Synchronously passes |signal| to |client_|'s handler, simulating the signal
295 // being emitted by powerd.
EmitSignal(dbus::Signal * signal)296 void EmitSignal(dbus::Signal* signal) {
297 const std::string signal_name = signal->GetMember();
298 const auto it = signal_callbacks_.find(signal_name);
299 ASSERT_TRUE(it != signal_callbacks_.end())
300 << "Client didn't register for signal " << signal_name;
301 it->second.Run(signal);
302 }
303
304 // Passes a SuspendImminent or DarkSuspendImminent signal to |client_|.
EmitSuspendImminentSignal(const std::string & signal_name,int suspend_id)305 void EmitSuspendImminentSignal(const std::string& signal_name,
306 int suspend_id) {
307 power_manager::SuspendImminent proto;
308 proto.set_suspend_id(suspend_id);
309 proto.set_reason(power_manager::SuspendImminent_Reason_OTHER);
310 dbus::Signal signal(kInterface, signal_name);
311 dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto);
312 EmitSignal(&signal);
313 }
314
315 // Passes a SuspendDone signal to |client_|.
EmitSuspendDoneSignal(int suspend_id)316 void EmitSuspendDoneSignal(int suspend_id) {
317 power_manager::SuspendDone proto;
318 proto.set_suspend_id(suspend_id);
319 dbus::Signal signal(kInterface, power_manager::kSuspendDoneSignal);
320 dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto);
321 EmitSignal(&signal);
322 }
323
324 // Adds an expectation to |proxy_| for a HandleSuspendReadiness or
325 // HandleDarkSuspendReadiness method call.
ExpectSuspendReadiness(const std::string & method_name,int suspend_id,int delay_id)326 void ExpectSuspendReadiness(const std::string& method_name,
327 int suspend_id,
328 int delay_id) {
329 EXPECT_CALL(
330 *proxy_.get(),
331 DoCallMethod(IsSuspendReadiness(method_name, suspend_id, delay_id), _,
332 _));
333 }
334
335 // Arbitrary delay IDs returned to |client_|.
336 static const int kSuspendDelayId = 100;
337 static const int kDarkSuspendDelayId = 200;
338
339 base::test::SingleThreadTaskEnvironment task_environment_;
340
341 // Mock bus and proxy for simulating calls to powerd.
342 scoped_refptr<dbus::MockBus> bus_;
343 scoped_refptr<dbus::MockObjectProxy> proxy_;
344
345 PowerManagerClient* client_ = nullptr;
346
347 // Maps from powerd signal name to the corresponding callback provided by
348 // |client_|.
349 std::map<std::string, dbus::ObjectProxy::SignalCallback> signal_callbacks_;
350
351 // Callback passed to |proxy_|'s SetNameOwnerChangedCallback() method.
352 // TODO(derat): Test that |client_| handles powerd restarts.
353 dbus::ObjectProxy::NameOwnerChangedCallback name_owner_changed_callback_;
354
355 private:
356 // Handles calls to |proxy_|'s ConnectToSignal() method.
ConnectToSignal(const std::string & interface_name,const std::string & signal_name,dbus::ObjectProxy::SignalCallback signal_callback,dbus::ObjectProxy::OnConnectedCallback * on_connected_callback)357 void ConnectToSignal(
358 const std::string& interface_name,
359 const std::string& signal_name,
360 dbus::ObjectProxy::SignalCallback signal_callback,
361 dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
362 CHECK_EQ(interface_name, power_manager::kPowerManagerInterface);
363 signal_callbacks_[signal_name] = signal_callback;
364
365 task_environment_.GetMainThreadTaskRunner()->PostTask(
366 FROM_HERE,
367 base::BindOnce(std::move(*on_connected_callback), interface_name,
368 signal_name, true /* success */));
369 }
370
371 // Handles calls to |proxy_|'s CallMethod() method to register suspend delays.
RegisterSuspendDelay(dbus::MethodCall * method_call,int timeout_ms,dbus::ObjectProxy::ResponseCallback * callback)372 void RegisterSuspendDelay(dbus::MethodCall* method_call,
373 int timeout_ms,
374 dbus::ObjectProxy::ResponseCallback* callback) {
375 power_manager::RegisterSuspendDelayReply proto;
376 proto.set_delay_id(method_call->GetMember() ==
377 power_manager::kRegisterDarkSuspendDelayMethod
378 ? kDarkSuspendDelayId
379 : kSuspendDelayId);
380
381 method_call->SetSerial(123); // Arbitrary but needed by FromMethodCall().
382 std::unique_ptr<dbus::Response> response(
383 dbus::Response::FromMethodCall(method_call));
384 CHECK(dbus::MessageWriter(response.get()).AppendProtoAsArrayOfBytes(proto));
385
386 task_environment_.GetMainThreadTaskRunner()->PostTask(
387 FROM_HERE, base::BindOnce(&RunResponseCallback, std::move(*callback),
388 std::move(response)));
389 }
390
391 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientTest);
392 };
393
394 // Tests that suspend readiness is reported immediately when there are no
395 // observers.
TEST_F(PowerManagerClientTest,ReportSuspendReadinessWithoutObservers)396 TEST_F(PowerManagerClientTest, ReportSuspendReadinessWithoutObservers) {
397 const int kSuspendId = 1;
398 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
399 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
400 EmitSuspendDoneSignal(kSuspendId);
401 }
402
403 // Tests that synchronous observers are notified about impending suspend
404 // attempts and completion.
TEST_F(PowerManagerClientTest,ReportSuspendReadinessWithoutCallbacks)405 TEST_F(PowerManagerClientTest, ReportSuspendReadinessWithoutCallbacks) {
406 TestObserver observer_1(client_);
407 TestObserver observer_2(client_);
408
409 // Observers should be notified when suspend is imminent. Readiness should be
410 // reported synchronously since GetSuspendReadinessCallback() hasn't been
411 // called.
412 const int kSuspendId = 1;
413 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
414 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
415 EXPECT_EQ(1, observer_1.num_suspend_imminent());
416 EXPECT_EQ(0, observer_1.num_suspend_done());
417 EXPECT_EQ(1, observer_2.num_suspend_imminent());
418 EXPECT_EQ(0, observer_2.num_suspend_done());
419
420 EmitSuspendDoneSignal(kSuspendId);
421 EXPECT_EQ(1, observer_1.num_suspend_imminent());
422 EXPECT_EQ(1, observer_1.num_suspend_done());
423 EXPECT_EQ(1, observer_2.num_suspend_imminent());
424 EXPECT_EQ(1, observer_2.num_suspend_done());
425 }
426
427 // Tests that readiness is deferred until asynchronous observers have run their
428 // callbacks.
TEST_F(PowerManagerClientTest,ReportSuspendReadinessWithCallbacks)429 TEST_F(PowerManagerClientTest, ReportSuspendReadinessWithCallbacks) {
430 TestObserver observer_1(client_);
431 observer_1.set_should_block_suspend(true);
432 TestObserver observer_2(client_);
433 observer_2.set_should_block_suspend(true);
434 TestObserver observer_3(client_);
435
436 // When observers call GetSuspendReadinessCallback() from their
437 // SuspendImminent() methods, the HandleSuspendReadiness method call should be
438 // deferred until all callbacks are run.
439 const int kSuspendId = 1;
440 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
441 EXPECT_TRUE(observer_1.UnblockSuspend());
442 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
443 EXPECT_TRUE(observer_2.UnblockSuspend());
444 EmitSuspendDoneSignal(kSuspendId);
445 EXPECT_EQ(1, observer_1.num_suspend_done());
446 EXPECT_EQ(1, observer_2.num_suspend_done());
447 }
448
449 // Tests that RenderProcessManagerDelegate is notified about suspend and resume
450 // in the common case where suspend readiness is reported.
TEST_F(PowerManagerClientTest,NotifyRenderProcessManagerDelegate)451 TEST_F(PowerManagerClientTest, NotifyRenderProcessManagerDelegate) {
452 TestDelegate delegate(client_);
453 TestObserver observer(client_);
454 observer.set_should_block_suspend(true);
455
456 const int kSuspendId = 1;
457 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
458 EXPECT_EQ(0, delegate.num_suspend_imminent());
459 EXPECT_EQ(0, delegate.num_suspend_done());
460
461 // The RenderProcessManagerDelegate should be notified that suspend is
462 // imminent only after observers have reported readiness.
463 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
464 EXPECT_TRUE(observer.UnblockSuspend());
465 EXPECT_EQ(1, delegate.num_suspend_imminent());
466 EXPECT_EQ(0, delegate.num_suspend_done());
467
468 // The delegate should be notified immediately after the attempt completes.
469 EmitSuspendDoneSignal(kSuspendId);
470 EXPECT_EQ(1, delegate.num_suspend_imminent());
471 EXPECT_EQ(1, delegate.num_suspend_done());
472 }
473
474 // Tests that DarkSuspendImminent is handled in a manner similar to
475 // SuspendImminent.
TEST_F(PowerManagerClientTest,ReportDarkSuspendReadiness)476 TEST_F(PowerManagerClientTest, ReportDarkSuspendReadiness) {
477 TestDelegate delegate(client_);
478 TestObserver observer(client_);
479 observer.set_should_block_suspend(true);
480
481 const int kSuspendId = 1;
482 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
483 EXPECT_EQ(1, observer.num_suspend_imminent());
484 EXPECT_EQ(0, delegate.num_suspend_imminent());
485
486 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
487 EXPECT_TRUE(observer.UnblockSuspend());
488 EXPECT_EQ(1, delegate.num_suspend_imminent());
489
490 // The RenderProcessManagerDelegate shouldn't be notified about dark suspend
491 // attempts.
492 const int kDarkSuspendId = 5;
493 EmitSuspendImminentSignal(kDarkSuspendImminent, kDarkSuspendId);
494 EXPECT_EQ(1, observer.num_dark_suspend_imminent());
495 EXPECT_EQ(1, delegate.num_suspend_imminent());
496 EXPECT_EQ(0, delegate.num_suspend_done());
497
498 ExpectSuspendReadiness(kHandleDarkSuspendReadiness, kDarkSuspendId,
499 kDarkSuspendDelayId);
500 EXPECT_TRUE(observer.UnblockSuspend());
501 EXPECT_EQ(0, delegate.num_suspend_done());
502
503 EmitSuspendDoneSignal(kSuspendId);
504 EXPECT_EQ(1, observer.num_suspend_done());
505 EXPECT_EQ(1, delegate.num_suspend_done());
506 }
507
508 // Tests the case where a SuspendDone signal is received while a readiness
509 // callback is still pending.
TEST_F(PowerManagerClientTest,SuspendCancelledWhileCallbackPending)510 TEST_F(PowerManagerClientTest, SuspendCancelledWhileCallbackPending) {
511 TestDelegate delegate(client_);
512 TestObserver observer(client_);
513 observer.set_should_block_suspend(true);
514
515 const int kSuspendId = 1;
516 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
517 EXPECT_EQ(1, observer.num_suspend_imminent());
518
519 // If the suspend attempt completes (probably due to cancellation) before the
520 // observer has run its readiness callback, the observer (but not the
521 // delegate, which hasn't been notified about suspend being imminent yet)
522 // should be notified about completion.
523 EmitSuspendDoneSignal(kSuspendId);
524 EXPECT_EQ(1, observer.num_suspend_done());
525 EXPECT_EQ(0, delegate.num_suspend_done());
526
527 // Ensure that the delegate doesn't receive late notification of suspend being
528 // imminent if the readiness callback runs at this point, since that would
529 // leave the renderers in a frozen state (http://crbug.com/646912). There's an
530 // implicit expectation that powerd doesn't get notified about readiness here,
531 // too.
532 EXPECT_TRUE(observer.UnblockSuspend());
533 EXPECT_EQ(0, delegate.num_suspend_imminent());
534 EXPECT_EQ(0, delegate.num_suspend_done());
535 }
536
537 // Tests the case where a SuspendDone signal is received while a dark suspend
538 // readiness callback is still pending.
TEST_F(PowerManagerClientTest,SuspendDoneWhileDarkSuspendCallbackPending)539 TEST_F(PowerManagerClientTest, SuspendDoneWhileDarkSuspendCallbackPending) {
540 TestDelegate delegate(client_);
541 TestObserver observer(client_);
542 observer.set_should_block_suspend(true);
543
544 const int kSuspendId = 1;
545 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
546 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
547 EXPECT_TRUE(observer.UnblockSuspend());
548 EXPECT_EQ(1, delegate.num_suspend_imminent());
549
550 const int kDarkSuspendId = 5;
551 EmitSuspendImminentSignal(kDarkSuspendImminent, kDarkSuspendId);
552 EXPECT_EQ(1, observer.num_dark_suspend_imminent());
553
554 // The delegate should be notified if the attempt completes now.
555 EmitSuspendDoneSignal(kSuspendId);
556 EXPECT_EQ(1, observer.num_suspend_done());
557 EXPECT_EQ(1, delegate.num_suspend_done());
558
559 // Dark suspend readiness shouldn't be reported even if the callback runs at
560 // this point, since the suspend attempt is already done. The delegate also
561 // shouldn't receive any more calls.
562 EXPECT_TRUE(observer.UnblockSuspend());
563 EXPECT_EQ(1, delegate.num_suspend_imminent());
564 EXPECT_EQ(1, delegate.num_suspend_done());
565 }
566
567 // Tests the case where dark suspend is announced while readiness hasn't been
568 // reported for the initial regular suspend attempt.
TEST_F(PowerManagerClientTest,DarkSuspendImminentWhileCallbackPending)569 TEST_F(PowerManagerClientTest, DarkSuspendImminentWhileCallbackPending) {
570 TestDelegate delegate(client_);
571 TestObserver observer(client_);
572 observer.set_should_block_suspend(true);
573
574 // Announce that suspend is imminent and grab, but don't run, the readiness
575 // callback.
576 const int kSuspendId = 1;
577 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
578 EXPECT_EQ(1, observer.num_suspend_imminent());
579 base::UnguessableToken regular_token = observer.block_suspend_token();
580
581 // Before readiness is reported, announce that dark suspend is imminent.
582 const int kDarkSuspendId = 1;
583 EmitSuspendImminentSignal(kDarkSuspendImminent, kDarkSuspendId);
584 EXPECT_EQ(1, observer.num_dark_suspend_imminent());
585 base::UnguessableToken dark_token = observer.block_suspend_token();
586
587 // Complete the suspend attempt and run both of the earlier callbacks. Neither
588 // should result in readiness being reported.
589 EmitSuspendDoneSignal(kSuspendId);
590 EXPECT_EQ(1, observer.num_suspend_done());
591 client_->UnblockSuspend(regular_token);
592 client_->UnblockSuspend(dark_token);
593 }
594
595 // Tests that PowerManagerClient handles a single observer that requests a
596 // suspend-readiness callback and then runs it synchronously from within
597 // SuspendImminent() instead of running it asynchronously:
598 // http://crosbug.com/p/58295
TEST_F(PowerManagerClientTest,SyncCallbackWithSingleObserver)599 TEST_F(PowerManagerClientTest, SyncCallbackWithSingleObserver) {
600 TestObserver observer(client_);
601 observer.set_should_block_suspend(true);
602 observer.set_run_unblock_suspend_immediately(true);
603
604 const int kSuspendId = 1;
605 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
606 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
607 EmitSuspendDoneSignal(kSuspendId);
608 }
609
610 // Tests the case where one observer reports suspend readiness by running its
611 // callback before a second observer even gets notified about the suspend
612 // attempt. We shouldn't report suspend readiness until the second observer has
613 // been notified and confirmed readiness.
TEST_F(PowerManagerClientTest,SyncCallbackWithMultipleObservers)614 TEST_F(PowerManagerClientTest, SyncCallbackWithMultipleObservers) {
615 TestObserver observer1(client_);
616 observer1.set_should_block_suspend(true);
617 observer1.set_run_unblock_suspend_immediately(true);
618
619 TestObserver observer2(client_);
620 observer2.set_should_block_suspend(true);
621
622 const int kSuspendId = 1;
623 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
624 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
625 EXPECT_TRUE(observer2.UnblockSuspend());
626 EmitSuspendDoneSignal(kSuspendId);
627 }
628
629 // Tests that observers are notified about changes in ambient color temperature.
TEST_F(PowerManagerClientTest,ChangeAmbientColorTemperature)630 TEST_F(PowerManagerClientTest, ChangeAmbientColorTemperature) {
631 TestObserver observer(client_);
632
633 constexpr int32_t kTemperature = 6500;
634 dbus::Signal signal(kInterface,
635 power_manager::kAmbientColorTemperatureChangedSignal);
636 dbus::MessageWriter(&signal).AppendInt32(kTemperature);
637 EmitSignal(&signal);
638
639 EXPECT_EQ(kTemperature, observer.ambient_color_temperature());
640 }
641
642 // Tests that base::PowerMonitor observers are notified about thermal event.
TEST_F(PowerManagerClientTest,ChangeThermalState)643 TEST_F(PowerManagerClientTest, ChangeThermalState) {
644 PowerMonitorTestObserverLocal observer;
645 base::PowerMonitor::AddObserver(&observer);
646
647 base::PowerMonitor::Initialize(
648 std::make_unique<base::PowerMonitorTestSource>());
649
650 typedef struct {
651 power_manager::ThermalEvent::ThermalState dbus_state;
652 base::PowerObserver::DeviceThermalState expected_state;
653 } ThermalDBusTestType;
654 ThermalDBusTestType thermal_states[] = {
655 {.dbus_state = power_manager::ThermalEvent_ThermalState_UNKNOWN,
656 .expected_state = base::PowerObserver::DeviceThermalState::kUnknown},
657 {.dbus_state = power_manager::ThermalEvent_ThermalState_NOMINAL,
658 .expected_state = base::PowerObserver::DeviceThermalState::kNominal},
659 {.dbus_state = power_manager::ThermalEvent_ThermalState_FAIR,
660 .expected_state = base::PowerObserver::DeviceThermalState::kFair},
661 {.dbus_state = power_manager::ThermalEvent_ThermalState_SERIOUS,
662 .expected_state = base::PowerObserver::DeviceThermalState::kSerious},
663 {.dbus_state = power_manager::ThermalEvent_ThermalState_CRITICAL,
664 .expected_state = base::PowerObserver::DeviceThermalState::kCritical},
665 };
666
667 for (const auto& p : thermal_states) {
668 power_manager::ThermalEvent proto;
669 proto.set_thermal_state(p.dbus_state);
670 proto.set_timestamp(0);
671
672 dbus::Signal signal(kInterface, power_manager::kThermalEventSignal);
673 dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto);
674 EmitSignal(&signal);
675
676 base::RunLoop run_loop;
677 observer.set_cb_for_testing(base::BindLambdaForTesting([&] {
678 run_loop.Quit();
679 EXPECT_EQ(observer.last_thermal_state(), p.expected_state);
680 }));
681
682 run_loop.Run();
683 }
684
685 base::PowerMonitor::RemoveObserver(&observer);
686 }
687
688 } // namespace chromeos
689