plugins – Testsuite plugins

Plugins to support the pyudev testsuite.

The following plugins are provided and enabled:

udev_database Provide access the udev device database.
privileged Support privileged operations to trigger real udev events.
fake_monitor Provide a fake Monitor.
mock_libudev Plugin to mock calls to libudev.
libudev Provide a list of all libudev functions as declared in libudev.h.

The main plugin is udev_database that extracts the real udev database using the udevadm utility and provides tests with a sample of this database. It also supports to restrict tests to certain udev versions.

The other plugins only provide support for specific test cases by tuning some hooks or adding some additional funcargs.

udev_databasepytest plugin to access the udev device database

Provide access the udev device database.

This plugin parses the udev device database from udevadm and attaches it to the test configuration object.

class plugins.udev_database.DeviceDatabase

The udev device database.

This class is an iterable over DeviceData objects that contain the data associated with each device stored in the udev database.

find_device_data(device_path)

Find device data for the device designated by device_path.

device_path is a string containing the device path.

Return a DeviceData object containing the data for the given device, or None if the device was not found.

class plugins.udev_database.DeviceData

Data for a single device.

device_path

The path of the device without the sysfs mountpoint.

attributes

Get the device attributes as mapping of attributes names as strings to property values as byte strings.

Warning

As udevadm only exports printable attributes, this list can be incomplete! Do not compare this dictionary directly to a attributes dictionary received through pyudev!

Get the device links as list of strings.

device_node

Get the device node path as string, or None if the device has no device node.

device_number

Get the device number as integer or 0 if the device has no device number.

properties

Get the device properties as mapping of property names as strings to property values as strings.

sys_path

Get the sysfs path of the device.

tags

Get the device tags as list of strings.

Test markers

pytest.mark.udev_version(version_spec)

Specify the udev version requirement for a test:

@pytest.mark.udev_version('>= 180')
def test_foo():
    assert True

test_foo will only be run, if the udev version is greater or equal than 180. Otherwise the test is skipped.

version_spec is a string specifying the udev version requirement. If the requirement is not met, the test is skipped.

Configuration values

The plugin attaches the following attributes to pytest.config:

pytest.config.udev_version

The udev version as integer.

pytest.config.udev_database

The whole udev device database as DeviceDatabase object.

pytest.config.udev_device_sample

A list of devices to use for tests as list of DeviceData objects, an excerpt of pytest.config.udev_database.

Funcargs

The plugin provides the following funcargs:

plugins.udev_database.pytest_funcarg__udev_database(request)

The udev database as provided by pytest.config.udev_database.

Command line options

The plugin adds the following command line options to py.test:

--all-devices

Run device tests against all devices in the database. By default, only a random sample of devices are being tested against.

Warning

Tests may take a very long time with this option.

--device DEVICE

Run device tests against a specific device only. DEVICE is the device path without the sysfs mountpoint.

--device-sample-size N

The size of the random sample. Defaults to 10.

privileged – Privileged operations

Support privileged operations to trigger real udev events.

This plugin adds load_dummy() and unload_dummy() to the pytest namespace.

Command line options

The plugin adds the following command line options to py.test:

--enable-privileged

Enable privileged tests. You’ll need to have sudo configured correctly in order to run tests with this option.

Configuration

In order to execute these tests without failure, you need to configure sudo to allow the user that executes the test to run the following commands:

  • modprobe dummy
  • modprobe -r dummy

To do so, create a file /etc/sudoers.d/20pyudev-tests with the following content:

me ALL = (root) NOPASSWD: /sbin/modprobe dummy, /sbin/modprobe -r dummy

Replace me with your actual user name. NOPASSWD: tells sudo not to ask for a password when executing these commands. This is simply for the sake of convenience and to allow unattended test execution. Remove this word if you want to be asked for a password.

Make sure to change the owner and group to root:root and the permissions of this file to 440 afterwards, other sudo will refuse to load the file. Also check the file with visudo to prevent syntactic errors:

$ chown root:root /etc/sudoers.d/20pyudev-tests
$ chmod 440 /etc/sudoers.d/20pyudev-tests
$ visudo -c -f /etc/sudoers.d/20pyudev-tests

pytest namespace

