mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-03-04 16:02:51 +01:00
test(device-manager-view): improve test coverage for device-manager-view
This commit is contained in:
@@ -77,27 +77,27 @@ class CustomBusyWidget(QWidget):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
# Widgets
|
||||
progress = DeviceInitializationProgressBar(parent=self, client=client)
|
||||
progress.setMinimumWidth(320)
|
||||
self.progress = DeviceInitializationProgressBar(parent=self, client=client)
|
||||
self.progress.setMinimumWidth(320)
|
||||
|
||||
# Spinner
|
||||
spinner = SpinnerWidget(parent=self)
|
||||
self.spinner = SpinnerWidget(parent=self)
|
||||
scale = self._ui_scale()
|
||||
spinner_size = int(scale * 0.12) if scale else 1
|
||||
spinner_size = max(32, min(spinner_size, 96))
|
||||
spinner.setFixedSize(spinner_size, spinner_size)
|
||||
self.spinner.setFixedSize(spinner_size, spinner_size)
|
||||
|
||||
# Cancel button
|
||||
cancel_button = QPushButton("Cancel Upload", parent=self)
|
||||
cancel_button.setIcon(material_icon("cancel"))
|
||||
cancel_button.clicked.connect(self.cancel_requested.emit)
|
||||
self.cancel_button = QPushButton("Cancel Upload", parent=self)
|
||||
self.cancel_button.setIcon(material_icon("cancel"))
|
||||
self.cancel_button.clicked.connect(self.cancel_requested.emit)
|
||||
button_height = int(spinner_size * 0.9)
|
||||
button_height = max(36, min(button_height, 72))
|
||||
aspect_ratio = 3.8 # width / height, visually stable for text buttons
|
||||
button_width = int(button_height * aspect_ratio)
|
||||
cancel_button.setFixedSize(button_width, button_height)
|
||||
self.cancel_button.setFixedSize(button_width, button_height)
|
||||
color = get_accent_colors()
|
||||
cancel_button.setStyleSheet(
|
||||
self.cancel_button.setStyleSheet(
|
||||
f"""
|
||||
QPushButton {{
|
||||
background-color: {color.emergency.name()};
|
||||
@@ -113,10 +113,10 @@ class CustomBusyWidget(QWidget):
|
||||
content_layout.setContentsMargins(24, 24, 24, 24)
|
||||
content_layout.setSpacing(16)
|
||||
content_layout.addStretch()
|
||||
content_layout.addWidget(spinner, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
content_layout.addWidget(progress, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
content_layout.addWidget(self.spinner, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
content_layout.addWidget(self.progress, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
content_layout.addStretch()
|
||||
content_layout.addWidget(cancel_button, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
content_layout.addWidget(self.cancel_button, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
if hasattr(color, "_colors"):
|
||||
bg_color = color._colors.get("BG", None)
|
||||
@@ -138,14 +138,12 @@ class CustomBusyWidget(QWidget):
|
||||
def showEvent(self, event):
|
||||
"""Show event to start the spinner."""
|
||||
super().showEvent(event)
|
||||
for child in self.findChildren(SpinnerWidget):
|
||||
child.start()
|
||||
self.spinner.start()
|
||||
|
||||
def hideEvent(self, event):
|
||||
"""Hide event to stop the spinner."""
|
||||
super().hideEvent(event)
|
||||
for child in self.findChildren(SpinnerWidget):
|
||||
child.stop()
|
||||
self.spinner.stop()
|
||||
|
||||
|
||||
class DeviceManagerDisplayWidget(DockAreaWidget):
|
||||
@@ -171,9 +169,6 @@ class DeviceManagerDisplayWidget(DockAreaWidget):
|
||||
self._config_helper = config_helper.ConfigHelper(self.client.connector)
|
||||
self._shared_selection = SharedSelectionSignal()
|
||||
|
||||
# Custom upload widget for busy overlay
|
||||
self._custom_overlay_widget: QWidget | None = None
|
||||
|
||||
# Device Table View widget
|
||||
self.device_table_view = DeviceTable(self)
|
||||
|
||||
@@ -687,20 +682,9 @@ class DeviceManagerDisplayWidget(DockAreaWidget):
|
||||
# Config is in sync with BEC, so we update the state
|
||||
self.device_table_view.device_config_in_sync_with_redis.emit(False)
|
||||
|
||||
# Cleanup custom overlay widget
|
||||
if self._custom_overlay_widget is not None:
|
||||
self._custom_overlay_widget.close()
|
||||
self._custom_overlay_widget.deleteLater()
|
||||
self._custom_overlay_widget = None
|
||||
|
||||
def _handle_push_complete_to_communicator(self):
|
||||
"""Handle completion of the config push to Redis."""
|
||||
self._set_busy_wrapper(enabled=False)
|
||||
# Cleanup custom overlay widget
|
||||
if self._custom_overlay_widget is not None:
|
||||
self._custom_overlay_widget.close()
|
||||
self._custom_overlay_widget.deleteLater()
|
||||
self._custom_overlay_widget = None
|
||||
|
||||
def _handle_exception_from_communicator(self, exception: Exception):
|
||||
"""Handle exceptions from the config communicator."""
|
||||
@@ -710,10 +694,6 @@ class DeviceManagerDisplayWidget(DockAreaWidget):
|
||||
f"An error occurred while uploading the configuration to BEC Server:\n{str(exception)}",
|
||||
)
|
||||
self._set_busy_wrapper(enabled=False)
|
||||
if self._custom_overlay_widget is not None:
|
||||
self._custom_overlay_widget.close()
|
||||
self._custom_overlay_widget.deleteLater()
|
||||
self._custom_overlay_widget = None
|
||||
|
||||
@SafeSlot()
|
||||
def _save_to_disk_action(self):
|
||||
|
||||
@@ -30,6 +30,7 @@ from bec_widgets.applications.views.device_manager_view.device_manager_view impo
|
||||
DeviceManagerView,
|
||||
DeviceManagerWidget,
|
||||
)
|
||||
from bec_widgets.utils.colors import get_accent_colors
|
||||
from bec_widgets.widgets.control.device_manager.components import (
|
||||
DeviceTable,
|
||||
DMConfigView,
|
||||
@@ -612,6 +613,34 @@ class TestDeviceManagerView:
|
||||
cfg_iter.append(dev_config_copy)
|
||||
return cfg_iter
|
||||
|
||||
def test_custom_busy_widget(self, custom_busy: CustomBusyWidget, qtbot):
|
||||
"""Test the CustomBusyWidget functionality."""
|
||||
|
||||
# Check layout
|
||||
assert custom_busy.progress is not None
|
||||
assert custom_busy.spinner is not None
|
||||
assert custom_busy.spinner._started is False
|
||||
|
||||
# Check background
|
||||
color = get_accent_colors()
|
||||
bg = color._colors["BG"]
|
||||
sheet = custom_busy.styleSheet()
|
||||
assert bg.name() in sheet
|
||||
assert "border-radius: 12px" in sheet
|
||||
|
||||
# Show event should start spinner
|
||||
custom_busy.showEvent(None)
|
||||
assert custom_busy.spinner._started is True
|
||||
|
||||
with qtbot.waitSignal(custom_busy.cancel_requested) as sig_blocker:
|
||||
qtbot.mouseClick(custom_busy.cancel_button, QtCore.Qt.LeftButton)
|
||||
# Check that the signal was emitted
|
||||
assert sig_blocker.signal_triggered is True
|
||||
|
||||
# Hide should
|
||||
custom_busy.hideEvent(None)
|
||||
assert custom_busy.spinner._started is False
|
||||
|
||||
def test_device_manager_view_add_remove_device(
|
||||
self, device_manager_display_widget: DeviceManagerDisplayWidget, device_config
|
||||
):
|
||||
@@ -750,3 +779,60 @@ class TestDeviceManagerView:
|
||||
"rerun_validation"
|
||||
].action.action.triggered.emit()
|
||||
assert len(mock_change_configs.call_args[0][0]) == 1
|
||||
|
||||
def test_handle_cancel_config_upload_failed(
|
||||
self, device_manager_display_widget: DeviceManagerDisplayWidget, qtbot
|
||||
):
|
||||
"""Test handling cancel during config upload failure."""
|
||||
dm_view = device_manager_display_widget
|
||||
validation_results = {
|
||||
"Device_1": (
|
||||
{"name": "Device_1"},
|
||||
ConfigStatus.VALID.value,
|
||||
ConnectionStatus.CANNOT_CONNECT.value,
|
||||
),
|
||||
"Device_2": (
|
||||
{"name": "Device_2"},
|
||||
ConfigStatus.INVALID.value,
|
||||
ConnectionStatus.UNKNOWN.value,
|
||||
),
|
||||
}
|
||||
with mock.patch.object(
|
||||
dm_view.device_table_view, "get_validation_results", return_value=validation_results
|
||||
):
|
||||
with (
|
||||
mock.patch.object(
|
||||
dm_view.device_table_view, "update_multiple_device_validations"
|
||||
) as mock_update,
|
||||
mock.patch.object(
|
||||
dm_view.ophyd_test_view, "change_device_configs"
|
||||
) as mock_change_configs,
|
||||
):
|
||||
with qtbot.waitSignal(
|
||||
dm_view.device_table_view.device_config_in_sync_with_redis
|
||||
) as sig_blocker:
|
||||
dm_view._handle_cancel_config_upload_failed(
|
||||
exception=Exception("Test Exception")
|
||||
)
|
||||
assert sig_blocker.signal_triggered is True
|
||||
mock_change_configs.assert_called_once_with(
|
||||
[validation_results["Device_1"][0], validation_results["Device_2"][0]],
|
||||
added=True,
|
||||
skip_validation=False,
|
||||
)
|
||||
mock_update.assert_called_once_with(
|
||||
[
|
||||
(
|
||||
validation_results["Device_1"][0],
|
||||
validation_results["Device_1"][1],
|
||||
ConnectionStatus.UNKNOWN.value,
|
||||
"Upload Cancelled",
|
||||
),
|
||||
(
|
||||
validation_results["Device_2"][0],
|
||||
validation_results["Device_2"][1],
|
||||
ConnectionStatus.UNKNOWN.value,
|
||||
"Upload Cancelled",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user