Skip to content

Commit

Permalink
Add tests for EigerHandler and EigerConfigHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
jsouter committed Nov 15, 2024
1 parent 3e1482b commit d2a86eb
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 0 deletions.
63 changes: 63 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,68 @@ async def _connection_get(uri):
# dummy response
return {"access_mode": "rw", "value": 0.0, "value_type": "float"}

async def _connection_put(uri: str, _):
# copied from tickit sim
key = uri.split("/", 4)[-1]
match key:
case "auto_summation":
return ["auto_summation", "frame_count_time"]
case "count_time" | "frame_time":
return [
"bit_depth_image",
"bit_depth_readout",
"count_time",
"countrate_correction_count_cutoff",
"frame_count_time",
"frame_time",
]
case "flatfield":
return ["flatfield", "threshold/1/flatfield"]
case "incident_energy" | "photon_energy":
return [
"element",
"flatfield",
"incident_energy",
"photon_energy",
"threshold/1/energy",
"threshold/1/flatfield",
"threshold/2/energy",
"threshold/2/flatfield",
"threshold_energy",
"wavelength",
]
case "pixel_mask":
return ["pixel_mask", "threshold/1/pixel_mask"]
case "threshold/1/flatfield":
return ["flatfield", "threshold/1/flatfield"]
case "roi_mode":
return ["count_time", "frame_time", "roi_mode"]
case "threshold_energy" | "threshold/1/energy":
return [
"flatfield",
"threshold/1/energy",
"threshold/1/flatfield",
"threshold/2/flatfield",
"threshold_energy",
]
case "threshold/2/energy":
return [
"flatfield",
"threshold/1/flatfield",
"threshold/2/energy",
"threshold/2/flatfield",
]
case "threshold/1/mode":
return ["threshold/1/mode", "threshold/difference/mode"]
case "threshold/2/mode":
return ["threshold/2/mode", "threshold/difference/mode"]
case "threshold/1/pixel_mask":
return ["pixel_mask", "threshold/1/pixel_mask"]
case "threshold/difference/mode":
return ["difference_mode"] # replicating API inconsistency
case _:
return [key]

connection.get.side_effect = _connection_get
connection.put.side_effect = _connection_put
return connection
122 changes: 122 additions & 0 deletions tests/test_controller.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
from unittest import mock

import pytest
from fastcs.attributes import Attribute
Expand All @@ -7,8 +8,10 @@
from fastcs_eiger.eiger_controller import (
IGNORED_KEYS,
MISSING_KEYS,
EigerConfigHandler,
EigerController,
EigerDetectorController,
EigerHandler,
EigerMonitorController,
EigerStreamController,
)
Expand Down Expand Up @@ -82,3 +85,122 @@ async def test_eiger_controller_initialises(mocker: MockerFixture, mock_connecti
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")


@pytest.mark.asyncio
async def test_EigerHandler_after_put(mock_connection):
subsystem_controller = EigerDetectorController(mock_connection, _lock)
await subsystem_controller.initialise()
attr = subsystem_controller.humidity
handler = attr.sender

assert type(handler) is EigerHandler
assert not subsystem_controller.stale_parameters.get()
await handler.put(subsystem_controller, attr, 0.1)
# eiger API does not return a list of updated parameters when we set status keys
# so _parameter_updates set to default case where we only update the key we changed
assert subsystem_controller._parameter_updates == {"humidity"}
# humidity is really read-only but given here for demonstration
assert subsystem_controller.stale_parameters.get()

# parameters with EigerHandler handlers do not get updated when
# controller update is called

subsystem_controller.humidity.updater.update = mock.AsyncMock()

await subsystem_controller.update()
assert subsystem_controller.stale_parameters.get()
subsystem_controller.humidity.updater.update.assert_not_called()

await subsystem_controller.update()
# stale does not get set False unless there are no stale parameters at start of
# update call
assert not subsystem_controller.stale_parameters.get()
assert not subsystem_controller._parameter_updates


@pytest.mark.asyncio
async def test_EigerHandler_update_updates_value(mock_connection):
subsystem_controller = EigerDetectorController(mock_connection, _lock)
await subsystem_controller.initialise()

async def _get_1_as_value(*args, **kwargs):
return {"access_mode": "r", "value": 1, "value_type": "int"}

assert type(subsystem_controller.state.updater) is EigerHandler
assert subsystem_controller.state.get() == 0

mock_connection.get = (
_get_1_as_value # show that value changes after update is awaited
)
await subsystem_controller.state.updater.update(
subsystem_controller, subsystem_controller.state
)
assert subsystem_controller.state.get() == 1


@pytest.mark.asyncio
async def test_EigerConfigHandler(mock_connection):
subsystem_controller = EigerDetectorController(mock_connection, _lock)
await subsystem_controller.initialise()
attr = subsystem_controller.threshold_1_energy
handler = attr.sender
assert isinstance(handler, EigerConfigHandler)
assert not subsystem_controller.stale_parameters.get()
await handler.put(subsystem_controller, attr, 100.0)
expected_changed_params = [
"flatfield",
"threshold/1/energy",
"threshold/1/flatfield",
"threshold/2/flatfield",
"threshold_energy",
]
assert subsystem_controller._parameter_updates == set(expected_changed_params)
assert subsystem_controller.stale_parameters.get()

# flatfields are ignored keys
subsystem_controller.threshold_energy.updater.config_update = mock.AsyncMock()

await subsystem_controller.update()
assert subsystem_controller.stale_parameters.get()
assert subsystem_controller.threshold_energy.updater.config_update.mock_calls == [
mock.call.config_update(
subsystem_controller, subsystem_controller.threshold_energy
)
]

await subsystem_controller.update()
# stale does not get set False unless there are no stale parameters at start of
# update call
assert not subsystem_controller.stale_parameters.get()
assert not subsystem_controller._parameter_updates


@pytest.mark.asyncio
async def test_stale_parameter_propagates_to_top_controller(mock_connection):
top_controller = EigerController("127.0.0.1", 80)
top_controller.connection = mock_connection
await top_controller.initialise()
detector_controller = top_controller.get_sub_controllers()["Detector"]
attr = detector_controller.threshold_energy

assert not detector_controller.stale_parameters.get()
assert not top_controller.stale_parameters.get()

await attr.sender.put(detector_controller, attr, 100.0)
assert detector_controller.stale_parameters.get()
# top controller not stale until update called
assert not top_controller.stale_parameters.get()
await top_controller.update()
assert top_controller.stale_parameters.get()

# need to update again to make detector controller update its
# stale parameter attribute
await top_controller.update()
assert not detector_controller.stale_parameters.get()
assert top_controller.stale_parameters.get()

# top controller needs to update another final time so that the
# detector controller stale attribute returning to False propagates to top
await top_controller.update()
assert not top_controller.stale_parameters.get()

0 comments on commit d2a86eb

Please sign in to comment.