From 4428ccfe596f977c9ba02bc5bbe68485f6b67b3b Mon Sep 17 00:00:00 2001 From: Mike Kinney Date: Wed, 22 Dec 2021 16:15:16 -0800 Subject: [PATCH] add unit tests for getMyUser(), getLongName(), getShortName(), and sendPacket() --- meshtastic/mesh_interface.py | 2 + meshtastic/tests/conftest.py | 45 +++++++++ meshtastic/tests/test_mesh_interface.py | 129 ++++++++++++++++++++++++ 3 files changed, 176 insertions(+) diff --git a/meshtastic/mesh_interface.py b/meshtastic/mesh_interface.py index 844e729..92581c5 100644 --- a/meshtastic/mesh_interface.py +++ b/meshtastic/mesh_interface.py @@ -103,6 +103,7 @@ class MeshInterface: rows = [] if self.nodes: + logging.debug(f'self.nodes:{self.nodes}') for node in self.nodes.values(): if not includeSelf and node['num'] == self.localNode.nodeNum: continue @@ -351,6 +352,7 @@ class MeshInterface: """Get info about my node.""" if self.myInfo is None: return None + logging.debug(f'self.nodesByNum:{self.nodesByNum}') return self.nodesByNum.get(self.myInfo.my_node_num) def getMyUser(self): diff --git a/meshtastic/tests/conftest.py b/meshtastic/tests/conftest.py index 3bcaecb..38b2554 100644 --- a/meshtastic/tests/conftest.py +++ b/meshtastic/tests/conftest.py @@ -3,8 +3,10 @@ import argparse import pytest +from unittest.mock import patch, MagicMock from meshtastic.__main__ import Globals +from ..mesh_interface import MeshInterface @pytest.fixture def reset_globals(): @@ -13,3 +15,46 @@ def reset_globals(): parser = argparse.ArgumentParser() Globals.getInstance().reset() Globals.getInstance().set_parser(parser) + + +@pytest.fixture +def iface_with_nodes(): + """Fixture to setup some nodes.""" + nodesById = { + '!9388f81c': { + 'num': 2475227164, + 'user': { + 'id': '!9388f81c', + 'longName': 'Unknown f81c', + 'shortName': '?1C', + 'macaddr': 'RBeTiPgc', + 'hwModel': 'TBEAM' + }, + 'position': {}, + 'lastHeard': 1640204888 + } + } + + nodesByNum = { + 2475227164: { + 'num': 2475227164, + 'user': { + 'id': '!9388f81c', + 'longName': 'Unknown f81c', + 'shortName': '?1C', + 'macaddr': 'RBeTiPgc', + 'hwModel': 'TBEAM' + }, + 'position': { + 'time': 1640206266 + }, + 'lastHeard': 1640206266 + } + } + iface = MeshInterface(noProto=True) + iface.nodes = nodesById + iface.nodesByNum = nodesByNum + myInfo = MagicMock() + iface.myInfo = myInfo + iface.myInfo.my_node_num = 2475227164 + return iface diff --git a/meshtastic/tests/test_mesh_interface.py b/meshtastic/tests/test_mesh_interface.py index 5888fd0..2bb865b 100644 --- a/meshtastic/tests/test_mesh_interface.py +++ b/meshtastic/tests/test_mesh_interface.py @@ -16,6 +16,29 @@ from ..__init__ import LOCAL_ADDR, BROADCAST_ADDR def test_MeshInterface(capsys, reset_globals): """Test that we can instantiate a MeshInterface""" iface = MeshInterface(noProto=True) + anode = Node('foo', 'bar') + + nodes = { + '!9388f81c': { + 'num': 2475227164, + 'user': { + 'id': '!9388f81c', + 'longName': 'Unknown f81c', + 'shortName': '?1C', + 'macaddr': 'RBeTiPgc', + 'hwModel': 'TBEAM' + }, + 'position': {}, + 'lastHeard': 1640204888 + } + } + + iface.nodesByNum = {1: anode } + iface.nodes = nodes + + myInfo = MagicMock() + iface.myInfo = myInfo + iface.showInfo() iface.localNode.showInfo() iface.showNodes() @@ -30,6 +53,62 @@ def test_MeshInterface(capsys, reset_globals): assert err == '' +@pytest.mark.unit +def test_getMyUser_and_LongName_and_ShortName(reset_globals): + """Test getMyUser(), getLongName(), and getShortName(). + Note: These should be separate tests, but feeling lazy. + Could move these nodes out to a fixture and + create smaller tests. + """ + + nodesById = { + '!9388f81c': { + 'num': 2475227164, + 'user': { + 'id': '!9388f81c', + 'longName': 'Unknown f81c', + 'shortName': '?1C', + 'macaddr': 'RBeTiPgc', + 'hwModel': 'TBEAM' + }, + 'position': {}, + 'lastHeard': 1640204888 + } + } + + nodesByNum = { + 2475227164: { + 'num': 2475227164, + 'user': { + 'id': '!9388f81c', + 'longName': 'Unknown f81c', + 'shortName': '?1C', + 'macaddr': 'RBeTiPgc', + 'hwModel': 'TBEAM' + }, + 'position': { + 'time': 1640206266 + }, + 'lastHeard': 1640206266 + } + } + + iface = MeshInterface(noProto=True) + iface.nodes = nodesById + iface.nodesByNum = nodesByNum + myInfo = MagicMock() + iface.myInfo = myInfo + iface.myInfo.my_node_num = 2475227164 + myuser = iface.getMyUser() + print(f'myuser:{myuser}') + assert myuser is not None + assert myuser["id"] == '!9388f81c' + mylongname = iface.getLongName() + assert mylongname == 'Unknown f81c' + myshortname = iface.getShortName() + assert myshortname == '?1C' + + @pytest.mark.unit def test_handlePacketFromRadio_no_from(capsys, reset_globals): """Test _handlePacketFromRadio with no 'from' in the mesh packet.""" @@ -309,6 +388,16 @@ def test_sendPacket_with_destination_as_int(caplog, reset_globals): assert re.search(r'Sending packet', caplog.text, re.MULTILINE) +@pytest.mark.unit +def test_sendPacket_with_destination_starting_with_a_bang(caplog, reset_globals): + """Test _sendPacket() with int as a destination""" + iface = MeshInterface(noProto=True) + with caplog.at_level(logging.DEBUG): + meshPacket = mesh_pb2.MeshPacket() + iface._sendPacket(meshPacket, destinationId='!1234') + assert re.search(r'Sending packet', caplog.text, re.MULTILINE) + + @pytest.mark.unit def test_sendPacket_with_destination_as_BROADCAST_ADDR(caplog, reset_globals): """Test _sendPacket() with BROADCAST_ADDR as a destination""" @@ -345,6 +434,31 @@ def test_sendPacket_with_destination_as_LOCAL_ADDR_with_myInfo(caplog, reset_glo assert re.search(r'Sending packet', caplog.text, re.MULTILINE) +@pytest.mark.unit +def test_sendPacket_with_destination_is_blank_with_nodes(capsys, reset_globals, iface_with_nodes): + """Test _sendPacket() with '' as a destination with myInfo""" + iface = iface_with_nodes + meshPacket = mesh_pb2.MeshPacket() + with pytest.raises(SystemExit) as pytest_wrapped_e: + iface._sendPacket(meshPacket, destinationId='') + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + out, err = capsys.readouterr() + assert re.match(r'Warning: NodeId not found in DB', out, re.MULTILINE) + assert err == '' + + +@pytest.mark.unit +def test_sendPacket_with_destination_is_blank_without_nodes(caplog, reset_globals, iface_with_nodes): + """Test _sendPacket() with '' as a destination with myInfo""" + iface = iface_with_nodes + iface.nodes = None + meshPacket = mesh_pb2.MeshPacket() + with caplog.at_level(logging.WARNING): + iface._sendPacket(meshPacket, destinationId='') + assert re.search(r'Warning: There were no self.nodes.', caplog.text, re.MULTILINE) + + @pytest.mark.unit def test_getMyNodeInfo(reset_globals): """Test getMyNodeInfo()""" @@ -357,3 +471,18 @@ def test_getMyNodeInfo(reset_globals): iface.myInfo.my_node_num = 1 myinfo = iface.getMyNodeInfo() assert myinfo == anode + + +@pytest.mark.unit +def test_generatePacketId(capsys, reset_globals): + """Test _generatePacketId() when no currentPacketId (not connected)""" + iface = MeshInterface(noProto=True) + # not sure when this condition would ever happen... but we can simulate it + iface.currentPacketId = None + assert iface.currentPacketId is None + with pytest.raises(Exception) as pytest_wrapped_e: + iface._generatePacketId() + out, err = capsys.readouterr() + assert re.search(r'Not connected yet, can not generate packet', out, re.MULTILINE) + assert err == '' + assert pytest_wrapped_e.type == Exception