Skip to content

Commit

Permalink
test(protocol-engine): Port some tests (#15477)
Browse files Browse the repository at this point in the history
  • Loading branch information
SyntaxColoring authored Jun 21, 2024
1 parent 3a2ce8f commit c0b17a1
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 229 deletions.
5 changes: 0 additions & 5 deletions api/src/opentrons/protocol_engine/state/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ def handle_action(self, action: Action) -> None: # noqa: C901
# TODO(mc, 2021-06-22): mypy has trouble with this automatic
# request > command mapping, figure out how to type precisely
# (or wait for a future mypy version that can figure it out).
# For now, unit tests cover mapping every request type
queued_command = action.request._CommandCls.construct(
id=action.command_id,
key=(
Expand Down Expand Up @@ -679,10 +678,6 @@ def get_is_door_blocking(self) -> bool:
"""Get whether the robot door is open when 'pause on door open' ff is True."""
return self._state.is_door_blocking

def get_is_implicitly_active(self) -> bool:
"""Get whether the queue is implicitly active, i.e., never 'played'."""
return self._state.queue_status == QueueStatus.SETUP

def get_is_running(self) -> bool:
"""Get whether the protocol is running & queued commands should be executed."""
return self._state.queue_status == QueueStatus.RUNNING
Expand Down
64 changes: 64 additions & 0 deletions api/tests/opentrons/protocol_engine/state/test_command_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,70 @@ def _make_config() -> Config:
)


def test_queue_command_action() -> None:
"""It should translate a command request into a queued command and add it."""
subject = CommandStore(is_door_open=False, config=_make_config())
subject_view = CommandView(subject.state)

id = "command-id"
key = "command-key"
params = commands.CommentParams(message="yay")
created_at = datetime(year=2021, month=1, day=1)
request = commands.CommentCreate(params=params, key=key)
action = actions.QueueCommandAction(
request=request,
request_hash=None,
created_at=created_at,
command_id=id,
)
expected_command = commands.Comment(
id=id,
key=key,
createdAt=created_at,
status=commands.CommandStatus.QUEUED,
params=params,
)

subject.handle_action(action)
assert subject_view.get("command-id") == expected_command
assert subject_view.get_all() == [expected_command]


def test_latest_protocol_command_hash() -> None:
"""It should return the latest protocol command's hash."""
subject = CommandStore(is_door_open=False, config=_make_config())
subject_view = CommandView(subject.state)

# The initial hash should be None.
assert subject_view.get_latest_protocol_command_hash() is None

# It should pick up the hash from an enqueued protocol command.
subject.handle_action(
actions.QueueCommandAction(
request=commands.CommentCreate(
params=commands.CommentParams(message="hello world"),
),
request_hash="hash-1",
command_id="command-id-1",
created_at=datetime.now(),
)
)
assert subject_view.get_latest_protocol_command_hash() == "hash-1"

# It should pick up newer hashes as they come in.
subject.handle_action(
actions.QueueCommandAction(
request=commands.CommentCreate(
params=commands.CommentParams(message="hello world"),
),
request_hash="hash-2",
command_id="command-id-2",
created_at=datetime.now(),
)
)
assert subject_view.get_latest_protocol_command_hash() == "hash-2"


@pytest.mark.parametrize("error_recovery_type", ErrorRecoveryType)
def test_command_failure(error_recovery_type: ErrorRecoveryType) -> None:
"""It should store an error and mark the command if it fails."""
Expand Down
218 changes: 1 addition & 217 deletions api/tests/opentrons/protocol_engine/state/test_command_store_old.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@

import pytest
from datetime import datetime
from typing import NamedTuple, Type

from opentrons_shared_data.errors import ErrorCodes
from opentrons_shared_data.pipette.dev_types import PipetteNameType

from opentrons.ordered_set import OrderedSet
from opentrons.protocol_engine.actions.actions import RunCommandAction
from opentrons.types import MountType, DeckSlotName
from opentrons.hardware_control.types import DoorState

from opentrons.protocol_engine import commands, errors
from opentrons.protocol_engine.types import DeckSlotLocation, DeckType, WellLocation
from opentrons.protocol_engine.types import DeckType
from opentrons.protocol_engine.state import Config
from opentrons.protocol_engine.state.commands import (
CommandState,
Expand Down Expand Up @@ -55,219 +52,6 @@ def _make_config(block_on_door_open: bool = False) -> Config:
)


@pytest.mark.parametrize(
("is_door_open", "config", "expected_is_door_blocking"),
[
(False, _make_config(), False),
(True, _make_config(), False),
(False, _make_config(block_on_door_open=True), False),
(True, _make_config(block_on_door_open=True), True),
],
)
def test_initial_state(
is_door_open: bool,
config: Config,
expected_is_door_blocking: bool,
) -> None:
"""It should set the initial state."""
subject = CommandStore(is_door_open=is_door_open, config=config)

assert subject.state == CommandState(
command_history=CommandHistory(),
queue_status=QueueStatus.SETUP,
run_completed_at=None,
run_started_at=None,
is_door_blocking=expected_is_door_blocking,
run_result=None,
run_error=None,
finish_error=None,
failed_command=None,
command_error_recovery_types={},
recovery_target_command_id=None,
latest_protocol_command_hash=None,
stopped_by_estop=False,
)


class QueueCommandSpec(NamedTuple):
"""Test data for the QueueCommandAction."""

command_request: commands.CommandCreate
expected_cls: Type[commands.Command]
created_at: datetime = datetime(year=2021, month=1, day=1)
command_id: str = "command-id"
command_key: str = "command-key"


@pytest.mark.parametrize(
QueueCommandSpec._fields,
[
QueueCommandSpec(
command_request=commands.AspirateCreate(
params=commands.AspirateParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
volume=42,
flowRate=1.23,
wellLocation=WellLocation(),
),
key="command-key",
),
expected_cls=commands.Aspirate,
),
QueueCommandSpec(
command_request=commands.DispenseCreate(
params=commands.DispenseParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
volume=42,
flowRate=1.23,
wellLocation=WellLocation(),
),
),
expected_cls=commands.Dispense,
# test when key prop is missing
command_key="command-id",
),
QueueCommandSpec(
command_request=commands.DropTipCreate(
params=commands.DropTipParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
),
key="command-key",
),
expected_cls=commands.DropTip,
),
QueueCommandSpec(
command_request=commands.LoadLabwareCreate(
params=commands.LoadLabwareParams(
location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1),
loadName="load-name",
namespace="namespace",
version=42,
),
key="command-key",
),
expected_cls=commands.LoadLabware,
),
QueueCommandSpec(
command_request=commands.LoadPipetteCreate(
params=commands.LoadPipetteParams(
mount=MountType.LEFT,
pipetteName=PipetteNameType.P300_SINGLE,
),
key="command-key",
),
expected_cls=commands.LoadPipette,
),
QueueCommandSpec(
command_request=commands.PickUpTipCreate(
params=commands.PickUpTipParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
),
key="command-key",
),
expected_cls=commands.PickUpTip,
),
QueueCommandSpec(
command_request=commands.MoveToWellCreate(
params=commands.MoveToWellParams(
pipetteId="pipette-id",
labwareId="labware-id",
wellName="well-name",
),
key="command-key",
),
expected_cls=commands.MoveToWell,
),
QueueCommandSpec(
command_request=commands.WaitForResumeCreate(
params=commands.WaitForResumeParams(message="hello world"),
key="command-key",
),
expected_cls=commands.WaitForResume,
),
QueueCommandSpec(
# a WaitForResumeCreate with `pause` should be mapped to
# a WaitForResume with `commandType="waitForResume"`
command_request=commands.WaitForResumeCreate(
commandType="pause",
params=commands.WaitForResumeParams(message="hello world"),
key="command-key",
),
expected_cls=commands.WaitForResume,
),
],
)
def test_command_store_queues_commands(
command_request: commands.CommandCreate,
expected_cls: Type[commands.Command],
created_at: datetime,
command_id: str,
command_key: str,
) -> None:
"""It should add a command to the store."""
action = QueueCommandAction(
request=command_request,
request_hash=None,
created_at=created_at,
command_id=command_id,
)
expected_command = expected_cls(
id=command_id,
key=command_key,
createdAt=created_at,
status=commands.CommandStatus.QUEUED,
params=command_request.params, # type: ignore[arg-type]
)

