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