def test_hash_frame(): """ Test that _hash_frame returns a consistent result regardless of digipeaters """ hash1 = APRSInterface._hash_frame( APRSMessageFrame(destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123, repeaters=['WIDE2-1', 'WIDE1-1'])) hash2 = APRSInterface._hash_frame( APRSMessageFrame(destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123, repeaters=['VK4RZB*', 'WIDE1-1'])) hash3 = APRSInterface._hash_frame( APRSMessageFrame(destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123, repeaters=['VK4RZB*', 'VK4RZA*'])) # These should all be the same eq_(hash1, hash2) eq_(hash1, hash3)
def test_hash_frame_mismatch_payload(): """ Test that _hash_frame returns different hashes for mismatching source """ hash1 = APRSInterface._hash_frame( APRSMessageFrame( destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing 1', msgid=123, repeaters=['WIDE2-1','WIDE1-1'] ) ) hash2 = APRSInterface._hash_frame( APRSMessageFrame( destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing 2', msgid=123, repeaters=['WIDE2-1','WIDE1-1'] ) ) # These should not be the same assert hash1 != hash2
def test_message_frame_malformed_delim(): """ Test the message frame decoder will reject malformed message delimiter """ try: APRSMessageFrame.decode(None, ':123456789xThis is not valid', None) except ValueError as e: eq_(str(e), "Not a message frame: ':123456789xThis is not valid'")
def test_message_frame_malformed_start(): """ Test the message frame decoder will reject malformed start of message. """ try: APRSMessageFrame.decode(None, 'x123456789:This is not valid', None) except ValueError as e: eq_(str(e), "Not a message frame: 'x123456789:This is not valid'")
def test_message_frame_copy(): """ Test we can copy a message frame """ msg = APRSMessageFrame(destination='APRS', source='VK4MSL', addressee='TEST', message='Station under test', msgid=12345) msgcopy = msg.copy() assert msg is not msgcopy eq_(to_hex(bytes(msgcopy)), to_hex(bytes(msg)))
def test_test_or_add_frame_expired(): """ Test that _test_or_add_frame returns False for expired repeats """ frame = APRSMessageFrame( destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123, repeaters=['WIDE2-1','WIDE1-1'] ) framedigest = APRSInterface._hash_frame(frame) ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') # Inject the frame expiry expiry_time = aprsint._loop.time() - 1 aprsint._msg_expiry[framedigest] = expiry_time # Try it out res = aprsint._test_or_add_frame(frame) # We should get 'False' as the response eq_(res, False) # The expiry time should be at least 25 seconds. eq_(len(aprsint._msg_expiry), 1) assert_greater(aprsint._msg_expiry.get(framedigest, 0), ax25int._loop.time() + 25) # A clean-up should have been scheduled. eq_(len(ax25int._loop.calls), 1) (_, callfunc) = ax25int._loop.calls.pop(0) eq_(callfunc, aprsint._schedule_dedup_cleanup)
def test_test_or_add_frame_repeat(): """ Test that _test_or_add_frame returns True for un-expired repeats """ frame = APRSMessageFrame( destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123, repeaters=['WIDE2-1','WIDE1-1'] ) framedigest = APRSInterface._hash_frame(frame) ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') # Inject the frame expiry expiry_time = aprsint._loop.time() + 1 aprsint._msg_expiry[framedigest] = expiry_time # Try it out res = aprsint._test_or_add_frame(frame) # We should get 'False' as the response eq_(res, True) # Expiry should not have changed eq_(len(aprsint._msg_expiry), 1) eq_(aprsint._msg_expiry[framedigest], expiry_time) # Nothing further should be done. eq_(len(ax25int._loop.calls), 0)
def test_transmit_exception(): """ Test that transmit swallows exceptions. """ ax25int = DummyAX25Interface() # Stub the transmit so it fails calls = [] def stub(*args): calls.append(args) raise RuntimeError('Oopsie') ax25int.transmit = stub aprsint = APRSInterface(ax25int, 'VK4MSL-10') aprsint.transmit( APRSMessageFrame( destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123 ) ) # Transmit should have been called eq_(len(calls), 1)
def test_message_frame_get_msg(): """ Test the message frame will return the message enclosed """ msg = APRSMessageFrame(destination='APRS', source='VK4MSL', addressee='TEST', message='Station under test', msgid=12345) eq_(msg.message, 'Station under test')
def test_message_encode_noreplyack(): """ Test we can encode without reply-ack. """ msg = APRSMessageFrame(destination='APRS', source='VK4MSL', addressee='VK4BWI', message='Test without "reply-ack" capability', msgid='321') eq_(msg.payload, b':VK4BWI :Test without "reply-ack" capability{321')
def test_message_encode_replyack_capable(): """ Test we can encode a reply-ack flag. """ msg = APRSMessageFrame(destination='APRS', source='VK4MSL', addressee='VK4BWI', message='Test announcing "reply-ack" capability', msgid='321', replyack=True) eq_(msg.payload, b':VK4BWI :Test announcing "reply-ack" capability{321}')
def test_message_frame_bad_msgid(): """ Test the message frame constructor rejects too-big message IDs """ try: APRSMessageFrame(destination='APRS', source='VK4MSL', addressee='BREAK', message='Break this!', msgid=123456) except ValueError as e: eq_(str(e), "message ID '123456' too long")
def test_message_encode_replyack_reply(): """ Test we can encode a reply-ack reply. """ msg = APRSMessageFrame(destination='APRS', source='VK4MSL', addressee='VK4BWI', message='Test reply using "reply-ack" capability', msgid='321', replyack='567') eq_(msg.payload, b':VK4BWI :Test reply using "reply-ack" capability{321}567')
def test_send_response_oneshot(): """ Test that send_response ignores one-shot messages. """ ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') aprsint.send_response( APRSMessageFrame(destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=None)) # Nothing should be sent eq_(len(ax25int.transmitted), 0)
def test_send_message_replyack_notreplyack(): """ Test that send_message in confirmable mode generates a message handler. """ ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') replymsg = APRSMessageFrame(destination='APRS', source='VK4MDL-7', addressee='VK4MSL-7', message='Hello', msgid='123', replyack=False) try: aprsint.send_message('VK4MDL-7', 'Hi', oneshot=False, replyack=replymsg) except ValueError as e: eq_(str(e), 'replyack is not a reply-ack message')
def test_send_response_rej(): """ Test that send_response with ack=False sends rejection. """ ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') aprsint.send_response(APRSMessageFrame(destination='VK4BWI-2', source='VK4MSL-10', addressee='VK4BWI-2', message=b'testing', msgid=123), ack=False) # The APRS message handler will have tried sending the message eq_(len(ax25int.transmitted), 1) frame = ax25int.transmitted.pop(0) # Frame is a APRS message rejection frame assert isinstance(frame, APRSMessageFrame) eq_(frame.payload, b':VK4MSL-10:rej123')
def test_send_message_replyack(): """ Test that send_message with a replyack message sets replyack. """ ax25int = DummyAX25Interface() aprsint = APRSInterface(ax25int, 'VK4MSL-10') replymsg = APRSMessageFrame( destination='APRS', source='VK4MDL-7', addressee='VK4MSL-7', message='Hello', msgid='123', replyack=True ) res = aprsint.send_message( 'VK4MDL-7', 'Hi', oneshot=False, replyack=replymsg ) # We got back a handler class assert isinstance(res, APRSMessageHandler) # That message handler should be registered with the interface eq_(len(aprsint._pending_msg), 1) assert res.msgid in aprsint._pending_msg assert_is(aprsint._pending_msg[res.msgid], res) # The APRS message handler will have tried sending the message eq_(len(ax25int.transmitted), 1) frame = ax25int.transmitted.pop(0) # Frame is a APRS message frame assert isinstance(frame, APRSMessageFrame) # Frame has reply-ACK set eq_(frame.replyack, '123') # Message handler is in 'SEND' state eq_(res.state, APRSMessageHandler.HandlerState.SEND)