subject = CommandStore(is_door_open=False, config=_make_config())
subject.handle_action(action)

assert subject.state.command_history.get("command-id") == CommandEntry(
index=0, command=expected_command
)
assert subject.state.command_history.get_all_ids() == ["command-id"]
assert subject.state.command_history.get_queue_ids() == OrderedSet(["command-id"])


def test_command_queue_with_hash() -> None:
"""It should queue a command with a command hash and no explicit key."""
create = commands.WaitForResumeCreate(
params=commands.WaitForResumeParams(message="hello world"),
)

subject = CommandStore(is_door_open=False, config=_make_config())
subject.handle_action(
QueueCommandAction(
request=create,
request_hash="abc123",
created_at=datetime(year=2021, month=1, day=1),
command_id="command-id-1",
)
)

assert subject.state.command_history.get("command-id-1").command.key == "abc123"
assert subject.state.latest_protocol_command_hash == "abc123"

subject.handle_action(
QueueCommandAction(
request=create,
request_hash="def456",
created_at=datetime(year=2021, month=1, day=1),
command_id="command-id-2",
)
)

assert subject.state.latest_protocol_command_hash == "def456"


def test_command_queue_and_unqueue() -> None:
"""It should queue on QueueCommandAction and dequeue on RunCommandAction."""
queue_1 = QueueCommandAction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ def test_get_next_to_execute_returns_no_commands_if_paused() -> None:
assert result is None


def test_get_next_to_execute_returns_no_commands_if_awaiting_recovery_no_fixit() -> None:
def test_get_next_to_execute_returns_no_commands_if_awaiting_recovery_no_fixit() -> (
None
):
"""It should not return any type of command if the engine is awaiting-recovery."""
subject = get_command_view(
queue_status=QueueStatus.AWAITING_RECOVERY,
Expand Down Expand Up @@ -1020,9 +1022,3 @@ def test_get_slice_default_cursor_queued() -> None:
cursor=2,
total_length=5,
)


def test_get_latest_command_hash() -> None:
"""It should get the latest command hash from state, if set."""
subject = get_command_view(latest_command_hash="abc123")
assert subject.get_latest_protocol_command_hash() == "abc123"

0 comments on commit c0b17a1

Please sign in to comment.