The plugin adds the following functions to the pytest namespace:

plugins.privileged.load_dummy()

Load the dummy module.

If privileged tests are disabled, the current test is skipped.

plugins.privileged.unload_dummy()

Unload the dummy module.

If privileged tests are disabled, the current test is skipped.

fake_monitor – A fake Monitor

Provide a fake Monitor.

This fake monitor allows to trigger arbitrary events. Use this class to test class building upon monitor without the need to rely on real events generated by privileged operations as provided by the privileged plugin.

class plugins.fake_monitor.FakeMonitor(device_to_emit)

A fake Monitor which allows you to trigger arbitrary events.

This fake monitor implements the complete Monitor interface and works on real file descriptors so that you can select() the monitor.

close()

Close sockets acquired by this monitor.

trigger_event()

Trigger an event on clients of this monitor.

Funcargs

The plugin provides the following funcargs:

plugins.fake_monitor.pytest_funcarg__fake_monitor(request)

Return a FakeMonitor, which emits the platform device as returned by the fake_monitor_device funcarg on all triggered actions.

Warning

To use this funcarg, you have to provide the fake_monitor_device funcarg!

mock_libudev – Mock calls to libudev

Plugin to mock calls to libudev.

This plugin adds calls_to_libudev() and libudev_list() to the pytest namespace.

plugins.mock_libudev.calls_to_libudev(function_calls)

Mock libudev functions and check calls to the mocked functions:

calls = {'udev_device_ref': [(device,)]}
with pytest.calls_to_libudev(calls):
    device.parent

function_calls is a dictionary that maps libudev function names to a list of calls, where each call is represented as tuple containing the arguments expected to be passed to the function.

If any call in function_calls does not occur, the function triggers an assertion.

All mocked functions are restored if the context exits.

plugins.mock_libudev.libudev_list(function, items)

Mock a libudev linked list:

with pytest.libudev_list('udev_device_get_tag_list_entry', ['foo', 'bar']):
    assert list(device.tags) == ['foo', 'bar']

function is a string containing the name of the libudev function that returns the list. items is an iterable yielding items which shall be returned by the mocked list function. An item in items can either be a tuple with two components, where the first component is the item name, and the second the item value, or a single element, which is the item name. The item value is None in this case.

libudev – Parse libudev.h

Provide a list of all libudev functions as declared in libudev.h.

This plugin parses libudev.h with gccxml and extracts all libudev functions from this header.

Configuration values

This plugin attaches the following attribute to pytest.config:

plugins.libudev.libudev_functions

All libudev functions as list of Function objects.

Funcargs

This plugin provides the the following funcarg:

plugins.libudev.pytest_funcarg__libudev_function(request)

Return each Function parsed from libudev.

If libudev could not be parsed, the invoking test is skipped.

Types

class plugins.libudev.GCCXMLParser(gccxml)

The parser to parse translation units.

classmethod default_parser()

Create a default parser.

This method searches gccxml in $PATH.

Return a GCCXMLParser, if gccxml is found. Raise LookupError otherwise.

class plugins.libudev.Unit(tree)

A translation unit.

Parses a translation unit and provides a list of all symbols in this unit.

functions

Yield all functions in this unit as Function objects.

classmethod parse(filename, parser=None)

Parse the translation unit denoted by filename.

filename is a string denoting the file to parse. parser is a GCCXMLParser to use for parsing. If None, GCCXMLParser.default_parser() is used.

Return a Unit representing the parsed unit. Raise EnvironmentError, if filename could not be opened or read.

symbols

Yield all symbols in this unit.

Warning

This does not really yield all symbols, but only those symbol types that are required to parse libudev.h. Other symbols, e.g. C++ classes or namespaces, are ignored.

Symbol classes

class plugins.libudev.Function

A function.

name

The function name as string

arguments

A tuple providing with the argument types of this function

return_type

The return type of this function

class plugins.libudev.Struct

A structure.

name

The struct name as string

class plugins.libudev.FundamentalType

A fundamental type.

name

The type name as string

class plugins.libudev.CvQualifiedType

A constant-qualified type.

type

The underlying type

class plugins.libudev.PointerType

A pointer type.

type

The underyling type