Conversation
2309926 to
f2b1050
Compare
bc73781 to
a9e49bb
Compare
| class FunctionThread(Thread): | ||
| def __init__( | ||
| self, handler_function: Callable[P, None], *args: P.args, **kwargs: P.kwargs | ||
| ): | ||
| self.handler_function = lambda: handler_function(*args, **kwargs) | ||
| Thread.__init__(self, name="Robot start mission thread") | ||
| self.start() | ||
|
|
||
| def run(self) -> None: | ||
| self.handler_function() |
There was a problem hiding this comment.
This class just runs whatever function it gets, with whatever arguments it gets. It's useful for when we want a function in its own thread, but we also want to type check its arguments.
| self.signal_thread_quitting: Event = signal_thread_quitting | ||
| self.error_message: Optional[ErrorMessage] = None | ||
| Thread.__init__(self, name="Robot pause mission thread") | ||
| def robot_pause_mission( |
There was a problem hiding this comment.
The robot service handlers are running in thier own threads, instead of the functions that the handlers call.
453916c to
0d72cab
Compare
ee57df1 to
a523518
Compare
a523518 to
207ad11
Compare
207ad11 to
cd975f4
Compare
| def test_mission_succeeds_to_stop( | ||
| mocked_robot_service: Robot, mocker: MockerFixture | ||
| ) -> None: | ||
| r_service = mocked_robot_service | ||
| mocker.patch.object(RobotStopMissionThread, "is_alive", return_value=False) | ||
|
|
||
| r_service.stop_mission_thread = RobotStopMissionThread( | ||
| r_service.robot, r_service.signal_thread_quitting | ||
| ) | ||
|
|
||
| r_service._stop_mission_done_handler() | ||
|
|
||
| assert not r_service.robot_service_events.mission_failed_to_stop.has_event() | ||
| assert r_service.robot_service_events.mission_successfully_stopped.has_event() | ||
|
|
||
| assert not r_service.robot_service_events.mission_succeeded.has_event() | ||
| assert not r_service.robot_service_events.mission_failed.has_event() | ||
|
|
||
| assert r_service.monitor_mission_thread is None |
There was a problem hiding this comment.
This test became equivalent to the test_successful_stop test after the refactor.
| def test_mission_stop_waits_for_mission_to_start( | ||
| mocked_robot_service: Robot, mocker: MockerFixture | ||
| ) -> None: | ||
| r_service = mocked_robot_service | ||
| mocker.patch.object(RobotStartMissionThread, "is_alive", return_value=True) | ||
|
|
||
| task_1: Task = TakeImage( | ||
| target=DummyPose.default_pose().position, robot_pose=DummyPose.default_pose() | ||
| ) | ||
| mission: Mission = Mission(name="Dummy misson", tasks=[task_1]) | ||
| r_service.start_mission_thread = RobotStartMissionThread( | ||
| r_service.robot, r_service.signal_thread_quitting, mission | ||
| ) | ||
| r_service.stop_mission_thread = None | ||
|
|
||
| r_service.state_machine_events.stop_mission.trigger_event(EmptyMessage()) | ||
|
|
||
| r_service._stop_mission_request_handler(r_service.state_machine_events.stop_mission) | ||
|
|
||
| assert r_service.state_machine_events.stop_mission.has_event() | ||
| assert r_service.stop_mission_thread is None |
There was a problem hiding this comment.
This test also became redundant after the rewrite. Only one action thread running is handled in the robot service loop, not by the individual threads.
| def test_mission_stop_starts_when_start_is_done( | ||
| mocked_robot_service: Robot, mocker: MockerFixture | ||
| ) -> None: | ||
| r_service = mocked_robot_service | ||
| mocker.patch.object(RobotStartMissionThread, "is_alive", return_value=False) | ||
|
|
||
| mock_stop_mission_start = mocker.patch( | ||
| "isar.robot.robot.RobotStopMissionThread.start" | ||
| ) | ||
|
|
||
| task_1: Task = TakeImage( | ||
| target=DummyPose.default_pose().position, robot_pose=DummyPose.default_pose() | ||
| ) | ||
| mission: Mission = Mission(name="Dummy misson", tasks=[task_1]) | ||
| r_service.start_mission_thread = RobotStartMissionThread( | ||
| r_service.robot, r_service.signal_thread_quitting, mission | ||
| ) | ||
| r_service.stop_mission_thread = None | ||
|
|
||
| r_service.state_machine_events.stop_mission.trigger_event(EmptyMessage()) | ||
|
|
||
| r_service._stop_mission_request_handler(r_service.state_machine_events.stop_mission) | ||
|
|
||
| assert not r_service.state_machine_events.stop_mission.has_event() | ||
| assert r_service.stop_mission_thread is not None | ||
| mock_stop_mission_start.assert_called_once() |
There was a problem hiding this comment.
This test also became redundant. Missions starting is now event based, instead of relying on logic checking the status of other threads.
| def test_mission_pause_waits_for_mission_to_start( | ||
| mocked_robot_service: Robot, mocker: MockerFixture | ||
| ) -> None: | ||
| r_service = mocked_robot_service | ||
| mocker.patch.object(RobotStartMissionThread, "is_alive", return_value=True) | ||
|
|
||
| task_1: Task = TakeImage( | ||
| target=DummyPose.default_pose().position, robot_pose=DummyPose.default_pose() | ||
| ) | ||
| mission: Mission = Mission(name="Dummy misson", tasks=[task_1]) | ||
| r_service.start_mission_thread = RobotStartMissionThread( | ||
| r_service.robot, r_service.signal_thread_quitting, mission | ||
| ) | ||
| r_service.pause_mission_thread = None | ||
|
|
||
| r_service.state_machine_events.pause_mission.trigger_event(EmptyMessage()) | ||
|
|
||
| r_service._pause_mission_request_handler( | ||
| r_service.state_machine_events.pause_mission | ||
| ) | ||
|
|
||
| assert r_service.state_machine_events.pause_mission.has_event() | ||
| assert r_service.pause_mission_thread is None |
There was a problem hiding this comment.
Same as above, the robot service handles this now.
cd975f4 to
ca5df35
Compare
The point of this PR is to simplify the robot interface.
Instead of having separate thread objections for each action, we create a generic action thread which runs each event handler. In the eventhandler we both run the action handler (which was previously its own thread) and handle the output, synchronously. Only one action is handled at a time. Other state machine events are ignored in the mean time.
Ready for review checklist: