Rework radar system
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""GPIO startup failures are optional; queued presses cannot survive shutdown."""
|
||||
|
||||
import threading
|
||||
import os
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from PyQt6.QtCore import QObject, pyqtSignal
|
||||
from PyQt6.QtWidgets import QApplication
|
||||
|
||||
from python_app.gui.controllers.control_button_controller import ControlButtonController
|
||||
from python_app.models.run_config_schema import ControlButtonModel
|
||||
from python_app.tests.gui_test_support import isolated_window
|
||||
|
||||
|
||||
class _Watcher(QObject):
|
||||
pressed = pyqtSignal()
|
||||
failed = pyqtSignal(str)
|
||||
|
||||
def __init__(self, *, parent: QObject, **_kwargs: object) -> None:
|
||||
super().__init__(parent)
|
||||
self.stopped = False
|
||||
|
||||
def start(self) -> None:
|
||||
pass
|
||||
|
||||
def stop(self) -> None:
|
||||
self.stopped = True
|
||||
self.pressed.emit()
|
||||
|
||||
|
||||
class ControlButtonControllerTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.app = QApplication.instance() or QApplication([])
|
||||
self.config = ControlButtonModel(enabled=True, pin=17)
|
||||
self.capture = mock.Mock()
|
||||
self.parent = QObject()
|
||||
self.controller = ControlButtonController(self.parent, lambda: self.config, self.capture, mock.MagicMock())
|
||||
self.addCleanup(self.controller.close)
|
||||
|
||||
def test_close_rejects_already_queued_and_stop_time_presses(self) -> None:
|
||||
with mock.patch("python_app.gui.controllers.control_button_controller.ControlButtonWatcher", _Watcher):
|
||||
self.controller.start()
|
||||
watcher = self.controller._watcher
|
||||
assert isinstance(watcher, _Watcher)
|
||||
watcher.pressed.emit()
|
||||
self.capture.assert_called_once()
|
||||
worker = threading.Thread(target=watcher.pressed.emit)
|
||||
worker.start()
|
||||
worker.join(timeout=1)
|
||||
self.controller.close()
|
||||
self.app.processEvents()
|
||||
self.assertTrue(watcher.stopped)
|
||||
self.capture.assert_called_once()
|
||||
self.assertIsNone(self.controller._watcher)
|
||||
|
||||
def test_disabled_invalid_and_unavailable_gpio_do_not_start_capture(self) -> None:
|
||||
with mock.patch("python_app.gui.controllers.control_button_controller.ControlButtonWatcher") as create:
|
||||
self.config.enabled = False
|
||||
self.controller.start()
|
||||
self.config.enabled, self.config.pin = True, -1
|
||||
self.controller.start()
|
||||
create.assert_not_called()
|
||||
self.config.pin = 17
|
||||
create.side_effect = OSError("GPIO unavailable")
|
||||
self.controller.start()
|
||||
self.assertIsNone(self.controller._watcher)
|
||||
self.capture.assert_not_called()
|
||||
|
||||
def test_gpio_capture_failure_is_logged_without_a_modal_dialog(self) -> None:
|
||||
window = isolated_window(self.addCleanup)
|
||||
window._profile.state.config.control_button.enabled = True
|
||||
window._profile.state.config.control_button.pin = 17
|
||||
window._control_button._capture_reference = lambda: window._log.show_error("GPIO capture failed")
|
||||
with mock.patch("python_app.gui.controllers.control_button_controller.ControlButtonWatcher", _Watcher), \
|
||||
mock.patch.dict(os.environ, {"RADAR_SYSTEM_HEADLESS": "0"}), \
|
||||
mock.patch("python_app.gui.controllers.log_controller.QMessageBox") as dialog, \
|
||||
self.assertLogs("python_app.gui", level="ERROR") as logs:
|
||||
window._control_button.start()
|
||||
watcher = window._control_button._watcher
|
||||
assert isinstance(watcher, _Watcher)
|
||||
watcher.pressed.emit()
|
||||
dialog.assert_not_called()
|
||||
self.assertTrue(any("GPIO capture failed" in line for line in logs.output))
|
||||
Reference in New Issue
Block a user