[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
|
|
Subscribe / Log in / New account

Driver regression testing with roadtest

By Jonathan Corbet
March 18, 2022
The kernel community has a number of excuses for the relative paucity of regression-test coverage in the project, some of which hold more water than others. One of the more convincing reasons is that a great deal of kernel code is hardware-specific, and nobody can ever hope to put together a testing system with even a small fraction of all the hardware that the kernel supports. A new driver-testing framework called roadtest, posted by Vincent Whitchurch, may make that excuse harder to sustain, though, at least for certain kinds of hardware.

One of the problems with hardware is its sheer variety. Consider a device as conceptually simple as a GPIO port which, at its core, drives a single electrical line to either a logical true or false value. GPIO drivers should be simple things, and many of them are, but vendors like to add their own flourishes with each new release. As a result, there are well over 150 GPIO drivers in the kernel source, many of which can drive more than one variant of a device. There is no way to build a system with all of those devices in it; most of them are part of a larger peripheral or system-on-chip, and many of them have not been commercially available for years.

Of course, each of those drivers was, at one point, tested on the hardware it drives. They would normally be expected to continue to work. But the kernel is constantly changing, and changes often affect drivers as well. Developers making those changes do their best to avoid breaking anything, but they have no way to test changes that affect most drivers; even subsystem maintainers will normally only have a subset of the devices available for testing. So there is always a possibility that regressions will slip in and go unnoticed until somebody's device stops working.

Roadtest aims to circumvent this problem by eliminating the need to actually have the hardware present to test whether a driver still works. This is done by pairing driver tests with mock devices that can run anywhere; when a developer makes a set of regression tests for a specific driver, that work includes the mocked version of the target device(s) as well. The tests are then run under a specially built User-Mode Linux kernel, with the mocked hardware filling in for the real thing.

Forcing a test author to also implement an emulated version of the device under test sounds like a high bar to overcome. The good news is that the mocked devices need not encapsulate the full complexity of the real thing; they simply need to respond well enough to verify that the driver is behaving in the expected way. Emulating the device's programming interface (without actually doing the things a real device would do) may well be sufficient.

Consider, for example, this test from the patch set, which verifies the driver for the opt3001 light-sensor driver. Both the tests and the mocked devices are written in Python; the core part of the implementation for the mocked opt3001 device looks like this:

    class OPT3001(SMBusModel):
        def __init__(self, **kwargs: Any) -> None:
            super().__init__(regbytes=2, byteorder="big", **kwargs)
            # Reset values from datasheet
            self.regs = {
                REG_RESULT: 0x0000,
                REG_CONFIGURATION: 0xC810,
                REG_LOW_LIMIT: 0xC000,
                REG_HIGH_LIMIT: 0xBFFF,
                REG_MANUFACTURER_ID: 0x5449,
                REG_DEVICE_ID: 0x3001,
            }
    
        def reg_read(self, addr: int) -> int:
            val = self.regs[addr]
    
            if addr == REG_CONFIGURATION:
                # Always indicate that the conversion is ready.  This is good
                # enough for our current purposes.
                val |= REG_CONFIGURATION_CRF
    
            return val
    
        def reg_write(self, addr: int, val: int) -> None:
            assert addr in self.regs
            self.regs[addr] = val

The opt3001 is an SMBus device, programmable via writes to (and reads from) a set of registers. Using the SMBus emulation provided with roadtest, this mock device simply implements a handful of registers. It is hard to imagine a simpler implementation; the read side doesn't even bother to check whether a requested register number is valid, presumably on the assumption that the crash resulting from a bad read request would say "test failure" with adequate volume.

The roadtest framework will take the mock device implementation and connect it to the driver (in the User-mode Linux instance) as if it were a real device. The test itself runs as a user-space process in that instance; it tweaks some of those registers to simulate the arrival of data, then reads that data using the IIO API:

    def test_illuminance(self) -> None:
        data = [
            # Some values from datasheet, and 0
            (0b_0000_0000_0000_0000, 0),
            (0b_0000_0000_0000_0001, 0.01),
            (0b_0011_0100_0101_0110, 88.80),
            (0b_0111_1000_1001_1010, 2818.56),
        ]
        with self.driver.bind(self.dts["addr"]) as dev:
            luxfile = dev.path / "iio:device0/in_illuminance_input"

            for regval, lux in data:
                self.hw.reg_write(REG_RESULT, regval)
                self.assertEqual(read_float(luxfile), lux)

The register writes (the self.hw.reg_write() call above) go straight to the mock device. The reads, instead, are directed to the driver, which will interact with the mock device to obtain the requested data. If the driver is working properly, it will read the simulated data from the mock device and return the results that the test is expecting.

This is a simple test; more complex tests could verify that the driver is setting up the hardware correctly, dealing with error conditions, and so on. Even so, there would appear to be limits to a mechanism like this; it will be difficult to use it to verify that, say, a Video4Linux driver is correctly managing the buffer queue when user-mapped buffers are in use with a planar YUV color scheme. But for simpler devices, of which there are many, a system like roadtest may provide a level of assurance that kernel developers currently do not have.

A lot more information on roadtest can be found in this documentation patch, which includes a tutorial on adding a test for a new device. The patch set as a whole contains tests for a few device types; presumably that list would grow considerably if this framework were to be merged into the mainline.

There have not been a lot of comments on the system so far, so it is hard to be sure about what roadtest's prospects for merging are. Brendan Higgins was clear enough on his opinion of roadtest, though: "I love the framework; this looks very easy to use". Testing frameworks like roadtest should not bother anybody who does not choose to use them and, if they are made comprehensive enough, they can significantly increase the chances of catching regressions before they get into a released kernel. So it is hard to see a reason why roadtest wouldn't eventually become part of the mainline kernel — unless, of course, kernel developers would really rather not lose an excuse justifying the lack of regression testing for drivers.

Index entries for this article
KernelDevelopment tools


to post comments

Driver regression testing with roadtest

Posted Mar 19, 2022 0:55 UTC (Sat) by pmulholland (subscriber, #124686) [Link]

It’s great to see an open framework like this emerge for kernel testing.

I’ve designed and used proprietary frameworks like this for embedded systems testing (bare metal, RTOS and embedded Linux), and the complexity of mocking the hardware can really be chosen to be almost as shallow as the register and interrupt interface, or you can build out an entire virtual device, or something in between.

As an idea of how powerful python based regression testing can be, with some abstraction I’ve emulated I2C, USB, and even PCI devices using a few lines of python, with the kernel booting up and discovering them.

Driver regression testing with roadtest

Posted Mar 19, 2022 6:44 UTC (Sat) by pabs (subscriber, #43278) [Link] (10 responses)

Is UML well maintained? Its website at least does not give that impression, as it references Linux 2.6.

Driver regression testing with roadtest

Posted Mar 19, 2022 8:42 UTC (Sat) by johill (subscriber, #25196) [Link] (9 responses)

The website is largely irrelevant these days, it was most interesting back in those days when the project was out of tree (though I should say I wasn't involved back then). It should probably be largely removed and replaced by pointers to the in-kernel documentation.

Which, sadly, is also lacking, but especially Anton has been working on it, and I still have a task in my backlog to describe all the stuff they're also using here (time-travel & virtio/vhost-user).

A couple of people also use it all the time (kunit, in wifi we use it for the hostap tests [1], etc.) so it's at least constantly maintained to work for those use cases.

[1] https://w1.fi/cgit/hostap/tree/tests/hwsim/vm

Driver regression testing with roadtest

Posted Mar 19, 2022 13:42 UTC (Sat) by pabs (subscriber, #43278) [Link] (8 responses)

Driver regression testing with roadtest

Posted Mar 19, 2022 20:54 UTC (Sat) by johill (subscriber, #25196) [Link] (7 responses)

I wasn't (and we should probably discuss this on the uml list), but:
  • x-terminal-emulator - that's just changing a default, not sure it makes that much sense for non-debian, but the best would probably be to make a new Kconfig variable for it, defaulting to the current value xterm
  • /tmp/uml.ctl - similarly, and likely it should also be made runtime-configurable?
  • the strrchr fix is just outdated? the bug report for it is from 2008, the fix from 2009, and in 2011 the bug was fixed upstream in commit 2c51a4bc023
  • WRITE_ZEROES was submitted upstream

Driver regression testing with roadtest

Posted Mar 20, 2022 0:42 UTC (Sun) by pabs (subscriber, #43278) [Link] (6 responses)

Kconfig and runtime config values sound good to me. It seems that it wasn't noticed that strrchr fix was already applied because Debian's patch modifies KERNEL_DEFINES while the upstream change was to KBUILD_CFLAGS. I don't understand enough of the Linux build system to know why both exist and which one the strrchr fix should be in though.

Also, I see there is also a DocBook based linux(1) manual page and of course the Kconfig files duplicate the upstream ones:

https://sources.debian.org/src/user-mode-linux/5.16um1/li...
https://sources.debian.org/src/user-mode-linux/5.16um1/co...
https://sources.debian.org/src/user-mode-linux/5.16um1/co...

Driver regression testing with roadtest

Posted Mar 21, 2022 11:23 UTC (Mon) by johill (subscriber, #25196) [Link] (5 responses)

Do you want to propose a couple of patches then? :) Should be pretty simple, I'd think, but if not I guess I can also just write them quickly.

Driver regression testing with roadtest

Posted Mar 22, 2022 1:02 UTC (Tue) by pabs (subscriber, #43278) [Link] (4 responses)

Sorry, I'll have to leave that to you. My Linux kernel knowledge is minimal at this point and I'm not the UML maintainer in Debian, just a bystander that looked it at one point.

Driver regression testing with roadtest

Posted Mar 24, 2022 10:37 UTC (Thu) by riteshsarraf (subscriber, #11138) [Link] (2 responses)

Thank you for bringing this up. I will try to review the set of patches we're carrying in Debian, and what all can be pushed upstream.

Driver regression testing with roadtest

Posted Mar 24, 2022 10:51 UTC (Thu) by pabs (subscriber, #43278) [Link] (1 responses)

One other thing I was thinking; that Debian's src:user-mode-linux should be merged into src:linux (like the RT builds are) so it is always up to date with Debian's other Linux kernel packages.

https://kernel-team.pages.debian.net/kernel-handbook/

Driver regression testing with roadtest

Posted Mar 24, 2022 15:56 UTC (Thu) by riteshsarraf (subscriber, #11138) [Link]

Yes. That is something we've been targeting. Just that this hasn't had the urgency, given that in its current model, it works fine.

Driver regression testing with roadtest

Posted Mar 24, 2022 12:14 UTC (Thu) by johill (subscriber, #25196) [Link]

Driver regression testing with roadtest

Posted Mar 19, 2022 10:46 UTC (Sat) by roc (subscriber, #30627) [Link] (1 responses)

This sounds like a really good approach. Bravo!

Driver regression testing with roadtest

Posted Mar 29, 2022 11:34 UTC (Tue) by qwertyface (subscriber, #84167) [Link]

There's a really nice property-based testing framework for Python called Hypothesis. I would imagine that in some cases using it to generate test-cases (register values etc.) would work quite nicely within Roadtest.

Driver regression testing with roadtest

Posted Apr 1, 2022 15:31 UTC (Fri) by andy_shev (subscriber, #75870) [Link]

`assertEqual()` against float, well done!

Driver regression testing with roadtest

Posted Apr 4, 2022 14:16 UTC (Mon) by arnout (subscriber, #94240) [Link]

There was a talk at FOSDEM discussing a completely different approach called EasyMock. Rather then using UML, it mocks away all of the kernel itself. It's not so great for regression testing of changes outside of the driver (because exactly those things are mocked away), but I think it has much more potential for testing the implementation of the driver itself, because it's much easier to mock corner cases and error paths (e.g. failing allocations).

With roadtest, I expect things like error paths for allocations will remain untested because they can't be mocked.


Copyright © 2022, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds