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

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

Powered by Google App Engine
This is Rietveld 408576698