async def _unittest_udp_transport() -> None: from pyuavcan.transport import MessageDataSpecifier, ServiceDataSpecifier, PayloadMetadata, Transfer, TransferFrom from pyuavcan.transport import Priority, Timestamp, InputSessionSpecifier, OutputSessionSpecifier from pyuavcan.transport import ProtocolParameters get_monotonic = asyncio.get_event_loop().time with pytest.raises(ValueError): _ = UDPTransport(ip_address='127.0.0.111/8', mtu=10) with pytest.raises(ValueError): _ = UDPTransport(ip_address='127.0.0.111/8', service_transfer_multiplier=100) tr = UDPTransport('127.0.0.111/8', mtu=9000) tr2 = UDPTransport('127.0.0.222/8', service_transfer_multiplier=2) assert tr.local_ip_address_with_netmask == '127.0.0.111/8' assert tr2.local_ip_address_with_netmask == '127.0.0.222/8' assert tr.loop is asyncio.get_event_loop() assert tr.local_node_id == 111 assert tr2.local_node_id == 222 assert tr.input_sessions == [] assert tr.output_sessions == [] assert list(xml.etree.ElementTree.fromstring( tr.descriptor).itertext()) == ['127.0.0.111/8'] assert tr.protocol_parameters == ProtocolParameters( transfer_id_modulo=2**56, max_nodes=2**UDPTransport.NODE_ID_BIT_LENGTH, mtu=9000, ) assert list(xml.etree.ElementTree.fromstring( tr2.descriptor).itertext()) == ['127.0.0.222/8'] assert tr2.protocol_parameters == ProtocolParameters( transfer_id_modulo=2**56, max_nodes=2**UDPTransport.NODE_ID_BIT_LENGTH, mtu=UDPTransport.DEFAULT_MTU, ) assert tr.sample_statistics() == tr2.sample_statistics( ) == UDPTransportStatistics() payload_single = [_mem('qwertyui'), _mem('01234567') ] * (UDPTransport.DEFAULT_MTU // 16) assert sum(map(len, payload_single)) == UDPTransport.DEFAULT_MTU payload_x3 = (payload_single * 3)[:-1] payload_x3_size_bytes = UDPTransport.DEFAULT_MTU * 3 - 8 assert sum(map(len, payload_x3)) == payload_x3_size_bytes # # Instantiate session objects. # meta = PayloadMetadata(0x_bad_c0ffee_0dd_f00d, 10000) broadcaster = tr2.get_output_session( OutputSessionSpecifier(MessageDataSpecifier(12345), None), meta) assert broadcaster is tr2.get_output_session( OutputSessionSpecifier(MessageDataSpecifier(12345), None), meta) subscriber_promiscuous = tr.get_input_session( InputSessionSpecifier(MessageDataSpecifier(12345), None), meta) assert subscriber_promiscuous is tr.get_input_session( InputSessionSpecifier(MessageDataSpecifier(12345), None), meta) subscriber_selective = tr.get_input_session( InputSessionSpecifier(MessageDataSpecifier(12345), 123), meta) assert subscriber_selective is tr.get_input_session( InputSessionSpecifier(MessageDataSpecifier(12345), 123), meta) server_listener = tr.get_input_session( InputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), None), meta) assert server_listener is tr.get_input_session( InputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), None), meta) server_responder = tr.get_output_session( OutputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 222), meta) assert server_responder is tr.get_output_session( OutputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 222), meta) client_requester = tr2.get_output_session( OutputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), 111), meta) assert client_requester is tr2.get_output_session( OutputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), 111), meta) client_listener = tr2.get_input_session( InputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 111), meta) assert client_listener is tr2.get_input_session( InputSessionSpecifier( ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 111), meta) print('tr :', tr.input_sessions, tr.output_sessions) assert set(tr.input_sessions) == { subscriber_promiscuous, subscriber_selective, server_listener } assert set(tr.output_sessions) == {server_responder} print('tr2:', tr2.input_sessions, tr2.output_sessions) assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {broadcaster, client_requester} assert tr.sample_statistics().demultiplexer[MessageDataSpecifier( 12345)].accepted_datagrams == {} assert tr.sample_statistics().demultiplexer[ServiceDataSpecifier( 444, ServiceDataSpecifier.Role.REQUEST)].accepted_datagrams == {} assert tr2.sample_statistics().demultiplexer[ServiceDataSpecifier( 444, ServiceDataSpecifier.Role.RESPONSE)].accepted_datagrams == {} # # Message exchange test. # assert await broadcaster.send_until( Transfer(timestamp=Timestamp.now(), priority=Priority.LOW, transfer_id=77777, fragmented_payload=payload_single), monotonic_deadline=get_monotonic() + 5.0) rx_transfer = await subscriber_promiscuous.receive_until(get_monotonic() + 5.0) print('PROMISCUOUS SUBSCRIBER TRANSFER:', rx_transfer) assert isinstance(rx_transfer, TransferFrom) assert rx_transfer.priority == Priority.LOW assert rx_transfer.transfer_id == 77777 assert rx_transfer.fragmented_payload == [b''.join(payload_single) ] # type: ignore print('tr :', tr.sample_statistics()) assert tr.sample_statistics().demultiplexer[MessageDataSpecifier( 12345)].accepted_datagrams == { 222: 1 } assert tr.sample_statistics().demultiplexer[ServiceDataSpecifier( 444, ServiceDataSpecifier.Role.REQUEST)].accepted_datagrams == {} print('tr2:', tr2.sample_statistics()) assert tr2.sample_statistics().demultiplexer[ServiceDataSpecifier( 444, ServiceDataSpecifier.Role.RESPONSE)].accepted_datagrams == {} assert None is await subscriber_selective.receive_until(get_monotonic() + 0.1) assert None is await subscriber_promiscuous.receive_until(get_monotonic() + 0.1) assert None is await server_listener.receive_until(get_monotonic() + 0.1) assert None is await client_listener.receive_until(get_monotonic() + 0.1) # # Service exchange test. # assert await client_requester.send_until( Transfer(timestamp=Timestamp.now(), priority=Priority.HIGH, transfer_id=88888, fragmented_payload=payload_x3), monotonic_deadline=get_monotonic() + 5.0) rx_transfer = await server_listener.receive_until(get_monotonic() + 5.0) print('SERVER LISTENER TRANSFER:', rx_transfer) assert isinstance(rx_transfer, TransferFrom) assert rx_transfer.priority == Priority.HIGH assert rx_transfer.transfer_id == 88888 assert len(rx_transfer.fragmented_payload) == 3 assert b''.join(rx_transfer.fragmented_payload) == b''.join(payload_x3) assert None is await subscriber_selective.receive_until(get_monotonic() + 0.1) assert None is await subscriber_promiscuous.receive_until(get_monotonic() + 0.1) assert None is await server_listener.receive_until(get_monotonic() + 0.1) assert None is await client_listener.receive_until(get_monotonic() + 0.1) print('tr :', tr.sample_statistics()) assert tr.sample_statistics().demultiplexer[MessageDataSpecifier( 12345)].accepted_datagrams == { 222: 1 } assert tr.sample_statistics().demultiplexer[ServiceDataSpecifier( 444, ServiceDataSpecifier.Role.REQUEST )].accepted_datagrams == { 222: 3 * 2 } # Deterministic data loss mitigation is enabled, multiplication factor 2 print('tr2:', tr2.sample_statistics()) assert tr2.sample_statistics().demultiplexer[ServiceDataSpecifier( 444, ServiceDataSpecifier.Role.RESPONSE)].accepted_datagrams == {} # # Termination. # assert set(tr.input_sessions) == { subscriber_promiscuous, subscriber_selective, server_listener } assert set(tr.output_sessions) == {server_responder} assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {broadcaster, client_requester} subscriber_promiscuous.close() subscriber_promiscuous.close() # Idempotency. assert set(tr.input_sessions) == {subscriber_selective, server_listener} assert set(tr.output_sessions) == {server_responder} assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {broadcaster, client_requester} broadcaster.close() broadcaster.close() # Idempotency. assert set(tr.input_sessions) == {subscriber_selective, server_listener} assert set(tr.output_sessions) == {server_responder} assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {client_requester} tr.close() tr.close() # Idempotency. tr2.close() tr2.close() # Idempotency. assert not set(tr.input_sessions) assert not set(tr.output_sessions) assert not set(tr2.input_sessions) assert not set(tr2.output_sessions) with pytest.raises(pyuavcan.transport.ResourceClosedError): _ = tr.get_output_session( OutputSessionSpecifier(MessageDataSpecifier(12345), None), meta) with pytest.raises(pyuavcan.transport.ResourceClosedError): _ = tr2.get_input_session( InputSessionSpecifier(MessageDataSpecifier(12345), None), meta)
async def _unittest_udp_transport_ipv4() -> None: from pyuavcan.transport import MessageDataSpecifier, ServiceDataSpecifier, PayloadMetadata, Transfer, TransferFrom from pyuavcan.transport import Priority, Timestamp, InputSessionSpecifier, OutputSessionSpecifier from pyuavcan.transport import ProtocolParameters asyncio.get_running_loop().slow_callback_duration = 5.0 get_monotonic = asyncio.get_event_loop().time with pytest.raises(ValueError): _ = UDPTransport("127.0.0.111", mtu=10) with pytest.raises(ValueError): _ = UDPTransport("127.0.0.111", service_transfer_multiplier=100) tr = UDPTransport("127.0.0.111", mtu=9000) tr2 = UDPTransport("127.0.0.222", service_transfer_multiplier=2) assert tr.local_ip_address == ipaddress.ip_address("127.0.0.111") assert tr2.local_ip_address == ipaddress.ip_address("127.0.0.222") assert tr.loop is asyncio.get_event_loop() assert tr.local_node_id == 111 assert tr2.local_node_id == 222 assert tr.input_sessions == [] assert tr.output_sessions == [] assert "127.0.0.111" in repr(tr) assert tr.protocol_parameters == ProtocolParameters( transfer_id_modulo=2 ** 64, max_nodes=65535, mtu=9000, ) default_mtu = min(UDPTransport.VALID_MTU_RANGE) assert "127.0.0.222" in repr(tr2) assert tr2.protocol_parameters == ProtocolParameters( transfer_id_modulo=2 ** 64, max_nodes=65535, mtu=default_mtu, ) assert tr.sample_statistics() == tr2.sample_statistics() == UDPTransportStatistics() payload_single = [_mem("qwertyui"), _mem("01234567")] * (default_mtu // 16) assert sum(map(len, payload_single)) == default_mtu payload_x3 = (payload_single * 3)[:-1] payload_x3_size_bytes = default_mtu * 3 - 8 assert sum(map(len, payload_x3)) == payload_x3_size_bytes # # Instantiate session objects. # meta = PayloadMetadata(10000) broadcaster = tr2.get_output_session(OutputSessionSpecifier(MessageDataSpecifier(2345), None), meta) assert broadcaster is tr2.get_output_session(OutputSessionSpecifier(MessageDataSpecifier(2345), None), meta) subscriber_promiscuous = tr.get_input_session(InputSessionSpecifier(MessageDataSpecifier(2345), None), meta) assert subscriber_promiscuous is tr.get_input_session(InputSessionSpecifier(MessageDataSpecifier(2345), None), meta) subscriber_selective = tr.get_input_session(InputSessionSpecifier(MessageDataSpecifier(2345), 123), meta) assert subscriber_selective is tr.get_input_session(InputSessionSpecifier(MessageDataSpecifier(2345), 123), meta) server_listener = tr.get_input_session( InputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), None), meta ) assert server_listener is tr.get_input_session( InputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), None), meta ) server_responder = tr.get_output_session( OutputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 222), meta ) assert server_responder is tr.get_output_session( OutputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 222), meta ) client_requester = tr2.get_output_session( OutputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), 111), meta ) assert client_requester is tr2.get_output_session( OutputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST), 111), meta ) client_listener = tr2.get_input_session( InputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 111), meta ) assert client_listener is tr2.get_input_session( InputSessionSpecifier(ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE), 111), meta ) print("tr :", tr.input_sessions, tr.output_sessions) assert set(tr.input_sessions) == {subscriber_promiscuous, subscriber_selective, server_listener} assert set(tr.output_sessions) == {server_responder} print("tr2:", tr2.input_sessions, tr2.output_sessions) assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {broadcaster, client_requester} assert tr.sample_statistics().received_datagrams[MessageDataSpecifier(2345)].accepted_datagrams == {} assert ( tr.sample_statistics() .received_datagrams[ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST)] .accepted_datagrams == {} ) assert ( tr2.sample_statistics() .received_datagrams[ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE)] .accepted_datagrams == {} ) # # Message exchange test. # assert await broadcaster.send( Transfer( timestamp=Timestamp.now(), priority=Priority.LOW, transfer_id=77777, fragmented_payload=payload_single ), monotonic_deadline=get_monotonic() + 5.0, ) rx_transfer = await subscriber_promiscuous.receive(get_monotonic() + 5.0) print("PROMISCUOUS SUBSCRIBER TRANSFER:", rx_transfer) assert isinstance(rx_transfer, TransferFrom) assert rx_transfer.priority == Priority.LOW assert rx_transfer.transfer_id == 77777 assert rx_transfer.fragmented_payload == [b"".join(payload_single)] print("tr :", tr.sample_statistics()) assert tr.sample_statistics().received_datagrams[MessageDataSpecifier(2345)].accepted_datagrams == {222: 1} assert ( tr.sample_statistics() .received_datagrams[ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST)] .accepted_datagrams == {} ) print("tr2:", tr2.sample_statistics()) assert ( tr2.sample_statistics() .received_datagrams[ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE)] .accepted_datagrams == {} ) assert None is await subscriber_selective.receive(get_monotonic() + 0.1) assert None is await subscriber_promiscuous.receive(get_monotonic() + 0.1) assert None is await server_listener.receive(get_monotonic() + 0.1) assert None is await client_listener.receive(get_monotonic() + 0.1) # # Service exchange test. # assert await client_requester.send( Transfer(timestamp=Timestamp.now(), priority=Priority.HIGH, transfer_id=88888, fragmented_payload=payload_x3), monotonic_deadline=get_monotonic() + 5.0, ) rx_transfer = await server_listener.receive(get_monotonic() + 5.0) print("SERVER LISTENER TRANSFER:", rx_transfer) assert isinstance(rx_transfer, TransferFrom) assert rx_transfer.priority == Priority.HIGH assert rx_transfer.transfer_id == 88888 assert len(rx_transfer.fragmented_payload) == 3 assert b"".join(rx_transfer.fragmented_payload) == b"".join(payload_x3) assert None is await subscriber_selective.receive(get_monotonic() + 0.1) assert None is await subscriber_promiscuous.receive(get_monotonic() + 0.1) assert None is await server_listener.receive(get_monotonic() + 0.1) assert None is await client_listener.receive(get_monotonic() + 0.1) print("tr :", tr.sample_statistics()) assert tr.sample_statistics().received_datagrams[MessageDataSpecifier(2345)].accepted_datagrams == {222: 1} assert tr.sample_statistics().received_datagrams[ ServiceDataSpecifier(444, ServiceDataSpecifier.Role.REQUEST) ].accepted_datagrams == { 222: 3 * 2 } # Deterministic data loss mitigation is enabled, multiplication factor 2 print("tr2:", tr2.sample_statistics()) assert ( tr2.sample_statistics() .received_datagrams[ServiceDataSpecifier(444, ServiceDataSpecifier.Role.RESPONSE)] .accepted_datagrams == {} ) # # Termination. # assert set(tr.input_sessions) == {subscriber_promiscuous, subscriber_selective, server_listener} assert set(tr.output_sessions) == {server_responder} assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {broadcaster, client_requester} subscriber_promiscuous.close() subscriber_promiscuous.close() # Idempotency. assert set(tr.input_sessions) == {subscriber_selective, server_listener} assert set(tr.output_sessions) == {server_responder} assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {broadcaster, client_requester} broadcaster.close() broadcaster.close() # Idempotency. assert set(tr.input_sessions) == {subscriber_selective, server_listener} assert set(tr.output_sessions) == {server_responder} assert set(tr2.input_sessions) == {client_listener} assert set(tr2.output_sessions) == {client_requester} tr.close() tr.close() # Idempotency. tr2.close() tr2.close() # Idempotency. assert not set(tr.input_sessions) assert not set(tr.output_sessions) assert not set(tr2.input_sessions) assert not set(tr2.output_sessions) with pytest.raises(pyuavcan.transport.ResourceClosedError): _ = tr.get_output_session(OutputSessionSpecifier(MessageDataSpecifier(2345), None), meta) with pytest.raises(pyuavcan.transport.ResourceClosedError): _ = tr2.get_input_session(InputSessionSpecifier(MessageDataSpecifier(2345), None), meta) await asyncio.sleep(1) # Let all pending tasks finalize properly to avoid stack traces in the output.