Add test to stop camera Thing APIs diverging futher without review
This commit is contained in:
parent
afc621b847
commit
d994119b36
1 changed files with 133 additions and 0 deletions
133
tests/test_cameras.py
Normal file
133
tests/test_cameras.py
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
"""Generic tests for cameras, specific camera hardware reqipres hardware specific tests."""
|
||||
|
||||
import pytest
|
||||
|
||||
from openflexure_microscope_server.things.camera import BaseCamera
|
||||
from openflexure_microscope_server.things.camera.simulation import SimulatedCamera
|
||||
from openflexure_microscope_server.things.camera.opencv import OpenCVCamera
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_picam_thing(mocker):
|
||||
"""Import PiCamera without hardware well enough to get a ThingDescription."""
|
||||
dummy_cam = mocker.Mock()
|
||||
mock_picamera2 = mocker.MagicMock()
|
||||
mock_picamera2.return_value.__enter__.return_value = dummy_cam
|
||||
mock_picamera2.return_value.__exit__.return_value = None
|
||||
|
||||
mocker.patch.dict(
|
||||
"sys.modules",
|
||||
{
|
||||
"picamera2": mock_picamera2,
|
||||
"picamera2.encoders": mocker.Mock(),
|
||||
"picamera2.outputs": mocker.Mock(),
|
||||
},
|
||||
)
|
||||
mocker.patch(
|
||||
"openflexure_microscope_server.things.camera.picamera.recalibrate_utils.load_default_tuning",
|
||||
return_value={"mock": "tuning"},
|
||||
)
|
||||
from openflexure_microscope_server.things.camera.picamera import StreamingPiCamera2
|
||||
|
||||
return StreamingPiCamera2()
|
||||
|
||||
|
||||
def _get_clean_camera_description(camera_thing):
|
||||
"""Return actions and properties for a camera Thing, separating those exposed to the UI.
|
||||
|
||||
Return cleaned sets of actions and properties for camera_thing, excluding
|
||||
calibration actions exposed to the UI as primary or secondary calibration actions,
|
||||
and excluding the properties exposed in manual camera settings.
|
||||
|
||||
:returns: Dict with keys:
|
||||
|
||||
* "actions" - Actions not explicitly exposed to the UI by this camera.
|
||||
* "properties" - Properties not explicitly exposed to the UI as manual camera
|
||||
settings.
|
||||
* "calibration_actions" - Actions explicitly exposed to the UI by this camera.
|
||||
* "manual_properties" - Properties explicitly exposed to the UI as manual
|
||||
camera settings.
|
||||
"""
|
||||
camera_thing.path = "/mock/"
|
||||
|
||||
td = camera_thing.thing_description()
|
||||
actions = set(td.actions.keys())
|
||||
properties = set(td.properties.keys())
|
||||
|
||||
# Calibration actions are camera specific
|
||||
primary = [btn.action for btn in camera_thing.primary_calibration_actions]
|
||||
secondary = [btn.action for btn in camera_thing.secondary_calibration_actions]
|
||||
calibration_actions = set(primary + secondary)
|
||||
|
||||
actions -= calibration_actions
|
||||
|
||||
# Manual properties are also camera specific
|
||||
manual_props = {ctrl.property_name for ctrl in camera_thing.manual_camera_settings}
|
||||
properties -= manual_props
|
||||
|
||||
return {
|
||||
"actions": actions,
|
||||
"properties": properties,
|
||||
"calibration_actions": calibration_actions,
|
||||
"manual_properties": manual_props,
|
||||
}
|
||||
|
||||
|
||||
def test_thing_description_equivalence(mock_picam_thing):
|
||||
"""Ensure extra actions and properties are not added to camera Things without explicit approval.
|
||||
|
||||
This test verifies that extra actions are not unintentionally introduced to
|
||||
camera child classes. Any addition of actions must be accompanied by an update
|
||||
to this test, prompting review and justification for why the action does not
|
||||
belong to the general base class.
|
||||
"""
|
||||
base_td = BaseCamera().thing_description()
|
||||
base_actions = set(base_td.actions.keys())
|
||||
base_props = set(base_td.properties.keys())
|
||||
|
||||
sim_description = _get_clean_camera_description(SimulatedCamera())
|
||||
opencv_description = _get_clean_camera_description(OpenCVCamera())
|
||||
picamera_description = _get_clean_camera_description(mock_picam_thing)
|
||||
|
||||
# Note. These are the actions and properties that are not exposed to the UI via
|
||||
# `primary_calibration_actions`, `secondary_calibration_actions`, or
|
||||
# `manual_camera_settings`.
|
||||
sim_actions = sim_description["actions"]
|
||||
sim_props = sim_description["properties"]
|
||||
|
||||
opencv_actions = opencv_description["actions"]
|
||||
opencv_props = opencv_description["properties"]
|
||||
|
||||
picamera_actions = picamera_description["actions"]
|
||||
picamera_props = picamera_description["properties"]
|
||||
|
||||
# Camera actions and properties should generally be equivalent except for exposed
|
||||
# manual settings and calibration actions.
|
||||
assert opencv_actions == sim_actions == base_actions
|
||||
assert opencv_props == sim_props == base_props
|
||||
|
||||
# For now PiCamera has a number of extra actions and properties. These should be
|
||||
# reduced over time by creating a way to use the functionality in a way as clearly
|
||||
# defined as PiCamera specific, or by replicating the functionality for other
|
||||
# cameras.
|
||||
picamera_extra_actions = {
|
||||
"flat_lens_shading_chrominance",
|
||||
"set_static_green_equalisation",
|
||||
"stop_streaming",
|
||||
"reset_ccm",
|
||||
}
|
||||
picamera_extra_props = {
|
||||
"mjpeg_bitrate",
|
||||
"colour_correction_matrix",
|
||||
"lens_shading_tables",
|
||||
"sensor_resolution",
|
||||
"lens_shading_is_static",
|
||||
"capture_metadata",
|
||||
"camera_configuration",
|
||||
"stream_resolution",
|
||||
"tuning",
|
||||
"sensor_modes",
|
||||
"sensor_mode",
|
||||
}
|
||||
assert picamera_actions - base_actions == picamera_extra_actions
|
||||
assert picamera_props - base_props == picamera_extra_props
|
||||
Loading…
Add table
Add a link
Reference in a new issue