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

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