hid-tools 0.10 fixed a test regression introduced in 6.16-rc1: the kernel might communicate with the uhid node while the test suite opens the evdev node. This leads to a full test-suite time which used to run in 6 minutes into an hour.
Merge the upstream hid-tools project in the selftest kernel dir to reduce that time to something manageable again.
Signed-off-by: Benjamin Tissoires bentiss@kernel.org --- Benjamin Tissoires (3): selftests/hid: run ruff format on the python part selftests/hid: sync the python tests to hid-tools 0.8 selftests/hid: sync python tests to hid-tools 0.10
tools/testing/selftests/hid/tests/base.py | 46 ++- tools/testing/selftests/hid/tests/base_device.py | 49 ++- .../selftests/hid/tests/test_apple_keyboard.py | 3 +- tools/testing/selftests/hid/tests/test_gamepad.py | 3 +- .../selftests/hid/tests/test_ite_keyboard.py | 3 +- .../testing/selftests/hid/tests/test_multitouch.py | 2 +- tools/testing/selftests/hid/tests/test_sony.py | 7 +- tools/testing/selftests/hid/tests/test_tablet.py | 11 +- .../selftests/hid/tests/test_wacom_generic.py | 445 +++++++++++++++------ 9 files changed, 412 insertions(+), 157 deletions(-) --- base-commit: 2043ae9019e0f75c7785048230586c3f3ca0a2a4 change-id: 20250709-wip-fix-ci-d03bd06f778e
Best regards,
We aim at syncing with the hid-tools repo on gitlab.freedesktop.org/libevdev/hid-tools. One of the commits is this mechanical formatting, so pull it over here so changes are not hidden by those.
Signed-off-by: Benjamin Tissoires bentiss@kernel.org --- tools/testing/selftests/hid/tests/test_tablet.py | 4 +- .../selftests/hid/tests/test_wacom_generic.py | 436 +++++++++++++++------ 2 files changed, 325 insertions(+), 115 deletions(-)
diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index a9e2de1e8861b2b1fec0f2a245e9bccee54b9645..52fb22cac91e86f85b00a312895c98e6379f02ad 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -1228,9 +1228,9 @@ class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer): pen.current_state = state
def call_input_event(self, report): - if report[0] == 0x0a: + if report[0] == 0x0A: # ensures the original second Eraser usage is null - report[1] &= 0xdf + report[1] &= 0xDF
# ensures the original last bit is equal to bit 6 (In Range) if report[1] & 0x40: diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py index b62c7dba6777f975dd9158f6788a6177307bc9e4..5cbc0cc9308f653b817e54a95f8b53a83782f105 100644 --- a/tools/testing/selftests/hid/tests/test_wacom_generic.py +++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py @@ -892,7 +892,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest locations. The value of `t` may be incremented over time to move the points along a linear path. """ - return [ self.make_contact(id, t) for id in range(0, n) ] + return [self.make_contact(id, t) for id in range(0, n)]
def assert_contact(self, uhdev, evdev, contact_ids, t=0): """ @@ -997,12 +997,17 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
- self.assert_contacts(uhdev, evdev, - [ self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), - self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), - self.ContactIds(contact_id = 2, tracking_id = -1, slot_num = None), - self.ContactIds(contact_id = 3, tracking_id = 1, slot_num = 1), - self.ContactIds(contact_id = 4, tracking_id = -1, slot_num = None) ]) + self.assert_contacts( + uhdev, + evdev, + [ + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None), + self.ContactIds(contact_id=1, tracking_id=0, slot_num=0), + self.ContactIds(contact_id=2, tracking_id=-1, slot_num=None), + self.ContactIds(contact_id=3, tracking_id=1, slot_num=1), + self.ContactIds(contact_id=4, tracking_id=-1, slot_num=None), + ], + )
def confidence_change_assert_playback(self, uhdev, evdev, timeline): """ @@ -1026,7 +1031,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest events = uhdev.next_sync_events() self.debug_reports(r, uhdev, events)
- ids = [ x[0] for x in state ] + ids = [x[0] for x in state] self.assert_contacts(uhdev, evdev, ids, t)
t += 1 @@ -1044,27 +1049,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest uhdev = self.uhdev evdev = uhdev.get_evdev()
- self.confidence_change_assert_playback(uhdev, evdev, [ - # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident - # Both fingers confidently in contact - [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident - # First finger looses confidence and clears only the tipswitch flag - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger has lost confidence and has both flags cleared - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger has lost confidence and has both flags cleared - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] - ]) + self.confidence_change_assert_playback( + uhdev, + evdev, + [ + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident + # Both fingers confidently in contact + [ + ( + self.ContactIds(contact_id=0, tracking_id=0, slot_num=0), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident + # First finger looses confidence and clears only the tipswitch flag + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger has lost confidence and has both flags cleared + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger has lost confidence and has both flags cleared + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + ], + )
def test_confidence_loss_b(self): """ @@ -1079,27 +1125,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest uhdev = self.uhdev evdev = uhdev.get_evdev()
- self.confidence_change_assert_playback(uhdev, evdev, [ - # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident - # Both fingers confidently in contact - [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger looses confidence and has both flags cleared simultaneously - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger has lost confidence and has both flags cleared - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger has lost confidence and has both flags cleared - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] - ]) + self.confidence_change_assert_playback( + uhdev, + evdev, + [ + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident + # Both fingers confidently in contact + [ + ( + self.ContactIds(contact_id=0, tracking_id=0, slot_num=0), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger looses confidence and has both flags cleared simultaneously + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger has lost confidence and has both flags cleared + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger has lost confidence and has both flags cleared + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + ], + )
def test_confidence_loss_c(self): """ @@ -1113,27 +1200,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest uhdev = self.uhdev evdev = uhdev.get_evdev()
- self.confidence_change_assert_playback(uhdev, evdev, [ - # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident - # Both fingers confidently in contact - [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident - # First finger looses confidence and clears only the confidence flag - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger has lost confidence and has both flags cleared - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident - # First finger has lost confidence and has both flags cleared - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] - ]) + self.confidence_change_assert_playback( + uhdev, + evdev, + [ + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident + # Both fingers confidently in contact + [ + ( + self.ContactIds(contact_id=0, tracking_id=0, slot_num=0), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident + # First finger looses confidence and clears only the confidence flag + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + True, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger has lost confidence and has both flags cleared + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident + # First finger has lost confidence and has both flags cleared + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + ], + )
def test_confidence_gain_a(self): """ @@ -1144,27 +1272,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest uhdev = self.uhdev evdev = uhdev.get_evdev()
- self.confidence_change_assert_playback(uhdev, evdev, [ - # t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident - # Only second finger is confidently in contact - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False), - (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)], - - # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident - # First finger gains confidence - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False), - (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)], - - # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident - # First finger remains confident - [(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)], - - # t=3: Contact 0 == Down + confident; Contact 1 == Down + confident - # First finger remains confident - [(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)] - ]) + self.confidence_change_assert_playback( + uhdev, + evdev, + [ + # t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident + # Only second finger is confidently in contact + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None), + True, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=0, slot_num=0), + True, + True, + ), + ], + # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident + # First finger gains confidence + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None), + True, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=0, slot_num=0), + True, + True, + ), + ], + # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident + # First finger remains confident + [ + ( + self.ContactIds(contact_id=0, tracking_id=1, slot_num=1), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=0, slot_num=0), + True, + True, + ), + ], + # t=3: Contact 0 == Down + confident; Contact 1 == Down + confident + # First finger remains confident + [ + ( + self.ContactIds(contact_id=0, tracking_id=1, slot_num=1), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=0, slot_num=0), + True, + True, + ), + ], + ], + )
def test_confidence_gain_b(self): """ @@ -1175,24 +1344,65 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest uhdev = self.uhdev evdev = uhdev.get_evdev()
- self.confidence_change_assert_playback(uhdev, evdev, [ - # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident - # First and second finger confidently in contact - [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident - # Firtst finger looses confidence - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident - # First finger gains confidence - [(self.ContactIds(contact_id = 0, tracking_id = 2, slot_num = 0), True, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)], - - # t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident - # First finger goes up - [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True), - (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)] - ]) + self.confidence_change_assert_playback( + uhdev, + evdev, + [ + # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident + # First and second finger confidently in contact + [ + ( + self.ContactIds(contact_id=0, tracking_id=0, slot_num=0), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident + # Firtst finger looses confidence + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + True, + False, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident + # First finger gains confidence + [ + ( + self.ContactIds(contact_id=0, tracking_id=2, slot_num=0), + True, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + # t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident + # First finger goes up + [ + ( + self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0), + False, + True, + ), + ( + self.ContactIds(contact_id=1, tracking_id=1, slot_num=1), + True, + True, + ), + ], + ], + )
Instead of backporting one by one each commits, let's pull them in bulk and reference the hid-tools project for a detailed history.
The short summary is: - make use of dataclass when possible, to avoid tuples - wacom: remove unused uhdev parameter - various small fixes not worth mentioning
Signed-off-by: Benjamin Tissoires bentiss@kernel.org --- tools/testing/selftests/hid/tests/base.py | 46 ++++++++++++++-------- tools/testing/selftests/hid/tests/base_device.py | 30 ++++++++------ .../selftests/hid/tests/test_apple_keyboard.py | 3 +- tools/testing/selftests/hid/tests/test_gamepad.py | 3 +- .../selftests/hid/tests/test_ite_keyboard.py | 3 +- .../testing/selftests/hid/tests/test_multitouch.py | 2 +- tools/testing/selftests/hid/tests/test_sony.py | 7 ++-- tools/testing/selftests/hid/tests/test_tablet.py | 7 ++-- .../selftests/hid/tests/test_wacom_generic.py | 11 +++--- 9 files changed, 69 insertions(+), 43 deletions(-)
diff --git a/tools/testing/selftests/hid/tests/base.py b/tools/testing/selftests/hid/tests/base.py index 3a465768e507dd8fe540c60ebc2dd3a133e6f19b..5175cf235b2f877b90a942139318a0cd3845b6aa 100644 --- a/tools/testing/selftests/hid/tests/base.py +++ b/tools/testing/selftests/hid/tests/base.py @@ -5,6 +5,7 @@ # Copyright (c) 2017 Benjamin Tissoires benjamin.tissoires@gmail.com # Copyright (c) 2017 Red Hat, Inc.
+import dataclasses import libevdev import os import pytest @@ -145,6 +146,18 @@ class UHIDTestDevice(BaseDevice): self.name = name
+@dataclasses.dataclass +class HidBpf: + object_name: str + has_rdesc_fixup: bool + + +@dataclasses.dataclass +class KernelModule: + driver_name: str + module_name: str + + class BaseTestCase: class TestUhid(object): syn_event = libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) # type: ignore @@ -155,20 +168,20 @@ class BaseTestCase:
# List of kernel modules to load before starting the test # if any module is not available (not compiled), the test will skip. - # Each element is a tuple '(kernel driver name, kernel module)', - # for example ("playstation", "hid-playstation") - kernel_modules: List[Tuple[str, str]] = [] + # Each element is a KernelModule object, for example + # KernelModule("playstation", "hid-playstation") + kernel_modules: List[KernelModule] = []
# List of in kernel HID-BPF object files to load # before starting the test # Any existing pre-loaded HID-BPF module will be removed # before the ones in this list will be manually loaded. - # Each Element is a tuple '(hid_bpf_object, rdesc_fixup_present)', - # for example '("xppen-ArtistPro16Gen2.bpf.o", True)' - # If 'rdesc_fixup_present' is True, the test needs to wait + # Each Element is a HidBpf object, for example + # 'HidBpf("xppen-ArtistPro16Gen2.bpf.o", True)' + # If 'has_rdesc_fixup' is True, the test needs to wait # for one unbind and rebind before it can be sure the kernel is # ready - hid_bpfs: List[Tuple[str, bool]] = [] + hid_bpfs: List[HidBpf] = []
def assertInputEventsIn(self, expected_events, effective_events): effective_events = effective_events.copy() @@ -232,25 +245,26 @@ class BaseTestCase:
@pytest.fixture() def load_kernel_module(self): - for kernel_driver, kernel_module in self.kernel_modules: - self._load_kernel_module(kernel_driver, kernel_module) + for k in self.kernel_modules: + self._load_kernel_module(k.driver_name, k.module_name) yield
def load_hid_bpfs(self): + # this function will only work when run in the kernel tree script_dir = Path(os.path.dirname(os.path.realpath(__file__))) root_dir = (script_dir / "../../../../..").resolve() bpf_dir = root_dir / "drivers/hid/bpf/progs"
+ if not bpf_dir.exists(): + pytest.skip("looks like we are not in the kernel tree, skipping") + udev_hid_bpf = shutil.which("udev-hid-bpf") if not udev_hid_bpf: pytest.skip("udev-hid-bpf not found in $PATH, skipping")
- wait = False - for _, rdesc_fixup in self.hid_bpfs: - if rdesc_fixup: - wait = True + wait = any(b.has_rdesc_fixup for b in self.hid_bpfs)
- for hid_bpf, _ in self.hid_bpfs: + for hid_bpf in self.hid_bpfs: # We need to start `udev-hid-bpf` in the background # and dispatch uhid events in case the kernel needs # to fetch features on the device @@ -260,13 +274,13 @@ class BaseTestCase: "--verbose", "add", str(self.uhdev.sys_path), - str(bpf_dir / hid_bpf), + str(bpf_dir / hid_bpf.object_name), ], ) while process.poll() is None: self.uhdev.dispatch(1)
- if process.poll() != 0: + if process.returncode != 0: pytest.fail( f"Couldn't insert hid-bpf program '{hid_bpf}', marking the test as failed" ) diff --git a/tools/testing/selftests/hid/tests/base_device.py b/tools/testing/selftests/hid/tests/base_device.py index e0515be97f83a4b5ff8ad47db15284365f7154dc..e13035fe1deb4c2ee5fd729d43c619bdd759c138 100644 --- a/tools/testing/selftests/hid/tests/base_device.py +++ b/tools/testing/selftests/hid/tests/base_device.py @@ -18,6 +18,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
+import dataclasses import fcntl import functools import libevdev @@ -104,6 +105,12 @@ class PowerSupply(object): return self._type.str_value
+@dataclasses.dataclass +class HidReadiness: + is_ready: bool = False + count: int = 0 + + class HIDIsReady(object): """ Companion class that binds to a kernel mechanism @@ -115,18 +122,18 @@ class HIDIsReady(object): def __init__(self: "HIDIsReady", uhid: UHIDDevice) -> None: self.uhid = uhid
- def is_ready(self: "HIDIsReady") -> bool: + def is_ready(self: "HIDIsReady") -> HidReadiness: """ Overwrite in subclasses: should return True or False whether the attached uhid device is ready or not. """ - return False + return HidReadiness()
class UdevHIDIsReady(HIDIsReady): _pyudev_context: ClassVar[Optional[pyudev.Context]] = None _pyudev_monitor: ClassVar[Optional[pyudev.Monitor]] = None - _uhid_devices: ClassVar[Dict[int, Tuple[bool, int]]] = {} + _uhid_devices: ClassVar[Dict[int, HidReadiness]] = {}
def __init__(self: "UdevHIDIsReady", uhid: UHIDDevice) -> None: super().__init__(uhid) @@ -157,18 +164,19 @@ class UdevHIDIsReady(HIDIsReady):
id = int(event.sys_path.strip().split(".")[-1], 16)
- device_ready, count = cls._uhid_devices.get(id, (False, 0)) + readiness = cls._uhid_devices.setdefault(id, HidReadiness())
ready = event.action == "bind" - if not device_ready and ready: - count += 1 - cls._uhid_devices[id] = (ready, count) + if not readiness.is_ready and ready: + readiness.count += 1 + + readiness.is_ready = ready
- def is_ready(self: "UdevHIDIsReady") -> Tuple[bool, int]: + def is_ready(self: "UdevHIDIsReady") -> HidReadiness: try: return self._uhid_devices[self.uhid.hid_id] except KeyError: - return (False, 0) + return HidReadiness()
class EvdevMatch(object): @@ -322,11 +330,11 @@ class BaseDevice(UHIDDevice):
@property def kernel_is_ready(self: "BaseDevice") -> bool: - return self._kernel_is_ready.is_ready()[0] and self.started + return self._kernel_is_ready.is_ready().is_ready and self.started
@property def kernel_ready_count(self: "BaseDevice") -> int: - return self._kernel_is_ready.is_ready()[1] + return self._kernel_is_ready.is_ready().count
@property def input_nodes(self: "BaseDevice") -> List[EvdevDevice]: diff --git a/tools/testing/selftests/hid/tests/test_apple_keyboard.py b/tools/testing/selftests/hid/tests/test_apple_keyboard.py index f81071d461663b36da8f48d75e7c178ffc145688..0e17588b945c222d1b52b944eebf0719ed7fa3fc 100644 --- a/tools/testing/selftests/hid/tests/test_apple_keyboard.py +++ b/tools/testing/selftests/hid/tests/test_apple_keyboard.py @@ -8,13 +8,14 @@
from .test_keyboard import ArrayKeyboard, TestArrayKeyboard from hidtools.util import BusType +from . import base
import libevdev import logging
logger = logging.getLogger("hidtools.test.apple-keyboard")
-KERNEL_MODULE = ("apple", "hid-apple") +KERNEL_MODULE = base.KernelModule("apple", "hid-apple")
class KbdData(object): diff --git a/tools/testing/selftests/hid/tests/test_gamepad.py b/tools/testing/selftests/hid/tests/test_gamepad.py index 8d5b5ffdae49505c213602e01cd6d92ee9eb83ca..6121978059311ef52ba83c91d39a08b522da84f2 100644 --- a/tools/testing/selftests/hid/tests/test_gamepad.py +++ b/tools/testing/selftests/hid/tests/test_gamepad.py @@ -12,6 +12,7 @@ import pytest
from .base_gamepad import BaseGamepad, JoystickGamepad, AxisMapping from hidtools.util import BusType +from .base import HidBpf
import logging
@@ -654,7 +655,7 @@ class TestAsusGamepad(BaseTest.TestGamepad):
class TestRaptorMach2Joystick(BaseTest.TestGamepad): - hid_bpfs = [("FR-TEC__Raptor-Mach-2.bpf.o", True)] + hid_bpfs = [HidBpf("FR-TEC__Raptor-Mach-2.bpf.o", True)]
def create_device(self): return RaptorMach2Joystick( diff --git a/tools/testing/selftests/hid/tests/test_ite_keyboard.py b/tools/testing/selftests/hid/tests/test_ite_keyboard.py index 38550c167baea440d2dc869d719dbea010ff7639..f695eaad1648e7ea48873725740ea4daf1f9203e 100644 --- a/tools/testing/selftests/hid/tests/test_ite_keyboard.py +++ b/tools/testing/selftests/hid/tests/test_ite_keyboard.py @@ -11,10 +11,11 @@ from hidtools.util import BusType
import libevdev import logging +from . import base
logger = logging.getLogger("hidtools.test.ite-keyboard")
-KERNEL_MODULE = ("itetech", "hid_ite") +KERNEL_MODULE = base.KernelModule("itetech", "hid_ite")
class KbdData(object): diff --git a/tools/testing/selftests/hid/tests/test_multitouch.py b/tools/testing/selftests/hid/tests/test_multitouch.py index 4265012231c660f4c97e4bff0feec324dd9115b6..5d2ffa3d59777e3cd93d1d7aebabc2a6b7ecb42a 100644 --- a/tools/testing/selftests/hid/tests/test_multitouch.py +++ b/tools/testing/selftests/hid/tests/test_multitouch.py @@ -17,7 +17,7 @@ import time
logger = logging.getLogger("hidtools.test.multitouch")
-KERNEL_MODULE = ("hid-multitouch", "hid_multitouch") +KERNEL_MODULE = base.KernelModule("hid-multitouch", "hid_multitouch")
def BIT(x): diff --git a/tools/testing/selftests/hid/tests/test_sony.py b/tools/testing/selftests/hid/tests/test_sony.py index 7e52c28e59c5c210e081579f7047a368c16063ce..7fd3a8e6137d0b404b544f7b886ba4783f81faf1 100644 --- a/tools/testing/selftests/hid/tests/test_sony.py +++ b/tools/testing/selftests/hid/tests/test_sony.py @@ -7,6 +7,7 @@ #
from .base import application_matches +from .base import KernelModule from .test_gamepad import BaseTest from hidtools.device.sony_gamepad import ( PS3Controller, @@ -24,9 +25,9 @@ import pytest
logger = logging.getLogger("hidtools.test.sony")
-PS3_MODULE = ("sony", "hid_sony") -PS4_MODULE = ("playstation", "hid_playstation") -PS5_MODULE = ("playstation", "hid_playstation") +PS3_MODULE = KernelModule("sony", "hid_sony") +PS4_MODULE = KernelModule("playstation", "hid_playstation") +PS5_MODULE = KernelModule("playstation", "hid_playstation")
class SonyBaseTest: diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 52fb22cac91e86f85b00a312895c98e6379f02ad..50d5699812bbad171f07386d1f914c3b8da9ac5b 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -10,6 +10,7 @@ from . import base import copy from enum import Enum from hidtools.util import BusType +from .base import HidBpf import libevdev import logging import pytest @@ -1472,7 +1473,7 @@ class TestGoodix_27c6_0e00(BaseTest.TestTablet):
class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet): - hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)] + hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]
def create_device(self): dev = XPPen_ArtistPro16Gen2_28bd_095b( @@ -1484,7 +1485,7 @@ class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet): - hid_bpfs = [("XPPen__Artist24.bpf.o", True)] + hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]
def create_device(self): return XPPen_Artist24_28bd_093a( @@ -1495,7 +1496,7 @@ class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet): - hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)] + hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]
def create_device(self): return Huion_Kamvas_Pro_19_256c_006b( diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py index 5cbc0cc9308f653b817e54a95f8b53a83782f105..2d6d04f0ff80bea46dc6c61c2b3a43383be6ac50 100644 --- a/tools/testing/selftests/hid/tests/test_wacom_generic.py +++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py @@ -40,7 +40,7 @@ import logging
logger = logging.getLogger("hidtools.test.wacom")
-KERNEL_MODULE = ("wacom", "wacom") +KERNEL_MODULE = base.KernelModule("wacom", "wacom")
class ProximityState(Enum): @@ -894,7 +894,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest """ return [self.make_contact(id, t) for id in range(0, n)]
- def assert_contact(self, uhdev, evdev, contact_ids, t=0): + def assert_contact(self, evdev, contact_ids, t=0): """ Assert properties of a contact generated by make_contact. """ @@ -916,12 +916,12 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y
- def assert_contacts(self, uhdev, evdev, data, t=0): + def assert_contacts(self, evdev, data, t=0): """ Assert properties of a list of contacts generated by make_contacts. """ for contact_ids in data: - self.assert_contact(uhdev, evdev, contact_ids, t) + self.assert_contact(evdev, contact_ids, t)
def test_contact_id_0(self): """ @@ -998,7 +998,6 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
self.assert_contacts( - uhdev, evdev, [ self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None), @@ -1032,7 +1031,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest self.debug_reports(r, uhdev, events)
ids = [x[0] for x in state] - self.assert_contacts(uhdev, evdev, ids, t) + self.assert_contacts(evdev, ids, t)
t += 1
On Wed, Jul 09, 2025 at 11:08:50AM +0200, Benjamin Tissoires wrote:
Instead of backporting one by one each commits, let's pull them in bulk and reference the hid-tools project for a detailed history.
s/reference/refer to/ ?
otherwise, series:
Reviewed-by: Peter Hutterer peter.hutterer@who-t.net
Cheers, Peter
The short summary is:
- make use of dataclass when possible, to avoid tuples
- wacom: remove unused uhdev parameter
- various small fixes not worth mentioning
Signed-off-by: Benjamin Tissoires bentiss@kernel.org
tools/testing/selftests/hid/tests/base.py | 46 ++++++++++++++-------- tools/testing/selftests/hid/tests/base_device.py | 30 ++++++++------ .../selftests/hid/tests/test_apple_keyboard.py | 3 +- tools/testing/selftests/hid/tests/test_gamepad.py | 3 +- .../selftests/hid/tests/test_ite_keyboard.py | 3 +- .../testing/selftests/hid/tests/test_multitouch.py | 2 +- tools/testing/selftests/hid/tests/test_sony.py | 7 ++-- tools/testing/selftests/hid/tests/test_tablet.py | 7 ++-- .../selftests/hid/tests/test_wacom_generic.py | 11 +++--- 9 files changed, 69 insertions(+), 43 deletions(-)
diff --git a/tools/testing/selftests/hid/tests/base.py b/tools/testing/selftests/hid/tests/base.py index 3a465768e507dd8fe540c60ebc2dd3a133e6f19b..5175cf235b2f877b90a942139318a0cd3845b6aa 100644 --- a/tools/testing/selftests/hid/tests/base.py +++ b/tools/testing/selftests/hid/tests/base.py @@ -5,6 +5,7 @@ # Copyright (c) 2017 Benjamin Tissoires benjamin.tissoires@gmail.com # Copyright (c) 2017 Red Hat, Inc. +import dataclasses import libevdev import os import pytest @@ -145,6 +146,18 @@ class UHIDTestDevice(BaseDevice): self.name = name +@dataclasses.dataclass +class HidBpf:
- object_name: str
- has_rdesc_fixup: bool
+@dataclasses.dataclass +class KernelModule:
- driver_name: str
- module_name: str
class BaseTestCase: class TestUhid(object): syn_event = libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) # type: ignore @@ -155,20 +168,20 @@ class BaseTestCase: # List of kernel modules to load before starting the test # if any module is not available (not compiled), the test will skip.
# Each element is a tuple '(kernel driver name, kernel module)',
# for example ("playstation", "hid-playstation")
kernel_modules: List[Tuple[str, str]] = []
# Each element is a KernelModule object, for example
# KernelModule("playstation", "hid-playstation")
kernel_modules: List[KernelModule] = []
# List of in kernel HID-BPF object files to load # before starting the test # Any existing pre-loaded HID-BPF module will be removed # before the ones in this list will be manually loaded.
# Each Element is a tuple '(hid_bpf_object, rdesc_fixup_present)',
# for example '("xppen-ArtistPro16Gen2.bpf.o", True)'
# If 'rdesc_fixup_present' is True, the test needs to wait
# Each Element is a HidBpf object, for example
# 'HidBpf("xppen-ArtistPro16Gen2.bpf.o", True)'
# If 'has_rdesc_fixup' is True, the test needs to wait # for one unbind and rebind before it can be sure the kernel is # ready
hid_bpfs: List[Tuple[str, bool]] = []
hid_bpfs: List[HidBpf] = []
def assertInputEventsIn(self, expected_events, effective_events): effective_events = effective_events.copy() @@ -232,25 +245,26 @@ class BaseTestCase: @pytest.fixture() def load_kernel_module(self):
for kernel_driver, kernel_module in self.kernel_modules:
self._load_kernel_module(kernel_driver, kernel_module)
for k in self.kernel_modules:
self._load_kernel_module(k.driver_name, k.module_name) yield
def load_hid_bpfs(self):
# this function will only work when run in the kernel tree script_dir = Path(os.path.dirname(os.path.realpath(__file__))) root_dir = (script_dir / "../../../../..").resolve() bpf_dir = root_dir / "drivers/hid/bpf/progs"
if not bpf_dir.exists():
pytest.skip("looks like we are not in the kernel tree, skipping")
udev_hid_bpf = shutil.which("udev-hid-bpf") if not udev_hid_bpf: pytest.skip("udev-hid-bpf not found in $PATH, skipping")
wait = False
for _, rdesc_fixup in self.hid_bpfs:
if rdesc_fixup:
wait = True
wait = any(b.has_rdesc_fixup for b in self.hid_bpfs)
for hid_bpf, _ in self.hid_bpfs:
for hid_bpf in self.hid_bpfs: # We need to start `udev-hid-bpf` in the background # and dispatch uhid events in case the kernel needs # to fetch features on the device
@@ -260,13 +274,13 @@ class BaseTestCase: "--verbose", "add", str(self.uhdev.sys_path),
str(bpf_dir / hid_bpf),
str(bpf_dir / hid_bpf.object_name), ], ) while process.poll() is None: self.uhdev.dispatch(1)
if process.poll() != 0:
if process.returncode != 0: pytest.fail( f"Couldn't insert hid-bpf program '{hid_bpf}', marking the test as failed" )
diff --git a/tools/testing/selftests/hid/tests/base_device.py b/tools/testing/selftests/hid/tests/base_device.py index e0515be97f83a4b5ff8ad47db15284365f7154dc..e13035fe1deb4c2ee5fd729d43c619bdd759c138 100644 --- a/tools/testing/selftests/hid/tests/base_device.py +++ b/tools/testing/selftests/hid/tests/base_device.py @@ -18,6 +18,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. +import dataclasses import fcntl import functools import libevdev @@ -104,6 +105,12 @@ class PowerSupply(object): return self._type.str_value +@dataclasses.dataclass +class HidReadiness:
- is_ready: bool = False
- count: int = 0
class HIDIsReady(object): """ Companion class that binds to a kernel mechanism @@ -115,18 +122,18 @@ class HIDIsReady(object): def __init__(self: "HIDIsReady", uhid: UHIDDevice) -> None: self.uhid = uhid
- def is_ready(self: "HIDIsReady") -> bool:
- def is_ready(self: "HIDIsReady") -> HidReadiness: """ Overwrite in subclasses: should return True or False whether the attached uhid device is ready or not. """
return False
return HidReadiness()
class UdevHIDIsReady(HIDIsReady): _pyudev_context: ClassVar[Optional[pyudev.Context]] = None _pyudev_monitor: ClassVar[Optional[pyudev.Monitor]] = None
- _uhid_devices: ClassVar[Dict[int, Tuple[bool, int]]] = {}
- _uhid_devices: ClassVar[Dict[int, HidReadiness]] = {}
def __init__(self: "UdevHIDIsReady", uhid: UHIDDevice) -> None: super().__init__(uhid) @@ -157,18 +164,19 @@ class UdevHIDIsReady(HIDIsReady): id = int(event.sys_path.strip().split(".")[-1], 16)
device_ready, count = cls._uhid_devices.get(id, (False, 0))
readiness = cls._uhid_devices.setdefault(id, HidReadiness())
ready = event.action == "bind"
if not device_ready and ready:
count += 1
cls._uhid_devices[id] = (ready, count)
if not readiness.is_ready and ready:
readiness.count += 1
readiness.is_ready = ready
- def is_ready(self: "UdevHIDIsReady") -> Tuple[bool, int]:
- def is_ready(self: "UdevHIDIsReady") -> HidReadiness: try: return self._uhid_devices[self.uhid.hid_id] except KeyError:
return (False, 0)
return HidReadiness()
class EvdevMatch(object): @@ -322,11 +330,11 @@ class BaseDevice(UHIDDevice): @property def kernel_is_ready(self: "BaseDevice") -> bool:
return self._kernel_is_ready.is_ready()[0] and self.started
return self._kernel_is_ready.is_ready().is_ready and self.started
@property def kernel_ready_count(self: "BaseDevice") -> int:
return self._kernel_is_ready.is_ready()[1]
return self._kernel_is_ready.is_ready().count
@property def input_nodes(self: "BaseDevice") -> List[EvdevDevice]: diff --git a/tools/testing/selftests/hid/tests/test_apple_keyboard.py b/tools/testing/selftests/hid/tests/test_apple_keyboard.py index f81071d461663b36da8f48d75e7c178ffc145688..0e17588b945c222d1b52b944eebf0719ed7fa3fc 100644 --- a/tools/testing/selftests/hid/tests/test_apple_keyboard.py +++ b/tools/testing/selftests/hid/tests/test_apple_keyboard.py @@ -8,13 +8,14 @@ from .test_keyboard import ArrayKeyboard, TestArrayKeyboard from hidtools.util import BusType +from . import base import libevdev import logging logger = logging.getLogger("hidtools.test.apple-keyboard") -KERNEL_MODULE = ("apple", "hid-apple") +KERNEL_MODULE = base.KernelModule("apple", "hid-apple") class KbdData(object): diff --git a/tools/testing/selftests/hid/tests/test_gamepad.py b/tools/testing/selftests/hid/tests/test_gamepad.py index 8d5b5ffdae49505c213602e01cd6d92ee9eb83ca..6121978059311ef52ba83c91d39a08b522da84f2 100644 --- a/tools/testing/selftests/hid/tests/test_gamepad.py +++ b/tools/testing/selftests/hid/tests/test_gamepad.py @@ -12,6 +12,7 @@ import pytest from .base_gamepad import BaseGamepad, JoystickGamepad, AxisMapping from hidtools.util import BusType +from .base import HidBpf import logging @@ -654,7 +655,7 @@ class TestAsusGamepad(BaseTest.TestGamepad): class TestRaptorMach2Joystick(BaseTest.TestGamepad):
- hid_bpfs = [("FR-TEC__Raptor-Mach-2.bpf.o", True)]
- hid_bpfs = [HidBpf("FR-TEC__Raptor-Mach-2.bpf.o", True)]
def create_device(self): return RaptorMach2Joystick( diff --git a/tools/testing/selftests/hid/tests/test_ite_keyboard.py b/tools/testing/selftests/hid/tests/test_ite_keyboard.py index 38550c167baea440d2dc869d719dbea010ff7639..f695eaad1648e7ea48873725740ea4daf1f9203e 100644 --- a/tools/testing/selftests/hid/tests/test_ite_keyboard.py +++ b/tools/testing/selftests/hid/tests/test_ite_keyboard.py @@ -11,10 +11,11 @@ from hidtools.util import BusType import libevdev import logging +from . import base logger = logging.getLogger("hidtools.test.ite-keyboard") -KERNEL_MODULE = ("itetech", "hid_ite") +KERNEL_MODULE = base.KernelModule("itetech", "hid_ite") class KbdData(object): diff --git a/tools/testing/selftests/hid/tests/test_multitouch.py b/tools/testing/selftests/hid/tests/test_multitouch.py index 4265012231c660f4c97e4bff0feec324dd9115b6..5d2ffa3d59777e3cd93d1d7aebabc2a6b7ecb42a 100644 --- a/tools/testing/selftests/hid/tests/test_multitouch.py +++ b/tools/testing/selftests/hid/tests/test_multitouch.py @@ -17,7 +17,7 @@ import time logger = logging.getLogger("hidtools.test.multitouch") -KERNEL_MODULE = ("hid-multitouch", "hid_multitouch") +KERNEL_MODULE = base.KernelModule("hid-multitouch", "hid_multitouch") def BIT(x): diff --git a/tools/testing/selftests/hid/tests/test_sony.py b/tools/testing/selftests/hid/tests/test_sony.py index 7e52c28e59c5c210e081579f7047a368c16063ce..7fd3a8e6137d0b404b544f7b886ba4783f81faf1 100644 --- a/tools/testing/selftests/hid/tests/test_sony.py +++ b/tools/testing/selftests/hid/tests/test_sony.py @@ -7,6 +7,7 @@ # from .base import application_matches +from .base import KernelModule from .test_gamepad import BaseTest from hidtools.device.sony_gamepad import ( PS3Controller, @@ -24,9 +25,9 @@ import pytest logger = logging.getLogger("hidtools.test.sony") -PS3_MODULE = ("sony", "hid_sony") -PS4_MODULE = ("playstation", "hid_playstation") -PS5_MODULE = ("playstation", "hid_playstation") +PS3_MODULE = KernelModule("sony", "hid_sony") +PS4_MODULE = KernelModule("playstation", "hid_playstation") +PS5_MODULE = KernelModule("playstation", "hid_playstation") class SonyBaseTest: diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py index 52fb22cac91e86f85b00a312895c98e6379f02ad..50d5699812bbad171f07386d1f914c3b8da9ac5b 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -10,6 +10,7 @@ from . import base import copy from enum import Enum from hidtools.util import BusType +from .base import HidBpf import libevdev import logging import pytest @@ -1472,7 +1473,7 @@ class TestGoodix_27c6_0e00(BaseTest.TestTablet): class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
- hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)]
- hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]
def create_device(self): dev = XPPen_ArtistPro16Gen2_28bd_095b( @@ -1484,7 +1485,7 @@ class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet): class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
- hid_bpfs = [("XPPen__Artist24.bpf.o", True)]
- hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]
def create_device(self): return XPPen_Artist24_28bd_093a( @@ -1495,7 +1496,7 @@ class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet): class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
- hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)]
- hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]
def create_device(self): return Huion_Kamvas_Pro_19_256c_006b( diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py index 5cbc0cc9308f653b817e54a95f8b53a83782f105..2d6d04f0ff80bea46dc6c61c2b3a43383be6ac50 100644 --- a/tools/testing/selftests/hid/tests/test_wacom_generic.py +++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py @@ -40,7 +40,7 @@ import logging logger = logging.getLogger("hidtools.test.wacom") -KERNEL_MODULE = ("wacom", "wacom") +KERNEL_MODULE = base.KernelModule("wacom", "wacom") class ProximityState(Enum): @@ -894,7 +894,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest """ return [self.make_contact(id, t) for id in range(0, n)]
- def assert_contact(self, uhdev, evdev, contact_ids, t=0):
- def assert_contact(self, evdev, contact_ids, t=0): """ Assert properties of a contact generated by make_contact. """
@@ -916,12 +916,12 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y
- def assert_contacts(self, uhdev, evdev, data, t=0):
- def assert_contacts(self, evdev, data, t=0): """ Assert properties of a list of contacts generated by make_contacts. """ for contact_ids in data:
self.assert_contact(uhdev, evdev, contact_ids, t)
self.assert_contact(evdev, contact_ids, t)
def test_contact_id_0(self): """ @@ -998,7 +998,6 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events self.assert_contacts(
uhdev, evdev, [ self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None),
@@ -1032,7 +1031,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest self.debug_reports(r, uhdev, events) ids = [x[0] for x in state]
self.assert_contacts(uhdev, evdev, ids, t)
self.assert_contacts(evdev, ids, t)
t += 1
-- 2.49.0
hid-tools 0.10 fixes one inconvenience introduced by commit 6a9e76f75c1a ("HID: multitouch: Disable touchpad on firmware level while not in use")
This change added a new callback when a hid-nultitouch device is opened or closed to put the underlying device into a given operating mode. However, in the test cases, that means that while the single threaded test is run, it opens the device but has to react to the device while the open() is still running. hid-tools now implements a minimal thread to circumvent this.
This makes the HID kernel tests in sync with hid-tools 0.10.
This has the net effect of running the full HID python testsuite in 6 minutes instead of 1 hour.
Signed-off-by: Benjamin Tissoires bentiss@kernel.org --- tools/testing/selftests/hid/tests/base_device.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/tools/testing/selftests/hid/tests/base_device.py b/tools/testing/selftests/hid/tests/base_device.py index e13035fe1deb4c2ee5fd729d43c619bdd759c138..59465c58d94dfd3993ae87b25a62e444e93e0f66 100644 --- a/tools/testing/selftests/hid/tests/base_device.py +++ b/tools/testing/selftests/hid/tests/base_device.py @@ -23,6 +23,7 @@ import fcntl import functools import libevdev import os +import threading
try: import pyudev @@ -344,10 +345,28 @@ class BaseDevice(UHIDDevice): if not self.kernel_is_ready or not self.started: return []
+ # Starting with kernel v6.16, an event is emitted when + # userspace opens a kernel device, and for some devices + # this translates into a SET_REPORT. + # Because EvdevDevice(path) opens every single evdev node + # we need to have a separate thread to process the incoming + # SET_REPORT or we end up having to wait for the kernel + # timeout of 5 seconds. + done = False + + def dispatch(): + while not done: + self.dispatch(1) + + t = threading.Thread(target=dispatch) + t.start() + self._input_nodes = [ EvdevDevice(path) for path in self.walk_sysfs("input", "input/input*/event*") ] + done = True + t.join() return self._input_nodes
def match_evdev_rule(self, application, evdev):
On Wed, 09 Jul 2025 11:08:48 +0200, Benjamin Tissoires wrote:
hid-tools 0.10 fixed a test regression introduced in 6.16-rc1: the kernel might communicate with the uhid node while the test suite opens the evdev node. This leads to a full test-suite time which used to run in 6 minutes into an hour.
Merge the upstream hid-tools project in the selftest kernel dir to reduce that time to something manageable again.
[...]
Applied to hid/hid.git (for-6.17/selftests), thanks!
[1/3] selftests/hid: run ruff format on the python part https://git.kernel.org/hid/hid/c/c85a8cb9b8d3 [2/3] selftests/hid: sync the python tests to hid-tools 0.8 https://git.kernel.org/hid/hid/c/642f9b2d608c [3/3] selftests/hid: sync python tests to hid-tools 0.10 https://git.kernel.org/hid/hid/c/1aee3a44fad2
Cheers,
linux-kselftest-mirror@lists.linaro.org