Skip to content

tests: hotplug API and virtual-device hotplug scenarios#826

Draft
Youw wants to merge 1 commit into
connection-callbackfrom
hotplug-tests
Draft

tests: hotplug API and virtual-device hotplug scenarios#826
Youw wants to merge 1 commit into
connection-callbackfrom
hotplug-tests

Conversation

@Youw

@Youw Youw commented Jul 14, 2026

Copy link
Copy Markdown
Member

Adds the test suite for the hotplug API (#764 / connection-callback), in two tiers, built on the virtual-device test harness from #815.

What is in here

  • src/tests/test_hotplug_api.c — tier 1, HotplugAPI_<backend>: everything in the hotplug contract that is observable without a device event (argument validation, callback-handle properties, implicit hid_init(), hid_exit() teardown incl. a register→immediate-hid_exit stress loop, and a 2-thread register/deregister churn). Needs no device, no privileges: registered for all four backends and runs in the ordinary per-push CI matrix. Self-skips (77) when a backend reports hotplug as unsupported at runtime (e.g. libusb without LIBUSB_CAP_HAS_HOTPLUG).
  • src/tests/test_hotplug.c — tier 2, Hotplug_<backend>: device-backed scenarios: async delivery, exactly-once ENUMERATE pass, callback-return deregistration (live + mid-pass), pass-before-live ordering, ARRIVED/LEFT payloads and path correlation, LEFT-without-ENUMERATE, VID/PID filtering, registration-order dispatch, the deregistration post-condition, and register/deregister from within a callback.
  • test_virtual_device_unplug() / test_virtual_device_replug() — new provider calls that toggle device presence without destroying the provider context. Implemented for the uhid provider (UHID_DESTROY/UHID_CREATE2 on the same fd); the rawgadget/vhidmini2/IOHIDUserDevice providers return TEST_VDEV_UNAVAILABLE for now, so their Hotplug_* tests self-skip everywhere (they compile and are registered, ready for when toggling is implemented).

The tier-2 test follows a strict synchronization discipline (see src/tests/README.md): callbacks only deep-copy events into a lock-protected log; every expectation is a deadline-based predicate poll; absence assertions sit behind event barriers, not time windows; no retries.

Where each test runs

Test Where it runs
HotplugAPI_hidraw, HotplugAPI_libusb per-push, builds.yml ubuntu-cmake
HotplugAPI_winapi per-push, builds.yml windows-cmake (MSVC, NMake, ClangCL, MinGW)
HotplugAPI_darwin per-push, builds.yml macos-cmake
Hotplug_hidraw per-push, builds.yml ubuntu-cmake (via modprobe uhid + sudo ctest)
Hotplug_libusb builds + self-skips (incl. in the dedicated libusb-vhid-test job) until rawgadget unplug/replug exists
Hotplug_winapi builds + self-skips (incl. in the dedicated win-vhid-test job) until driver-side presence toggling exists
Hotplug_darwin builds + self-skips; local-only on an entitled Mac, like DeviceIO_darwin

⚠️ Expected to be red until the backend PRs land

The behavioral expectations encode the async-ENUMERATE contract, i.e. they require #822, #823, #824 and #825. On connection-callback as-is, tier 1 fails (e.g. *callback_handle is not zeroed on a failed registration yet), so this PR's CI will be red until those four PRs land — that is expected and is the reason this PR is a draft.

Validation ahead of that: an integration branch (hotplug-integration = connection-callback + all four backend PRs + these tests) runs the same CI; there, HotplugAPI_hidraw/HotplugAPI_libusb pass in a local WSL run of both backends and HotplugAPI_winapi passes locally on Windows/MSVC.

Relates to: #764

Assisted-by: claude-code:claude-fable-5

Two new test tiers for the hotplug API:

- test_hotplug_api.c (HotplugAPI_<backend>): argument validation,
  callback-handle properties, implicit init, hid_exit() teardown and
  register/deregister thread churn. Needs no device or privileges, so
  it runs against every backend in the ordinary CI matrix.

- test_hotplug.c (Hotplug_<backend>): device-backed hotplug scenarios
  (async delivery, exactly-once ENUMERATE pass, callback-return
  deregistration, pass-before-live ordering, ARRIVED/LEFT payloads,
  filtering, dispatch order, deregistration post-condition and
  re-entrant registration) against a virtual device whose presence is
  toggled with the new test_virtual_device_unplug()/_replug() calls.
  Implemented for the uhid provider (UHID_DESTROY/UHID_CREATE2 on the
  same fd); the other providers return TEST_VDEV_UNAVAILABLE and their
  hotplug tests self-skip until presence toggling is implemented.

Assisted-by: claude-code:claude-fable-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant