tests: Add umockdev based testing

Initially only the vfs5011 driver is tested. Please note that these
tests will be unreliable before umockdev 0.13.2.

See also https://github.com/martinpitt/umockdev/pull/92
This commit is contained in:
Benjamin Berg 2019-08-12 14:34:37 +02:00
parent e372311afe
commit 538038867b
8 changed files with 329 additions and 2 deletions

View file

@ -7,7 +7,7 @@ stages:
variables:
DEPENDENCIES: libgusb-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
gobject-introspection-devel python3-cairo python3-gobject
gobject-introspection-devel python3-cairo python3-gobject umockdev
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
@ -44,7 +44,7 @@ test:
stage: test
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
- meson -Ddrivers=virtual_image . _build
- meson -Ddrivers=all . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit

21
tests/README-umockdev Normal file
View file

@ -0,0 +1,21 @@
To create a new umockdev test, you should:
1. Decide on what to test, the easiest case is just using the existing
capture test case.
2. Find the USB device you are testing with lsusb, e.g.:
Bus 001 Device 005: ID 138a:0090 Validity Sensors, Inc. VFS7500 Touch Fingerprint Sensor
This means we need to record USB device /dev/bus/usb/001/005
3. Run "umockdev-record /dev/bus/usb/001/005 >device"
This records the information about device, it should be placed into test/DRIVER/device
4. Run the test, for a capture test this would be:
umockdev-record -i /dev/bus/usb/001/005=capture.ioctl -- ./capture.py capture.png
This will create a capture.ioctl and capture.png file.
5. Place all files into the driver subdirectory test/DRIVER,
i.e. device, capture.ioctl, capture.png
6. Add glue to meson.build
7. Test whether everything works as expected
Please note, there is no need to use a real finger print in this case. If
you would like to avoid submitting your own fingerprint then please just
use e.g. the side of your finger, arm, or anything else that will produce
an image with the device.

46
tests/capture.py Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/python3
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib
import cairo
import sys
if len(sys.argv) != 2:
print("Please specify exactly one argument, the output location for the capture image")
sys.exit(1)
ctx = GLib.main_context_default()
c = FPrint.Context()
c.enumerate()
devices = c.get_devices()
d = devices[0]
d.open_sync()
img = d.capture_sync(True)
d.close_sync()
width = img.get_width()
height = img.get_height()
c_img = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height)
c_rowstride = c_img.get_stride()
buf = img.get_data()
c_buf = c_img.get_data()
for x in range(width):
for y in range(height):
c_buf[y * c_rowstride + x * 4 + 0] = buf[y * width + x]
c_buf[y * c_rowstride + x * 4 + 1] = buf[y * width + x]
c_buf[y * c_rowstride + x * 4 + 2] = buf[y * width + x]
# Byte 4 is don't care
c_img.mark_dirty()
c_img.write_to_png(sys.argv[1])

View file

@ -15,3 +15,11 @@ if 'virtual_image' in drivers
)
endif
if 'vfs5011' in drivers
test(
'vfs5011',
find_program('umockdev-test.py'),
args: join_paths(meson.current_source_dir(), 'vfs5011'),
env: envs,
)
endif

65
tests/umockdev-test.py Executable file
View file

