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

Side by Side Diff: chromeos/dbus/biod/biod_client_unittest.cc

Issue 2567813002: cros: DBUS client to interact with fingerprint DBUS API. (Closed)
Patch Set: Fixed patch set 11 errors. Created 3 years, 8 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
OLDNEW
(Empty)
1 // Copyright 2017 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/biod/biod_client.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/run_loop.h"
12 #include "dbus/mock_bus.h"
13 #include "dbus/mock_object_proxy.h"
14 #include "dbus/object_path.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 using ::testing::_;
19 using ::testing::Invoke;
20 using ::testing::Return;
21
22 namespace chromeos {
23
24 namespace {
25
26 // Shorthand for a commonly-used constant.
27 const char* kInterface = biod::kBiometricsManagerInterface;
28
29 void TestObjectPathCallback(dbus::ObjectPath** expected_object_path_out,
30 const dbus::ObjectPath& object_path) {
Daniel Erat 2017/04/01 00:46:27 you're leaking memory in tests now, i think. just
sammiequon 2017/04/01 01:22:44 Done. Yeah i thought of this but for some reason I
31 ASSERT_FALSE(*expected_object_path_out);
32 *expected_object_path_out = new dbus::ObjectPath(object_path);
33 }
34
35 void TestObjectPathArrayCallback(
36 std::vector<dbus::ObjectPath>** expected_object_paths_out,
Daniel Erat 2017/04/01 00:46:27 same comment applies here. pass a std::vector<dbus
sammiequon 2017/04/01 01:22:44 Done.
37 const std::vector<dbus::ObjectPath>& object_paths) {
38 ASSERT_FALSE(*expected_object_paths_out);
39 *expected_object_paths_out = new std::vector<dbus::ObjectPath>();
40 for (size_t i = 0; i < object_paths.size(); ++i)
41 (*expected_object_paths_out)->push_back(object_paths[i]);
42 }
43
44 // Matcher that verifies that a dbus::Message has member |name|.
45 MATCHER_P(HasMember, name, "") {
46 if (arg->GetMember() != name) {
47 *result_listener << "has member " << arg->GetMember();
48 return false;
49 }
50 return true;
51 }
52
53 // Runs |callback| with |response|. Needed due to ResponseCallback expecting a
54 // bare pointer rather than an std::unique_ptr.
55 void RunResponseCallback(dbus::ObjectProxy::ResponseCallback callback,
56 std::unique_ptr<dbus::Response> response) {
57 callback.Run(response.get());
58 }
59
60 // Implementation of BiodClient::Observer.
61 class TestBiodObserver : public BiodClient::Observer {
62 public:
63 TestBiodObserver() {}
64 ~TestBiodObserver() override {}
65
66 int num_enroll_scans_received() const { return num_enroll_scans_received_; }
67 int num_auth_scans_received() const { return num_auth_scans_received_; }
68 int num_failures_received() const { return num_failures_received_; }
69
70 // BiodClient::Observer:
71 void BiodServiceRestarted() override {}
72
73 void BiodEnrollScanDoneReceived(biod::ScanResult scan_result,
74 bool enroll_sesion_complete) override {
75 num_enroll_scans_received_++;
76 }
77
78 void BiodAuthScanDoneReceived(biod::ScanResult scan_result,
79 const AuthScanMatches& matches) override {
80 num_auth_scans_received_++;
81 }
82
83 void BiodSessionFailedReceived() override { num_failures_received_++; }
84
85 private:
86 int num_enroll_scans_received_ = 0;
87 int num_auth_scans_received_ = 0;
88 int num_failures_received_ = 0;
89
90 DISALLOW_COPY_AND_ASSIGN(TestBiodObserver);
91 };
92
93 } // namespace
94
95 class BiodClientTest : public testing::Test {
96 public:
97 BiodClientTest() {}
98 ~BiodClientTest() override {}
99
100 void SetUp() override {
101 dbus::Bus::Options options;
102 options.bus_type = dbus::Bus::SYSTEM;
103 bus_ = new dbus::MockBus(options);
104
105 proxy_ =
106 new dbus::MockObjectProxy(bus_.get(), biod::kBiodServiceName,
107 dbus::ObjectPath(biod::kBiodServicePath));
108
109 // |client_|'s Init() method should request a proxy for communicating with
110 // biometrics api.
111 EXPECT_CALL(*bus_.get(),
112 GetObjectProxy(biod::kBiodServiceName,
113 dbus::ObjectPath(biod::kBiodServicePath)))
114 .WillRepeatedly(Return(proxy_.get()));
115
116 // Save |client_|'s signal callback.
117 EXPECT_CALL(*proxy_.get(), ConnectToSignal(kInterface, _, _, _))
118 .WillRepeatedly(Invoke(this, &BiodClientTest::ConnectToSignal));
119
120 client_.reset(BiodClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION));
121 client_->Init(bus_.get());
122
123 // Execute callbacks posted by Init().
124 base::RunLoop().RunUntilIdle();
125 }
126
127 protected:
128 // Add an expectation for method with |method_name| to be called. When the
129 // method is called the response shoudl match |response|.
130 void AddMethodExpectation(const std::string& method_name,
131 std::unique_ptr<dbus::Response> response) {
132 ASSERT_FALSE(pending_method_calls_.count(method_name));
133 pending_method_calls_[method_name] = std::move(response);
134 EXPECT_CALL(*proxy_.get(), CallMethod(HasMember(method_name), _, _))
135 .WillOnce(Invoke(this, &BiodClientTest::OnCallMethod));
136 }
137
138 // Synchronously passes |signal| to |client_|'s handler, simulating the signal
139 // from biometrics.
140 void EmitSignal(dbus::Signal* signal) {
141 const std::string signal_name = signal->GetMember();
142 const auto it = signal_callbacks_.find(signal_name);
143 ASSERT_TRUE(it != signal_callbacks_.end())
144 << "Client didn't register for signal " << signal_name;
145 it->second.Run(signal);
146 }
147
148 // Passes a enroll scan done signal to |client_|.
149 void EmitEnrollScanDoneSignal(biod::ScanResult scan_result,
150 bool enroll_session_complete) {
151 dbus::Signal signal(kInterface,
152 biod::kBiometricsManagerEnrollScanDoneSignal);
153 dbus::MessageWriter writer(&signal);
154 writer.AppendUint32(uint32_t{scan_result});
155 writer.AppendBool(enroll_session_complete);
156 EmitSignal(&signal);
157 }
158
159 // Passes a auth scan done signal to |client_|.
160 void EmitAuthScanDoneSignal(biod::ScanResult scan_result,
161 const AuthScanMatches& matches) {
162 dbus::Signal signal(kInterface, biod::kBiometricsManagerAuthScanDoneSignal);
163 dbus::MessageWriter writer(&signal);
164 writer.AppendUint32(uint32_t{scan_result});
165
166 dbus::MessageWriter array_writer(nullptr);
167 writer.OpenArray("{sx}", &array_writer);
168 for (auto& match : matches) {
169 dbus::MessageWriter entry_writer(nullptr);
170 array_writer.OpenDictEntry(&entry_writer);
171 entry_writer.AppendString(match.first);
172 entry_writer.AppendArrayOfStrings(match.second);
173 array_writer.CloseContainer(&entry_writer);
174 }
175 writer.CloseContainer(&array_writer);
176 EmitSignal(&signal);
177 }
178
179 // Passes a scan failed signal to |client_|.
180 void EmitScanFailedSignal() {
181 dbus::Signal signal(kInterface,
182 biod::kBiometricsManagerSessionFailedSignal);
183 EmitSignal(&signal);
184 }
185
186 std::map<std::string, std::unique_ptr<dbus::Response>> pending_method_calls_;
187
188 base::MessageLoop message_loop_;
189
190 // Mock bus and proxy for simulating calls.
191 scoped_refptr<dbus::MockBus> bus_;
192 scoped_refptr<dbus::MockObjectProxy> proxy_;
193
194 std::unique_ptr<BiodClient> client_;
195
196 // Maps from biod signal name to the corresponding callback provided by
197 // |client_|.
198 std::map<std::string, dbus::ObjectProxy::SignalCallback> signal_callbacks_;
199
200 private:
201 // Handles calls to |proxy_|'s ConnectToSignal() method.
202 void ConnectToSignal(
203 const std::string& interface_name,
204 const std::string& signal_name,
205 dbus::ObjectProxy::SignalCallback signal_callback,
206 dbus::ObjectProxy::OnConnectedCallback on_connected_callback) {
207 EXPECT_EQ(interface_name, kInterface);
208 signal_callbacks_[signal_name] = signal_callback;
209 message_loop_.task_runner()->PostTask(
210 FROM_HERE, base::Bind(on_connected_callback, interface_name,
211 signal_name, true /* success */));
212 }
213
214 // Handles calls to |proxy_|'s CallMethod().
215 void OnCallMethod(dbus::MethodCall* method_call,
216 int timeout_ms,
217 const dbus::ObjectProxy::ResponseCallback& callback) {
218 auto it = pending_method_calls_.find(method_call->GetMember());
219 ASSERT_TRUE(it != pending_method_calls_.end());
220 auto pending_response = std::move(it->second);
221 pending_method_calls_.erase(it);
222
223 message_loop_.task_runner()->PostTask(
224 FROM_HERE, base::Bind(&RunResponseCallback, callback,
225 base::Passed(&pending_response)));
226 }
227
228 DISALLOW_COPY_AND_ASSIGN(BiodClientTest);
229 };
230
231 TEST_F(BiodClientTest, TestStartEnrollSession) {
232 const std::string kFakeId("fakeId");
233 const std::string kFakeLabel("fakeLabel");
234 const dbus::ObjectPath kFakeObjectPath(std::string("/fake/object/path"));
235 const dbus::ObjectPath kFakeObjectPath2(std::string("/fake/object/path2"));
236
237 std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
238 dbus::MessageWriter writer(response.get());
239 writer.AppendObjectPath(kFakeObjectPath);
240
241 // Create a fake response with a fake object path. The start enroll
242 // call should return this object path.
243 AddMethodExpectation(biod::kBiometricsManagerStartEnrollSessionMethod,
244 std::move(response));
245 dbus::ObjectPath* callback_result = nullptr;
246 client_->StartEnrollSession(
247 kFakeId, kFakeLabel,
248 base::Bind(&TestObjectPathCallback, &callback_result));
249 base::RunLoop().RunUntilIdle();
250 ASSERT_TRUE(callback_result);
251 EXPECT_EQ(kFakeObjectPath, *callback_result);
252
253 // Verify that by sending a empty reponse or a improperly formatted one, the
254 // response is an empty object path. Also, logs will get printed.
255 AddMethodExpectation(biod::kBiometricsManagerStartEnrollSessionMethod,
256 nullptr);
257 callback_result = nullptr;
Daniel Erat 2017/04/01 00:46:27 here's one of the places where memory is being lea
sammiequon 2017/04/01 01:22:44 Oops. Yeah.
258 client_->StartEnrollSession(
259 kFakeId, kFakeLabel,
260 base::Bind(&TestObjectPathCallback, &callback_result));
261 base::RunLoop().RunUntilIdle();
262 ASSERT_TRUE(callback_result);
Daniel Erat 2017/04/01 00:46:27 after getting rid of the new calls, you won't need
sammiequon 2017/04/01 01:22:44 Done.
263 EXPECT_EQ(dbus::ObjectPath(), *callback_result);
264
265 std::unique_ptr<dbus::Response> bad_response(dbus::Response::CreateEmpty());
266 dbus::MessageWriter bad_writer(bad_response.get());
267 bad_writer.AppendString("");
268 AddMethodExpectation(biod::kBiometricsManagerStartEnrollSessionMethod,
269 std::move(bad_response));
270 callback_result = nullptr;
271 client_->StartEnrollSession(
272 kFakeId, kFakeLabel,
273 base::Bind(&TestObjectPathCallback, &callback_result));
274 base::RunLoop().RunUntilIdle();
275 ASSERT_TRUE(callback_result);
276 EXPECT_EQ(dbus::ObjectPath(), *callback_result);
277
278 delete callback_result;
279 }
280
281 TEST_F(BiodClientTest, TestGetRecordsForUser) {
282 const std::string kFakeId("fakeId");
283 const dbus::ObjectPath kFakeObjectPath(std::string("/fake/object/path"));
284 const dbus::ObjectPath kFakeObjectPath2(std::string("/fake/object/path2"));
285 const std::vector<dbus::ObjectPath> kFakeObjectPaths = {kFakeObjectPath,
286 kFakeObjectPath2};
287
288 std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
289 dbus::MessageWriter writer(response.get());
290 writer.AppendArrayOfObjectPaths(kFakeObjectPaths);
291
292 // Create a fake response with an array of fake object paths. The get
293 // enrollments call should return this array of object paths.
294 AddMethodExpectation(biod::kBiometricsManagerGetRecordsForUserMethod,
295 std::move(response));
296 std::vector<dbus::ObjectPath>* callback_result = nullptr;
297 client_->GetRecordsForUser(
298 kFakeId, base::Bind(&TestObjectPathArrayCallback, &callback_result));
299 base::RunLoop().RunUntilIdle();
300 ASSERT_TRUE(callback_result);
301 EXPECT_EQ(kFakeObjectPaths, *callback_result);
302
303 // Verify that by sending a empty reponse the response is an empty array of
304 // object paths. Also, logs will get printed.
305 AddMethodExpectation(biod::kBiometricsManagerGetRecordsForUserMethod,
306 nullptr);
307 callback_result = nullptr;
308 client_->GetRecordsForUser(
309 kFakeId, base::Bind(&TestObjectPathArrayCallback, &callback_result));
310 base::RunLoop().RunUntilIdle();
311 ASSERT_TRUE(callback_result);
312 EXPECT_EQ(std::vector<dbus::ObjectPath>(), *callback_result);
313
314 delete callback_result;
315 }
316
317 TEST_F(BiodClientTest, TestStartAuthentication) {
318 const dbus::ObjectPath kFakeObjectPath(std::string("/fake/object/path"));
319
320 // Create a fake response with a fake object path. The start authentication
321 // call should return this object path.
322 std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
323 dbus::MessageWriter writer(response.get());
324 writer.AppendObjectPath(kFakeObjectPath);
325
326 AddMethodExpectation(biod::kBiometricsManagerStartAuthSessionMethod,
327 std::move(response));
328 dbus::ObjectPath* callback_result = nullptr;
329 client_->StartAuthSession(
330 base::Bind(&TestObjectPathCallback, &callback_result));
331 base::RunLoop().RunUntilIdle();
332 ASSERT_TRUE(callback_result);
333 EXPECT_EQ(kFakeObjectPath, *callback_result);
334
335 // Verify that by sending a empty reponse or a improperly formatted one, the
336 // response is an empty object path. Also, logs will get printed.
337 AddMethodExpectation(biod::kBiometricsManagerStartAuthSessionMethod, nullptr);
338 callback_result = nullptr;
339 client_->StartAuthSession(
340 base::Bind(&TestObjectPathCallback, &callback_result));
341 base::RunLoop().RunUntilIdle();
342 ASSERT_TRUE(callback_result);
343 EXPECT_EQ(dbus::ObjectPath(), *callback_result);
344
345 std::unique_ptr<dbus::Response> bad_response(dbus::Response::CreateEmpty());
346 dbus::MessageWriter bad_writer(bad_response.get());
347 bad_writer.AppendString("");
348 AddMethodExpectation(biod::kBiometricsManagerStartAuthSessionMethod,
349 std::move(bad_response));
350 callback_result = nullptr;
351 client_->StartAuthSession(
352 base::Bind(&TestObjectPathCallback, &callback_result));
353 base::RunLoop().RunUntilIdle();
354 ASSERT_TRUE(callback_result);
355 EXPECT_EQ(dbus::ObjectPath(), *callback_result);
356
357 delete callback_result;
358 }
359
360 // Verify when signals are mocked, an observer will catch the signals as
361 // expected.
362 TEST_F(BiodClientTest, TestEnrollScanDoneObserver) {
Daniel Erat 2017/04/01 00:46:27 nit: TestNotifyObserverAboutScan?
sammiequon 2017/04/01 01:22:44 Done. I opted to skip the AboutScan since I put th
363 TestBiodObserver observer;
364 client_->AddObserver(&observer);
365 EXPECT_TRUE(client_->HasObserver(&observer));
366
367 const biod::ScanResult scan_signal = biod::ScanResult::SCAN_RESULT_SUCCESS;
368 const bool enroll_session_complete = false;
369 const AuthScanMatches test_attempt;
370 EXPECT_EQ(0, observer.num_enroll_scans_received());
371 EXPECT_EQ(0, observer.num_auth_scans_received());
372 EXPECT_EQ(0, observer.num_failures_received());
373
374 EmitEnrollScanDoneSignal(scan_signal, enroll_session_complete);
375 EXPECT_EQ(1, observer.num_enroll_scans_received());
376
377 EmitAuthScanDoneSignal(scan_signal, test_attempt);
378 EXPECT_EQ(1, observer.num_auth_scans_received());
379
380 EmitScanFailedSignal();
381 EXPECT_EQ(1, observer.num_failures_received());
382
383 client_->RemoveObserver(&observer);
384
385 EmitEnrollScanDoneSignal(scan_signal, enroll_session_complete);
386 EmitAuthScanDoneSignal(scan_signal, test_attempt);
387 EXPECT_EQ(1, observer.num_enroll_scans_received());
388 EXPECT_EQ(1, observer.num_auth_scans_received());
389 EXPECT_EQ(1, observer.num_failures_received());
390 }
391 } // namespace chromeos
OLDNEW
« chromeos/dbus/biod/biod_client.cc ('K') | « chromeos/dbus/biod/biod_client.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698