From 96a5f316ea285bb95cef9130d56e79f9250f57a8 Mon Sep 17 00:00:00 2001 From: Mike Kinney Date: Thu, 9 Dec 2021 13:41:24 -0800 Subject: [PATCH 1/3] refactor two more globals into Globals: channel_index and target_node --- meshtastic/__main__.py | 12 +++--- meshtastic/globals.py | 21 ++++++++- meshtastic/remote_hardware.py | 3 +- meshtastic/test/test_main.py | 81 ++++++++++++++++++++++++++++++++++- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index 24217bb..cc8c484 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -23,8 +23,6 @@ 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 +129,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 +140,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 +370,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? @@ -521,8 +519,8 @@ def common(): sys.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: diff --git a/meshtastic/globals.py b/meshtastic/globals.py index c255e81..eec25f5 100644 --- a/meshtastic/globals.py +++ b/meshtastic/globals.py @@ -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 diff --git a/meshtastic/remote_hardware.py b/meshtastic/remote_hardware.py index 2e0dac9..5fa9f76 100644 --- a/meshtastic/remote_hardware.py +++ b/meshtastic/remote_hardware.py @@ -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) diff --git a/meshtastic/test/test_main.py b/meshtastic/test/test_main.py index c745d5a..d9eaaaa 100644 --- a/meshtastic/test/test_main.py +++ b/meshtastic/test/test_main.py @@ -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 == '' From 89058799c5964f0792f691146f2e51dfab892e7d Mon Sep 17 00:00:00 2001 From: Mike Kinney Date: Thu, 9 Dec 2021 16:21:13 -0800 Subject: [PATCH 2/3] revert --test change; move tunnel import back; add encoding info to support --- meshtastic/__main__.py | 17 ++++++++--------- meshtastic/test.py | 2 +- meshtastic/test/test_smoke2.py | 2 +- meshtastic/util.py | 4 +++- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index cc8c484..f060465 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -16,7 +16,6 @@ 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 @@ -473,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) @@ -511,12 +512,11 @@ 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: channelIndex = int(args.ch_index) @@ -540,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: @@ -720,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) diff --git a/meshtastic/test.py b/meshtastic/test.py index 20eced2..9930cae 100644 --- a/meshtastic/test.py +++ b/meshtastic/test.py @@ -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. diff --git a/meshtastic/test/test_smoke2.py b/meshtastic/test/test_smoke2.py index 2d1a6c4..4788a2e 100644 --- a/meshtastic/test/test_smoke2.py +++ b/meshtastic/test/test_smoke2.py @@ -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) diff --git a/meshtastic/util.py b/meshtastic/util.py index dc9d0b2..d129384 100644 --- a/meshtastic/util.py +++ b/meshtastic/util.py @@ -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('') From 9f7a42b0592e8ea7e08d5de3c75875410ca27e41 Mon Sep 17 00:00:00 2001 From: Mike Kinney Date: Thu, 9 Dec 2021 16:30:23 -0800 Subject: [PATCH 3/3] clean up --test tests --- meshtastic/test/test_smoke1.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/meshtastic/test/test_smoke1.py b/meshtastic/test/test_smoke1.py index a7f4b00..0eb66c1 100644 --- a/meshtastic/test/test_smoke1.py +++ b/meshtastic/test/test_smoke1.py @@ -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