Merge pull request #153 from mkinney/even_more_unit_tests

Even more unit tests
This commit is contained in:
mkinney
2021-12-09 16:33:30 -08:00
committed by GitHub
8 changed files with 120 additions and 33 deletions

View File

@@ -16,15 +16,12 @@ from .tcp_interface import TCPInterface
from .ble_interface import BLEInterface
from . import test, remote_hardware
from . import portnums_pb2, channel_pb2, mesh_pb2, radioconfig_pb2
from . import tunnel
from .util import support_info, our_exit, genPSK256, fromPSK, fromStr
from .globals import Globals
"""We only import the tunnel code if we are on a platform that can run it"""
have_tunnel = platform.system() == 'Linux'
channelIndex = 0
def onReceive(packet, interface):
"""Callback invoked when a packet arrives"""
@@ -131,9 +128,6 @@ def setPref(attributes, name, valStr):
print(f"Can't set {name} due to {ex}")
targetNode = None
def onConnected(interface):
"""Callback invoked when we connect to a radio"""
closeNow = False # Should we drop the connection after we finish?
@@ -145,9 +139,10 @@ def onConnected(interface):
def getNode():
"""This operation could be expensive, so we try to cache the results"""
global targetNode
targetNode = our_globals.get_target_node()
if not targetNode:
targetNode = interface.getNode(args.destOrLocal)
our_globals.set_target_node(targetNode)
return targetNode
if args.setlat or args.setlon or args.setalt:
@@ -374,12 +369,14 @@ def onConnected(interface):
if args.ch_del:
closeNow = True
channelIndex = our_globals.get_channel_index()
print(f"Deleting channel {channelIndex}")
ch = getNode().deleteChannel(channelIndex)
if args.ch_set or args.ch_longslow or args.ch_longfast or args.ch_mediumslow or args.ch_mediumfast or args.ch_shortslow or args.ch_shortfast:
closeNow = True
channelIndex = our_globals.get_channel_index()
ch = getNode().channels[channelIndex]
enable = args.ch_enable # should we enable this channel?
@@ -475,6 +472,8 @@ def onConnected(interface):
print(qr.terminal())
if have_tunnel and args.tunnel:
# pylint: disable=C0415
from . import tunnel
# Even if others said we could close, stay open if the user asked for a tunnel
closeNow = False
tunnel.Tunnel(interface, subnet=args.tunnel_net)
@@ -513,16 +512,15 @@ def common():
if len(sys.argv) == 1:
parser.print_help(sys.stderr)
sys.exit(1)
our_exit("", 1)
else:
if args.support:
print("")
support_info()
sys.exit(0)
our_exit("", 0)
if args.ch_index is not None:
global channelIndex
channelIndex = int(args.ch_index)
our_globals.set_channel_index(channelIndex)
# Some commands require dest to be set, so we now use destOrAll/destOrLocal for more lenient commands
if not args.dest:
@@ -542,10 +540,9 @@ def common():
logging.error(
'This option has been deprecated, see help below for the correct replacement...')
parser.print_help(sys.stderr)
sys.exit(1)
elif args.numTests:
numTests = int(args.numTests[0])
result = test.testAll(numTests)
our_exit('', 1)
elif args.test:
result = test.testAll()
if not result:
our_exit("Warning: Test was not successful.")
else:
@@ -722,7 +719,7 @@ def initParser():
action="store_true")
parser.add_argument("--test", help="Run stress test against all connected Meshtastic devices",
nargs=1, dest='numTests', action="store")
action="store_true")
parser.add_argument("--ble", help="BLE mac address to connect to (BLE is not yet supported for this tool)",
default=None)

View File

@@ -4,7 +4,8 @@
This is not much better than using python's globals, but it allows
us to better test meshtastic. Plus, there are some weird python
global issues/gotcha that we can hopefully avoid by using this
class in stead.
class instead.
"""
class Globals:
@@ -26,6 +27,8 @@ class Globals:
Globals.__instance = self
self.args = None
self.parser = None
self.target_node = None
self.channel_index = 0
def set_args(self, args):
"""Set the args"""
@@ -35,6 +38,14 @@ class Globals:
"""Set the parser"""
self.parser = parser
def set_target_node(self, target_node):
"""Set the target_node"""
self.target_node = target_node
def set_channel_index(self, channel_index):
"""Set the channel_index"""
self.channel_index = channel_index
def get_args(self):
"""Get args"""
return self.args
@@ -42,3 +53,11 @@ class Globals:
def get_parser(self):
"""Get parser"""
return self.parser
def get_target_node(self):
"""Get target_node"""
return self.target_node
def get_channel_index(self):
"""Get channel_index"""
return self.channel_index

View File

@@ -38,9 +38,8 @@ class RemoteHardwareClient:
def _sendHardware(self, nodeid, r, wantResponse=False, onResponse=None):
if not nodeid:
# pylint: disable=W1401
raise Exception(
"You must set a destination node ID for this operation (use --dest \!xxxxxxxxx)")
r"You must set a destination node ID for this operation (use --dest \!xxxxxxxxx)")
return self.iface.sendData(r, nodeid, portnums_pb2.REMOTE_HARDWARE_APP,
wantAck=True, channelIndex=self.channelIndex, wantResponse=wantResponse, onResponse=onResponse)

View File

@@ -140,7 +140,7 @@ def openDebugLog(portName):
return open(debugname, 'w+', buffering=1, encoding='utf8')
def testAll(numTests=50):
def testAll(numTests=5):
"""
Run a series of tests using devices we can find.
This is called from the cli with the "--test" option.

