Index: chromeos/dbus/biod/fake_biod_client_unittest.cc |
diff --git a/chromeos/dbus/biod/fake_biod_client_unittest.cc b/chromeos/dbus/biod/fake_biod_client_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..82812c123aa3796b1dbffdd628548972eb2bfb32 |
--- /dev/null |
+++ b/chromeos/dbus/biod/fake_biod_client_unittest.cc |
@@ -0,0 +1,362 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chromeos/dbus/biod/fake_biod_client.h" |
Daniel Erat
2017/04/07 18:27:56
add a blank line after this one
sammiequon
2017/04/07 20:45:51
Done.
|
+#include "base/bind.h" |
+#include "base/macros.h" |
+#include "base/test/test_simple_task_runner.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "dbus/object_path.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace chromeos { |
+ |
+namespace { |
+ |
+const char kTestUserId[] = "testuser@gmail.com"; |
+const char kTestLabel[] = "testLabel"; |
+ |
+void CopyObjectPath(dbus::ObjectPath* dest_path, |
Daniel Erat
2017/04/07 18:27:56
instead of copy-and-pasting code from biod_client_
sammiequon
2017/04/07 20:45:51
Yeah, sorry that should've been obvious. Done.
|
+ const dbus::ObjectPath& src_path) { |
+ CHECK(dest_path); |
+ *dest_path = src_path; |
+} |
+ |
+void CopyObjectPathArray( |
+ std::vector<dbus::ObjectPath>* dest_object_paths, |
+ const std::vector<dbus::ObjectPath>& src_object_paths) { |
+ CHECK(dest_object_paths); |
+ *dest_object_paths = src_object_paths; |
+} |
+ |
+void CopyNumRecords(int* out_num, |
+ const std::vector<dbus::ObjectPath>& object_path_array) { |
+ CHECK(out_num); |
+ *out_num = int{object_path_array.size()}; |
Daniel Erat
2017/04/07 18:27:56
static_cast
sammiequon
2017/04/07 20:45:51
https://google.github.io/styleguide/cppguide.html#
Daniel Erat
2017/04/07 20:57:25
i think that this is one place where chromium styl
sammiequon
2017/04/07 22:43:55
Understood, I would say those half are mine :S (sm
|
+} |
+ |
+void CopyLabel(std::string* expected_label, const std::string& src_label) { |
+ CHECK(expected_label); |
+ *expected_label = src_label; |
+} |
+ |
+// Implementation of BiodClient::Observer for testing. |
+class TestBiometricsObserver : public BiodClient::Observer { |
Daniel Erat
2017/04/07 18:27:56
put this into the utils class as well; it looks li
sammiequon
2017/04/07 20:45:50
Done.
|
+ public: |
+ TestBiometricsObserver() {} |
+ ~TestBiometricsObserver() override {} |
+ |
+ bool CheckExpectedLastAttemptMatches( |
+ const AuthScanMatches& expected_matches) { |
+ return expected_matches == last_auth_scan_matches_; |
+ } |
+ |
+ int num_complete_enroll_scan_received() const { |
+ return num_complete_enroll_scan_received_; |
+ } |
+ |
+ int num_incomplete_enroll_scan_received() const { |
+ return num_incomplete_enroll_scan_received_; |
+ } |
+ |
+ int num_matched_auth_scan_received() const { |
+ return num_matched_auth_scan_received_; |
+ } |
+ |
+ int num_unmatched_auth_scan_received() const { |
+ return num_unmatched_auth_scan_received_; |
+ } |
+ |
+ // BiodClient::Observer: |
+ void BiodServiceRestarted() override {} |
+ |
+ void BiodEnrollScanDoneReceived(biod::ScanResult scan_result, |
+ bool is_complete) override { |
+ is_complete ? num_complete_enroll_scan_received_++ |
+ : num_incomplete_enroll_scan_received_++; |
+ } |
+ |
+ void BiodAuthScanDoneReceived(biod::ScanResult scan_result, |
+ const AuthScanMatches& matches) override { |
+ matches.empty() ? num_unmatched_auth_scan_received_++ |
+ : num_matched_auth_scan_received_++; |
+ last_auth_scan_matches_ = matches; |
+ } |
+ |
+ void BiodSessionFailedReceived() override { num_failure_received_++; } |
+ |
+ private: |
+ int num_complete_enroll_scan_received_ = 0; |
+ int num_incomplete_enroll_scan_received_ = 0; |
+ int num_matched_auth_scan_received_ = 0; |
+ int num_unmatched_auth_scan_received_ = 0; |
+ int num_failure_received_ = 0; |
+ |
+ // When auth scan is received, store the result. |
+ AuthScanMatches last_auth_scan_matches_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestBiometricsObserver); |
+}; |
+ |
+} // namepsace |
+ |
+class FakeBiodClientTest : public testing::Test { |
+ public: |
+ FakeBiodClientTest() |
+ : task_runner_(new base::TestSimpleTaskRunner), |
+ task_runner_handle_(task_runner_) {} |
+ ~FakeBiodClientTest() override {} |
+ |
+ int NumRecords() { return int{fake_biod_client_.records_.size()}; } |
Daniel Erat
2017/04/07 18:27:56
again, static_cast
sammiequon
2017/04/07 20:45:51
Done.
|
+ |
+ int NumRecords(const std::string& user_id) { |
+ std::vector<dbus::ObjectPath> enrollment_paths; |
+ fake_biod_client_.GetRecordsForUser( |
+ kTestUserId, base::Bind(&CopyObjectPathArray, &enrollment_paths)); |
+ task_runner_->RunUntilIdle(); |
+ return int{enrollment_paths.size()}; |
Daniel Erat
2017/04/07 18:27:56
static_cast
sammiequon
2017/04/07 20:45:51
Done.
|
+ } |
+ |
+ void SendAuthScanDone(char c) { |
+ fake_biod_client_.SendAuthScanDone(c, |
+ biod::ScanResult::SCAN_RESULT_SUCCESS); |
+ } |
+ |
+ // Helper function which enrolls a fingerprint. Each element in |
+ // |fingerprint_data| corresponds to a finger tap. |
+ void EnrollFingerprint(const std::string& id, |
+ const std::string& label, |
+ const std::string& fingerprint_data) { |
+ if (fingerprint_data.size() < 1) |
+ return; |
+ |
+ dbus::ObjectPath returned_path; |
+ fake_biod_client_.StartEnrollSession( |
+ id, label, base::Bind(CopyObjectPath, &returned_path)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_NE(returned_path, dbus::ObjectPath()); |
+ |
+ // Send |fingerprint_data| size - 1 incomplete scans. |
+ for (int i = 0; i < int{fingerprint_data.size()} - 1; ++i) { |
Daniel Erat
2017/04/07 18:27:56
static_cast
sammiequon
2017/04/07 20:45:51
Done.
|
+ fake_biod_client_.SendEnrollScanDone( |
+ fingerprint_data[i], biod::ScanResult::SCAN_RESULT_SUCCESS, |
+ false /* is_complete*/); |
+ } |
+ |
+ // Finish the enrollment by sending a complete scan signal. |
+ fake_biod_client_.SendEnrollScanDone(fingerprint_data.back(), |
+ biod::ScanResult::SCAN_RESULT_SUCCESS, |
+ true /*is_complete*/); |
+ } |
+ |
+ // Helper function which enrolls |n| fingerprints with the same |id|, |label| |
+ // and |fingerprint_data|. |
+ void EnrollNTestFingerprints(const std::string& id, |
+ const std::string& label, |
+ const std::string& fingerprint_data, |
+ int n) { |
+ for (int i = 0; i < n; ++i) |
+ EnrollFingerprint(id, label, fingerprint_data); |
+ } |
+ |
+ protected: |
+ FakeBiodClient fake_biod_client_; |
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
+ base::ThreadTaskRunnerHandle task_runner_handle_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(FakeBiodClientTest); |
+}; |
+ |
+TEST_F(FakeBiodClientTest, TestEnrollSessionWorkflow) { |
+ TestBiometricsObserver observer; |
+ fake_biod_client_.AddObserver(&observer); |
+ |
+ // Verify that successful enrollments gets stored as expected. A fingerprint |
+ // that was created with 3 chars should have 2 incomplete scans and 1 complete |
+ // scans. |
+ EnrollFingerprint(kTestUserId, kTestLabel, "aaa"); |
+ EXPECT_EQ(1, NumRecords()); |
+ EXPECT_EQ(2, observer.num_incomplete_enroll_scan_received()); |
+ EXPECT_EQ(1, observer.num_complete_enroll_scan_received()); |
+ |
+ // Verify that the enroll session worflow can be used repeatedly. A |
+ // fingerprint that was created with 4 chars should have 3 incomplete scans |
+ // and 1 complete scan. |
+ EnrollNTestFingerprints(kTestUserId, kTestLabel, "aaaa", 2); |
+ EXPECT_EQ(3, NumRecords()); |
+ EXPECT_EQ(8, observer.num_incomplete_enroll_scan_received()); |
+ EXPECT_EQ(3, observer.num_complete_enroll_scan_received()); |
+} |
+ |
+// Test authentication when one user has one or more fingerprints registered. |
+// This should be the normal scenario. |
+TEST_F(FakeBiodClientTest, TestAuthSessionWorkflowSingleUser) { |
+ TestBiometricsObserver observer; |
+ fake_biod_client_.AddObserver(&observer); |
+ EXPECT_EQ(0, NumRecords(kTestUserId)); |
+ |
+ // Add two fingerprints a and b and start an auth session. |
+ EnrollFingerprint(kTestUserId, kTestLabel, "a"); |
+ EnrollFingerprint(kTestUserId, kTestLabel, "b"); |
+ dbus::ObjectPath returned_path; |
+ fake_biod_client_.StartAuthSession( |
+ base::Bind(CopyObjectPath, &returned_path)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_NE(returned_path, dbus::ObjectPath()); |
+ |
+ // Verify that by sending two attempts signals of fingerprints that have been |
+ // enrolled, the observer should received two matches and zero unmatches. |
+ SendAuthScanDone('a'); |
+ SendAuthScanDone('b'); |
+ EXPECT_EQ(2, observer.num_matched_auth_scan_received()); |
+ EXPECT_EQ(0, observer.num_unmatched_auth_scan_received()); |
+ |
+ // Verify that by sending two attempts signals of fingerprints that have not |
+ // been enrolled, the observer should received two unmatches and zero |
+ // matches. |
+ SendAuthScanDone('c'); |
+ SendAuthScanDone('d'); |
+ EXPECT_EQ(2, observer.num_matched_auth_scan_received()); |
+ EXPECT_EQ(2, observer.num_unmatched_auth_scan_received()); |
+} |
+ |
+// Test authentication when multiple users have fingerprints registered. Cover |
+// cases such as when both users use the same labels, a user had registered the |
+// same fingerprint multiple times, or two users use the same fingerprint. |
+TEST_F(FakeBiodClientTest, TestAuthenticateWorkflowMultipleUsers) { |
+ TestBiometricsObserver observer; |
+ fake_biod_client_.AddObserver(&observer); |
+ EXPECT_EQ(0, NumRecords(kTestUserId)); |
+ |
+ // Add two users, who have scanned three fingers between the two of them. |
+ const std::string& kUserOne = std::string(kTestUserId) + "1"; |
+ const std::string& kUserTwo = std::string(kTestUserId) + "2"; |
+ |
+ const std::string& kLabelOne = std::string(kTestLabel) + "1"; |
+ const std::string& kLabelTwo = std::string(kTestLabel) + "2"; |
+ const std::string& kLabelThree = std::string(kTestLabel) + "3"; |
+ |
+ EnrollFingerprint(kUserOne, kLabelOne, "a"); |
+ EnrollFingerprint(kUserOne, kLabelTwo, "b"); |
+ // User one has registered finger two twice. |
+ EnrollFingerprint(kUserOne, kLabelThree, "b"); |
+ EnrollFingerprint(kUserTwo, kLabelOne, "d"); |
+ EnrollFingerprint(kUserTwo, kLabelTwo, "e"); |
+ // User two has allowed user one to unlock his/her account with his/her first |
+ // finger. |
+ EnrollFingerprint(kUserTwo, kLabelThree, "a"); |
+ |
+ dbus::ObjectPath returned_path; |
+ fake_biod_client_.StartAuthSession( |
+ base::Bind(CopyObjectPath, &returned_path)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_NE(returned_path, dbus::ObjectPath()); |
+ |
+ // Verify that if a user registers the same finger to two different labels, |
+ // both labels are returned as matches. |
+ AuthScanMatches expected_auth_scan_matches; |
+ expected_auth_scan_matches[kUserOne] = {kLabelTwo, kLabelThree}; |
+ SendAuthScanDone('b'); |
+ EXPECT_TRUE( |
+ observer.CheckExpectedLastAttemptMatches(expected_auth_scan_matches)); |
+ |
+ // Verify that a fingerprint associated with one user and one label returns a |
+ // match with one user and one label. |
+ expected_auth_scan_matches.clear(); |
+ expected_auth_scan_matches[kUserTwo] = {kLabelOne}; |
+ SendAuthScanDone('d'); |
+ EXPECT_TRUE( |
+ observer.CheckExpectedLastAttemptMatches(expected_auth_scan_matches)); |
+ |
+ // Verify if two users register the same fingerprint, the matches contain both |
+ // users. |
+ expected_auth_scan_matches.clear(); |
+ expected_auth_scan_matches[kUserOne] = {kLabelOne}; |
+ expected_auth_scan_matches[kUserTwo] = {kLabelThree}; |
+ SendAuthScanDone('a'); |
+ EXPECT_TRUE( |
+ observer.CheckExpectedLastAttemptMatches(expected_auth_scan_matches)); |
+ |
+ // Verify if a unregistered finger is scanned, the matches are empty. |
+ expected_auth_scan_matches.clear(); |
+ SendAuthScanDone('f'); |
+ EXPECT_TRUE( |
+ observer.CheckExpectedLastAttemptMatches(expected_auth_scan_matches)); |
+} |
+ |
+TEST_F(FakeBiodClientTest, TestGetAllRecords) { |
+ // Verify that initially |kTestUserId| will have no fingerprints. |
+ int num_fingerprints = -1; |
+ fake_biod_client_.GetRecordsForUser( |
+ kTestUserId, base::Bind(&CopyNumRecords, &num_fingerprints)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(0, num_fingerprints); |
+ |
+ // Verify that after enrolling 2 fingerprints, a GetRecords call return 2 |
+ // items. |
+ EnrollNTestFingerprints(kTestUserId, kTestLabel, "aa", 2); |
+ num_fingerprints = -1; |
+ fake_biod_client_.GetRecordsForUser( |
+ kTestUserId, base::Bind(&CopyNumRecords, &num_fingerprints)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(2, num_fingerprints); |
+ |
+ // Verify that GetRecords call for a user with no registered fingerprints |
+ // should return 0 items. |
+ num_fingerprints = -1; |
+ fake_biod_client_.GetRecordsForUser( |
+ "noregisteredginerprints@gmail.com", |
+ base::Bind(&CopyNumRecords, &num_fingerprints)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(0, num_fingerprints); |
+} |
+ |
+TEST_F(FakeBiodClientTest, TestDestroyingRecords) { |
+ // Verify that after enrolling 2 fingerprints and destroying them, 0 |
+ // fingerprints will remain. |
+ EnrollNTestFingerprints(kTestUserId, kTestLabel, "aaaa", 2); |
+ EXPECT_EQ(2, NumRecords(kTestUserId)); |
+ fake_biod_client_.DestroyAllRecords(); |
+ EXPECT_EQ(0, NumRecords(kTestUserId)); |
+} |
+ |
+TEST_F(FakeBiodClientTest, TestGetAndSetRecordLabels) { |
+ const std::string& kLabelOne = "Finger 1"; |
+ const std::string& kLabelTwo = "Finger 2"; |
+ |
+ EnrollFingerprint(kTestUserId, kLabelOne, "abc"); |
+ EnrollFingerprint(kTestUserId, kLabelTwo, "abc"); |
+ EXPECT_EQ(2, NumRecords(kTestUserId)); |
+ std::vector<dbus::ObjectPath> enrollment_paths; |
+ fake_biod_client_.GetRecordsForUser( |
+ kTestUserId, base::Bind(&CopyObjectPathArray, &enrollment_paths)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(2u, enrollment_paths.size()); |
+ |
+ // Verify the labels we get using GetLabel are the same as the one we |
+ // originally set. |
+ std::string returned_label; |
+ fake_biod_client_.RequestRecordLabel(enrollment_paths[0], |
+ base::Bind(&CopyLabel, &returned_label)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(kLabelOne, returned_label); |
+ |
+ returned_label = ""; |
+ fake_biod_client_.RequestRecordLabel(enrollment_paths[1], |
+ base::Bind(&CopyLabel, &returned_label)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(kLabelTwo, returned_label); |
+ |
+ // Verify that by setting a new label, getting the label will return the value |
+ // of the new label. |
+ const std::string& kNewLabelTwo = "Finger 2 New"; |
+ fake_biod_client_.SetRecordLabel(enrollment_paths[1], kNewLabelTwo); |
+ fake_biod_client_.RequestRecordLabel(enrollment_paths[1], |
+ base::Bind(&CopyLabel, &returned_label)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_EQ(kNewLabelTwo, returned_label); |
+} |
+ |
+} // namespace chromeos |