From 8bf1dd6dcb992dea655e892e3ce5ec8c63d1e595 Mon Sep 17 00:00:00 2001 From: Mike Kinney Date: Tue, 21 Dec 2021 22:13:02 -0800 Subject: [PATCH] add unit tests for showChannels(), deleteChannel(), getChannelByName(), getDisabledChannel(), getAdminChannelIndex(), turnOffEncryptionOnPrimaryChannel(), and writeConfig() --- meshtastic/node.py | 2 + meshtastic/tests/test_node.py | 275 ++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) diff --git a/meshtastic/node.py b/meshtastic/node.py index 4b682b3..92ce433 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -28,7 +28,9 @@ class Node: """Show human readable description of our channels.""" print("Channels:") if self.channels: + logging.debug(f'self.channels:{self.channels}') for c in self.channels: + #print('c.settings.psk:', c.settings.psk) cStr = stripnl(MessageToJson(c.settings)) # only show if there is no psk (meaning disabled channel) if c.settings.psk: diff --git a/meshtastic/tests/test_node.py b/meshtastic/tests/test_node.py index 528bead..ff1b288 100644 --- a/meshtastic/tests/test_node.py +++ b/meshtastic/tests/test_node.py @@ -9,6 +9,7 @@ import pytest from ..node import Node from ..serial_interface import SerialInterface from ..admin_pb2 import AdminMessage +from ..channel_pb2 import Channel @pytest.mark.unit @@ -139,3 +140,277 @@ def test_setURL_valid_URL_but_no_settings(caplog): anode.setURL(url) assert pytest_wrapped_e.type == SystemExit assert pytest_wrapped_e.value.code == 1 + + +@pytest.mark.unit +def test_showChannels(capsys): + """Test showChannels""" + anode = Node('foo', 'bar') + + # primary channel + # role: 0=Disabled, 1=Primary, 2=Secondary + # modem_config: 0-5 + # role: 0=Disabled, 1=Primary, 2=Secondary + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=2) + channel2.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84' + channel2.settings.name = 'testing' + + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + anode.showChannels() + out, err = capsys.readouterr() + assert re.search(r'Channels:', out, re.MULTILINE) + # primary channel + assert re.search(r'Primary channel URL', out, re.MULTILINE) + assert re.search(r'PRIMARY psk=default ', out, re.MULTILINE) + assert re.search(r'"modemConfig": "Bw125Cr48Sf4096"', out, re.MULTILINE) + assert re.search(r'"psk": "AQ=="', out, re.MULTILINE) + # secondary channel + assert re.search(r'SECONDARY psk=secret ', out, re.MULTILINE) + assert re.search(r'"psk": "ipR5DsbJHjWREkCmMKi0M4cA8ksO539Bes31sJAwqDQ="', out, re.MULTILINE) + assert err == '' + + +@pytest.mark.unit +def test_deleteChannel_try_to_delete_primary_channel(capsys): + """Try to delete primary channel.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + # no secondary channels + channel2 = Channel(index=2, role=0) + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + with pytest.raises(SystemExit) as pytest_wrapped_e: + anode.deleteChannel(0) + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + out, err = capsys.readouterr() + assert re.search(r'Warning: Only SECONDARY channels can be deleted', out, re.MULTILINE) + assert err == '' + + +@pytest.mark.unit +def test_getChannelByName(capsys): + """Get a channel by the name.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=2) + channel2.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84' + channel2.settings.name = 'admin' + + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + ch = anode.getChannelByName('admin') + assert ch.index == 2 + + +@pytest.mark.unit +def test_getChannelByName_invalid_name(capsys): + """Get a channel by the name but one that is not present.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=2) + channel2.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84' + channel2.settings.name = 'admin' + + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + ch = anode.getChannelByName('testing') + assert ch is None + + +@pytest.mark.unit +def test_getDisabledChannel(capsys): + """Get the first disabled channel.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=2) + channel2.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84' + channel2.settings.name = 'testingA' + + channel3 = Channel(index=3, role=2) + channel3.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84' + channel3.settings.name = 'testingB' + + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + ch = anode.getDisabledChannel() + assert ch.index == 4 + + +@pytest.mark.unit +def test_getDisabledChannel_where_all_channels_are_used(capsys): + """Get the first disabled channel.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=2) + channel3 = Channel(index=3, role=2) + channel4 = Channel(index=4, role=2) + channel5 = Channel(index=5, role=2) + channel6 = Channel(index=6, role=2) + channel7 = Channel(index=7, role=2) + channel8 = Channel(index=8, role=2) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + ch = anode.getDisabledChannel() + assert ch is None + + +@pytest.mark.unit +def test_getAdminChannelIndex(capsys): + """Get the 'admin' channel index.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=2) + channel2.settings.psk = b'\x8a\x94y\x0e\xc6\xc9\x1e5\x91\x12@\xa60\xa8\xb43\x87\x00\xf2K\x0e\xe7\x7fAz\xcd\xf5\xb0\x900\xa84' + channel2.settings.name = 'admin' + + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + i = anode._getAdminChannelIndex() + assert i == 2 + + +@pytest.mark.unit +def test_getAdminChannelIndex_when_no_admin_named_channel(capsys): + """Get the 'admin' channel when there is not one.""" + anode = Node('foo', 'bar') + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + channel1.settings.psk = b'\x01' + + channel2 = Channel(index=2, role=0) + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + i = anode._getAdminChannelIndex() + assert i == 0 + + +# TODO: should we check if we need to turn it off? +@pytest.mark.unit +def test_turnOffEncryptionOnPrimaryChannel(capsys): + """Turn off encryption when there is a psk.""" + #iface = MagicMock(autospec=SerialInterface) + anode = Node('foo', 'bar', noProto=True) + + channel1 = Channel(index=1, role=1) + channel1.settings.modem_config = 3 + # value from using "--ch-set psk 0x1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b " + channel1.settings.psk = b'\x1a\x1a\x1a\x1a++++\x1a\x1a\x1a\x1a++++\x1a\x1a\x1a\x1a++++\x1a\x1a\x1a\x1a++++' + + channel2 = Channel(index=2, role=0) + channel3 = Channel(index=3, role=0) + channel4 = Channel(index=4, role=0) + channel5 = Channel(index=5, role=0) + channel6 = Channel(index=6, role=0) + channel7 = Channel(index=7, role=0) + channel8 = Channel(index=8, role=0) + + channels = [ channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8 ] + + anode.channels = channels + anode.turnOffEncryptionOnPrimaryChannel() + out, err = capsys.readouterr() + assert re.search(r'Writing modified channels to device', out) + assert err == '' + + +@pytest.mark.unit +def test_writeConfig_with_no_radioConfig(capsys): + """Test writeConfig with no radioConfig.""" + #iface = MagicMock(autospec=SerialInterface) + anode = Node('foo', 'bar', noProto=True) + + with pytest.raises(SystemExit) as pytest_wrapped_e: + anode.writeConfig() + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 1 + out, err = capsys.readouterr() + assert re.search(r'Error: No RadioConfig has been read', out) + assert err == ''