def test_decode_message_replyack_reply(): """ Test the decode routine can recognise a message frame sent as a reply-ack. """ frame = AX25UnnumberedInformationFrame(destination='APZAIO', source='VK4MSL-7', pid=0xf0, payload=b':VK4MDL-7 :Hi{01}45') decoded = APRSFrame.decode(frame, logging.getLogger('decoder')) assert_is_not(decoded, frame) assert isinstance(decoded, APRSMessageFrame) eq_(decoded.replyack, '45') eq_(decoded.msgid, '01')
def test_transmit_waits_if_cts_reset(): """ Test the interface waits if CTS timer is reset. """ my_port = DummyKISS() my_frame = AX25UnnumberedInformationFrame( destination='VK4BWI-4', source='VK4MSL', pid=0xf0, payload=b'testing') transmit_future = Future() my_interface = AX25Interface(my_port, cts_delay=0.250) def _on_transmit(interface, frame, **kwargs): try: eq_(len(kwargs), 0, msg='Too many arguments') assert_is(interface, my_interface, msg='Wrong interface') eq_(bytes(frame), bytes(my_frame), msg='Wrong frame') transmit_future.set_result(None) except Exception as e: transmit_future.set_exception(e) def _on_timeout(): transmit_future.set_exception(AssertionError('Timed out')) # The time before transmission time_before = time.monotonic() # Set a timeout get_event_loop().call_later(1.0, _on_timeout) # Send the message my_interface.transmit(my_frame, _on_transmit) # Whilst that is pending, call reset_cts, this should delay transmission my_interface._reset_cts() yield from transmit_future eq_(len(my_port.sent), 1) (send_time, sent_frame) = my_port.sent.pop(0) eq_(bytes(sent_frame), bytes(my_frame)) assert_less((time.monotonic() - send_time), 0.05) assert_greater(send_time - time_before, 0.25) assert_less(send_time - time_before, 1.05)
def test_transmit_sends_if_not_expired(): """ Test the interface sends frame if not expired. """ my_port = DummyKISS() my_frame = AX25UnnumberedInformationFrame( destination='VK4BWI-4', source='VK4MSL', pid=0xf0, payload=b'testing') my_frame.deadline = time.time() + 3600.0 transmit_future = Future() my_interface = AX25Interface(my_port) # Override clear to send expiry my_interface._cts_expiry = 0 def _on_transmit(interface, frame, **kwargs): try: eq_(len(kwargs), 0, msg='Too many arguments') assert_is(interface, my_interface, msg='Wrong interface') eq_(bytes(frame), bytes(my_frame), msg='Wrong frame') transmit_future.set_result(None) except Exception as e: transmit_future.set_exception(e) def _on_timeout(): transmit_future.set_exception(AssertionError('Timed out')) # The time before transmission time_before = time.monotonic() # Set a timeout get_event_loop().call_later(1.0, _on_timeout) # Send the message my_interface.transmit(my_frame, _on_transmit) yield from transmit_future eq_(len(my_port.sent), 1) (send_time, sent_frame) = my_port.sent.pop(0) eq_(bytes(sent_frame), bytes(my_frame)) assert_less((time.monotonic() - send_time), 0.05) assert_less((send_time - time_before), 0.05)
def test_encode_ui(): """ Test that we can encode a UI frame. """ frame = AX25UnnumberedInformationFrame(destination='VK4BWI', source='VK4MSL', cr=True, pid=0xf0, payload=b'This is a test') hex_cmp( bytes(frame), 'ac 96 68 84 ae 92 e0' # Destination 'ac 96 68 9a a6 98 61' # Source '03' # Control 'f0' # PID '54 68 69 73 20 69 73 20 61 20 74 65 73 74' # Payload )
def test_receive_re_filter(): """ Test matching messages can trigger regex filters (without SSID). """ my_port = DummyKISS() unmatched_filter_received = [] my_frame = AX25UnnumberedInformationFrame(destination='VK4BWI-4', source='VK4MSL', pid=0xf0, payload=b'testing') receive_future = Future() my_interface = AX25Interface(my_port) def _on_receive_match(interface, frame, match, **kwargs): try: eq_(len(kwargs), 0, msg='Too many arguments') assert_is(interface, my_interface, msg='Wrong interface') eq_(bytes(frame), bytes(my_frame), msg='Wrong frame') receive_future.set_result(None) except Exception as e: receive_future.set_exception(e) def _on_receive_nomatch(**kwargs): unmatched_filter_received.append(kwargs) def _on_timeout(): receive_future.set_exception(AssertionError('Timed out')) # This should match my_interface.bind(_on_receive_match, r'^VK4[BR]WI$', ssid=None, regex=True) # This should not match my_interface.bind(_on_receive_nomatch, r'^VK4[AZ]WI$', ssid=None, regex=True) # Set a timeout get_event_loop().call_later(1.0, _on_timeout) # Pass in a message my_port.received.emit(frame=bytes(my_frame)) yield from receive_future eq_(len(unmatched_filter_received), 0)
def test_rx_irrelevant(): """ Test the digipeater module ignores irrelevant frames. """ interface = DummyAPRSInterface() digipeater = APRSDigipeater() digipeater.connect(interface) interface.received_msg.emit(interface=interface, frame=AX25UnnumberedInformationFrame( destination='VK4MSL-1', source='VK4MSL-2', repeaters=['VK4RZA', 'VK4RZB'], pid=0xff, payload=b'testing')) # This should have been dropped eq_(len(interface.transmitted), 0)
def test_on_receive_sol_replyack(): """ Test _on_receive of solicited reply-ack addressed to station. """ # Create a frame frame = AX25UnnumberedInformationFrame( destination='APZAIO', source='VK4BWI-2', pid=0xf0, payload=b':VK4MSL-10:testing{356}123', repeaters=['WIDE2-1','WIDE1-1'] ) # Create our interface ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') # Inject a message handler for the message ID handler = DummyMessageHandler() aprsint._pending_msg['123'] = handler # Now pass the frame in as if it were just received aprsint._on_receive(frame) # There should be four calls made, one to our deduplication clean-up, the # second to our superclass, the third to the handler's _on_response method # and finally the incoming message should be emitted like a normal message. eq_(len(ax25int._loop.calls), 4) (_, callfunc) = ax25int._loop.calls.pop(0) eq_(callfunc, aprsint._schedule_dedup_cleanup) (_, callfunc) = ax25int._loop.calls.pop(0) assert isinstance(callfunc, partial) eq_(callfunc.func, super(APRSInterface, aprsint)._on_receive) (_, callfunc, msg) = ax25int._loop.calls.pop(0) eq_(callfunc, handler._on_response) eq_(bytes(frame), bytes(msg)) # The message should also have been treated as a new incoming message. (_, callfunc) = ax25int._loop.calls.pop(0) assert isinstance(callfunc, partial) eq_(callfunc.func, aprsint.received_addressed_msg.emit)
def test_reception_resets_cts(): """ Check the clear-to-send expiry is updated with received traffic. """ my_port = DummyKISS() my_frame = AX25UnnumberedInformationFrame(destination='VK4BWI', source='VK4MSL', pid=0xf0, payload=b'testing') my_interface = AX25Interface(my_port) cts_before = my_interface._cts_expiry # Pass in a message my_port.received.emit(frame=bytes(my_frame)) cts_after = my_interface._cts_expiry assert_less(cts_before, cts_after) assert_greater(cts_after, time.monotonic())
def test_rx_hybridpath(): """ Test the digipeater module handles typical APRS paths. """ interface = DummyAPRSInterface() digipeater = APRSDigipeater() digipeater.connect(interface) interface.received_msg.emit(interface=interface, frame=AX25UnnumberedInformationFrame( destination='VK4MSL-1', source='VK4MSL-2', repeaters=['WIDE1-1', 'WIDE2-2'], pid=0xff, payload=b'testing')) # This should have been digipeated eq_(len(interface.transmitted), 1) frame = interface.transmitted.pop() eq_(str(frame.header.repeaters), 'VK4MSL-10*,WIDE2-2')
def test_rx_nexthop(): """ Test the digipeater module appends the correct WIDEn-N next hop. """ interface = DummyAPRSInterface() digipeater = APRSDigipeater() digipeater.connect(interface) interface.received_msg.emit(interface=interface, frame=AX25UnnumberedInformationFrame( destination='VK4MSL-1', source='VK4MSL-2', repeaters=['WIDE3-3'], pid=0xff, payload=b'testing')) # This should have been digipeated eq_(len(interface.transmitted), 1) frame = interface.transmitted.pop() eq_(str(frame.header.repeaters), 'VK4MSL-10*,WIDE3-2')
def test_ui_copy(): """ Test we can make a copy of a unnumbered information frame. """ frame = AX25UnnumberedInformationFrame(destination='VK4BWI', source='VK4MSL', cr=True, pid=0xf0, payload=b'This is a test') framecopy = frame.copy() assert framecopy is not frame hex_cmp( bytes(framecopy), 'ac 96 68 84 ae 92 e0' # Destination 'ac 96 68 9a a6 98 61' # Source '03' # Control 'f0' # PID '54 68 69 73 20 69 73 20 61 20 74 65 73 74' # Payload )
def test_rx_selftodigi_first(): """ Test the digipeater module digipeats when own call is first. """ interface = DummyAPRSInterface() digipeater = APRSDigipeater() digipeater.connect(interface) interface.received_msg.emit(interface=interface, frame=AX25UnnumberedInformationFrame( destination='VK4MSL-1', source='VK4MSL-2', repeaters=['VK4MSL-10', 'VK4RZB'], pid=0xff, payload=b'testing')) # This should have been digipeated eq_(len(interface.transmitted), 1) frame = interface.transmitted.pop() # It should be passed through VK4MSL-10. eq_(str(frame.header.repeaters), 'VK4MSL-10*,VK4RZB')
def test_transmit_cancel(): """ Test that pending messages can be cancelled. """ my_port = DummyKISS() my_frame = AX25UnnumberedInformationFrame(destination='VK4BWI-4', source='VK4MSL', pid=0xf0, payload=b'testing') my_interface = AX25Interface(my_port) # Send the message my_interface.transmit(my_frame) # Cancel it! my_interface.cancel_transmit(my_frame) # Wait a second yield from sleep(1) # Nothing should have been sent. eq_(len(my_port.sent), 0)