blob: 2f19805de8c5eed7c96841feec595c2228c61a15 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/binder_process.h>
#include <face.sysprop.h>
#include <gtest/gtest.h>
#include <android-base/logging.h>
#include "Face.h"
#include "VirtualHal.h"
using namespace ::android::face::virt;
using namespace ::aidl::android::hardware::biometrics::face;
namespace aidl::android::hardware::biometrics::face {
class VirtualHalTest : public ::testing::Test {
public:
static const int32_t STATUS_FAILED_TO_SET_PARAMETER = 2;
protected:
void SetUp() override {
mHal = ndk::SharedRefBase::make<Face>();
mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
ASSERT_TRUE(mVhal != nullptr);
mHal->resetConfigToDefault();
}
void TearDown() override { mHal->resetConfigToDefault(); }
std::shared_ptr<VirtualHal> mVhal;
ndk::ScopedAStatus validateNonNegativeInputOfInt32(const char* name,
ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
const std::vector<int32_t>& in_good);
private:
std::shared_ptr<Face> mHal;
};
ndk::ScopedAStatus VirtualHalTest::validateNonNegativeInputOfInt32(
const char* name, ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
const std::vector<int32_t>& in_params_good) {
ndk::ScopedAStatus status;
for (auto& param : in_params_good) {
status = (*mVhal.*f)(param);
if (!status.isOk()) return status;
if (Face::cfg().get<int32_t>(name) != param) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
"Error: fail to set non-negative parameter"));
}
}
int32_t old_param = Face::cfg().get<int32_t>(name);
status = (*mVhal.*f)(-1);
if (status.isOk()) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, "Error: should return NOK"));
}
if (status.getServiceSpecificError() != IVirtualHal::STATUS_INVALID_PARAMETER) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
"Error: unexpected return error code"));
}
if (Face::cfg().get<int32_t>(name) != old_param) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
"Error: unexpected parameter change on failed attempt"));
}
return ndk::ScopedAStatus::ok();
}
TEST_F(VirtualHalTest, init) {
mVhal->setLockout(false);
ASSERT_TRUE(Face::cfg().get<bool>("lockout") == false);
ASSERT_TRUE(Face::cfg().get<std::string>("type") == "rgb");
ASSERT_TRUE(Face::cfg().get<std::string>("strength") == "strong");
std::int64_t id = Face::cfg().get<std::int64_t>("authenticator_id");
ASSERT_TRUE(Face::cfg().get<std::int64_t>("authenticator_id") == 0);
ASSERT_TRUE(Face::cfg().getopt<OptIntVec>("enrollments") == OptIntVec());
}
TEST_F(VirtualHalTest, enrollment_hit_int32) {
mVhal->setEnrollmentHit(11);
ASSERT_TRUE(Face::cfg().get<int32_t>("enrollment_hit") == 11);
}
TEST_F(VirtualHalTest, next_enrollment) {
struct {
std::string nextEnrollmentStr;
face::NextEnrollment nextEnrollment;
} testData[] = {
{"1:20:true", {1, {{20}}, true}},
{"1:50,60,70:true", {1, {{50}, {60}, {70}}, true}},
{"2:50-[21],60,70-[4,1002,1]:false",
{2,
{{50, {{AcquiredInfo::START}}},
{60},
{70, {{AcquiredInfo::TOO_DARK}, {1002}, {AcquiredInfo::GOOD}}}},
false}},
};
for (auto& d : testData) {
mVhal->setNextEnrollment(d.nextEnrollment);
ASSERT_TRUE(Face::cfg().get<std::string>("next_enrollment") == d.nextEnrollmentStr);
}
}
TEST_F(VirtualHalTest, authenticator_id_int64) {
mVhal->setAuthenticatorId(12345678900);
ASSERT_TRUE(Face::cfg().get<int64_t>("authenticator_id") == 12345678900);
}
TEST_F(VirtualHalTest, opeationAuthenticateFails_bool) {
mVhal->setOperationAuthenticateFails(true);
ASSERT_TRUE(Face::cfg().get<bool>("operation_authenticate_fails"));
}
TEST_F(VirtualHalTest, operationAuthenticateAcquired_int32_vector) {
using Tag = AcquiredInfoAndVendorCode::Tag;
std::vector<AcquiredInfoAndVendorCode> ac{
{AcquiredInfo::START}, {AcquiredInfo::TOO_FAR}, {1023}};
mVhal->setOperationAuthenticateAcquired(ac);
OptIntVec ac_get = Face::cfg().getopt<OptIntVec>("operation_authenticate_acquired");
ASSERT_TRUE(ac_get.size() == ac.size());
for (int i = 0; i < ac.size(); i++) {
int acCode = (ac[i].getTag() == Tag::acquiredInfo) ? (int)ac[i].get<Tag::acquiredInfo>()
: ac[i].get<Tag::vendorCode>();
ASSERT_TRUE(acCode == ac_get[i]);
}
}
TEST_F(VirtualHalTest, type) {
struct {
FaceSensorType type;
const char* typeStr;
} typeMap[] = {{FaceSensorType::RGB, "rgb"},
{FaceSensorType::IR, "ir"},
{FaceSensorType::UNKNOWN, "unknown"}};
for (auto const& x : typeMap) {
mVhal->setType(x.type);
ASSERT_TRUE(Face::cfg().get<std::string>("type") == x.typeStr);
}
}
TEST_F(VirtualHalTest, sensorStrength) {
struct {
common::SensorStrength strength;
const char* strengthStr;
} strengths[] = {{common::SensorStrength::CONVENIENCE, "CONVENIENCE"},
{common::SensorStrength::WEAK, "WEAK"},
{common::SensorStrength::STRONG, "STRONG"}};
for (auto const& x : strengths) {
mVhal->setSensorStrength(x.strength);
ASSERT_TRUE(Face::cfg().get<std::string>("strength") == x.strengthStr);
}
}
TEST_F(VirtualHalTest, setLatency) {
ndk::ScopedAStatus status;
std::vector<int32_t> in_lats[] = {{1}, {2, 3}, {5, 4}};
for (auto const& in_lat : in_lats) {
status = mVhal->setOperationAuthenticateLatency(in_lat);
ASSERT_TRUE(status.isOk());
OptIntVec out_lat = Face::cfg().getopt<OptIntVec>("operation_authenticate_latency");
ASSERT_TRUE(in_lat.size() == out_lat.size());
for (int i = 0; i < in_lat.size(); i++) {
ASSERT_TRUE(in_lat[i] == out_lat[i]);
}
}
std::vector<int32_t> bad_in_lats[] = {{}, {1, 2, 3}, {1, -3}};
for (auto const& in_lat : bad_in_lats) {
status = mVhal->setOperationAuthenticateLatency(in_lat);
ASSERT_TRUE(!status.isOk());
ASSERT_TRUE(status.getServiceSpecificError() == IVirtualHal::STATUS_INVALID_PARAMETER);
}
}
TEST_F(VirtualHalTest, setOperationAuthenticateDuration) {
ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
"operation_authenticate_duration", &IVirtualHal::setOperationAuthenticateDuration,
{0, 33});
ASSERT_TRUE(status.isOk());
}
TEST_F(VirtualHalTest, setLockoutTimedDuration) {
ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
"lockout_timed_duration", &IVirtualHal::setLockoutTimedDuration, {0, 35});
ASSERT_TRUE(status.isOk());
}
TEST_F(VirtualHalTest, setLockoutTimedThreshold) {
ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
"lockout_timed_threshold", &IVirtualHal::setLockoutTimedThreshold, {0, 36});
ASSERT_TRUE(status.isOk());
}
TEST_F(VirtualHalTest, setLockoutPermanentThreshold) {
ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
"lockout_permanent_threshold", &IVirtualHal::setLockoutPermanentThreshold, {0, 37});
ASSERT_TRUE(status.isOk());
}
TEST_F(VirtualHalTest, setOthers) {
// Verify that there is no CHECK() failures
mVhal->setEnrollments({7, 6, 5});
mVhal->setChallenge(111222333444555666);
mVhal->setOperationAuthenticateError(4);
mVhal->setOperationEnrollLatency({4, 5});
mVhal->setLockout(false);
mVhal->setLockoutEnable(false);
}
} // namespace aidl::android::hardware::biometrics::face
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}