View File

@@ -6,7 +6,7 @@ import re
import pytest
from meshtastic.__main__ import initParser, Globals
from meshtastic.__main__ import initParser, main, Globals
@pytest.mark.unit
@@ -41,3 +41,82 @@ def test_main_init_parser_version(capsys):
out, err = capsys.readouterr()
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
assert err == ''
@pytest.mark.unit
def test_main_main_version(capsys):
"""Test --version"""
sys.argv = ['', '--version']
args = sys.argv
parser = None
parser = argparse.ArgumentParser()
our_globals = Globals.getInstance()
our_globals.set_parser(parser)
our_globals.set_args(args)
with pytest.raises(SystemExit) as pytest_wrapped_e:
main()
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 0
out, err = capsys.readouterr()
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
assert err == ''
@pytest.mark.unit
def test_main_main_no_args():
"""Test with no args"""
sys.argv = ['']
args = sys.argv
parser = None
parser = argparse.ArgumentParser()
our_globals = Globals.getInstance()
our_globals.set_parser(parser)
our_globals.set_args(args)
with pytest.raises(SystemExit) as pytest_wrapped_e:
main()
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 1
@pytest.mark.unit
def test_main_support(capsys):
"""Test --support"""
sys.argv = ['', '--support']
args = sys.argv
parser = None
parser = argparse.ArgumentParser()
our_globals = Globals.getInstance()
our_globals.set_parser(parser)
our_globals.set_args(args)
with pytest.raises(SystemExit) as pytest_wrapped_e:
main()
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 0
out, err = capsys.readouterr()
assert re.search(r'System', out, re.MULTILINE)
assert re.search(r'Platform', out, re.MULTILINE)
assert re.search(r'Machine', out, re.MULTILINE)
assert re.search(r'Executable', out, re.MULTILINE)
assert err == ''
@pytest.mark.unit
def test_main_ch_index_no_devices(capsys):
"""Test --ch-index 1"""
sys.argv = ['', '--ch-index', '1']
args = sys.argv
parser = None
parser = argparse.ArgumentParser()
our_globals = Globals.getInstance()
our_globals.set_parser(parser)
our_globals.set_args(args)
assert our_globals.get_target_node() is None
assert our_globals.get_channel_index() == 0
with pytest.raises(SystemExit) as pytest_wrapped_e:
main()
assert our_globals.get_channel_index() == 1
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 1
out, err = capsys.readouterr()
assert re.search(r'Warning: No Meshtastic devices detected', out, re.MULTILINE)
assert err == ''

View File

@@ -65,21 +65,12 @@ def test_smoke1_pos_fields():
assert return_value == 0
@pytest.mark.smoke1
def test_smoke1_test_no_arg():
"""Test --test
Note: Test without arg.
"""
return_value, _ = subprocess.getstatusoutput('meshtastic --test')
assert return_value == 2
@pytest.mark.smoke1
def test_smoke1_test_with_arg_but_no_hardware():
"""Test --test
Note: Since only one device is connected, it will not do much.
"""
return_value, out = subprocess.getstatusoutput('meshtastic --test 5')
return_value, out = subprocess.getstatusoutput('meshtastic --test')
assert re.search(r'^Warning: Must have at least two devices', out, re.MULTILINE)
assert return_value == 1

View File

@@ -16,7 +16,7 @@ def test_smoke2_info():
@pytest.mark.smoke2
def test_smoke2_test():
"""Test --test"""
return_value, out = subprocess.getstatusoutput('meshtastic --test 5')
return_value, out = subprocess.getstatusoutput('meshtastic --test')
assert re.search(r'Writing serial debugging', out, re.MULTILINE)
assert re.search(r'Ports opened', out, re.MULTILINE)
assert re.search(r'Running 5 tests', out, re.MULTILINE)

View File

@@ -175,6 +175,7 @@ def our_exit(message, return_value = 1):
def support_info():
"""Print out info that is helping in support of the cli."""
print('')
print('If having issues with meshtastic cli or python library')
print('or wish to make feature requests, visit:')
print('https://github.com/meshtastic/Meshtastic-python/issues')
@@ -183,10 +184,11 @@ def support_info():
print(' Platform: {0}'.format(platform.platform()))
print(' Release: {0}'.format(platform.uname().release))
print(' Machine: {0}'.format(platform.uname().machine))
print(' Encoding (stdin): {0}'.format(sys.stdin.encoding))
print(' Encoding (stdout): {0}'.format(sys.stdout.encoding))
print(' meshtastic: v{0}'.format(pkg_resources.require('meshtastic')[0].version))
print(' Executable: {0}'.format(sys.argv[0]))
print(' Python: {0} {1} {2}'.format(platform.python_version(),
platform.python_implementation(), platform.python_compiler()))
print('')
print('Please add the output from the command: meshtastic --info')
print('')