@ -0,0 +1,65 @@
#!/usr/bin/env python3
import sys
import os
import os.path
import shutil
import tempfile
import subprocess
if len(sys.argv) != 2:
print("You need to specify exactly one argument, the directory with test data")
edir = os.path.dirname(sys.argv[0])
ddir = sys.argv[1]
tmpdir = tempfile.mkdtemp(prefix='libfprint-umockdev-test-')
assert os.path.isdir(ddir)
assert os.path.isfile(os.path.join(ddir, "device"))
def cmp_pngs(png_a, png_b):
print("Comparing PNGs %s and %s" % (png_a, png_b))
import cairo
img_a = cairo.ImageSurface.create_from_png(png_a)
img_b = cairo.ImageSurface.create_from_png(png_b)
assert img_a.get_format() == cairo.FORMAT_RGB24
assert img_b.get_format() == cairo.FORMAT_RGB24
assert img_a.get_width() == img_b.get_width()
assert img_a.get_height() == img_b.get_height()
assert img_a.get_stride () == img_b.get_stride()
data_a = img_a.get_data()
data_b = img_b.get_data()
stride = img_a.get_stride()
for x in range(img_a.get_width()):
for y in range(img_a.get_height()):
assert(data_a[y * stride + x * 4] == data_b[y * stride + x * 4])
def capture():
ioctl = os.path.join(ddir, "capture.ioctl")
device = os.path.join(ddir, "device")
dev = open(ioctl).readline().strip()
assert dev.startswith('@DEV ')
dev = dev[5:]
subprocess.check_call(['umockdev-run', '-d', device,
'-i', "%s=%s" % (dev, ioctl),
'--',
'%s' % os.path.join(edir, "capture.py"),
'%s' % os.path.join(tmpdir, "capture.png")])
assert os.path.isfile(os.path.join(tmpdir, "capture.png"))
if os.path.isfile(os.path.join(ddir, "capture.png")):
# Compare the images, they need to be identical
cmp_pngs(os.path.join(tmpdir, "capture.png"), os.path.join(ddir, "capture.png"))
try:
if os.path.exists(os.path.join(ddir, "capture.ioctl")):
capture()
finally:
shutil.rmtree(tmpdir)

107
tests/vfs5011/capture.ioctl Normal file

File diff suppressed because one or more lines are too long

BIN
tests/vfs5011/capture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

80
tests/vfs5011/device Normal file
View file

@ -0,0 +1,80 @@
P: /devices/pci0000:00/0000:00:14.0/usb2/2-6
N: bus/usb/002/017=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004
E: DEVNAME=/dev/bus/usb/002/017
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=138a/17/78
E: TYPE=255/17/255
E: BUSNUM=002
E: DEVNUM=017
E: MAJOR=189
E: MINOR=144
E: SUBSYSTEM=usb
E: ID_VENDOR=138a
E: ID_VENDOR_ENC=138a
E: ID_VENDOR_ID=138a
E: ID_MODEL=0017
E: ID_MODEL_ENC=0017
E: ID_MODEL_ID=0017
E: ID_REVISION=0078
E: ID_SERIAL=138a_0017_6c3b5712a6c0
E: ID_SERIAL_SHORT=6c3b5712a6c0
E: ID_BUS=usb
E: ID_USB_INTERFACES=:ff0000:
E: ID_VENDOR_FROM_DATABASE=Validity Sensors, Inc.
E: ID_MODEL_FROM_DATABASE=VFS 5011 fingerprint sensor
A: authorized=1
A: avoid_reset_quirk=0
A: bConfigurationValue=1
A: bDeviceClass=ff
A: bDeviceProtocol=ff
A: bDeviceSubClass=11
A: bMaxPacketSize0=8
A: bMaxPower=100mA
A: bNumConfigurations=1
A: bNumInterfaces= 1
A: bcdDevice=0078
A: bmAttributes=a0
A: busnum=2
A: configuration=
H: descriptors=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004
A: dev=189:144
A: devnum=17
A: devpath=6
L: driver=../../../../../bus/usb/drivers/usb
A: idProduct=0017
A: idVendor=138a
A: ltm_capable=no
A: maxchild=0
L: port=../2-0:1.0/usb2-port6
A: power/active_duration=624952
A: power/async=enabled
A: power/autosuspend=2
A: power/autosuspend_delay_ms=2000
A: power/connected_duration=624952
A: power/control=on
A: power/level=on
A: power/persist=1
A: power/runtime_active_kids=0
A: power/runtime_active_time=624676
A: power/runtime_enabled=forbidden
A: power/runtime_status=active
A: power/runtime_suspended_time=0
A: power/runtime_usage=1
A: power/wakeup=disabled
A: power/wakeup_abort_count=
A: power/wakeup_active=
A: power/wakeup_active_count=
A: power/wakeup_count=
A: power/wakeup_expire_count=
A: power/wakeup_last_time_ms=
A: power/wakeup_max_time_ms=
A: power/wakeup_total_time_ms=
A: quirks=0x0
A: removable=fixed
A: rx_lanes=1
A: serial=6c3b5712a6c0
A: speed=12
A: tx_lanes=1
A: urbnum=7
A: version= 1.10