From 89ba73db2965938f9f53fcc82c1f8e07e89327b9 Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:34:06 +0100 Subject: [PATCH 1/5] Remove legacy path handling Python 2 compatibility is no longer needed. Related #2273 --- bin/solaar | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/bin/solaar b/bin/solaar index 17cecc26b9..07ceeee90f 100755 --- a/bin/solaar +++ b/bin/solaar @@ -24,20 +24,7 @@ def init_paths(): import os.path import sys - # Python 3 might have problems converting back to UTF-8 in case of Unicode surrogates - decoded_path = None - try: - decoded_path = sys.path[0] - sys.path[0].encode(sys.getfilesystemencoding()) - - except UnicodeError: - sys.stderr.write( - "ERROR: Solaar cannot recognize encoding of filesystem path, " - "this may happen due to non UTF-8 characters in the pathname.\n" - ) - sys.exit(1) - - root = os.path.join(os.path.realpath(decoded_path), "..") + root = os.path.join(os.path.realpath(sys.path[0]), "..") prefix = os.path.normpath(root) src_lib = os.path.join(prefix, "lib") share_lib = os.path.join(prefix, "share", "solaar", "lib") From a42b34958145c6480d6221850f50bd6fd2ef0899 Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:19:29 +0100 Subject: [PATCH 2/5] Remove legacy queue import This compatibility pattern for Python 2 is no longer needed. Related #2273 --- lib/solaar/tasks.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/solaar/tasks.py b/lib/solaar/tasks.py index 195cfa5ab6..f39b19b46f 100644 --- a/lib/solaar/tasks.py +++ b/lib/solaar/tasks.py @@ -18,15 +18,11 @@ import logging +from queue import Queue from threading import Thread logger = logging.getLogger(__name__) -try: - from Queue import Queue -except ImportError: - from queue import Queue - class TaskRunner(Thread): def __init__(self, name): From b34729b59b8d299ecc7f8a4124728e85701a98cf Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:31:08 +0100 Subject: [PATCH 3/5] Restructure tests Move unit tests into a subdirectory of tests to support the introduction of integration tests. --- tests/{hid_parser => integrationtests}/__init__.py | 0 tests/{hidapi => unittests}/__init__.py | 0 tests/{logitech_receiver => unittests/hid_parser}/__init__.py | 0 tests/{ => unittests}/hid_parser/test_data.py | 0 tests/{test_keysyms => unittests/hidapi}/__init__.py | 0 tests/{ => unittests}/hidapi/test_hidapi.py | 0 tests/unittests/logitech_receiver/__init__.py | 0 tests/{ => unittests}/logitech_receiver/fake_hidpp.py | 0 tests/{ => unittests}/logitech_receiver/test_base.py | 0 tests/{ => unittests}/logitech_receiver/test_common.py | 0 .../logitech_receiver/test_desktop_notifications.py | 0 tests/{ => unittests}/logitech_receiver/test_device.py | 0 tests/{ => unittests}/logitech_receiver/test_diversion.py | 0 tests/{ => unittests}/logitech_receiver/test_hidpp10.py | 0 tests/{ => unittests}/logitech_receiver/test_hidpp20_complex.py | 0 tests/{ => unittests}/logitech_receiver/test_hidpp20_simple.py | 0 tests/{ => unittests}/logitech_receiver/test_notifications.py | 0 tests/{ => unittests}/logitech_receiver/test_receiver.py | 0 tests/{ => unittests}/logitech_receiver/test_setting_templates.py | 0 tests/{ => unittests}/logitech_receiver/test_settings.py | 0 tests/unittests/solaar/__init__.py | 0 tests/unittests/solaar/ui/__init__.py | 0 tests/{ => unittests}/solaar/ui/test_about_dialog.py | 0 tests/{ => unittests}/solaar/ui/test_common.py | 0 tests/{ => unittests}/solaar/ui/test_desktop_notifications.py | 0 tests/{ => unittests}/solaar/ui/test_i18n.py | 0 tests/{ => unittests}/solaar/ui/test_pair_window.py | 0 tests/{ => unittests}/solaar/ui/test_probe.py | 0 tests/unittests/test_keysyms/__init__.py | 0 tests/{ => unittests}/test_keysyms/test_keysymdef.py | 0 30 files changed, 0 insertions(+), 0 deletions(-) rename tests/{hid_parser => integrationtests}/__init__.py (100%) rename tests/{hidapi => unittests}/__init__.py (100%) rename tests/{logitech_receiver => unittests/hid_parser}/__init__.py (100%) rename tests/{ => unittests}/hid_parser/test_data.py (100%) rename tests/{test_keysyms => unittests/hidapi}/__init__.py (100%) rename tests/{ => unittests}/hidapi/test_hidapi.py (100%) create mode 100644 tests/unittests/logitech_receiver/__init__.py rename tests/{ => unittests}/logitech_receiver/fake_hidpp.py (100%) rename tests/{ => unittests}/logitech_receiver/test_base.py (100%) rename tests/{ => unittests}/logitech_receiver/test_common.py (100%) rename tests/{ => unittests}/logitech_receiver/test_desktop_notifications.py (100%) rename tests/{ => unittests}/logitech_receiver/test_device.py (100%) rename tests/{ => unittests}/logitech_receiver/test_diversion.py (100%) rename tests/{ => unittests}/logitech_receiver/test_hidpp10.py (100%) rename tests/{ => unittests}/logitech_receiver/test_hidpp20_complex.py (100%) rename tests/{ => unittests}/logitech_receiver/test_hidpp20_simple.py (100%) rename tests/{ => unittests}/logitech_receiver/test_notifications.py (100%) rename tests/{ => unittests}/logitech_receiver/test_receiver.py (100%) rename tests/{ => unittests}/logitech_receiver/test_setting_templates.py (100%) rename tests/{ => unittests}/logitech_receiver/test_settings.py (100%) create mode 100644 tests/unittests/solaar/__init__.py create mode 100644 tests/unittests/solaar/ui/__init__.py rename tests/{ => unittests}/solaar/ui/test_about_dialog.py (100%) rename tests/{ => unittests}/solaar/ui/test_common.py (100%) rename tests/{ => unittests}/solaar/ui/test_desktop_notifications.py (100%) rename tests/{ => unittests}/solaar/ui/test_i18n.py (100%) rename tests/{ => unittests}/solaar/ui/test_pair_window.py (100%) rename tests/{ => unittests}/solaar/ui/test_probe.py (100%) create mode 100644 tests/unittests/test_keysyms/__init__.py rename tests/{ => unittests}/test_keysyms/test_keysymdef.py (100%) diff --git a/tests/hid_parser/__init__.py b/tests/integrationtests/__init__.py similarity index 100% rename from tests/hid_parser/__init__.py rename to tests/integrationtests/__init__.py diff --git a/tests/hidapi/__init__.py b/tests/unittests/__init__.py similarity index 100% rename from tests/hidapi/__init__.py rename to tests/unittests/__init__.py diff --git a/tests/logitech_receiver/__init__.py b/tests/unittests/hid_parser/__init__.py similarity index 100% rename from tests/logitech_receiver/__init__.py rename to tests/unittests/hid_parser/__init__.py diff --git a/tests/hid_parser/test_data.py b/tests/unittests/hid_parser/test_data.py similarity index 100% rename from tests/hid_parser/test_data.py rename to tests/unittests/hid_parser/test_data.py diff --git a/tests/test_keysyms/__init__.py b/tests/unittests/hidapi/__init__.py similarity index 100% rename from tests/test_keysyms/__init__.py rename to tests/unittests/hidapi/__init__.py diff --git a/tests/hidapi/test_hidapi.py b/tests/unittests/hidapi/test_hidapi.py similarity index 100% rename from tests/hidapi/test_hidapi.py rename to tests/unittests/hidapi/test_hidapi.py diff --git a/tests/unittests/logitech_receiver/__init__.py b/tests/unittests/logitech_receiver/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/logitech_receiver/fake_hidpp.py b/tests/unittests/logitech_receiver/fake_hidpp.py similarity index 100% rename from tests/logitech_receiver/fake_hidpp.py rename to tests/unittests/logitech_receiver/fake_hidpp.py diff --git a/tests/logitech_receiver/test_base.py b/tests/unittests/logitech_receiver/test_base.py similarity index 100% rename from tests/logitech_receiver/test_base.py rename to tests/unittests/logitech_receiver/test_base.py diff --git a/tests/logitech_receiver/test_common.py b/tests/unittests/logitech_receiver/test_common.py similarity index 100% rename from tests/logitech_receiver/test_common.py rename to tests/unittests/logitech_receiver/test_common.py diff --git a/tests/logitech_receiver/test_desktop_notifications.py b/tests/unittests/logitech_receiver/test_desktop_notifications.py similarity index 100% rename from tests/logitech_receiver/test_desktop_notifications.py rename to tests/unittests/logitech_receiver/test_desktop_notifications.py diff --git a/tests/logitech_receiver/test_device.py b/tests/unittests/logitech_receiver/test_device.py similarity index 100% rename from tests/logitech_receiver/test_device.py rename to tests/unittests/logitech_receiver/test_device.py diff --git a/tests/logitech_receiver/test_diversion.py b/tests/unittests/logitech_receiver/test_diversion.py similarity index 100% rename from tests/logitech_receiver/test_diversion.py rename to tests/unittests/logitech_receiver/test_diversion.py diff --git a/tests/logitech_receiver/test_hidpp10.py b/tests/unittests/logitech_receiver/test_hidpp10.py similarity index 100% rename from tests/logitech_receiver/test_hidpp10.py rename to tests/unittests/logitech_receiver/test_hidpp10.py diff --git a/tests/logitech_receiver/test_hidpp20_complex.py b/tests/unittests/logitech_receiver/test_hidpp20_complex.py similarity index 100% rename from tests/logitech_receiver/test_hidpp20_complex.py rename to tests/unittests/logitech_receiver/test_hidpp20_complex.py diff --git a/tests/logitech_receiver/test_hidpp20_simple.py b/tests/unittests/logitech_receiver/test_hidpp20_simple.py similarity index 100% rename from tests/logitech_receiver/test_hidpp20_simple.py rename to tests/unittests/logitech_receiver/test_hidpp20_simple.py diff --git a/tests/logitech_receiver/test_notifications.py b/tests/unittests/logitech_receiver/test_notifications.py similarity index 100% rename from tests/logitech_receiver/test_notifications.py rename to tests/unittests/logitech_receiver/test_notifications.py diff --git a/tests/logitech_receiver/test_receiver.py b/tests/unittests/logitech_receiver/test_receiver.py similarity index 100% rename from tests/logitech_receiver/test_receiver.py rename to tests/unittests/logitech_receiver/test_receiver.py diff --git a/tests/logitech_receiver/test_setting_templates.py b/tests/unittests/logitech_receiver/test_setting_templates.py similarity index 100% rename from tests/logitech_receiver/test_setting_templates.py rename to tests/unittests/logitech_receiver/test_setting_templates.py diff --git a/tests/logitech_receiver/test_settings.py b/tests/unittests/logitech_receiver/test_settings.py similarity index 100% rename from tests/logitech_receiver/test_settings.py rename to tests/unittests/logitech_receiver/test_settings.py diff --git a/tests/unittests/solaar/__init__.py b/tests/unittests/solaar/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/unittests/solaar/ui/__init__.py b/tests/unittests/solaar/ui/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/solaar/ui/test_about_dialog.py b/tests/unittests/solaar/ui/test_about_dialog.py similarity index 100% rename from tests/solaar/ui/test_about_dialog.py rename to tests/unittests/solaar/ui/test_about_dialog.py diff --git a/tests/solaar/ui/test_common.py b/tests/unittests/solaar/ui/test_common.py similarity index 100% rename from tests/solaar/ui/test_common.py rename to tests/unittests/solaar/ui/test_common.py diff --git a/tests/solaar/ui/test_desktop_notifications.py b/tests/unittests/solaar/ui/test_desktop_notifications.py similarity index 100% rename from tests/solaar/ui/test_desktop_notifications.py rename to tests/unittests/solaar/ui/test_desktop_notifications.py diff --git a/tests/solaar/ui/test_i18n.py b/tests/unittests/solaar/ui/test_i18n.py similarity index 100% rename from tests/solaar/ui/test_i18n.py rename to tests/unittests/solaar/ui/test_i18n.py diff --git a/tests/solaar/ui/test_pair_window.py b/tests/unittests/solaar/ui/test_pair_window.py similarity index 100% rename from tests/solaar/ui/test_pair_window.py rename to tests/unittests/solaar/ui/test_pair_window.py diff --git a/tests/solaar/ui/test_probe.py b/tests/unittests/solaar/ui/test_probe.py similarity index 100% rename from tests/solaar/ui/test_probe.py rename to tests/unittests/solaar/ui/test_probe.py diff --git a/tests/unittests/test_keysyms/__init__.py b/tests/unittests/test_keysyms/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_keysyms/test_keysymdef.py b/tests/unittests/test_keysyms/test_keysymdef.py similarity index 100% rename from tests/test_keysyms/test_keysymdef.py rename to tests/unittests/test_keysyms/test_keysymdef.py From f2e4e8c90c9d184898f67919bc860a2a5814d40e Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:37:26 +0100 Subject: [PATCH 4/5] Introduce integrationtests for listeners --- lib/hidapi/hidapi_impl.py | 8 +++--- tests/integrationtests/test_device_monitor.py | 25 +++++++++++++++++++ .../integrationtests/test_events_listener.py | 16 ++++++++++++ .../integrationtests/test_solaar_listener.py | 15 +++++++++++ tests/integrationtests/test_task_runner.py | 15 +++++++++++ 5 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 tests/integrationtests/test_device_monitor.py create mode 100644 tests/integrationtests/test_events_listener.py create mode 100644 tests/integrationtests/test_solaar_listener.py create mode 100644 tests/integrationtests/test_task_runner.py diff --git a/lib/hidapi/hidapi_impl.py b/lib/hidapi/hidapi_impl.py index 9e04153a21..062e47e7d9 100644 --- a/lib/hidapi/hidapi_impl.py +++ b/lib/hidapi/hidapi_impl.py @@ -171,7 +171,7 @@ class HIDError(Exception): pass -def _enumerate_devices(): +def _enumerate_devices() -> list: """Returns all HID devices which are potentially useful to us""" devices = [] c_devices = _hidapi.hid_enumerate(0, 0) @@ -201,7 +201,7 @@ def _enumerate_devices(): # Use a separate thread to check if devices have been removed or connected -class _DeviceMonitor(Thread): +class DeviceMonitor(Thread): def __init__(self, device_callback, polling_delay=5.0): self.device_callback = device_callback self.polling_delay = polling_delay @@ -359,11 +359,11 @@ def device_callback(action: str, device): # Removed devices will be detected by Solaar directly pass - monitor = _DeviceMonitor(device_callback=device_callback) + monitor = DeviceMonitor(device_callback=device_callback) monitor.start() -def enumerate(filter_func) -> DeviceInfo: +def enumerate(filter_func: Callable) -> DeviceInfo: """Enumerate the HID Devices. List all the HID devices attached to the system, optionally filtering by diff --git a/tests/integrationtests/test_device_monitor.py b/tests/integrationtests/test_device_monitor.py new file mode 100644 index 0000000000..699fd6c9f1 --- /dev/null +++ b/tests/integrationtests/test_device_monitor.py @@ -0,0 +1,25 @@ +import platform +import time + +import pytest + + +@pytest.mark.skipif(platform.system() == "Linux", reason="Test for non Linux platforms") +def test_device_monitor(mocker): + from hidapi.hidapi_impl import DeviceMonitor + + mock_callback = mocker.Mock() + monitor = DeviceMonitor(device_callback=mock_callback, polling_delay=1) + monitor.start() + + while not monitor.is_alive(): + time.sleep(0.1) + + assert monitor.alive + + monitor.stop() + + while monitor.is_alive(): + time.sleep(0.1) + + assert not monitor.alive diff --git a/tests/integrationtests/test_events_listener.py b/tests/integrationtests/test_events_listener.py new file mode 100644 index 0000000000..8c08c85ae6 --- /dev/null +++ b/tests/integrationtests/test_events_listener.py @@ -0,0 +1,16 @@ +from logitech_receiver.listener import EventsListener + + +def test_events_listener(mocker): + receiver = mocker.MagicMock() + status_callback = mocker.MagicMock() + + e = EventsListener(receiver, status_callback) + e.start() + + assert bool(e) + + e.stop() + + assert not bool(e) + assert status_callback.call_count == 0 diff --git a/tests/integrationtests/test_solaar_listener.py b/tests/integrationtests/test_solaar_listener.py new file mode 100644 index 0000000000..166d601b07 --- /dev/null +++ b/tests/integrationtests/test_solaar_listener.py @@ -0,0 +1,15 @@ +from solaar.listener import SolaarListener + + +def test_solaar_listener(mocker): + receiver = mocker.MagicMock() + receiver.handle = 1 + receiver.path = "dsda" + status_callback = mocker.MagicMock() + + rl = SolaarListener(receiver, status_callback) + # rl.run() + # rl.stop() + + assert not rl.is_alive() + assert status_callback.call_count == 0 diff --git a/tests/integrationtests/test_task_runner.py b/tests/integrationtests/test_task_runner.py new file mode 100644 index 0000000000..0ff7c3e894 --- /dev/null +++ b/tests/integrationtests/test_task_runner.py @@ -0,0 +1,15 @@ +from solaar import tasks + + +def run_task(): + print("Hi!") + + +def test_task_runner(mocker): + tr = tasks.TaskRunner(name="Testrunner") + tr.queue.put((run_task, {}, {})) + # tr.run() + # tr.stop() + # assert tr.alive + # tr.stop() + # assert not tr.alive From 46a8fd894f3b01d6e3fe10ea24a46ac42f6694e3 Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Wed, 6 Nov 2024 23:23:11 +0100 Subject: [PATCH 5/5] WIP --- lib/hidapi/hidapi_impl.py | 10 +++++- lib/logitech_receiver/listener.py | 36 ++++++++++++++----- lib/solaar/listener.py | 22 ++++++++++-- tests/integrationtests/test_device_monitor.py | 10 +++--- .../integrationtests/test_events_listener.py | 8 ++--- .../integrationtests/test_solaar_listener.py | 12 ++++--- tests/integrationtests/test_task_runner.py | 13 +++---- .../logitech_receiver/test_notifications.py | 3 ++ 8 files changed, 82 insertions(+), 32 deletions(-) diff --git a/lib/hidapi/hidapi_impl.py b/lib/hidapi/hidapi_impl.py index 062e47e7d9..a6fe80616c 100644 --- a/lib/hidapi/hidapi_impl.py +++ b/lib/hidapi/hidapi_impl.py @@ -206,15 +206,18 @@ def __init__(self, device_callback, polling_delay=5.0): self.device_callback = device_callback self.polling_delay = polling_delay self.prev_devices = None + self.alive = False + self.abort_triggered = False # daemon threads are automatically killed when main thread exits super().__init__(daemon=True) def run(self): + self.alive = True # Populate initial set of devices so startup doesn't cause any callbacks self.prev_devices = {tuple(dev.items()): dev for dev in _enumerate_devices()} # Continously enumerate devices and raise callback for changes - while True: + while not self.abort_triggered: current_devices = {tuple(dev.items()): dev for dev in _enumerate_devices()} for key, device in self.prev_devices.items(): if key not in current_devices: @@ -225,6 +228,11 @@ def run(self): self.prev_devices = current_devices sleep(self.polling_delay) + self.alive = False + + def stop(self): + self.abort_triggered = True + def _match( action: str, diff --git a/lib/logitech_receiver/listener.py b/lib/logitech_receiver/listener.py index 44c7487e4f..4641a679b4 100644 --- a/lib/logitech_receiver/listener.py +++ b/lib/logitech_receiver/listener.py @@ -19,25 +19,42 @@ import queue import threading -from . import base +from typing import Any +from typing import Protocol + from . import exceptions logger = logging.getLogger(__name__) +class LowLevelInterface(Protocol): + def open_path(self, path): + ... + + def ping(self, handle, number, long_message=False): + ... + + def make_notification(self, report_id: int, devnumber: int, data: bytes) -> Any: + ... + + def close(self, handle): + ... + + class _ThreadedHandle: """A thread-local wrapper with different open handles for each thread. Closing a ThreadedHandle will close all handles. """ - __slots__ = ("path", "_local", "_handles", "_listener") + __slots__ = ("path", "_local", "_handles", "_listener", "_base") - def __init__(self, listener, path, handle): + def __init__(self, listener, path, handle, low_level_api: LowLevelInterface): assert listener is not None assert path is not None assert handle is not None assert isinstance(handle, int) + self._base = low_level_api self._listener = listener self.path = path self._local = threading.local() @@ -46,7 +63,7 @@ def __init__(self, listener, path, handle): self._handles = [handle] def _open(self): - handle = base.open_path(self.path) + handle = self._base.open_path(self.path) if handle is None: logger.error("%r failed to open new handle", self) else: @@ -63,7 +80,7 @@ def close(self): if logger.isEnabledFor(logging.DEBUG): logger.debug("%r closing %s", self, handles) for h in handles: - base.close(h) + self._base.close(h) @property def notifications_hook(self): @@ -112,12 +129,13 @@ class EventsListener(threading.Thread): Incoming packets will be passed to the callback function in sequence. """ - def __init__(self, receiver, notifications_callback): + def __init__(self, receiver, notifications_callback, low_level: LowLevelInterface): try: path_name = receiver.path.split("/")[2] except IndexError: path_name = receiver.path super().__init__(name=self.__class__.__name__ + ":" + path_name) + self._base = low_level self.daemon = True self._active = False self.receiver = receiver @@ -127,7 +145,7 @@ def __init__(self, receiver, notifications_callback): def run(self): self._active = True # replace the handle with a threaded one - self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle) + self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle, self._base) if logger.isEnabledFor(logging.INFO): logger.info("started with %s (%d)", self.receiver, int(self.receiver.handle)) self.has_started() @@ -139,13 +157,13 @@ def run(self): while self._active: if self._queued_notifications.empty(): try: - n = base.read(self.receiver.handle, _EVENT_READ_TIMEOUT) + n = self._base.read(self.receiver.handle, _EVENT_READ_TIMEOUT) except exceptions.NoReceiver: logger.warning("%s disconnected", self.receiver.name) self.receiver.close() break if n: - n = base.make_notification(*n) + n = self._base.make_notification(*n) else: n = self._queued_notifications.get() # deliver any queued notifications if n: diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py index 76a4b1afde..f18c8336bf 100644 --- a/lib/solaar/listener.py +++ b/lib/solaar/listener.py @@ -22,6 +22,8 @@ from collections import namedtuple from functools import partial +from typing import Any +from typing import Protocol import gi import logitech_receiver @@ -58,12 +60,26 @@ def _ghost(device): ) +class LowLevelInterface(Protocol): + def open_path(self, path): + ... + + def ping(self, handle, number, long_message=False): + ... + + def make_notification(self, report_id: int, devnumber: int, data: bytes) -> Any: + ... + + def close(self, handle): + ... + + class SolaarListener(listener.EventsListener): """Keeps the status of a Receiver or Device (member name is receiver but it can also be a device).""" - def __init__(self, receiver, status_changed_callback): + def __init__(self, receiver, status_changed_callback, low_level): assert status_changed_callback - super().__init__(receiver, self._notifications_handler) + super().__init__(receiver, self._notifications_handler, low_level) self.status_changed_callback = status_changed_callback receiver.status_callback = self._status_changed @@ -275,7 +291,7 @@ def _start(device_info): receiver_.cleanups.append(_cleanup_bluez_dbus) if receiver_: - rl = SolaarListener(receiver_, _status_callback) + rl = SolaarListener(receiver_, _status_callback, base) rl.start() _all_listeners[device_info.path] = rl return rl diff --git a/tests/integrationtests/test_device_monitor.py b/tests/integrationtests/test_device_monitor.py index 699fd6c9f1..0b19f45d5a 100644 --- a/tests/integrationtests/test_device_monitor.py +++ b/tests/integrationtests/test_device_monitor.py @@ -9,17 +9,17 @@ def test_device_monitor(mocker): from hidapi.hidapi_impl import DeviceMonitor mock_callback = mocker.Mock() - monitor = DeviceMonitor(device_callback=mock_callback, polling_delay=1) + monitor = DeviceMonitor(device_callback=mock_callback, polling_delay=0.1) monitor.start() - while not monitor.is_alive(): - time.sleep(0.1) + while not monitor.alive: + time.sleep(0.01) assert monitor.alive monitor.stop() - while monitor.is_alive(): - time.sleep(0.1) + while monitor.alive: + time.sleep(0.01) assert not monitor.alive diff --git a/tests/integrationtests/test_events_listener.py b/tests/integrationtests/test_events_listener.py index 8c08c85ae6..4e68770e02 100644 --- a/tests/integrationtests/test_events_listener.py +++ b/tests/integrationtests/test_events_listener.py @@ -3,14 +3,14 @@ def test_events_listener(mocker): receiver = mocker.MagicMock() + receiver.handle = 1 + receiver.path = "pathname" status_callback = mocker.MagicMock() + low_level_mock = mocker.MagicMock() - e = EventsListener(receiver, status_callback) + e = EventsListener(receiver, status_callback, low_level_mock) e.start() assert bool(e) e.stop() - - assert not bool(e) - assert status_callback.call_count == 0 diff --git a/tests/integrationtests/test_solaar_listener.py b/tests/integrationtests/test_solaar_listener.py index 166d601b07..e9e415ffe9 100644 --- a/tests/integrationtests/test_solaar_listener.py +++ b/tests/integrationtests/test_solaar_listener.py @@ -1,15 +1,19 @@ from solaar.listener import SolaarListener +# @pytest.mark.skip(reason="Unstable") def test_solaar_listener(mocker): receiver = mocker.MagicMock() - receiver.handle = 1 + receiver.handle = mocker.MagicMock() receiver.path = "dsda" status_callback = mocker.MagicMock() + low_level_mock = mocker.MagicMock() - rl = SolaarListener(receiver, status_callback) - # rl.run() - # rl.stop() + rl = SolaarListener(receiver, status_callback, low_level_mock) + rl.start() + rl.stop() + + rl.join() assert not rl.is_alive() assert status_callback.call_count == 0 diff --git a/tests/integrationtests/test_task_runner.py b/tests/integrationtests/test_task_runner.py index 0ff7c3e894..d36e3f850f 100644 --- a/tests/integrationtests/test_task_runner.py +++ b/tests/integrationtests/test_task_runner.py @@ -7,9 +7,10 @@ def run_task(): def test_task_runner(mocker): tr = tasks.TaskRunner(name="Testrunner") - tr.queue.put((run_task, {}, {})) - # tr.run() - # tr.stop() - # assert tr.alive - # tr.stop() - # assert not tr.alive + tr.start() + assert tr.alive + + tr(run_task) + + tr.stop() + assert not tr.alive diff --git a/tests/unittests/logitech_receiver/test_notifications.py b/tests/unittests/logitech_receiver/test_notifications.py index 9cc8dd3338..426f42fb0a 100644 --- a/tests/unittests/logitech_receiver/test_notifications.py +++ b/tests/unittests/logitech_receiver/test_notifications.py @@ -22,6 +22,9 @@ def ping(self, handle, number, long_message=False): def request(self, handle, devnumber, request_id, *params, **kwargs): pass + def close(self): + pass + @pytest.mark.parametrize( "sub_id, notification_data, expected_error, expected_new_device",