From acb09623c8ad31ae024c1df905caedbe2e70e666 Mon Sep 17 00:00:00 2001 From: mockoocy Date: Thu, 20 Feb 2025 09:42:24 +0100 Subject: [PATCH] Adds test case for TangoShutter The ruff config had to be adjusted to ignore the rule saying that methods have to start with lowercase letter - as there is a mocked Tango Device. --- ruff.toml | 3 + test/pytest/test_hwo_isara_maint.py | 2 +- test/pytest/test_hwo_tango_shutter.py | 123 ++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 test/pytest/test_hwo_tango_shutter.py diff --git a/ruff.toml b/ruff.toml index 3c56f9706b..ea85fbc2f5 100644 --- a/ruff.toml +++ b/ruff.toml @@ -7118,3 +7118,6 @@ convention = "google" "PT022", "S108", ] +"test/pytest/test_hwo_tango_shutter.py" = [ + "N802" +] diff --git a/test/pytest/test_hwo_isara_maint.py b/test/pytest/test_hwo_isara_maint.py index 8c61c0c1f6..8a7b1a18b5 100644 --- a/test/pytest/test_hwo_isara_maint.py +++ b/test/pytest/test_hwo_isara_maint.py @@ -90,7 +90,7 @@ def disable_remote_mode(self): def _disconnect_channels(maint: ISARAMaint): """ - disconnect signal callbacks from tango attribute pollers + disconnect signal callbacks from tango attribute pollersf We need to disconnect signals, otherwise we'll get exceptions when shut down the tango device, while tearing down text fixture. diff --git a/test/pytest/test_hwo_tango_shutter.py b/test/pytest/test_hwo_tango_shutter.py new file mode 100644 index 0000000000..e731b3b788 --- /dev/null +++ b/test/pytest/test_hwo_tango_shutter.py @@ -0,0 +1,123 @@ +"""Test the HardwareObjects.TangoShutter shutter hardware object.""" + +from typing import Callable + +import gevent +import pytest +from gevent import Timeout +from tango import ( + DeviceProxy, + DevState, +) +from tango.server import ( + Device, + command, +) +from tango.test_context import DeviceTestContext + +from mxcubecore.HardwareObjects import TangoShutter + +TANGO_SHUTTER_STATES_MAPPING = """ +{"OPEN": "OPEN", "CLOSED": "CLOSE", "MOVING" : "MOVING"} +""" + + +class Shutter(Device): + """Very simple Tango shutter device, that only goes + between 'open' and 'close' states.""" + + def __init__(self, *args, **kwargs): + self._is_open = False + super().__init__(*args, **kwargs) + + @command() + def Open(self): + self._is_open = True + + @command() + def Close(self): + self._is_open = False + + def dev_state(self): + return DevState.OPEN if self._is_open else DevState.CLOSE + + +@pytest.fixture +def shutter(): + tangods_test_context = DeviceTestContext(Shutter, process=True) + tangods_test_context.start() + + # + # set up the TangoShutter hardware object + # + hwo_shutter = TangoShutter.TangoShutter("/random_name") + hwo_shutter.tangoname = tangods_test_context.get_device_access() + hwo_shutter.set_property("values", TANGO_SHUTTER_STATES_MAPPING) + hwo_shutter.add_channel( + { + "name": "State", + "type": "tango", + }, + "State", + add_now=True, + ) + hwo_shutter.add_command( + { + "name": "Open", + "type": "tango", + }, + "Open", + add_now=True, + ) + hwo_shutter.add_command( + { + "name": "Close", + "type": "tango", + }, + "Close", + add_now=True, + ) + + hwo_shutter.init() + + yield hwo_shutter + + tangods_test_context.stop() + tangods_test_context.join() + + +def _wait_until(condition: Callable, condition_desc: str): + with Timeout(1.2, Exception(f"timed out while waiting for {condition_desc}")): + while not condition(): + gevent.sleep(0.01) + + +def test_open(shutter): + """ + test opening the shutter + """ + dev = DeviceProxy(shutter.tangoname) + + assert dev.State() == DevState.CLOSE + assert not shutter.is_open + + shutter.open() + + _wait_until(lambda: shutter.is_open, "shutter to open") + assert dev.State() == DevState.OPEN + + +def test_close(shutter): + """ + test closing the shutter + """ + dev = DeviceProxy(shutter.tangoname) + dev.Open() + + assert dev.State() == DevState.OPEN + assert shutter.is_open + + shutter.close() + + _wait_until(lambda: not shutter.is_open, "shutter to close") + assert dev.State() == DevState.CLOSE