martinpitt / umockdev

Mock hardware devices for creating unit tests and bug reporting
https://launchpad.net/umockdev
GNU Lesser General Public License v2.1
312 stars 57 forks source link

CI status

umockdev

umockdev mocks Linux devices for creating integration tests for hardware related libraries and programs. It also provides tools to record the properties and behaviour of particular devices, and to run a program or test suite under a test bed with the previously recorded devices loaded. This allows developers of software like gphoto or libmtp to receive these records in bug reports and recreate the problem on their system without having access to the affected hardware.

The UMockdevTestbed class builds a temporary sandbox for mock devices. You can add a number of devices including arbitrary sysfs attributes and udev properties, and then run your software in that test bed that is independent of the actual hardware it is running on. With this you can simulate particular hardware in virtual environments up to some degree, without needing any particular privileges or disturbing the whole system.

You can use this from the command line, and a wide range of programming languages (C, Vala, and everything which supports gobject-introspection, such as JavaScript or Python).

Right now umockdev supports the following features:

Other aspects and functionality will be added in the future as use cases arise.

Component overview

umockdev consists of the following parts:

Mocking /proc and /dev

When enabled, the preload library diverts access to /proc and /dev to the corresponding directories in $UMOCKDEV_DIR, aka. umockdev_testbed_get_root(). However, if a path does not exist there, it falls through the real /proc and /dev. Thus you can easily replace files like /proc/cpuinfo or add new ones without losing standard files such as /dev/null or /proc/pid/*. Currently there is no way to "remove" files from the real directories or fully control them. You can get the effect of removing a file by creating a broken symlink in the umockdev directory though.

In contrast, an UMockdevTestbed fully controls the visible /sys directory; for a program there is no (regular) way to see the real /sys, unless it circumvents the libc API.

Examples

API: Create a fake battery

Batteries, and power supplies in general, are simple devices in the sense that userspace programs such as upower only communicate with them through sysfs and uevents. No /dev nor ioctls are necessary. docs/examples/ has two example programs how to use libumockdev to create a fake battery device, change it to low charge, sending an uevent, and running upower on a local test system D-BUS in the testbed, with watching what happens with upower --monitor-detail. battery.c shows how to do that with plain GObject in C, battery.py is the equivalent program in Python that uses the GI binding.

Command line: Record and replay PtP/MTP USB devices (unordered)

With this method of record and replay a tree of dependent USB URBs is generated and replayed. The advantage is that discontinuities may occur during replay, as the replayer will always try to find the appropriate response, possibly changing the order of replay.

If you need completely in-order replay or USB control commands, then the pcap based replayer will be more appropriate.

Note that if your *.ioctl files get too large for some purpose, you can xz-compress them.

Command line: Record and replay USB devices using usbmon pcap captures

This method of USB replay is a pure in-order replay. This has the advantage that timeouts will be correctly emulated rather than causing discontinuities in the replayer and possibly incorrect device state emulation. pcap currently also has the advantage of correctly replaying USB control transfers.

Command line: Record and replay tty devices

This example records the behaviour of an USB 3G stick with ModemManager.

Record and replay an Unix socket

This example records the behaviour of ofonod when talking to Android's rild through /dev/socket/rild.

Record and replay input devices

For those the "evemu" format is preferable as it is platform independent (scripts depend on the architecture endianess and size of time_t) and human readable. ioctls need to be recorded as well, as they specify the input device's capability beyond what it is already exposed in sysfs, particularly for multi-touch devices.

This uses the evtest program, but you can use anything which listens to evdev devices.

Command line: Mock file in /proc

By default, /proc is the standard system directory:

$ umockdev-run -- head -n2 /proc/cpuinfo
processor   : 0
vendor_id   : GenuineIntel

But you can replace files (or directories) in it by the ones in the mock dir:

$ umockdev-run -- sh -c 'mkdir $UMOCKDEV_DIR/proc;
>   echo hello > $UMOCKDEV_DIR/proc/cpuinfo;
>   cat /proc/cpuinfo'
hello

Build, Test, Run

If you want to build umockdev from a git checkout, install the necessary build dependencies first. On a Debian based system:

sudo apt install -y meson pkg-config valac libglib2.0-dev libudev-dev libgudev-1.0-dev libpcap-dev python3-gi gobject-introspection libgirepository1.0-dev gir1.2-glib-2.0 gir1.2-gudev-1.0 gtk-doc-tools

In order to run all integration tests, install the test dependencies:

sudo apt install -y udev xserver-xorg-video-dummy xserver-xorg-input-evdev xserver-xorg-input-synaptics xinput usbutils gphoto2

umockdev uses the meson build system. Configure a build tree with desired options with

meson setup build/
cd build/

You may want to supply --prefix=/usr or similar options, see meson setup --help.

If you don't want to install umockdev but use it from the build tree, run the programs with these environment variables, assuming that your current directory is the build directory:

LD_LIBRARY_PATH=`pwd` GI_TYPELIB_PATH=`pwd` ./umockdev-run ...

Debugging

To debug umockdev itself and what it's doing, you can set the $UMOCKDEV_DEBUG environment variable to a list (comma or space separated) of

Development

umockdev is being developed and released on https://github.com/martinpitt/umockdev.

umockdev is very much demand driven. If you want to work on a new feature (such as adding support for more ioctls) or contribute a bug fix, please check out the git repository, push your changes to github, and create a pull request. Contributions are appreciated, and I will do my best to provide timely reviews.

If you find a bug in umockdev or have an idea about a new feature but don't want to implement it yourself, please file a report in the github issue tracker. Please always include the version of umockdev that you are using, and a complete runnable reproducer of the problem (i. e. the code and recorded scripts/ioctls, etc.), unless it is a feature request.

License

umockdev 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 2.1 of the License, or (at your option) any later version.

umockdev is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program; If not, see http://www.gnu.org/licenses/.