From d745855b558257bd67a14d88bcd193101bffb0ae Mon Sep 17 00:00:00 2001 From: James Souter Date: Tue, 15 Oct 2024 09:55:08 +0100 Subject: [PATCH] Fix tests for new structure --- tests/conftest.py | 129 ++ tests/system/parameters.json | 1864 ++++++++++++++-------------- tests/system/test_introspection.py | 52 +- tests/test_controller.py | 96 +- 4 files changed, 1165 insertions(+), 976 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index ebe9c10..fb437f0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ from typing import Any import pytest +from pytest_mock import MockerFixture # Prevent pytest from catching exceptions when debugging in vscode so that break on # exception works correctly (see: https://github.com/pytest-dev/pytest/issues/7409) @@ -19,3 +20,131 @@ def pytest_exception_interact(call: pytest.CallInfo[Any]): @pytest.hookimpl(tryfirst=True) def pytest_internalerror(excinfo: pytest.ExceptionInfo[Any]): raise excinfo.value + + +_detector_config_keys = [ + "auto_summation", + "beam_center_x", + "beam_center_y", + "bit_depth_image", + "bit_depth_readout", + "chi_increment", + "chi_start", + "compression", + "count_time", + "counting_mode", + "countrate_correction_applied", + "countrate_correction_count_cutoff", + "data_collection_date", + "description", + "detector_distance", + "detector_number", + "detector_readout_time", + "eiger_fw_version", + "element", + "extg_mode", + "fast_arm", + "flatfield_correction_applied", + "frame_count_time", + "frame_time", + "incident_energy", + "incident_particle_type", + "instrument_name", + "kappa_increment", + "kappa_start", + "mask_to_zero", + "nexpi", + "nimages", + "ntrigger", + "ntriggers_skipped", + "number_of_excluded_pixels", + "omega_increment", + "omega_start", + "phi_increment", + "phi_start", + "photon_energy", + "pixel_mask_applied", + "roi_mode", + "sample_name", + "sensor_material", + "sensor_thickness", + "software_version", + "source_name", + "threshold/1/energy", + "threshold/1/mode", + "threshold/1/number_of_excluded_pixels", + "threshold/2/energy", + "threshold/2/mode", + "threshold/2/number_of_excluded_pixels", + "threshold/difference/lower_threshold", + "threshold/difference/mode", + "threshold/difference/upper_threshold", + "threshold_energy", + "total_flux", + "trigger_mode", + "trigger_start_delay", + "two_theta_increment", + "two_theta_start", + "virtual_pixel_correction_applied", + "x_pixel_size", + "x_pixels_in_detector", + "y_pixel_size", + "y_pixels_in_detector", +] + +_detector_status_keys = [ + "humidity", + "link_0", + "link_1", + "series_unique_id", + "state", + "temperature", + "time", +] + +_stream_config_keys = [ + "format", + "header_appendix", + "header_detail", + "image_appendix", + "mode", +] +_stream_status_keys = ["dropped", "state"] +_monitor_config_keys = ["buffer_size", "discard_new", "mode"] +_monitor_status_keys = ["buffer_free", "dropped", "error", "state"] + + +@pytest.fixture +def detector_config_keys(): + return _detector_config_keys + + +@pytest.fixture +def detector_status_keys(): + return _detector_status_keys + + +@pytest.fixture +def mock_connection(mocker: MockerFixture): + connection = mocker.patch("fastcs_eiger.http_connection.HTTPConnection") + connection.get = mocker.AsyncMock() + + async def _connection_get(uri): + if "detector/api/1.8.0/status/keys" in uri: + return _detector_status_keys + elif "detector/api/1.8.0/config/keys" in uri: + return _detector_config_keys + elif "monitor/api/1.8.0/status/keys" in uri: + return _monitor_status_keys + elif "monitor/api/1.8.0/config/keys" in uri: + return _monitor_config_keys + elif "stream/api/1.8.0/status/keys" in uri: + return _stream_status_keys + elif "stream/api/1.8.0/config/keys" in uri: + return _stream_config_keys + else: + # dummy response + return {"access_mode": "rw", "value": 0.0, "value_type": "float"} + + connection.get.side_effect = _connection_get + return connection diff --git a/tests/system/parameters.json b/tests/system/parameters.json index a799bdf..ce3d8fa 100644 --- a/tests/system/parameters.json +++ b/tests/system/parameters.json @@ -1,933 +1,939 @@ { - "humidity": { - "subsystem": "detector", - "mode": "status", - "key": "humidity", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "link_0": { - "subsystem": "detector", - "mode": "status", - "key": "link_0", - "response": { - "access_mode": "r", - "allowed_values": [ - "up", - "down" - ], - "value_type": "string" - } - }, - "link_1": { - "subsystem": "detector", - "mode": "status", - "key": "link_1", - "response": { - "access_mode": "r", - "allowed_values": [ - "up", - "down" - ], - "value_type": "string" - } - }, - "series_unique_id": { - "subsystem": "detector", - "mode": "status", - "key": "series_unique_id", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "detector_state": { - "subsystem": "detector", - "mode": "status", - "key": "state", - "response": { - "access_mode": "r", - "allowed_values": [ - "na", - "idle", - "ready", - "acquire", - "configure", - "initialize", - "error" - ], - "value_type": "string" - } - }, - "temperature": { - "subsystem": "detector", - "mode": "status", - "key": "temperature", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "time": { - "subsystem": "detector", - "mode": "status", - "key": "time", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "detector_error": { - "subsystem": "detector", - "mode": "status", - "key": "error", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "auto_summation": { - "subsystem": "detector", - "mode": "config", - "key": "auto_summation", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "beam_center_x": { - "subsystem": "detector", - "mode": "config", - "key": "beam_center_x", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "beam_center_y": { - "subsystem": "detector", - "mode": "config", - "key": "beam_center_y", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "bit_depth_image": { - "subsystem": "detector", - "mode": "config", - "key": "bit_depth_image", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "bit_depth_readout": { - "subsystem": "detector", - "mode": "config", - "key": "bit_depth_readout", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "chi_increment": { - "subsystem": "detector", - "mode": "config", - "key": "chi_increment", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "chi_start": { - "subsystem": "detector", - "mode": "config", - "key": "chi_start", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "compression": { - "subsystem": "detector", - "mode": "config", - "key": "compression", - "response": { - "access_mode": "rw", - "allowed_values": [ - "lz4", - "bslz4", - "none" - ], - "value_type": "string" - } - }, - "count_time": { - "subsystem": "detector", - "mode": "config", - "key": "count_time", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "counting_mode": { - "subsystem": "detector", - "mode": "config", - "key": "counting_mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "normal", - "retrigger" - ], - "value_type": "string" - } - }, - "countrate_correction_applied": { - "subsystem": "detector", - "mode": "config", - "key": "countrate_correction_applied", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "countrate_correction_count_cutoff": { - "subsystem": "detector", - "mode": "config", - "key": "countrate_correction_count_cutoff", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "data_collection_date": { - "subsystem": "detector", - "mode": "config", - "key": "data_collection_date", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "description": { - "subsystem": "detector", - "mode": "config", - "key": "description", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "detector_distance": { - "subsystem": "detector", - "mode": "config", - "key": "detector_distance", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "detector_number": { - "subsystem": "detector", - "mode": "config", - "key": "detector_number", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "detector_readout_time": { - "subsystem": "detector", - "mode": "config", - "key": "detector_readout_time", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "eiger_fw_version": { - "subsystem": "detector", - "mode": "config", - "key": "eiger_fw_version", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "element": { - "subsystem": "detector", - "mode": "config", - "key": "element", - "response": { - "access_mode": "rw", - "allowed_values": [ - "Li", - "Be", - "B", - "C", - "N", - "O", - "F", - "Ne", - "Na", - "Mg", - "Al", - "Si", - "P", - "S", - "Cl", - "Ar", - "K", - "Ca", - "Sc", - "Ti", - "V", - "Cr", - "Mn", - "Fe", - "Co", - "Ni", - "Cu", - "Zn" - ], - "value_type": "string" - } - }, - "extg_mode": { - "subsystem": "detector", - "mode": "config", - "key": "extg_mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "single", - "double" - ], - "value_type": "string" - } - }, - "fast_arm": { - "subsystem": "detector", - "mode": "config", - "key": "fast_arm", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "flatfield_correction_applied": { - "subsystem": "detector", - "mode": "config", - "key": "flatfield_correction_applied", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "frame_count_time": { - "subsystem": "detector", - "mode": "config", - "key": "frame_count_time", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "frame_time": { - "subsystem": "detector", - "mode": "config", - "key": "frame_time", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "incident_energy": { - "subsystem": "detector", - "mode": "config", - "key": "incident_energy", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "incident_particle_type": { - "subsystem": "detector", - "mode": "config", - "key": "incident_particle_type", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "instrument_name": { - "subsystem": "detector", - "mode": "config", - "key": "instrument_name", - "response": { - "access_mode": "rw", - "value_type": "string" - } - }, - "kappa_increment": { - "subsystem": "detector", - "mode": "config", - "key": "kappa_increment", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "kappa_start": { - "subsystem": "detector", - "mode": "config", - "key": "kappa_start", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "mask_to_zero": { - "subsystem": "detector", - "mode": "config", - "key": "mask_to_zero", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "nexpi": { - "subsystem": "detector", - "mode": "config", - "key": "nexpi", - "response": { - "access_mode": "rw", - "value_type": "uint" - } - }, - "nimages": { - "subsystem": "detector", - "mode": "config", - "key": "nimages", - "response": { - "access_mode": "rw", - "value_type": "uint" - } - }, - "ntrigger": { - "subsystem": "detector", - "mode": "config", - "key": "ntrigger", - "response": { - "access_mode": "rw", - "value_type": "uint" - } - }, - "ntriggers_skipped": { - "subsystem": "detector", - "mode": "config", - "key": "ntriggers_skipped", - "response": { - "access_mode": "rw", - "value_type": "uint" - } - }, - "number_of_excluded_pixels": { - "subsystem": "detector", - "mode": "config", - "key": "number_of_excluded_pixels", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "omega_increment": { - "subsystem": "detector", - "mode": "config", - "key": "omega_increment", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "omega_start": { - "subsystem": "detector", - "mode": "config", - "key": "omega_start", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "phi_increment": { - "subsystem": "detector", - "mode": "config", - "key": "phi_increment", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "phi_start": { - "subsystem": "detector", - "mode": "config", - "key": "phi_start", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "photon_energy": { - "subsystem": "detector", - "mode": "config", - "key": "photon_energy", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "pixel_mask_applied": { - "subsystem": "detector", - "mode": "config", - "key": "pixel_mask_applied", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "roi_mode": { - "subsystem": "detector", - "mode": "config", - "key": "roi_mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "disabled", - "4M-L", - "4M-R" - ], - "value_type": "string" - } - }, - "sample_name": { - "subsystem": "detector", - "mode": "config", - "key": "sample_name", - "response": { - "access_mode": "rw", - "value_type": "string" - } - }, - "sensor_material": { - "subsystem": "detector", - "mode": "config", - "key": "sensor_material", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "sensor_thickness": { - "subsystem": "detector", - "mode": "config", - "key": "sensor_thickness", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "software_version": { - "subsystem": "detector", - "mode": "config", - "key": "software_version", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "source_name": { - "subsystem": "detector", - "mode": "config", - "key": "source_name", - "response": { - "access_mode": "rw", - "value_type": "string" - } - }, - "threshold/1/energy": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/1/energy", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "threshold/1/mode": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/1/mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "enabled", - "disabled" - ], - "value_type": "string" - } - }, - "threshold/1/number_of_excluded_pixels": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/1/number_of_excluded_pixels", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "threshold/2/energy": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/2/energy", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "threshold/2/mode": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/2/mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "enabled", - "disabled" - ], - "value_type": "string" - } - }, - "threshold/2/number_of_excluded_pixels": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/2/number_of_excluded_pixels", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "threshold/difference/lower_threshold": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/difference/lower_threshold", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "threshold/difference/mode": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/difference/mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "enabled", - "disabled" - ], - "value_type": "string" - } - }, - "threshold/difference/upper_threshold": { - "subsystem": "detector", - "mode": "config", - "key": "threshold/difference/upper_threshold", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "threshold_energy": { - "subsystem": "detector", - "mode": "config", - "key": "threshold_energy", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "total_flux": { - "subsystem": "detector", - "mode": "config", - "key": "total_flux", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "trigger_mode": { - "subsystem": "detector", - "mode": "config", - "key": "trigger_mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "eies", - "exte", - "extg", - "exts", - "inte", - "ints" - ], - "value_type": "string" - } - }, - "trigger_start_delay": { - "subsystem": "detector", - "mode": "config", - "key": "trigger_start_delay", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "two_theta_increment": { - "subsystem": "detector", - "mode": "config", - "key": "two_theta_increment", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "two_theta_start": { - "subsystem": "detector", - "mode": "config", - "key": "two_theta_start", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "virtual_pixel_correction_applied": { - "subsystem": "detector", - "mode": "config", - "key": "virtual_pixel_correction_applied", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "x_pixel_size": { - "subsystem": "detector", - "mode": "config", - "key": "x_pixel_size", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "x_pixels_in_detector": { - "subsystem": "detector", - "mode": "config", - "key": "x_pixels_in_detector", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "y_pixel_size": { - "subsystem": "detector", - "mode": "config", - "key": "y_pixel_size", - "response": { - "access_mode": "r", - "value_type": "float" - } - }, - "y_pixels_in_detector": { - "subsystem": "detector", - "mode": "config", - "key": "y_pixels_in_detector", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "wavelength": { - "subsystem": "detector", - "mode": "config", - "key": "wavelength", - "response": { - "access_mode": "rw", - "value_type": "float" - } - }, - "stream_dropped": { - "subsystem": "stream", - "mode": "status", - "key": "dropped", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "stream_state": { - "subsystem": "stream", - "mode": "status", - "key": "state", - "response": { - "access_mode": "r", - "allowed_values": [ - "disabled", - "ready", - "acquire", - "error" - ], - "value_type": "string" - } - }, - "stream_error": { - "subsystem": "stream", - "mode": "status", - "key": "error", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "format": { - "subsystem": "stream", - "mode": "config", - "key": "format", - "response": { - "access_mode": "rw", - "allowed_values": [ - "legacy", - "cbor" - ], - "value_type": "string" - } - }, - "header_appendix": { - "subsystem": "stream", - "mode": "config", - "key": "header_appendix", - "response": { - "access_mode": "rw", - "value_type": "string" - } - }, - "header_detail": { - "subsystem": "stream", - "mode": "config", - "key": "header_detail", - "response": { - "access_mode": "rw", - "allowed_values": [ - "none", - "basic", - "all" - ], - "value_type": "string" - } - }, - "image_appendix": { - "subsystem": "stream", - "mode": "config", - "key": "image_appendix", - "response": { - "access_mode": "rw", - "value_type": "string" - } - }, - "stream_mode": { - "subsystem": "stream", - "mode": "config", - "key": "mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "enabled", - "disabled" - ], - "value_type": "string" - } - }, - "buffer_free": { - "subsystem": "monitor", - "mode": "status", - "key": "buffer_free", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "monitor_dropped": { - "subsystem": "monitor", - "mode": "status", - "key": "dropped", - "response": { - "access_mode": "r", - "value_type": "uint" - } - }, - "monitor_error": { - "subsystem": "monitor", - "mode": "status", - "key": "error", - "response": { - "access_mode": "r", - "value_type": "string" - } - }, - "monitor_state": { - "subsystem": "monitor", - "mode": "status", - "key": "state", - "response": { - "access_mode": "r", - "allowed_values": [ - "normal", - "overflow" - ], - "value_type": "string" - } - }, - "buffer_size": { - "subsystem": "monitor", - "mode": "config", - "key": "buffer_size", - "response": { - "access_mode": "rw", - "value_type": "uint" - } - }, - "discard_new": { - "subsystem": "monitor", - "mode": "config", - "key": "discard_new", - "response": { - "access_mode": "rw", - "value_type": "bool" - } - }, - "monitor_mode": { - "subsystem": "monitor", - "mode": "config", - "key": "mode", - "response": { - "access_mode": "rw", - "allowed_values": [ - "enabled", - "disabled" - ], - "value_type": "string" + "DETECTOR": { + "humidity": { + "subsystem": "detector", + "mode": "status", + "key": "humidity", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "link_0": { + "subsystem": "detector", + "mode": "status", + "key": "link_0", + "response": { + "access_mode": "r", + "allowed_values": [ + "up", + "down" + ], + "value_type": "string" + } + }, + "link_1": { + "subsystem": "detector", + "mode": "status", + "key": "link_1", + "response": { + "access_mode": "r", + "allowed_values": [ + "up", + "down" + ], + "value_type": "string" + } + }, + "series_unique_id": { + "subsystem": "detector", + "mode": "status", + "key": "series_unique_id", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "state": { + "subsystem": "detector", + "mode": "status", + "key": "state", + "response": { + "access_mode": "r", + "allowed_values": [ + "na", + "idle", + "ready", + "acquire", + "configure", + "initialize", + "error" + ], + "value_type": "string" + } + }, + "temperature": { + "subsystem": "detector", + "mode": "status", + "key": "temperature", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "time": { + "subsystem": "detector", + "mode": "status", + "key": "time", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "error": { + "subsystem": "detector", + "mode": "status", + "key": "error", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "auto_summation": { + "subsystem": "detector", + "mode": "config", + "key": "auto_summation", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "beam_center_x": { + "subsystem": "detector", + "mode": "config", + "key": "beam_center_x", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "beam_center_y": { + "subsystem": "detector", + "mode": "config", + "key": "beam_center_y", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "bit_depth_image": { + "subsystem": "detector", + "mode": "config", + "key": "bit_depth_image", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "bit_depth_readout": { + "subsystem": "detector", + "mode": "config", + "key": "bit_depth_readout", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "chi_increment": { + "subsystem": "detector", + "mode": "config", + "key": "chi_increment", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "chi_start": { + "subsystem": "detector", + "mode": "config", + "key": "chi_start", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "compression": { + "subsystem": "detector", + "mode": "config", + "key": "compression", + "response": { + "access_mode": "rw", + "allowed_values": [ + "lz4", + "bslz4", + "none" + ], + "value_type": "string" + } + }, + "count_time": { + "subsystem": "detector", + "mode": "config", + "key": "count_time", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "counting_mode": { + "subsystem": "detector", + "mode": "config", + "key": "counting_mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "normal", + "retrigger" + ], + "value_type": "string" + } + }, + "countrate_correction_applied": { + "subsystem": "detector", + "mode": "config", + "key": "countrate_correction_applied", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "countrate_correction_count_cutoff": { + "subsystem": "detector", + "mode": "config", + "key": "countrate_correction_count_cutoff", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "data_collection_date": { + "subsystem": "detector", + "mode": "config", + "key": "data_collection_date", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "description": { + "subsystem": "detector", + "mode": "config", + "key": "description", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "detector_distance": { + "subsystem": "detector", + "mode": "config", + "key": "detector_distance", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "detector_number": { + "subsystem": "detector", + "mode": "config", + "key": "detector_number", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "detector_readout_time": { + "subsystem": "detector", + "mode": "config", + "key": "detector_readout_time", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "eiger_fw_version": { + "subsystem": "detector", + "mode": "config", + "key": "eiger_fw_version", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "element": { + "subsystem": "detector", + "mode": "config", + "key": "element", + "response": { + "access_mode": "rw", + "allowed_values": [ + "Li", + "Be", + "B", + "C", + "N", + "O", + "F", + "Ne", + "Na", + "Mg", + "Al", + "Si", + "P", + "S", + "Cl", + "Ar", + "K", + "Ca", + "Sc", + "Ti", + "V", + "Cr", + "Mn", + "Fe", + "Co", + "Ni", + "Cu", + "Zn" + ], + "value_type": "string" + } + }, + "extg_mode": { + "subsystem": "detector", + "mode": "config", + "key": "extg_mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "single", + "double" + ], + "value_type": "string" + } + }, + "fast_arm": { + "subsystem": "detector", + "mode": "config", + "key": "fast_arm", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "flatfield_correction_applied": { + "subsystem": "detector", + "mode": "config", + "key": "flatfield_correction_applied", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "frame_count_time": { + "subsystem": "detector", + "mode": "config", + "key": "frame_count_time", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "frame_time": { + "subsystem": "detector", + "mode": "config", + "key": "frame_time", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "incident_energy": { + "subsystem": "detector", + "mode": "config", + "key": "incident_energy", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "incident_particle_type": { + "subsystem": "detector", + "mode": "config", + "key": "incident_particle_type", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "instrument_name": { + "subsystem": "detector", + "mode": "config", + "key": "instrument_name", + "response": { + "access_mode": "rw", + "value_type": "string" + } + }, + "kappa_increment": { + "subsystem": "detector", + "mode": "config", + "key": "kappa_increment", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "kappa_start": { + "subsystem": "detector", + "mode": "config", + "key": "kappa_start", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "mask_to_zero": { + "subsystem": "detector", + "mode": "config", + "key": "mask_to_zero", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "nexpi": { + "subsystem": "detector", + "mode": "config", + "key": "nexpi", + "response": { + "access_mode": "rw", + "value_type": "uint" + } + }, + "nimages": { + "subsystem": "detector", + "mode": "config", + "key": "nimages", + "response": { + "access_mode": "rw", + "value_type": "uint" + } + }, + "ntrigger": { + "subsystem": "detector", + "mode": "config", + "key": "ntrigger", + "response": { + "access_mode": "rw", + "value_type": "uint" + } + }, + "ntriggers_skipped": { + "subsystem": "detector", + "mode": "config", + "key": "ntriggers_skipped", + "response": { + "access_mode": "rw", + "value_type": "uint" + } + }, + "number_of_excluded_pixels": { + "subsystem": "detector", + "mode": "config", + "key": "number_of_excluded_pixels", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "omega_increment": { + "subsystem": "detector", + "mode": "config", + "key": "omega_increment", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "omega_start": { + "subsystem": "detector", + "mode": "config", + "key": "omega_start", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "phi_increment": { + "subsystem": "detector", + "mode": "config", + "key": "phi_increment", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "phi_start": { + "subsystem": "detector", + "mode": "config", + "key": "phi_start", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "photon_energy": { + "subsystem": "detector", + "mode": "config", + "key": "photon_energy", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "pixel_mask_applied": { + "subsystem": "detector", + "mode": "config", + "key": "pixel_mask_applied", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "roi_mode": { + "subsystem": "detector", + "mode": "config", + "key": "roi_mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "disabled", + "4M-L", + "4M-R" + ], + "value_type": "string" + } + }, + "sample_name": { + "subsystem": "detector", + "mode": "config", + "key": "sample_name", + "response": { + "access_mode": "rw", + "value_type": "string" + } + }, + "sensor_material": { + "subsystem": "detector", + "mode": "config", + "key": "sensor_material", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "sensor_thickness": { + "subsystem": "detector", + "mode": "config", + "key": "sensor_thickness", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "software_version": { + "subsystem": "detector", + "mode": "config", + "key": "software_version", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "source_name": { + "subsystem": "detector", + "mode": "config", + "key": "source_name", + "response": { + "access_mode": "rw", + "value_type": "string" + } + }, + "threshold/1/energy": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/1/energy", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "threshold/1/mode": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/1/mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "enabled", + "disabled" + ], + "value_type": "string" + } + }, + "threshold/1/number_of_excluded_pixels": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/1/number_of_excluded_pixels", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "threshold/2/energy": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/2/energy", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "threshold/2/mode": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/2/mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "enabled", + "disabled" + ], + "value_type": "string" + } + }, + "threshold/2/number_of_excluded_pixels": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/2/number_of_excluded_pixels", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "threshold/difference/lower_threshold": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/difference/lower_threshold", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "threshold/difference/mode": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/difference/mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "enabled", + "disabled" + ], + "value_type": "string" + } + }, + "threshold/difference/upper_threshold": { + "subsystem": "detector", + "mode": "config", + "key": "threshold/difference/upper_threshold", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "threshold_energy": { + "subsystem": "detector", + "mode": "config", + "key": "threshold_energy", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "total_flux": { + "subsystem": "detector", + "mode": "config", + "key": "total_flux", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "trigger_mode": { + "subsystem": "detector", + "mode": "config", + "key": "trigger_mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "eies", + "exte", + "extg", + "exts", + "inte", + "ints" + ], + "value_type": "string" + } + }, + "trigger_start_delay": { + "subsystem": "detector", + "mode": "config", + "key": "trigger_start_delay", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "two_theta_increment": { + "subsystem": "detector", + "mode": "config", + "key": "two_theta_increment", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "two_theta_start": { + "subsystem": "detector", + "mode": "config", + "key": "two_theta_start", + "response": { + "access_mode": "rw", + "value_type": "float" + } + }, + "virtual_pixel_correction_applied": { + "subsystem": "detector", + "mode": "config", + "key": "virtual_pixel_correction_applied", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "x_pixel_size": { + "subsystem": "detector", + "mode": "config", + "key": "x_pixel_size", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "x_pixels_in_detector": { + "subsystem": "detector", + "mode": "config", + "key": "x_pixels_in_detector", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "y_pixel_size": { + "subsystem": "detector", + "mode": "config", + "key": "y_pixel_size", + "response": { + "access_mode": "r", + "value_type": "float" + } + }, + "y_pixels_in_detector": { + "subsystem": "detector", + "mode": "config", + "key": "y_pixels_in_detector", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "wavelength": { + "subsystem": "detector", + "mode": "config", + "key": "wavelength", + "response": { + "access_mode": "rw", + "value_type": "float" + } + } + }, + "STREAM": { + "dropped": { + "subsystem": "stream", + "mode": "status", + "key": "dropped", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "state": { + "subsystem": "stream", + "mode": "status", + "key": "state", + "response": { + "access_mode": "r", + "allowed_values": [ + "disabled", + "ready", + "acquire", + "error" + ], + "value_type": "string" + } + }, + "error": { + "subsystem": "stream", + "mode": "status", + "key": "error", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "format": { + "subsystem": "stream", + "mode": "config", + "key": "format", + "response": { + "access_mode": "rw", + "allowed_values": [ + "legacy", + "cbor" + ], + "value_type": "string" + } + }, + "header_appendix": { + "subsystem": "stream", + "mode": "config", + "key": "header_appendix", + "response": { + "access_mode": "rw", + "value_type": "string" + } + }, + "header_detail": { + "subsystem": "stream", + "mode": "config", + "key": "header_detail", + "response": { + "access_mode": "rw", + "allowed_values": [ + "none", + "basic", + "all" + ], + "value_type": "string" + } + }, + "image_appendix": { + "subsystem": "stream", + "mode": "config", + "key": "image_appendix", + "response": { + "access_mode": "rw", + "value_type": "string" + } + }, + "mode": { + "subsystem": "stream", + "mode": "config", + "key": "mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "enabled", + "disabled" + ], + "value_type": "string" + } + } + }, + "MONITOR": { + "buffer_free": { + "subsystem": "monitor", + "mode": "status", + "key": "buffer_free", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "dropped": { + "subsystem": "monitor", + "mode": "status", + "key": "dropped", + "response": { + "access_mode": "r", + "value_type": "uint" + } + }, + "error": { + "subsystem": "monitor", + "mode": "status", + "key": "error", + "response": { + "access_mode": "r", + "value_type": "string" + } + }, + "state": { + "subsystem": "monitor", + "mode": "status", + "key": "state", + "response": { + "access_mode": "r", + "allowed_values": [ + "normal", + "overflow" + ], + "value_type": "string" + } + }, + "buffer_size": { + "subsystem": "monitor", + "mode": "config", + "key": "buffer_size", + "response": { + "access_mode": "rw", + "value_type": "uint" + } + }, + "discard_new": { + "subsystem": "monitor", + "mode": "config", + "key": "discard_new", + "response": { + "access_mode": "rw", + "value_type": "bool" + } + }, + "mode": { + "subsystem": "monitor", + "mode": "config", + "key": "mode", + "response": { + "access_mode": "rw", + "allowed_values": [ + "enabled", + "disabled" + ], + "value_type": "string" + } } } } diff --git a/tests/system/test_introspection.py b/tests/system/test_introspection.py index 6bb0a0c..da19ec2 100644 --- a/tests/system/test_introspection.py +++ b/tests/system/test_introspection.py @@ -4,12 +4,18 @@ import subprocess from pathlib import Path from time import sleep +from typing import Any import pytest from fastcs.attributes import AttrR from fastcs.datatypes import Float -from fastcs_eiger.eiger_controller import EigerController, EigerParameter +from fastcs_eiger.eiger_controller import ( + EigerController, + EigerDetectorController, + EigerParameter, + EigerSubsystemController, +) HERE = Path(__file__).parent @@ -65,26 +71,44 @@ def sim_eiger_controller(request): ) async def test_introspection(sim_eiger_controller: EigerController): controller = sim_eiger_controller - # controller = eiger_controller - - controller.connection.open() - _parameters = await controller._introspect_detector() - controller._tag_key_clashes(_parameters) - parameters = {p.name: _serialise_parameter(p) for p in _parameters} + await controller.initialise() + serialised_parameters: dict[str, dict[str, Any]] = {} + subsystem_parameters = {} + for subsystem_name, subcontroller in controller.get_sub_controllers().items(): + serialised_parameters[subsystem_name] = {} + subsystem_parameters[ + subsystem_name + ] = await subcontroller._introspect_detector_subsystem() + for param in subsystem_parameters[subsystem_name]: + serialised_parameters[subsystem_name][param.key] = _serialise_parameter( + param + ) expected_file = HERE / "parameters.json" if os.environ.get("REGENERATE_TEST_OUTPUT", None): - expected_file.write_text(json.dumps(parameters, indent=4)) + expected_file.write_text(json.dumps(serialised_parameters, indent=4)) expected_parameters = json.loads(expected_file.read_text()) - assert parameters == expected_parameters, "Detector API does not match" + assert serialised_parameters == expected_parameters, "Detector API does not match" - attributes = controller._create_attributes(_parameters) + detector_attributes = EigerDetectorController._create_attributes( + subsystem_parameters["DETECTOR"] + ) + assert len(detector_attributes) == 76 + monitor_attributes = EigerSubsystemController._create_attributes( + subsystem_parameters["MONITOR"] + ) + assert len(monitor_attributes) == 7 + stream_attributes = EigerSubsystemController._create_attributes( + subsystem_parameters["STREAM"] + ) + assert len(stream_attributes) == 8 - assert len(attributes) == 91 - assert isinstance(attributes["humidity"], AttrR) - assert isinstance(attributes["humidity"].datatype, Float) - assert attributes["humidity"]._group == "DetectorStatus" + assert isinstance(detector_attributes["humidity"], AttrR) + assert isinstance(detector_attributes["humidity"].datatype, Float) + assert detector_attributes["humidity"]._group == "DetectorStatus" + assert detector_attributes["threshold_2_energy"]._group == "Threshold2" + assert detector_attributes["threshold_energy"]._group == "Threshold" await controller.connection.close() diff --git a/tests/test_controller.py b/tests/test_controller.py index fd8950e..dd27f23 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -1,45 +1,75 @@ +import asyncio + import pytest +from fastcs.attributes import Attribute from pytest_mock import MockerFixture -from fastcs_eiger.eiger_controller import EigerController +from fastcs_eiger.eiger_controller import ( + IGNORED_KEYS, + MISSING_KEYS, + EigerController, + EigerDetectorController, + EigerSubsystemController, +) + +_lock = asyncio.Lock() @pytest.mark.asyncio -async def test_initialise(mocker: MockerFixture): - controller = EigerController("127.0.0.1", 80) +async def test_detector_controller( + mock_connection, detector_config_keys, detector_status_keys +): + detector_controller = EigerDetectorController(mock_connection, _lock) + parameters = await detector_controller._introspect_detector_subsystem() + assert all(parameter.key not in IGNORED_KEYS for parameter in parameters) + for parameter in parameters: + assert parameter.key not in IGNORED_KEYS + if parameter.mode == "config": + assert ( + parameter.key in detector_config_keys + or parameter.key in MISSING_KEYS["detector"]["config"] + ) + elif parameter.mode == "status": + assert ( + parameter.key in detector_status_keys + or parameter.key in MISSING_KEYS["detector"]["status"] + ) - connection = mocker.patch.object(controller, "connection") - connection.get = mocker.AsyncMock() - connection.get.return_value = {"value": "idle"} - initialize = mocker.patch.object(controller, "initialize") - introspect = mocker.patch.object(controller, "_introspect_detector") - create_attributes = mocker.patch.object(controller, "_create_attributes") - attr = mocker.MagicMock() - create_attributes.return_value = {"attr_name": attr} + # test queue_update side effect + assert not detector_controller.stale_parameters.get() + await detector_controller.queue_update(["chi_start"]) + assert detector_controller._parameter_updates == {"chi_start"} + assert detector_controller.stale_parameters.get() - await controller.initialise() - connection.get.assert_called_once_with("detector/api/1.8.0/status/state") - initialize.assert_not_called() - introspect.assert_awaited_once_with() - create_attributes.assert_called_once_with(introspect.return_value) - assert controller.attr_name == attr, "Attribute not added to controller" +@pytest.mark.asyncio +async def test_subsystem_controller_initialises(mock_connection): + subsystem_controller = EigerSubsystemController("stream", mock_connection, _lock) + await subsystem_controller.initialise() + + +@pytest.mark.asyncio +async def test_detector_subsystem_controller(mock_connection): + subsystem_controller = EigerDetectorController(mock_connection, _lock) + await subsystem_controller.initialise() + + for attr_name in dir(subsystem_controller): + attr = getattr(subsystem_controller, attr_name) + if isinstance(attr, Attribute) and "threshold" in attr_name: + assert "Threshold" in attr.group @pytest.mark.asyncio -async def test_initialise_state_na(mocker: MockerFixture): - controller = EigerController("127.0.0.1", 80) - - connection = mocker.patch.object(controller, "connection") - connection.get = mocker.AsyncMock() - connection.get.return_value = {"value": "na"} - initialize = mocker.patch.object(controller, "initialize") - introspect = mocker.patch.object(controller, "_introspect_detector") - create_attributes = mocker.patch.object(controller, "_create_attributes") - - await controller.initialise() - - connection.get.assert_called_once_with("detector/api/1.8.0/status/state") - initialize.assert_awaited_once_with() - introspect.assert_awaited_once_with() - create_attributes.assert_called_once_with(introspect.return_value) +async def test_eiger_controller_initialises(mocker: MockerFixture, mock_connection): + eiger_controller = EigerController("127.0.0.1", 80) + connection = mocker.patch.object(eiger_controller, "connection") + connection.get = mock_connection.get + await eiger_controller.initialise() + assert list(eiger_controller.get_sub_controllers().keys()) == [ + "DETECTOR", + "STREAM", + "MONITOR", + ] + connection.get.assert_any_call("detector/api/1.8.0/status/state") + connection.get.assert_any_call("stream/api/1.8.0/status/state") + connection.get.assert_any_call("monitor/api/1.8.0/status/state")