def test_MantarrayMcSimulator__processes_start_stimulation_command__before_protocols_have_been_set( mantarray_mc_simulator_no_beacon, ): simulator = mantarray_mc_simulator_no_beacon["simulator"] set_simulator_idle_ready(mantarray_mc_simulator_no_beacon) expected_stim_running_statuses = { convert_module_id_to_well_name(module_id): False for module_id in range(1, 25) } # send start stim command expected_pc_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) start_stimulation_command = create_data_packet( expected_pc_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_START_STIM_PACKET_TYPE, ) simulator.write(start_stimulation_command) invoke_process_run_and_check_errors(simulator) # assert that stimulation was not started on any wells assert simulator.get_stim_running_statuses() == expected_stim_running_statuses # assert command response is correct expected_size = get_full_packet_size_from_packet_body_size(SERIAL_COMM_TIMESTAMP_LENGTH_BYTES + 1) stim_command_response = simulator.read(size=expected_size) assert_serial_packet_is_expected( stim_command_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_COMMAND_RESPONSE_PACKET_TYPE, additional_bytes=convert_to_timestamp_bytes(expected_pc_timestamp) + bytes([SERIAL_COMM_COMMAND_FAILURE_BYTE]), )
def test_MantarrayMcSimulator__processes_set_stimulation_protocol_command__when_stimulation_not_running_on_any_wells( mantarray_mc_simulator_no_beacon, ): simulator = mantarray_mc_simulator_no_beacon["simulator"] set_simulator_idle_ready(mantarray_mc_simulator_no_beacon) test_protocol_ids = ("A", "B", "E", None) stim_info_dict = { "protocols": [ { "protocol_id": protocol_id, "stimulation_type": choice(["C", "V"]), "run_until_stopped": choice([True, False]), "subprotocols": [ choice([get_random_subprotocol(), get_null_subprotocol(600)]) for _ in range(randint(1, 3)) ], } for protocol_id in test_protocol_ids[:-1] ], "protocol_assignments": { GENERIC_24_WELL_DEFINITION.get_well_name_from_well_index(well_idx): choice(test_protocol_ids) for well_idx in range(24) }, } expected_pc_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) set_protocols_command = create_data_packet( expected_pc_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_SET_STIM_PROTOCOL_PACKET_TYPE, convert_stim_dict_to_bytes(stim_info_dict), ) simulator.write(set_protocols_command) invoke_process_run_and_check_errors(simulator) # assert that stim info was stored actual = simulator.get_stim_info() for protocol_idx in range(len(test_protocol_ids) - 1): del stim_info_dict["protocols"][protocol_idx][ "protocol_id" ] # the actual protocol ID letter is not included assert actual["protocols"][protocol_idx] == stim_info_dict["protocols"][protocol_idx], protocol_idx assert actual["protocol_assignments"] == { # indices of the protocol are used instead well_name: (None if protocol_id is None else test_protocol_ids.index(protocol_id)) for well_name, protocol_id in stim_info_dict["protocol_assignments"].items() } # assert command response is correct stim_command_response = simulator.read( size=get_full_packet_size_from_packet_body_size(SERIAL_COMM_TIMESTAMP_LENGTH_BYTES + 1) ) assert_serial_packet_is_expected( stim_command_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_COMMAND_RESPONSE_PACKET_TYPE, additional_bytes=convert_to_timestamp_bytes(expected_pc_timestamp) + bytes([SERIAL_COMM_COMMAND_SUCCESS_BYTE]), )
def test_MantarrayMcSimulator__processes_start_stimulation_command__after_protocols_have_been_set( mantarray_mc_simulator_no_beacon, mocker ): simulator = mantarray_mc_simulator_no_beacon["simulator"] set_simulator_idle_ready(mantarray_mc_simulator_no_beacon) spied_global_timer = mocker.spy(simulator, "_get_global_timer") # mock so no protocol status packets are sent mocker.patch.object(mc_simulator, "_get_us_since_subprotocol_start", autospec=True, return_value=0) # set single arbitrary protocol applied to wells randomly stim_info = simulator.get_stim_info() stim_info["protocols"] = [ { "protocol_id": "A", "stimulation_type": "C", "run_until_stopped": True, "subprotocols": [get_random_subprotocol()], } ] stim_info["protocol_assignments"] = { GENERIC_24_WELL_DEFINITION.get_well_name_from_well_index(well_idx): choice(["A", None]) if well_idx else "A" for well_idx in range(24) } expected_stim_running_statuses = { well_name: bool(protocol_id) for well_name, protocol_id in stim_info["protocol_assignments"].items() } for response_byte_value in ( SERIAL_COMM_COMMAND_SUCCESS_BYTE, SERIAL_COMM_COMMAND_FAILURE_BYTE, ): # send start stim command expected_pc_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) start_stimulation_command = create_data_packet( expected_pc_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_START_STIM_PACKET_TYPE, ) simulator.write(start_stimulation_command) invoke_process_run_and_check_errors(simulator) # assert that stimulation was started on wells that were assigned a protocol assert simulator.get_stim_running_statuses() == expected_stim_running_statuses # assert command response is correct additional_bytes = convert_to_timestamp_bytes(expected_pc_timestamp) + bytes([response_byte_value]) if not response_byte_value: additional_bytes += spied_global_timer.spy_return.to_bytes(8, byteorder="little") expected_size = get_full_packet_size_from_packet_body_size(len(additional_bytes)) stim_command_response = simulator.read(size=expected_size) assert_serial_packet_is_expected( stim_command_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_COMMAND_RESPONSE_PACKET_TYPE, additional_bytes=additional_bytes, )
def test_McCommunicationProcess__automatically_sends_time_set_command_when_receiving_a_status_beacon_with_time_sync_ready_code__and_processes_command_response( four_board_mc_comm_process_no_handshake, mantarray_mc_simulator_no_beacon, mocker): simulator = mantarray_mc_simulator_no_beacon["simulator"] mc_process = four_board_mc_comm_process_no_handshake["mc_process"] output_queue = four_board_mc_comm_process_no_handshake["board_queues"][0][ 1] testing_queue = mantarray_mc_simulator_no_beacon["testing_queue"] set_connection_and_register_simulator( four_board_mc_comm_process_no_handshake, mantarray_mc_simulator_no_beacon) spied_write = mocker.spy(simulator, "write") spied_get_timestamp = mocker.spy(mc_comm, "get_serial_comm_timestamp") # put simulator in time sync ready status and send beacon test_commands = [ { "command": "set_status_code", "status_code": SERIAL_COMM_TIME_SYNC_READY_CODE, }, { "command": "send_single_beacon" }, ] handle_putting_multiple_objects_into_empty_queue(test_commands, testing_queue) invoke_process_run_and_check_errors(simulator, num_iterations=2) # read status beacon and send time sync command invoke_process_run_and_check_errors(mc_process) # assert correct time is sent assert_serial_packet_is_expected( spied_write.call_args[0][0], SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_SIMPLE_COMMAND_PACKET_TYPE, additional_bytes=bytes([SERIAL_COMM_SET_TIME_COMMAND_BYTE]) + convert_to_timestamp_bytes(spied_get_timestamp.spy_return), ) # process command and send response invoke_process_run_and_check_errors(simulator) # process command response invoke_process_run_and_check_errors(mc_process) # remove initial status beacon log message output_queue.get(timeout=QUEUE_CHECK_TIMEOUT_SECONDS) # assert command response processed and message sent to main confirm_queue_is_eventually_of_size(output_queue, 1) message_to_main = output_queue.get(timeout=QUEUE_CHECK_TIMEOUT_SECONDS) assert message_to_main == { "communication_type": "to_instrument", "command": "set_time", "message": "Instrument time synced with PC", }
def test_MantarrayMcSimulator__processes_set_stimulation_protocol_command__when_an_incorrect_amount_of_module_assignments_are_given( mantarray_mc_simulator_no_beacon, test_num_module_assignments, test_description ): simulator = mantarray_mc_simulator_no_beacon["simulator"] set_simulator_idle_ready(mantarray_mc_simulator_no_beacon) stim_info_dict = { "protocols": [ { "protocol_id": "V", "stimulation_type": choice(["C", "V"]), "run_until_stopped": choice([True, False]), "subprotocols": [get_random_subprotocol()], } ], "protocol_assignments": { GENERIC_24_WELL_DEFINITION.get_well_name_from_well_index(well_idx): "V" for well_idx in range(24) }, } stim_info_bytes = convert_stim_dict_to_bytes(stim_info_dict) # add or remove an assignment if test_num_module_assignments > 24: stim_info_bytes += bytes([0]) else: stim_info_bytes = stim_info_bytes[:-1] expected_pc_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) set_protocols_command = create_data_packet( expected_pc_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_SET_STIM_PROTOCOL_PACKET_TYPE, stim_info_bytes, ) simulator.write(set_protocols_command) invoke_process_run_and_check_errors(simulator) # assert stim info was not updated assert simulator.get_stim_info() == {} # assert command response is correct stim_command_response = simulator.read( size=get_full_packet_size_from_packet_body_size(SERIAL_COMM_TIMESTAMP_LENGTH_BYTES + 1) ) assert_serial_packet_is_expected( stim_command_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_COMMAND_RESPONSE_PACKET_TYPE, additional_bytes=convert_to_timestamp_bytes(expected_pc_timestamp) + bytes([SERIAL_COMM_COMMAND_FAILURE_BYTE]), )
def test_MantarrayMcSimulator__processes_testing_commands_during_reboot( mantarray_mc_simulator_no_beacon, mocker): simulator = mantarray_mc_simulator_no_beacon["simulator"] testing_queue = mantarray_mc_simulator_no_beacon["testing_queue"] mocker.patch.object( mc_simulator, "_get_secs_since_reboot_command", autospec=True, return_value=AVERAGE_MC_REBOOT_DURATION_SECONDS - 1, ) spied_get_absolute_timer = mocker.spy(simulator, "_get_absolute_timer") # send reboot command test_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) simulator.write( create_data_packet( test_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_SIMPLE_COMMAND_PACKET_TYPE, bytes([SERIAL_COMM_REBOOT_COMMAND_BYTE]), )) invoke_process_run_and_check_errors(simulator) # remove reboot response packet invoke_process_run_and_check_errors(simulator) reboot_response_size = get_full_packet_size_from_packet_body_size( SERIAL_COMM_TIMESTAMP_LENGTH_BYTES) reboot_response = simulator.read(size=reboot_response_size) assert_serial_packet_is_expected( reboot_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_COMMAND_RESPONSE_PACKET_TYPE, additional_bytes=convert_to_timestamp_bytes(test_timestamp), timestamp=spied_get_absolute_timer.spy_return, ) # add read bytes as test command expected_item = b"the_item" test_dict = {"command": "add_read_bytes", "read_bytes": expected_item} put_object_into_queue_and_raise_error_if_eventually_still_empty( test_dict, testing_queue) invoke_process_run_and_check_errors(simulator) actual = simulator.read(size=len(expected_item)) assert actual == expected_item
def test_MantarrayMcSimulator__automatically_sends_plate_barcode_after_time_is_synced( mantarray_mc_simulator_no_beacon, ): simulator = mantarray_mc_simulator_no_beacon["simulator"] testing_queue = mantarray_mc_simulator_no_beacon["testing_queue"] # put simulator in time sync ready status put_object_into_queue_and_raise_error_if_eventually_still_empty( { "command": "set_status_code", "status_code": SERIAL_COMM_TIME_SYNC_READY_CODE }, testing_queue, ) invoke_process_run_and_check_errors(simulator) # send set time command test_pc_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) test_set_time_command = create_data_packet( test_pc_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_SIMPLE_COMMAND_PACKET_TYPE, bytes([SERIAL_COMM_SET_TIME_COMMAND_BYTE]) + convert_to_timestamp_bytes(test_pc_timestamp), ) simulator.write(test_set_time_command) # process set time command and remove response invoke_process_run_and_check_errors(simulator) simulator.read(size=get_full_packet_size_from_packet_body_size( SERIAL_COMM_TIMESTAMP_LENGTH_BYTES)) barcode_packet_size = get_full_packet_size_from_packet_body_size( len(MantarrayMcSimulator.default_barcode)) # assert barcode packet sent correctly barcode_packet = simulator.read(size=barcode_packet_size) assert_serial_packet_is_expected( barcode_packet, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_BARCODE_FOUND_PACKET_TYPE, bytes(MantarrayMcSimulator.default_barcode, encoding="ascii"), )
def test_MantarrayMcSimulator__processes_stop_stimulation_command(mantarray_mc_simulator_no_beacon, mocker): simulator = mantarray_mc_simulator_no_beacon["simulator"] set_simulator_idle_ready(mantarray_mc_simulator_no_beacon) spied_global_timer = mocker.spy(simulator, "_get_global_timer") # set single arbitrary protocol applied to wells randomly stim_info = simulator.get_stim_info() stim_info["protocols"] = [ { "protocol_id": "B", "stimulation_type": "V", "run_until_stopped": True, "subprotocols": [get_random_subprotocol()], } ] stim_info["protocol_assignments"] = { GENERIC_24_WELL_DEFINITION.get_well_name_from_well_index(well_idx): choice(["B", None]) if well_idx else "B" for well_idx in range(24) } initial_stim_running_statuses = { well_name: bool(protocol_id) for well_name, protocol_id in stim_info["protocol_assignments"].items() } simulator.get_stim_running_statuses().update(initial_stim_running_statuses) for response_byte_value in ( SERIAL_COMM_COMMAND_SUCCESS_BYTE, SERIAL_COMM_COMMAND_FAILURE_BYTE, ): # send start stim command expected_pc_timestamp = randint(0, SERIAL_COMM_MAX_TIMESTAMP_VALUE) stop_stimulation_command = create_data_packet( expected_pc_timestamp, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_STOP_STIM_PACKET_TYPE, ) simulator.write(stop_stimulation_command) invoke_process_run_and_check_errors(simulator) # make sure finished status updates are sent if command succeeded if response_byte_value == SERIAL_COMM_COMMAND_SUCCESS_BYTE: status_update_bytes = bytes([sum(initial_stim_running_statuses.values())]) for well_name in simulator.get_stim_running_statuses().keys(): if not initial_stim_running_statuses[well_name]: continue well_idx = GENERIC_24_WELL_DEFINITION.get_well_index_from_well_name(well_name) status_update_bytes += ( bytes([STIM_WELL_IDX_TO_MODULE_ID[well_idx]]) + bytes([StimStatuses.FINISHED]) + (spied_global_timer.spy_return).to_bytes(8, byteorder="little") + bytes([STIM_COMPLETE_SUBPROTOCOL_IDX]) ) expected_size = get_full_packet_size_from_packet_body_size(len(status_update_bytes)) stim_command_response = simulator.read(size=expected_size) assert_serial_packet_is_expected( stim_command_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_STIM_STATUS_PACKET_TYPE, additional_bytes=status_update_bytes, ) # assert that stimulation was stopped on all wells assert simulator.get_stim_running_statuses() == { convert_module_id_to_well_name(module_id): False for module_id in range(1, 25) } # assert command response is correct additional_bytes = convert_to_timestamp_bytes(expected_pc_timestamp) + bytes([response_byte_value]) expected_size = get_full_packet_size_from_packet_body_size(len(additional_bytes)) stim_command_response = simulator.read(size=expected_size) assert_serial_packet_is_expected( stim_command_response, SERIAL_COMM_MAIN_MODULE_ID, SERIAL_COMM_COMMAND_RESPONSE_PACKET_TYPE, additional_bytes=additional_bytes, )