Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(333)

Side by Side Diff: chromeos/dbus/power_manager_client_unittest.cc

Issue 2345593002: chromeos: Add suspend delay tests for PowerManagerClient. (Closed)
Patch Set: remove unneeded ShutdownAndBlock call Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chromeos/dbus/power_manager_client.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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_manager_client.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "chromeos/dbus/power_manager/suspend.pb.h"
17 #include "dbus/mock_bus.h"
18 #include "dbus/mock_object_proxy.h"
19 #include "dbus/object_path.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
23
24 using ::testing::_;
25 using ::testing::Return;
26
27 namespace chromeos {
28
29 namespace {
30
31 // Shorthand for a few commonly-used constants.
32 const char* kInterface = power_manager::kPowerManagerInterface;
33 const char* kSuspendImminent = power_manager::kSuspendImminentSignal;
34 const char* kHandleSuspendReadiness =
35 power_manager::kHandleSuspendReadinessMethod;
36
37 // Matcher that verifies that a dbus::Message has member |name|.
38 MATCHER_P(HasMember, name, "") {
39 if (arg->GetMember() != name) {
40 *result_listener << "has member " << arg->GetMember();
41 return false;
42 }
43 return true;
44 }
45
46 // Matcher that verifies that a dbus::MethodCall has member |method_name| and
47 // contains a SuspendReadinessInfo protobuf referring to |suspend_id| and
48 // |delay_id|.
49 MATCHER_P3(IsSuspendReadiness, method_name, suspend_id, delay_id, "") {
50 if (arg->GetMember() != method_name) {
51 *result_listener << "has member " << arg->GetMember();
52 return false;
53 }
54 power_manager::SuspendReadinessInfo proto;
55 if (!dbus::MessageReader(arg).PopArrayOfBytesAsProto(&proto)) {
56 *result_listener << "does not contain SuspendReadinessInfo protobuf";
57 return false;
58 }
59 if (proto.suspend_id() != suspend_id) {
60 *result_listener << "suspend ID is " << proto.suspend_id();
61 return false;
62 }
63 if (proto.delay_id() != delay_id) {
64 *result_listener << "delay ID is " << proto.delay_id();
65 return false;
66 }
67 return true;
68 }
69
70 // Runs |callback| with |response|. Needed due to ResponseCallback expecting a
71 // bare pointer rather than an std::unique_ptr.
72 void RunResponseCallback(dbus::ObjectProxy::ResponseCallback callback,
73 std::unique_ptr<dbus::Response> response) {
74 callback.Run(response.get());
75 }
76
77 // Stub implementation of PowerManagerClient::Observer.
78 class TestObserver : public PowerManagerClient::Observer {
79 public:
80 explicit TestObserver(PowerManagerClient* client) : client_(client) {
81 client_->AddObserver(this);
82 }
83 ~TestObserver() override { client_->RemoveObserver(this); }
84
85 int num_suspend_imminent() const { return num_suspend_imminent_; }
86 int num_suspend_done() const { return num_suspend_done_; }
87
88 void set_take_suspend_readiness_callback(bool take_callback) {
89 take_suspend_readiness_callback_ = take_callback;
90 }
91
92 // Runs |suspend_readiness_callback_|.
93 bool RunSuspendReadinessCallback() WARN_UNUSED_RESULT {
94 if (suspend_readiness_callback_.is_null())
95 return false;
96
97 auto cb = suspend_readiness_callback_;
98 suspend_readiness_callback_.Reset();
99 cb.Run();
100 return true;
101 }
102
103 // PowerManagerClient::Observer:
104 void SuspendImminent() override {
105 num_suspend_imminent_++;
106 if (take_suspend_readiness_callback_)
107 suspend_readiness_callback_ = client_->GetSuspendReadinessCallback();
108 }
109 void SuspendDone(const base::TimeDelta& sleep_duration) override {
110 num_suspend_done_++;
111 }
112
113 private:
114 PowerManagerClient* client_; // Not owned.
115
116 // Number of times SuspendImminent() and SuspendDone() have been called.
117 int num_suspend_imminent_ = 0;
118 int num_suspend_done_ = 0;
119
120 // Should SuspendImminent() call |client_|'s GetSuspendReadinessCallback()
121 // method?
122 bool take_suspend_readiness_callback_ = false;
123
124 // Callback returned by |client_|'s GetSuspendReadinessCallback() method.
125 base::Closure suspend_readiness_callback_;
126
127 DISALLOW_COPY_AND_ASSIGN(TestObserver);
128 };
129
130 // Stub implementation of PowerManagerClient::RenderProcessManagerDelegate.
131 class TestDelegate : public PowerManagerClient::RenderProcessManagerDelegate {
132 public:
133 TestDelegate(PowerManagerClient* client) : weak_ptr_factory_(this) {
Chirantan Ekbote 2016/09/14 22:31:30 explicit?
Daniel Erat 2016/09/14 22:42:13 whoops, yes. thanks.
134 client->SetRenderProcessManagerDelegate(weak_ptr_factory_.GetWeakPtr());
135 }
136 ~TestDelegate() override {}
137
138 int num_suspend_imminent() const { return num_suspend_imminent_; }
139 int num_suspend_done() const { return num_suspend_done_; }
140
141 // PowerManagerClient::RenderProcessManagerDelegate:
142 void SuspendImminent() override { num_suspend_imminent_++; }
143 void SuspendDone() override { num_suspend_done_++; }
144
145 private:
146 // Number of times SuspendImminent() and SuspendDone() have been called.
147 int num_suspend_imminent_ = 0;
148 int num_suspend_done_ = 0;
149
150 base::WeakPtrFactory<TestDelegate> weak_ptr_factory_;
151
152 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
153 };
154
155 } // namespace
156
157 class PowerManagerClientTest : public testing::Test {
158 public:
159 PowerManagerClientTest() {}
160 ~PowerManagerClientTest() override {}
161
162 void SetUp() override {
163 dbus::Bus::Options options;
164 options.bus_type = dbus::Bus::SYSTEM;
165 bus_ = new dbus::MockBus(options);
166
167 proxy_ = new dbus::MockObjectProxy(
168 bus_.get(), power_manager::kPowerManagerServiceName,
169 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
170
171 // |client_|'s Init() method should request a proxy for communicating with
172 // powerd.
173 EXPECT_CALL(*bus_.get(),
174 GetObjectProxy(
175 power_manager::kPowerManagerServiceName,
176 dbus::ObjectPath(power_manager::kPowerManagerServicePath)))
177 .WillRepeatedly(Return(proxy_.get()));
178
179 // Save |client_|'s signal callbacks.
180 EXPECT_CALL(*proxy_.get(), ConnectToSignal(kInterface, _, _, _))
181 .WillRepeatedly(Invoke(this, &PowerManagerClientTest::ConnectToSignal));
182
183 // |client_|'s Init() method should register regular and dark suspend
184 // delays.
185 EXPECT_CALL(
186 *proxy_.get(),
187 CallMethod(HasMember(power_manager::kRegisterSuspendDelayMethod), _, _))
188 .WillRepeatedly(
189 Invoke(this, &PowerManagerClientTest::RegisterSuspendDelay));
190 EXPECT_CALL(
191 *proxy_.get(),
192 CallMethod(HasMember(power_manager::kRegisterDarkSuspendDelayMethod), _,
193 _))
194 .WillRepeatedly(
195 Invoke(this, &PowerManagerClientTest::RegisterSuspendDelay));
196
197 client_.reset(PowerManagerClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION));
198 client_->Init(bus_.get());
199
200 // Execute callbacks posted by Init().
201 base::RunLoop().RunUntilIdle();
202 }
203
204 void TearDown() override { client_.reset(); }
205
206 protected:
207 // Synchronously passes |signal| to |client_|'s handler, simulating the signal
208 // being emitted by powerd.
209 void EmitSignal(dbus::Signal* signal) {
210 const std::string signal_name = signal->GetMember();
211 const auto it = signal_callbacks_.find(signal_name);
212 ASSERT_TRUE(it != signal_callbacks_.end())
213 << "Client didn't register for signal " << signal_name;
214 it->second.Run(signal);
215 }
216
217 // Passes a SuspendImminent or DarkSuspendImminent signal to |client_|.
218 void EmitSuspendImminentSignal(const std::string& signal_name,
Chirantan Ekbote 2016/09/14 22:31:30 So far all callers of this function pass in kSuspe
Daniel Erat 2016/09/14 22:42:13 yep, exactly. i'll mention dark suspend in the TOD
219 int suspend_id) {
220 power_manager::SuspendImminent proto;
221 proto.set_suspend_id(suspend_id);
222 dbus::Signal signal(kInterface, signal_name);
223 dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto);
224 EmitSignal(&signal);
225 }
226
227 // Passes a SuspendDone signal to |client_|.
228 void EmitSuspendDoneSignal(int suspend_id) {
229 power_manager::SuspendDone proto;
230 proto.set_suspend_id(suspend_id);
231 dbus::Signal signal(kInterface, power_manager::kSuspendDoneSignal);
232 dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto);
233 EmitSignal(&signal);
234 }
235
236 // Adds an expectation to |proxy_| for a HandleSuspendReadiness or
237 // HandleDarkSuspendReadiness method call.
238 void ExpectSuspendReadiness(const std::string& method_name,
239 int suspend_id,
240 int delay_id) {
241 EXPECT_CALL(
242 *proxy_.get(),
243 CallMethod(IsSuspendReadiness(method_name, suspend_id, delay_id), _,
244 _));
245 }
246
247 // Arbitrary delay IDs returned to |client_|.
248 static const int kSuspendDelayId = 100;
249 static const int kDarkSuspendDelayId = 200;
250
251 base::MessageLoop message_loop_;
252
253 // Mock bus and proxy for simulating calls to powerd.
254 scoped_refptr<dbus::MockBus> bus_;
255 scoped_refptr<dbus::MockObjectProxy> proxy_;
256
257 std::unique_ptr<PowerManagerClient> client_;
258
259 // Maps from powerd signal name to the corresponding callback provided by
260 // |client_|.
261 std::map<std::string, dbus::ObjectProxy::SignalCallback> signal_callbacks_;
262
263 private:
264 // Handles calls to |proxy_|'s ConnectToSignal() method.
265 void ConnectToSignal(
266 const std::string& interface_name,
267 const std::string& signal_name,
268 dbus::ObjectProxy::SignalCallback signal_callback,
269 dbus::ObjectProxy::OnConnectedCallback on_connected_callback) {
270 CHECK_EQ(interface_name, power_manager::kPowerManagerInterface);
271 signal_callbacks_[signal_name] = signal_callback;
272
273 message_loop_.task_runner()->PostTask(
274 FROM_HERE, base::Bind(on_connected_callback, interface_name,
275 signal_name, true /* success */));
276 }
277
278 // Handles calls to |proxy_|'s CallMethod() method to register suspend delays.
279 void RegisterSuspendDelay(dbus::MethodCall* method_call,
280 int timeout_ms,
281 dbus::ObjectProxy::ResponseCallback callback) {
282 power_manager::RegisterSuspendDelayReply proto;
283 proto.set_delay_id(method_call->GetMember() ==
284 power_manager::kRegisterDarkSuspendDelayMethod
285 ? kDarkSuspendDelayId
286 : kSuspendDelayId);
287
288 method_call->SetSerial(123); // Arbitrary but needed by FromMethodCall().
289 std::unique_ptr<dbus::Response> response(
290 dbus::Response::FromMethodCall(method_call));
291 CHECK(dbus::MessageWriter(response.get()).AppendProtoAsArrayOfBytes(proto));
292
293 message_loop_.task_runner()->PostTask(
294 FROM_HERE,
295 base::Bind(&RunResponseCallback, callback, base::Passed(&response)));
296 }
297
298 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientTest);
299 };
300
301 // Suspend readiness should be reported immediately when there are no observers.
302 TEST_F(PowerManagerClientTest, ReportSuspendReadinessWithoutObservers) {
303 const int kSuspendId = 1;
304 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
305 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
306 EmitSuspendDoneSignal(kSuspendId);
307 }
308
309 // Observers should be notified when suspend is imminent and done. Readiness
310 // should be reported synchronously when GetSuspendReadinessCallback() hasn't
311 // been called.
312 TEST_F(PowerManagerClientTest, ReportSuspendReadinessWithoutCallbacks) {
313 TestObserver observer_1(client_.get());
314 TestObserver observer_2(client_.get());
315
316 const int kSuspendId = 1;
317 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
318 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
319 EXPECT_EQ(1, observer_1.num_suspend_imminent());
320 EXPECT_EQ(0, observer_1.num_suspend_done());
321 EXPECT_EQ(1, observer_2.num_suspend_imminent());
322 EXPECT_EQ(0, observer_2.num_suspend_done());
323
324 EmitSuspendDoneSignal(kSuspendId);
325 EXPECT_EQ(1, observer_1.num_suspend_imminent());
326 EXPECT_EQ(1, observer_1.num_suspend_done());
327 EXPECT_EQ(1, observer_2.num_suspend_imminent());
328 EXPECT_EQ(1, observer_2.num_suspend_done());
329 }
330
331 // When observers call GetSuspendReadinessCallback() from their
332 // SuspendImminent() methods, the HandleSuspendReadiness method call should be
333 // deferred until all callbacks are run.
334 TEST_F(PowerManagerClientTest, ReportSuspendReadinessWithCallbacks) {
335 TestObserver observer_1(client_.get());
336 observer_1.set_take_suspend_readiness_callback(true);
337 TestObserver observer_2(client_.get());
338 observer_2.set_take_suspend_readiness_callback(true);
339 TestObserver observer_3(client_.get());
340
341 const int kSuspendId = 1;
342 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
343 EXPECT_TRUE(observer_1.RunSuspendReadinessCallback());
344 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
345 EXPECT_TRUE(observer_2.RunSuspendReadinessCallback());
346 EmitSuspendDoneSignal(kSuspendId);
347 }
348
349 // The RenderProcessManagerDelegate should be notified that suspend is imminent
350 // only after observers have reported readiness.
351 TEST_F(PowerManagerClientTest, NotifyRenderProcessManagerDelegate) {
352 TestDelegate delegate(client_.get());
353 TestObserver observer(client_.get());
354 observer.set_take_suspend_readiness_callback(true);
355
356 const int kSuspendId = 1;
357 EmitSuspendImminentSignal(kSuspendImminent, kSuspendId);
358 EXPECT_EQ(0, delegate.num_suspend_imminent());
359 EXPECT_EQ(0, delegate.num_suspend_done());
360
361 ExpectSuspendReadiness(kHandleSuspendReadiness, kSuspendId, kSuspendDelayId);
362 EXPECT_TRUE(observer.RunSuspendReadinessCallback());
363 EXPECT_EQ(1, delegate.num_suspend_imminent());
364 EXPECT_EQ(0, delegate.num_suspend_done());
365
366 EmitSuspendDoneSignal(kSuspendId);
367 EXPECT_EQ(1, delegate.num_suspend_imminent());
368 EXPECT_EQ(1, delegate.num_suspend_done());
369 }
370
371 // TODO(derat): Add tests around SuspendDone being received while readiness
372 // callbacks are still outstanding (see http://crbug.com/646912).
373
374 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/dbus/power_manager_client.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698