From 0a42b90390dbfb8d2ec1bd3581bb5e505918ecf5 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Fri, 17 Jan 2020 14:47:13 +0100 Subject: [PATCH] tests: Add dbusmock template for fprintd daemon --- tests/Makefile.am | 1 + tests/dbusmock/fprintd.py | 320 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 321 insertions(+) create mode 100644 tests/dbusmock/fprintd.py diff --git a/tests/Makefile.am b/tests/Makefile.am index ca96c86..cbeac8d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,6 +3,7 @@ TESTS = fprintd.py EXTRA_DIST = \ $(TESTS) \ + dbusmock/fprintd.py \ prints/README \ prints/*.png \ prints/*.jpg diff --git a/tests/dbusmock/fprintd.py b/tests/dbusmock/fprintd.py new file mode 100644 index 0000000..2052d7f --- /dev/null +++ b/tests/dbusmock/fprintd.py @@ -0,0 +1,320 @@ +# -*- coding: utf-8 -*- + +'''fprintd mock template + +This creates the expected methods and properties of the +net.reactivated.Fprint.Manager object (/net/reactivated/Fprint/Manager) +but no devices. +''' + +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text +# of the license. + +__author__ = 'Bastien Nocera' +__email__ = 'hadess@hadess.net' +__copyright__ = '(c) 2020 Red Hat Inc.' +__license__ = 'LGPL 3+' + +import dbus + +from dbusmock import MOCK_IFACE, mockobject + +BUS_NAME = 'net.reactivated.Fprint' +MAIN_OBJ = '/net/reactivated/Fprint/Manager' +SYSTEM_BUS = True +IS_OBJECT_MANAGER = False + +MAIN_IFACE = 'net.reactivated.Fprint.Manager' +MANAGER_MOCK_IFACE = 'net.reactivated.Fprint.Manager.Mock' + +DEVICE_IFACE = 'net.reactivated.Fprint.Device' +DEVICE_MOCK_IFACE = 'net.reactivated.Fprint.Device.Mock' + +VALID_FINGER_NAMES = [ + 'left-thumb', + 'left-index-finger', + 'left-middle-finger', + 'left-ring-finger', + 'left-little-finger', + 'right-thumb', + 'right-index-finger', + 'right-middle-finger', + 'right-ring-finger', + 'right-little-finger' +] + +VALID_VERIFY_STATUS = [ + 'verify-no-match', + 'verify-match', + 'verify-retry-scan', + 'verify-swipe-too-short', + 'verify-finger-not-centered', + 'verify-remove-and-retry', + 'verify-disconnected', + 'verify-unknown-error' +] + +VALID_ENROLL_STATUS = [ + 'enroll-completed', + 'enroll-failed', + 'enroll-stage-passed', + 'enroll-retry-scan', + 'enroll-swipe-too-short', + 'enroll-finger-not-centered', + 'enroll-remove-and-retry', + 'enroll-data-full', + 'enroll-disconnected', + 'enroll-unknown-error' +] + +# Ever incrementing device ID +last_id = 0 + +def load(mock, parameters): + fprintd = mockobject.objects[MAIN_OBJ] + mock.last_device_id = 0 + fprintd.fingers = {} + +@dbus.service.method(MAIN_IFACE, + in_signature='', out_signature='ao') +def GetDevices(self): + return [(k) for k in mockobject.objects.keys() if "/Device/" in k] + +@dbus.service.method(MAIN_IFACE, + in_signature='', out_signature='o') +def GetDefaultDevice(self): + devices = self.GetDevices() + if len(devices) < 1: + raise dbus.exceptions.DBusException( + 'No devices available', + name='net.reactivated.Fprint.Error.NoSuchDevice') + return devices[0] + +@dbus.service.method(MANAGER_MOCK_IFACE, + in_signature='sis', out_signature='s') +def AddDevice(self, device_name, num_enroll_stages, scan_type): + '''Convenience method to add a fingerprint reader device + + You have to specify a device name, the number of enrollment + stages it would use (> 0) and the scan type, as a string + (either 'press' or 'swipe') + ''' + + if scan_type not in ['swipe', 'press']: + raise dbus.exceptions.DBusException( + 'Invalid scan_type \'%s\'.' % scan_type, + name='org.freedesktop.DBus.Error.InvalidArgs') + + if num_enroll_stages <= 0: + raise dbus.exceptions.DBusException( + 'Invalid num_enroll_stages \'%s\'.' % num_enroll_stages, + name='org.freedesktop.DBus.Error.InvalidArgs') + + self.last_device_id += 1 + path = '/net/reactivated/Fprint/Device/%d' % last_id + device_properties = { + 'name': dbus.String(device_name, variant_level=1), + 'num-enroll-stages': dbus.UInt32(num_enroll_stages, variant_level=1), + 'scan-type': scan_type + } + + self.AddObject(path, + DEVICE_IFACE, + # Properties + device_properties, + # Methods + [ + ('ListEnrolledFingers', 's', 'as', ListEnrolledFingers), + ('DeleteEnrolledFingers', 's', '', DeleteEnrolledFingers), + ('DeleteEnrolledFingers2', '', '', DeleteEnrolledFingers2), + ('Claim', 's', '', Claim), + ('Release', '', '', Release), + ('VerifyStart', 's', '', VerifyStart), + ('VerifyStop', '', '', VerifyStop), + ('EnrollStart', 's', '', EnrollStart), + ('EnrollStop', '', '', EnrollStop) + ]) + + device = mockobject.objects[path] + device.fingers = {} + device.claimed_user = None + device.action = None + + return path + +@dbus.service.method(DEVICE_IFACE, + in_signature='s', out_signature='as') +def ListEnrolledFingers(device, user): + if user in device.fingers: + return device.fingers[user] + raise dbus.exceptions.DBusException( + 'No enrolled prints in device %s for user %s' % (device.path, user), + name='net.reactivated.Fprint.Error.NoEnrolledPrints') + +@dbus.service.method(DEVICE_IFACE, + in_signature='s', out_signature='') +def DeleteEnrolledFingers(device, user): + device.fingers[user] = [] + +@dbus.service.method(DEVICE_IFACE, + in_signature='', out_signature='') +def DeleteEnrolledFingers2(device): + if not device.claimed_user: + raise dbus.exceptions.DBusException( + 'Device was not claimed before use', + name='net.reactivated.Fprint.Error.ClaimDevice') + device.fingers[device.claimed_user] = [] + +@dbus.service.method(DEVICE_IFACE, + in_signature='s', out_signature='') +def Claim(device, user): + if device.claimed_user: + raise dbus.exceptions.DBusException( + 'Device already in use by %s' % device.claimed_user, + name='net.reactivated.Fprint.Error.AlreadyInUse') + + device.claimed_user = user + +@dbus.service.method(DEVICE_IFACE, + in_signature='', out_signature='') +def Release(device): + if not device.claimed_user: + raise dbus.exceptions.DBusException( + 'Device was not claimed before use', + name='net.reactivated.Fprint.Error.ClaimDevice') + device.claimed_user = None + +def can_verify_finger(device, finger_name): + # We should already have checked that there are enrolled fingers + if finger_name == 'any': + return True + if finger_name in device.fingers[device.claimed_user]: + return True + return False + +@dbus.service.method(DEVICE_IFACE, + in_signature='s', out_signature='') +def VerifyStart(device, finger_name): + if not device.claimed_user: + raise dbus.exceptions.DBusException( + 'Device was not claimed before use', + name='net.reactivated.Fprint.Error.ClaimDevice') + if device.claimed_user not in device.fingers: + raise dbus.exceptions.DBusException( + 'No enrolled prints for user \'%s\'' % device.claimed_user, + name='net.reactivated.Fprint.Error.NoEnrolledPrints') + if not finger_name: + raise dbus.exceptions.DBusException( + 'Invalid empty finger_name.', + name='org.freedesktop.DBus.Error.InvalidArgs') + if not can_verify_finger(device, finger_name): + raise dbus.exceptions.DBusException( + 'Finger \'%s\' not enrolled.' % finger_name, + name='org.freedesktop.DBus.Error.Internal') + if device.action: + raise dbus.exceptions.DBusException( + 'Action \'%s\' already in progress' % device.action, + name='net.reactivated.Fprint.Error.AlreadyInUse') + device.action = 'verify' + + if finger_name == 'any': + finger_name = device.fingers[device.claimed_user][0] + device.EmitSignal(DEVICE_IFACE, 'VerifyFingerSelected', 's', [ + finger_name + ]) + +@dbus.service.method(DEVICE_MOCK_IFACE, + in_signature='sb', out_signature='') +def EmitVerifyStatus(device, result, done): + if (not device.action) or (device.action != 'verify'): + raise dbus.exceptions.DBusException( + 'Cannot send verify statuses when not verifying', + name='org.freedesktop.DBus.Error.InvalidArgs') + if result not in VALID_VERIFY_STATUS: + raise dbus.exceptions.DBusException( + 'Unknown verify status \'%s\'' % result, + name='org.freedesktop.DBus.Error.InvalidArgs') + device.EmitSignal(DEVICE_IFACE, 'VerifyStatus', 'sb', [ + result, + done + ]) + +@dbus.service.method(DEVICE_IFACE, + in_signature='', out_signature='') +def VerifyStop(device): + if device.action != 'verify': + raise dbus.exceptions.DBusException( + 'No verification to stop', + name='net.reactivated.Fprint.Error.NoActionInProgress') + device.action = None + +@dbus.service.method(DEVICE_IFACE, + in_signature='s', out_signature='') +def EnrollStart(device, finger_name): + if finger_name not in VALID_FINGER_NAMES: + raise dbus.exceptions.DBusException( + 'Invalid finger name \'%s\'' % finger_name, + name='net.reactivated.Fprint.Error.InvalidFingername') + if not device.claimed_user: + raise dbus.exceptions.DBusException( + 'Device was not claimed before use', + name='net.reactivated.Fprint.Error.ClaimDevice') + if device.action: + raise dbus.exceptions.DBusException( + 'Action \'%s\' already in progress' % device.action, + name='net.reactivated.Fprint.Error.AlreadyInUse') + device.action = 'enroll' + +@dbus.service.method(DEVICE_MOCK_IFACE, + in_signature='sb', out_signature='') +def EmitEnrollStatus(device, result, done): + if (not device.action) or (device.action != 'enroll'): + raise dbus.exceptions.DBusException( + 'Cannot send enroll statuses when not enrolling', + name='org.freedesktop.DBus.Error.InvalidArgs') + if result not in VALID_ENROLL_STATUS: + raise dbus.exceptions.DBusException( + 'Unknown enroll status \'%s\'' % result, + name='org.freedesktop.DBus.Error.InvalidArgs') + device.EmitSignal(DEVICE_IFACE, 'EnrollStatus', 'sb', [ + result, + done + ]) + # FIXME save enrolled finger? + +@dbus.service.method(DEVICE_IFACE, + in_signature='', out_signature='') +def EnrollStop(device): + if device.action != 'enroll': + raise dbus.exceptions.DBusException( + 'No enrollment to stop', + name='net.reactivated.Fprint.Error.NoActionInProgress') + device.action = None + +@dbus.service.method(DEVICE_MOCK_IFACE, + in_signature='sas', out_signature='') +def SetEnrolledFingers(device, user, fingers): + '''Convenience method to set the list of enrolled fingers. + + The device_path is the return value from AddDevice(), and the + array of fingers must only contain valid finger names. + + Returns nothing. + ''' + + if len(fingers) < 1: + raise dbus.exceptions.DBusException( + 'Fingers array must not be empty', + name='org.freedesktop.DBus.Error.InvalidArgs') + + for k in fingers: + if k not in VALID_FINGER_NAMES: + raise dbus.exceptions.DBusException( + 'Invalid finger name \'%s\'' % k, + name='org.freedesktop.DBus.Error.InvalidArgs') + + device.fingers[user] = fingers +