Improve gallery tests and fix behaviour if a provider errors
This commit is contained in:
parent
cc6caa39d7
commit
03d74bb044
2 changed files with 124 additions and 1 deletions
|
|
@ -111,4 +111,7 @@ class GalleryThing(lt.Thing):
|
||||||
def delete_all_data(self) -> None:
|
def delete_all_data(self) -> None:
|
||||||
"""Delete all the gallery data on this microscope."""
|
"""Delete all the gallery data on this microscope."""
|
||||||
for thing in self.gallery_providing_things.values():
|
for thing in self.gallery_providing_things.values():
|
||||||
thing.delete_all_gallery_items()
|
try:
|
||||||
|
thing.delete_all_gallery_items()
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.exception(e)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
"""Tests that captures have the expected metadata."""
|
"""Tests that captures have the expected metadata."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
import pytest
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from labthings_fastapi.exceptions import InvocationCancelledError
|
||||||
from labthings_fastapi.testing import create_thing_without_server
|
from labthings_fastapi.testing import create_thing_without_server
|
||||||
|
|
||||||
from openflexure_microscope_server.things import OFMThing
|
from openflexure_microscope_server.things import OFMThing
|
||||||
|
|
@ -15,6 +19,16 @@ from openflexure_microscope_server.things.gallery import (
|
||||||
from ..shared_utils.lt_test_utils import LabThingsTestEnv
|
from ..shared_utils.lt_test_utils import LabThingsTestEnv
|
||||||
|
|
||||||
|
|
||||||
|
def test_error_if_accessing_gallery_things_before_started():
|
||||||
|
"""Check that gallery_providing_things property errors before init."""
|
||||||
|
thing = create_thing_without_server(GalleryThing)
|
||||||
|
with pytest.raises(
|
||||||
|
RuntimeError,
|
||||||
|
match="Cannot access gallery_providing_things before server has started.",
|
||||||
|
):
|
||||||
|
thing.gallery_providing_things
|
||||||
|
|
||||||
|
|
||||||
class MockGalleryData(BaseModel):
|
class MockGalleryData(BaseModel):
|
||||||
"""Mock gallery data."""
|
"""Mock gallery data."""
|
||||||
|
|
||||||
|
|
@ -126,3 +140,109 @@ def test_gallery_logs_for_bad_providers(caplog):
|
||||||
record = caplog.records[0]
|
record = caplog.records[0]
|
||||||
assert "Data from bad_thing cannot be shown in gallery" in record.message
|
assert "Data from bad_thing cannot be shown in gallery" in record.message
|
||||||
assert record.levelname == "ERROR"
|
assert record.levelname == "ERROR"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def minimal_gallery_env():
|
||||||
|
"""Return a minimal working environment for testing the gallery."""
|
||||||
|
things = {
|
||||||
|
"minimal_thing1": MinimalGallerySource,
|
||||||
|
"minimal_thing2": MinimalGallerySource,
|
||||||
|
"gallery": GalleryThing,
|
||||||
|
}
|
||||||
|
with LabThingsTestEnv(
|
||||||
|
things=things, application_config={"data_folder": "./openflexure/data/"}
|
||||||
|
) as env:
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def test_gallery_lists_data(minimal_gallery_env, mocker, caplog):
|
||||||
|
"""Test that the gallery calls all gallery things to list data."""
|
||||||
|
# Create a config with the minimal Thing and the bad Thing
|
||||||
|
gallery = minimal_gallery_env.get_thing_by_name("gallery")
|
||||||
|
thing_1 = minimal_gallery_env.get_thing_by_name("minimal_thing1")
|
||||||
|
thing_2 = minimal_gallery_env.get_thing_by_name("minimal_thing2")
|
||||||
|
|
||||||
|
thing_1_data = [
|
||||||
|
MockGalleryData(mock="thing_1", foobar=1),
|
||||||
|
MockGalleryData(mock="thing_1", foobar=2),
|
||||||
|
]
|
||||||
|
|
||||||
|
thing_2_data = [
|
||||||
|
MockGalleryData(mock="thing_2", foobar=1),
|
||||||
|
MockGalleryData(mock="thing_2", foobar=2),
|
||||||
|
]
|
||||||
|
|
||||||
|
mocker.patch.object(thing_1, "get_data_for_gallery", return_value=thing_1_data)
|
||||||
|
mocker.patch.object(thing_2, "get_data_for_gallery", return_value=thing_2_data)
|
||||||
|
|
||||||
|
thing_1_return = [
|
||||||
|
{"mock": "thing_1", "foobar": 1},
|
||||||
|
{"mock": "thing_1", "foobar": 2},
|
||||||
|
]
|
||||||
|
thing_2_return = [
|
||||||
|
{"mock": "thing_2", "foobar": 1},
|
||||||
|
{"mock": "thing_2", "foobar": 2},
|
||||||
|
]
|
||||||
|
|
||||||
|
assert gallery.list_data == thing_1_return + thing_2_return
|
||||||
|
|
||||||
|
thing_1.get_data_for_gallery.side_effect = RuntimeError
|
||||||
|
with caplog.at_level(logging.INFO):
|
||||||
|
assert gallery.list_data == thing_2_return
|
||||||
|
assert len(caplog.records) == 1
|
||||||
|
assert caplog.records[0].levelname == "ERROR"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GalleryDeleteTestCase:
|
||||||
|
"""Inputs and expected outputs for testing ``save_from_memory``.
|
||||||
|
|
||||||
|
The default save kwargs assume a jpeg.
|
||||||
|
"""
|
||||||
|
|
||||||
|
thing_1_side_effect: Optional[Callable]
|
||||||
|
thing_2_call_count: int
|
||||||
|
# Expect directly calling the action will raise the thing 1 side_effect error
|
||||||
|
action_errors: bool
|
||||||
|
|
||||||
|
|
||||||
|
GALLERY_DELETE_TEST_CASES = [
|
||||||
|
# No errors from thing 1, thing 2 gets called
|
||||||
|
GalleryDeleteTestCase(
|
||||||
|
thing_1_side_effect=None, thing_2_call_count=1, action_errors=False
|
||||||
|
),
|
||||||
|
# Thing 1 errors, thing 2 is still called
|
||||||
|
GalleryDeleteTestCase(
|
||||||
|
thing_1_side_effect=RuntimeError, thing_2_call_count=1, action_errors=False
|
||||||
|
),
|
||||||
|
# Thing 1 raises invocation cancelled error. Thing 2 is not called. The InvocationError is raised
|
||||||
|
GalleryDeleteTestCase(
|
||||||
|
thing_1_side_effect=InvocationCancelledError,
|
||||||
|
thing_2_call_count=0,
|
||||||
|
action_errors=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("test_case", GALLERY_DELETE_TEST_CASES)
|
||||||
|
def test_gallery_calls_delete(test_case, minimal_gallery_env, mocker):
|
||||||
|
"""Test that the gallery delete on all gallery providing things.."""
|
||||||
|
# Create a config with the minimal Thing and the bad Thing
|
||||||
|
gallery = minimal_gallery_env.get_thing_by_name("gallery")
|
||||||
|
thing_1 = minimal_gallery_env.get_thing_by_name("minimal_thing1")
|
||||||
|
thing_2 = minimal_gallery_env.get_thing_by_name("minimal_thing2")
|
||||||
|
|
||||||
|
mocker.patch.object(
|
||||||
|
thing_1, "delete_all_gallery_items", side_effect=test_case.thing_1_side_effect
|
||||||
|
)
|
||||||
|
mocker.patch.object(thing_2, "delete_all_gallery_items")
|
||||||
|
|
||||||
|
if test_case.action_errors:
|
||||||
|
with pytest.raises(test_case.thing_1_side_effect):
|
||||||
|
gallery.delete_all_data()
|
||||||
|
else:
|
||||||
|
gallery.delete_all_data()
|
||||||
|
|
||||||
|
assert thing_1.delete_all_gallery_items.call_count == 1
|
||||||
|
assert thing_2.delete_all_gallery_items.call_count == test_case.thing_2_call_count
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue