From e0e12590ca233c9be822d672e12034248e21adca Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Tue, 19 Mar 2024 15:39:49 -0400 Subject: [PATCH] More test boilerplate. --- .../execution/test_command_executor.py | 23 +++++++++++++++++++ .../protocol_engine/test_protocol_engine.py | 6 ++++- .../test_legacy_command_mapper.py | 3 +++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/api/tests/opentrons/protocol_engine/execution/test_command_executor.py b/api/tests/opentrons/protocol_engine/execution/test_command_executor.py index 961bfa3ac54..34b459a9661 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_command_executor.py +++ b/api/tests/opentrons/protocol_engine/execution/test_command_executor.py @@ -10,6 +10,10 @@ from opentrons.hardware_control import HardwareControlAPI, OT2HardwareControlAPI from opentrons.protocol_engine import errors +from opentrons.protocol_engine.error_recovery_policy import ( + ErrorRecoveryPolicy, + ErrorRecoveryType, +) from opentrons.protocol_engine.errors.exceptions import ( EStopActivatedError as PE_EStopActivatedError, ) @@ -132,6 +136,12 @@ def command_note_tracker_provider(decoy: Decoy) -> CommandNoteTrackerProvider: return decoy.mock(cls=CommandNoteTrackerProvider) +@pytest.fixture +def error_recovery_policy(decoy: Decoy) -> ErrorRecoveryPolicy: + """Get a mock error recovery policy.""" + return decoy.mock(cls=ErrorRecoveryPolicy) + + def get_next_tracker( decoy: Decoy, provider: CommandNoteTrackerProvider ) -> CommandNoteTracker: @@ -169,6 +179,7 @@ def subject( status_bar: StatusBarHandler, model_utils: ModelUtils, command_note_tracker_provider: CommandNoteTrackerProvider, + error_recovery_policy: ErrorRecoveryPolicy, ) -> CommandExecutor: """Get a CommandExecutor test subject with its dependencies mocked out.""" return CommandExecutor( @@ -186,6 +197,7 @@ def subject( rail_lights=rail_lights, status_bar=status_bar, command_note_tracker_provider=command_note_tracker_provider, + error_recovery_policy=error_recovery_policy, ) @@ -357,6 +369,7 @@ async def test_execute_raises_protocol_engine_error( model_utils: ModelUtils, subject: CommandExecutor, command_note_tracker: CommandNoteTracker, + error_recovery_policy: ErrorRecoveryPolicy, command_error: Exception, expected_error: Any, unexpected_error: bool, @@ -430,6 +443,10 @@ def _ImplementationCls(self) -> Type[_TestCommandImpl]: datetime(year=2023, month=3, day=3), ) + decoy.when(error_recovery_policy(matchers.Anything(), expected_error)).then_return( + ErrorRecoveryType.WAIT_FOR_RECOVERY + ) + await subject.execute("command-id") decoy.verify( @@ -442,6 +459,7 @@ def _ImplementationCls(self) -> Type[_TestCommandImpl]: error_id="error-id", failed_at=datetime(year=2023, month=3, day=3), error=expected_error, + type=ErrorRecoveryType.WAIT_FOR_RECOVERY, ) ), ) @@ -588,6 +606,7 @@ async def test_executor_forwards_notes_on_command_failure( model_utils: ModelUtils, subject: CommandExecutor, command_note_tracker: CommandNoteTracker, + error_recovery_policy: ErrorRecoveryPolicy, ) -> None: """It should handle an error occuring during execution.""" TestCommandImplCls = decoy.mock(func=_TestCommandImpl) @@ -668,6 +687,9 @@ def _ImplementationCls(self) -> Type[_TestCommandImpl]: datetime(year=2022, month=2, day=2), datetime(year=2023, month=3, day=3), ) + decoy.when( + error_recovery_policy(matchers.Anything(), matchers.Anything()) + ).then_return(ErrorRecoveryType.WAIT_FOR_RECOVERY) decoy.when(command_note_tracker.get_notes()).then_return(command_notes) await subject.execute("command-id") @@ -685,6 +707,7 @@ def _ImplementationCls(self) -> Type[_TestCommandImpl]: error_id="error-id", failed_at=datetime(year=2023, month=3, day=3), error=matchers.ErrorMatching(PythonException, match="oh no"), + type=ErrorRecoveryType.WAIT_FOR_RECOVERY, ) ), ) diff --git a/api/tests/opentrons/protocol_engine/test_protocol_engine.py b/api/tests/opentrons/protocol_engine/test_protocol_engine.py index 58b9109376c..8af30d521df 100644 --- a/api/tests/opentrons/protocol_engine/test_protocol_engine.py +++ b/api/tests/opentrons/protocol_engine/test_protocol_engine.py @@ -9,6 +9,7 @@ from opentrons_shared_data.robot.dev_types import RobotType from opentrons.ordered_set import OrderedSet from opentrons.protocol_engine.actions.actions import ResumeFromRecoveryAction +from opentrons.protocol_engine.error_recovery_policy import ErrorRecoveryType from opentrons.types import DeckSlotName from opentrons.hardware_control import HardwareControlAPI, OT2HardwareControlAPI @@ -695,7 +696,8 @@ async def test_wait_until_complete( decoy.verify( await state_store.wait_for( condition=state_store.commands.get_all_commands_final - ) + ), + state_store.commands.raise_fatal_command_error(), ) @@ -778,12 +780,14 @@ async def test_estop_during_command( error_id=error_id, failed_at=timestamp, error=EStopActivatedError(message="Estop Activated"), + type=ErrorRecoveryType.FAIL_RUN, ) expected_action_2 = FailCommandAction( command_id=fake_command_set.head(), error_id=error_id, failed_at=timestamp, error=EStopActivatedError(message="Estop Activated"), + type=ErrorRecoveryType.FAIL_RUN, ) subject.estop(maintenance_run=maintenance_run) diff --git a/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py b/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py index e5995136685..54a5a435c6b 100644 --- a/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py +++ b/api/tests/opentrons/protocol_runner/test_legacy_command_mapper.py @@ -16,6 +16,7 @@ commands as pe_commands, actions as pe_actions, ) +from opentrons.protocol_engine.error_recovery_policy import ErrorRecoveryType from opentrons.protocol_engine.resources import ( ModuleDataProvider, pipette_data_provider, @@ -158,6 +159,7 @@ def test_map_after_with_error_command() -> None: LegacyContextCommandError, match="oh no", ), + type=ErrorRecoveryType.FAIL_RUN, ) ] @@ -251,6 +253,7 @@ def test_command_stack() -> None: error_id=matchers.IsA(str), failed_at=matchers.IsA(datetime), error=matchers.ErrorMatching(LegacyContextCommandError, "oh no"), + type=ErrorRecoveryType.FAIL_RUN, ), ]