linux-kselftest.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10
@ 2025-07-09  9:08 Benjamin Tissoires
  2025-07-09  9:08 ` [PATCH 1/3] selftests/hid: run ruff format on the python part Benjamin Tissoires
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Benjamin Tissoires @ 2025-07-09  9:08 UTC (permalink / raw)
  To: Jiri Kosina, Peter Hutterer, Shuah Khan
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires

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,
-- 
Benjamin Tissoires <bentiss@kernel.org>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] selftests/hid: run ruff format on the python part
  2025-07-09  9:08 [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10 Benjamin Tissoires
@ 2025-07-09  9:08 ` Benjamin Tissoires
  2025-07-09  9:08 ` [PATCH 2/3] selftests/hid: sync the python tests to hid-tools 0.8 Benjamin Tissoires
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Benjamin Tissoires @ 2025-07-09  9:08 UTC (permalink / raw)
  To: Jiri Kosina, Peter Hutterer, Shuah Khan
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires

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,
+                    ),
+                ],
+            ],
+        )

-- 
2.49.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] selftests/hid: sync the python tests to hid-tools 0.8
  2025-07-09  9:08 [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10 Benjamin Tissoires
  2025-07-09  9:08 ` [PATCH 1/3] selftests/hid: run ruff format on the python part Benjamin Tissoires
@ 2025-07-09  9:08 ` Benjamin Tissoires
  2025-07-10  2:58   ` Peter Hutterer
  2025-07-09  9:08 ` [PATCH 3/3] selftests/hid: sync python tests to hid-tools 0.10 Benjamin Tissoires
  2025-07-10 14:21 ` [PATCH 0/3] selftests/hid: upgrade the python scripts to match " Benjamin Tissoires
  3 siblings, 1 reply; 6+ messages in thread
From: Benjamin Tissoires @ 2025-07-09  9:08 UTC (permalink / raw)
  To: Jiri Kosina, Peter Hutterer, Shuah Khan
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires

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
 

-- 
2.49.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] selftests/hid: sync python tests to hid-tools 0.10
  2025-07-09  9:08 [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10 Benjamin Tissoires
  2025-07-09  9:08 ` [PATCH 1/3] selftests/hid: run ruff format on the python part Benjamin Tissoires
  2025-07-09  9:08 ` [PATCH 2/3] selftests/hid: sync the python tests to hid-tools 0.8 Benjamin Tissoires
@ 2025-07-09  9:08 ` Benjamin Tissoires
  2025-07-10 14:21 ` [PATCH 0/3] selftests/hid: upgrade the python scripts to match " Benjamin Tissoires
  3 siblings, 0 replies; 6+ messages in thread
From: Benjamin Tissoires @ 2025-07-09  9:08 UTC (permalink / raw)
  To: Jiri Kosina, Peter Hutterer, Shuah Khan
  Cc: linux-input, linux-kselftest, linux-kernel, Benjamin Tissoires

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):

-- 
2.49.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] selftests/hid: sync the python tests to hid-tools 0.8
  2025-07-09  9:08 ` [PATCH 2/3] selftests/hid: sync the python tests to hid-tools 0.8 Benjamin Tissoires
@ 2025-07-10  2:58   ` Peter Hutterer
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Hutterer @ 2025-07-10  2:58 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Jiri Kosina, Shuah Khan, linux-input, linux-kselftest,
	linux-kernel

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
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10
  2025-07-09  9:08 [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10 Benjamin Tissoires
                   ` (2 preceding siblings ...)
  2025-07-09  9:08 ` [PATCH 3/3] selftests/hid: sync python tests to hid-tools 0.10 Benjamin Tissoires
@ 2025-07-10 14:21 ` Benjamin Tissoires
  3 siblings, 0 replies; 6+ messages in thread
From: Benjamin Tissoires @ 2025-07-10 14:21 UTC (permalink / raw)
  To: Jiri Kosina, Peter Hutterer, Shuah Khan, Benjamin Tissoires
  Cc: linux-input, linux-kselftest, linux-kernel

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,
-- 
Benjamin Tissoires <bentiss@kernel.org>


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-07-10 14:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-09  9:08 [PATCH 0/3] selftests/hid: upgrade the python scripts to match hid-tools 0.10 Benjamin Tissoires
2025-07-09  9:08 ` [PATCH 1/3] selftests/hid: run ruff format on the python part Benjamin Tissoires
2025-07-09  9:08 ` [PATCH 2/3] selftests/hid: sync the python tests to hid-tools 0.8 Benjamin Tissoires
2025-07-10  2:58   ` Peter Hutterer
2025-07-09  9:08 ` [PATCH 3/3] selftests/hid: sync python tests to hid-tools 0.10 Benjamin Tissoires
2025-07-10 14:21 ` [PATCH 0/3] selftests/hid: upgrade the python scripts to match " Benjamin Tissoires

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).