Files
AareCommon/tests/test_aare_exception.py
T
2026-07-02 12:52:45 +02:00

253 lines
7.6 KiB
Python

"""Tests for the AareException hierarchy introduced in Phase 1 of the
exception-handling redesign.
These cover:
- class-level ``critical`` default
- instance-level override via ``critical=...`` kwarg
- correct parent/family relationships so watchers can match by family
"""
from __future__ import annotations
import pytest
from aarecommon.errors.exception_handler import (
AareAuthError,
AareDBCommunicationError,
AareException,
AareUserError,
AerotechCommunicationError,
AerotechException,
AuthenticationException,
AutomationError,
AutoRasterSampleSkipped,
AXCFailed,
BeamlineBusyException,
BeamlineBusyTimeoutException,
BeamlineStateException,
BECCommunicationError,
BECException,
CriticalTellException,
DataCollectionException,
JFJochCommunicationError,
JFJochException,
LoopCenteringFailed,
MagnetPositionSensorErorr,
MaintenanceStateException,
ManualMountException,
MountingFailed,
RasterScanException,
SampleException,
SmargonCommunicationError,
SmargonException,
SmartMagnetFaultException,
StateTransitionFailed,
TellCommandWhileBusyException,
TellCommunicationError,
TellConnectionException,
TellException,
TransformationInvalidException,
UnmountingFailed,
UserRightsException,
WarningTellException,
)
# ---------------------------------------------------------------------------
# Class-level criticality defaults
# ---------------------------------------------------------------------------
def test_aare_exception_class_critical_default_false():
assert AareException.critical is False
def test_phase3_classes_have_critical_default_true():
for cls in (
TellCommunicationError,
TellConnectionException,
CriticalTellException,
SmargonCommunicationError,
AerotechCommunicationError,
JFJochCommunicationError,
BECCommunicationError,
StateTransitionFailed,
MaintenanceStateException,
BeamlineBusyException,
BeamlineBusyTimeoutException,
MagnetPositionSensorErorr,
SmartMagnetFaultException,
TransformationInvalidException,
):
assert cls.critical is True, f"{cls.__name__} should default to critical=True in Phase 3"
def test_other_core_classes_keep_critical_default_false():
for cls in (
AutomationError,
AareUserError,
AareAuthError,
TellException,
SmargonException,
AerotechException,
JFJochException,
BECException,
BeamlineStateException,
MountingFailed,
UnmountingFailed,
LoopCenteringFailed,
TellCommandWhileBusyException,
WarningTellException,
AareDBCommunicationError,
):
assert cls.critical is False, f"{cls.__name__} should remain critical=False"
# ---------------------------------------------------------------------------
# Instance-level critical override
# ---------------------------------------------------------------------------
def test_instance_critical_override_true():
exc = MountingFailed("mount fail", critical=True)
assert exc.critical is True
# class default unchanged
assert MountingFailed.critical is False
def test_instance_critical_override_false():
exc = MountingFailed("mount fail", critical=False)
assert exc.critical is False
def test_instance_critical_none_keeps_class_default():
# Omitting critical uses class default
exc = MountingFailed("mount fail")
assert exc.critical is False # class default
def test_aaredb_communication_error_instance_critical_override():
exc = AareDBCommunicationError("db down", critical=True, operation="GET")
assert exc.critical is True
assert exc.operation == "GET"
# ---------------------------------------------------------------------------
# Routing-root membership
# ---------------------------------------------------------------------------
def test_automation_errors_are_automation_error():
for cls in (
LoopCenteringFailed,
MountingFailed,
UnmountingFailed,
AXCFailed,
TellCommunicationError,
SmargonCommunicationError,
AerotechCommunicationError,
JFJochCommunicationError,
BECCommunicationError,
AareDBCommunicationError,
BeamlineBusyException,
RasterScanException,
MagnetPositionSensorErorr,
SmartMagnetFaultException,
TransformationInvalidException,
AutoRasterSampleSkipped,
):
exc = cls() if cls is not AutoRasterSampleSkipped else cls("skipped")
assert isinstance(exc, AutomationError), f"{cls.__name__} should be AutomationError"
assert isinstance(exc, AareException), f"{cls.__name__} should be AareException"
def test_auth_errors_are_aare_auth_error():
for cls in (AuthenticationException, UserRightsException):
exc = cls()
assert isinstance(exc, AareAuthError)
assert isinstance(exc, AareException)
def test_user_errors_are_aare_user_error():
for cls in (ManualMountException, SampleException):
exc = cls()
assert isinstance(exc, AareUserError)
assert isinstance(exc, AareException)
# ---------------------------------------------------------------------------
# Family-base membership (drives watcher matching)
# ---------------------------------------------------------------------------
def test_tell_family_membership():
for cls in (
TellCommunicationError,
TellConnectionException,
CriticalTellException,
TellCommandWhileBusyException,
WarningTellException,
MountingFailed,
UnmountingFailed,
):
exc = cls()
assert isinstance(exc, TellException), f"{cls.__name__} should be in Tell family"
assert isinstance(exc, AutomationError)
def test_smargon_family_membership():
exc = SmargonCommunicationError()
assert isinstance(exc, SmargonException)
assert isinstance(exc, AutomationError)
def test_aerotech_family_membership():
exc = AerotechCommunicationError()
assert isinstance(exc, AerotechException)
assert isinstance(exc, AutomationError)
def test_jfjoch_family_membership():
exc = JFJochCommunicationError()
assert isinstance(exc, JFJochException)
assert isinstance(exc, AutomationError)
def test_bec_family_membership():
exc = BECCommunicationError()
assert isinstance(exc, BECException)
assert isinstance(exc, AutomationError)
def test_beamline_state_family_membership():
for cls in (
StateTransitionFailed,
MaintenanceStateException,
BeamlineBusyException,
BeamlineBusyTimeoutException,
):
exc = cls()
assert isinstance(exc, BeamlineStateException)
assert isinstance(exc, AutomationError)
def test_data_collection_family_membership():
exc = RasterScanException()
assert isinstance(exc, DataCollectionException)
assert isinstance(exc, AutomationError)
# ---------------------------------------------------------------------------
# Backward compat: existing __str__/.message contracts preserved
# ---------------------------------------------------------------------------
def test_message_attribute_preserved():
exc = LoopCenteringFailed("custom message")
assert exc.message == "custom message"
assert str(exc) == "custom message"
def test_default_messages_preserved():
assert str(MountingFailed()) == "A sample was not mounted"
assert str(UnmountingFailed()) == "A sample was not unmounted"
assert str(LoopCenteringFailed()) == "Loop Centering did not detect a sample"