mirror of
https://github.com/meshtastic/python.git
synced 2026-04-23 08:17:38 -04:00
had to move test dir to tests because of pytest looking for __init__.py
This commit is contained in:
0
meshtastic/tests/__init__.py
Normal file
0
meshtastic/tests/__init__.py
Normal file
25
meshtastic/tests/test_globals.py
Normal file
25
meshtastic/tests/test_globals.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""Meshtastic unit tests for globals.py
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from ..globals import Globals
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_globals_get_instaance():
|
||||
"""Test that we can instantiate a Globals instance"""
|
||||
ourglobals = Globals.getInstance()
|
||||
ourglobals2 = Globals.getInstance()
|
||||
assert ourglobals == ourglobals2
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_globals_there_can_be_only_one():
|
||||
"""Test that we can cannot create two Globals instances"""
|
||||
# if we have an instance, delete it
|
||||
Globals.getInstance()
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
# try to create another instance
|
||||
Globals()
|
||||
assert pytest_wrapped_e.type == Exception
|
||||
38
meshtastic/tests/test_int.py
Normal file
38
meshtastic/tests/test_int.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""Meshtastic integration tests"""
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_no_args():
|
||||
"""Test without any args"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic')
|
||||
assert re.match(r'usage: meshtastic', out)
|
||||
assert return_value == 1
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_version():
|
||||
"""Test '--version'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --version')
|
||||
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_help():
|
||||
"""Test '--help'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --help')
|
||||
assert re.match(r'usage: meshtastic ', out)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_support():
|
||||
"""Test '--support'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --support')
|
||||
assert re.search(r'System', out)
|
||||
assert re.search(r'Python', out)
|
||||
assert return_value == 0
|
||||
181
meshtastic/tests/test_main.py
Normal file
181
meshtastic/tests/test_main.py
Normal file
@@ -0,0 +1,181 @@
|
||||
"""Meshtastic unit tests for __main__.py"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from meshtastic.__main__ import initParser, main, Globals
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_main_init_parser_no_args(capsys):
|
||||
"""Test no arguments"""
|
||||
sys.argv = ['']
|
||||
args = sys.argv
|
||||
our_globals = Globals.getInstance()
|
||||
parser = argparse.ArgumentParser()
|
||||
our_globals.set_parser(parser)
|
||||
our_globals.set_args(args)
|
||||
initParser()
|
||||
out, err = capsys.readouterr()
|
||||
assert out == ''
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_main_init_parser_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:
|
||||
initParser()
|
||||
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_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 == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=[])
|
||||
def test_main_test_no_ports(patched_find_ports):
|
||||
"""Test --test with no hardware"""
|
||||
sys.argv = ['', '--test']
|
||||
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
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
main()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
patched_find_ports.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1'])
|
||||
def test_main_test_one_port(patched_find_ports):
|
||||
"""Test --test with one fake port"""
|
||||
sys.argv = ['', '--test']
|
||||
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
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
main()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
patched_find_ports.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.test.testAll', return_value=True)
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyFake1', '/dev/ttyFake2'])
|
||||
def test_main_test_two_ports_success(patched_find_ports, patched_test_all):
|
||||
"""Test --test two fake ports"""
|
||||
sys.argv = ['', '--test']
|
||||
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
|
||||
# TODO: why does this fail? patched_find_ports.assert_called()
|
||||
patched_test_all.assert_called()
|
||||
23
meshtastic/tests/test_mesh_interface.py
Normal file
23
meshtastic/tests/test_mesh_interface.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Meshtastic unit tests for mesh_interface.py"""
|
||||
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from ..mesh_interface import MeshInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_MeshInterface(capsys):
|
||||
"""Test that we can instantiate a MeshInterface"""
|
||||
iface = MeshInterface(noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Owner: None \(None\)', out, re.MULTILINE)
|
||||
assert re.search(r'Nodes', out, re.MULTILINE)
|
||||
assert re.search(r'Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'Channels', out, re.MULTILINE)
|
||||
assert re.search(r'Primary channel URL', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
iface.close()
|
||||
49
meshtastic/tests/test_serial_interface.py
Normal file
49
meshtastic/tests/test_serial_interface.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""Meshtastic unit tests for serial_interface.py"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from ..serial_interface import SerialInterface
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('serial.Serial')
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyUSBfake'])
|
||||
def test_SerialInterface_single_port(mocked_findPorts, mocked_serial):
|
||||
"""Test that we can instantiate a SerialInterface with a single port"""
|
||||
iface = SerialInterface(noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
iface.close()
|
||||
mocked_findPorts.assert_called()
|
||||
mocked_serial.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=[])
|
||||
def test_SerialInterface_no_ports(mocked_findPorts, capsys):
|
||||
"""Test that we can instantiate a SerialInterface with no ports"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
SerialInterface(noProto=True)
|
||||
mocked_findPorts.assert_called()
|
||||
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 == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyUSBfake1', '/dev/ttyUSBfake2'])
|
||||
def test_SerialInterface_multiple_ports(mocked_findPorts, capsys):
|
||||
"""Test that we can instantiate a SerialInterface with two ports"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
SerialInterface(noProto=True)
|
||||
mocked_findPorts.assert_called()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: Multiple serial ports were detected', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
415
meshtastic/tests/test_smoke1.py
Normal file
415
meshtastic/tests/test_smoke1.py
Normal file
@@ -0,0 +1,415 @@
|
||||
"""Meshtastic smoke tests with a single device via USB"""
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
|
||||
# Do not like using hard coded sleeps, but it probably makes
|
||||
# sense to pause for the radio at apprpriate times
|
||||
import pytest
|
||||
|
||||
from ..util import findPorts
|
||||
|
||||
# seconds to pause after running a meshtastic command
|
||||
PAUSE_AFTER_COMMAND = 2
|
||||
PAUSE_AFTER_REBOOT = 7
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_reboot():
|
||||
"""Test reboot"""
|
||||
return_value, _ = subprocess.getstatusoutput('meshtastic --reboot')
|
||||
assert return_value == 0
|
||||
# pause for the radio to reset (10 seconds for the pause, and a few more seconds to be back up)
|
||||
time.sleep(18)
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_info():
|
||||
"""Test --info"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Owner', out, re.MULTILINE)
|
||||
assert re.search(r'^My info', out, re.MULTILINE)
|
||||
assert re.search(r'^Nodes in mesh', out, re.MULTILINE)
|
||||
assert re.search(r'^Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'^Channels', out, re.MULTILINE)
|
||||
assert re.search(r'^ PRIMARY', out, re.MULTILINE)
|
||||
assert re.search(r'^Primary channel URL', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_sendping():
|
||||
"""Test --sendping"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --sendping')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Sending ping message', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_pos_fields():
|
||||
"""Test --pos-fields (with some values POS_ALTITUDE POS_ALT_MSL POS_BATTERY)"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --pos-fields POS_ALTITUDE POS_ALT_MSL POS_BATTERY')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Setting position fields to 35', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --pos-fields')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'POS_ALTITUDE', out, re.MULTILINE)
|
||||
assert re.search(r'POS_ALT_MSL', out, re.MULTILINE)
|
||||
assert re.search(r'POS_BATTERY', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@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')
|
||||
assert re.search(r'^Warning: Must have at least two devices', out, re.MULTILINE)
|
||||
assert return_value == 1
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_debug():
|
||||
"""Test --debug"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info --debug')
|
||||
assert re.search(r'^Owner', out, re.MULTILINE)
|
||||
assert re.search(r'^DEBUG:root', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_seriallog_to_file():
|
||||
"""Test --seriallog to a file creates a file"""
|
||||
filename = 'tmpoutput.txt'
|
||||
if os.path.exists(f"{filename}"):
|
||||
os.remove(f"{filename}")
|
||||
return_value, _ = subprocess.getstatusoutput(f'meshtastic --info --seriallog {filename}')
|
||||
assert os.path.exists(f"{filename}")
|
||||
assert return_value == 0
|
||||
os.remove(f"{filename}")
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_qr():
|
||||
"""Test --qr"""
|
||||
filename = 'tmpqr'
|
||||
if os.path.exists(f"{filename}"):
|
||||
os.remove(f"{filename}")
|
||||
return_value, _ = subprocess.getstatusoutput(f'meshtastic --qr > {filename}')
|
||||
assert os.path.exists(f"{filename}")
|
||||
# not really testing that a valid qr code is created, just that the file size
|
||||
# is reasonably big enough for a qr code
|
||||
assert os.stat(f"{filename}").st_size > 20000
|
||||
assert return_value == 0
|
||||
os.remove(f"{filename}")
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_nodes():
|
||||
"""Test --nodes"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --nodes')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^│ N │ User', out, re.MULTILINE)
|
||||
assert re.search(r'^│ 1 │', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_send_hello():
|
||||
"""Test --sendtext hello"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --sendtext hello')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Sending text message hello to \^all', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_port():
|
||||
"""Test --port"""
|
||||
# first, get the ports
|
||||
ports = findPorts()
|
||||
# hopefully there is just one
|
||||
assert len(ports) == 1
|
||||
port = ports[0]
|
||||
return_value, out = subprocess.getstatusoutput(f'meshtastic --port {port} --info')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Owner', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_is_router_true():
|
||||
"""Test --set is_router true"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set is_router true')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Set is_router to true', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --get is_router')
|
||||
assert re.search(r'^is_router: True', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_location_info():
|
||||
"""Test --setlat, --setlon and --setalt """
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --setlat 32.7767 --setlon -96.7970 --setalt 1337')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Fixing altitude', out, re.MULTILINE)
|
||||
assert re.search(r'^Fixing latitude', out, re.MULTILINE)
|
||||
assert re.search(r'^Fixing longitude', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out2 = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'1337', out2, re.MULTILINE)
|
||||
assert re.search(r'32.7767', out2, re.MULTILINE)
|
||||
assert re.search(r'-96.797', out2, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_is_router_false():
|
||||
"""Test --set is_router false"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set is_router false')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Set is_router to false', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --get is_router')
|
||||
assert re.search(r'^is_router: False', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_owner():
|
||||
"""Test --set-owner name"""
|
||||
# make sure the owner is not Joe
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-owner Bob')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Setting device owner to Bob', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert not re.search(r'Owner: Joe', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-owner Joe')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Setting device owner to Joe', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'Owner: Joe', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_team():
|
||||
"""Test --set-team """
|
||||
# unset the team
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-team CLEAR')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Setting team to CLEAR', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-team CYAN')
|
||||
assert re.search(r'Setting team to CYAN', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'CYAN', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_ch_values():
|
||||
"""Test --ch-longslow, --ch-longfast, --ch-mediumslow, --ch-mediumsfast,
|
||||
--ch-shortslow, and --ch-shortfast arguments
|
||||
"""
|
||||
exp = {
|
||||
'--ch-longslow': 'Bw125Cr48Sf4096',
|
||||
# TODO: not sure why these fail thru tests, but ok manually
|
||||
#'--ch-longfast': 'Bw31_25Cr48Sf512',
|
||||
#'--ch-mediumslow': 'Bw250Cr46Sf2048',
|
||||
#'--ch-mediumfast': 'Bw250Cr47Sf1024',
|
||||
# TODO '--ch-shortslow': '?',
|
||||
'--ch-shortfast': 'Bw500Cr45Sf128'
|
||||
}
|
||||
|
||||
for key, val in exp.items():
|
||||
print(key, val)
|
||||
return_value, out = subprocess.getstatusoutput(f'meshtastic {key}')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio (might reboot)
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(val, out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_ch_set_name():
|
||||
"""Test --ch-set name"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert not re.search(r'MyChannel', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --ch-set name MyChannel')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Set name to MyChannel', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'MyChannel', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_ch_add_and_ch_del():
|
||||
"""Test --ch-add"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --ch-add testing')
|
||||
assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'SECONDARY', out, re.MULTILINE)
|
||||
assert re.search(r'testing', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --ch-index 1 --ch-del')
|
||||
assert re.search(r'Deleting channel 1', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
# make sure the secondar channel is not there
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert not re.search(r'SECONDARY', out, re.MULTILINE)
|
||||
assert not re.search(r'testing', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_ch_set_modem_config():
|
||||
"""Test --ch-set modem_config"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert not re.search(r'Bw31_25Cr48Sf512', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --ch-set modem_config Bw31_25Cr48Sf512')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Set modem_config to Bw31_25Cr48Sf512', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'Bw31_25Cr48Sf512', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_seturl_default():
|
||||
"""Test --seturl with default value"""
|
||||
# set some channel value so we no longer have a default channel
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --ch-set name foo')
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
# ensure we no longer have a default primary channel
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert not re.search('CgUYAyIBAQ', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
url = "https://www.meshtastic.org/d/#CgUYAyIBAQ"
|
||||
return_value, out = subprocess.getstatusoutput(f"meshtastic --seturl {url}")
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search('CgUYAyIBAQ', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_seturl_invalid_url():
|
||||
"""Test --seturl with invalid url"""
|
||||
# Note: This url is no longer a valid url.
|
||||
url = "https://www.meshtastic.org/c/#GAMiENTxuzogKQdZ8Lz_q89Oab8qB0RlZmF1bHQ="
|
||||
return_value, out = subprocess.getstatusoutput(f"meshtastic --seturl {url}")
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search('Warning: There were no settings', out, re.MULTILINE)
|
||||
assert return_value == 1
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_COMMAND)
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_configure():
|
||||
"""Test --configure"""
|
||||
_ , out = subprocess.getstatusoutput(f"meshtastic --configure example_config.yaml")
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search('^Setting device owner to Bob TBeam', out, re.MULTILINE)
|
||||
assert re.search('^Fixing altitude at 304 meters', out, re.MULTILINE)
|
||||
assert re.search('^Fixing latitude at 35.8', out, re.MULTILINE)
|
||||
assert re.search('^Fixing longitude at -93.8', out, re.MULTILINE)
|
||||
assert re.search('^Setting device position', out, re.MULTILINE)
|
||||
assert re.search('^Set region to 1', out, re.MULTILINE)
|
||||
assert re.search('^Set is_always_powered to true', out, re.MULTILINE)
|
||||
assert re.search('^Set send_owner_interval to 2', out, re.MULTILINE)
|
||||
assert re.search('^Set screen_on_secs to 31536000', out, re.MULTILINE)
|
||||
assert re.search('^Set wait_bluetooth_secs to 31536000', out, re.MULTILINE)
|
||||
assert re.search('^Writing modified preferences to device', out, re.MULTILINE)
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_ham():
|
||||
"""Test --set-ham
|
||||
Note: Do a factory reset after this setting so it is very short-lived.
|
||||
"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-ham KI1234')
|
||||
assert re.search(r'Setting HAM ID', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'Owner: KI1234', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_factory_reset():
|
||||
"""Test factory reset"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set factory_reset true')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Set factory_reset to true', out, re.MULTILINE)
|
||||
assert re.search(r'^Writing modified preferences to device', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# NOTE: The radio may not be responsive after this, may need to do a manual reboot
|
||||
# by pressing the button
|
||||
23
meshtastic/tests/test_smoke2.py
Normal file
23
meshtastic/tests/test_smoke2.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Meshtastic smoke tests with 2 devices connected via USB"""
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.smoke2
|
||||
def test_smoke2_info():
|
||||
"""Test --info with 2 devices connected serially"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'Warning: Multiple', out, re.MULTILINE)
|
||||
assert return_value == 1
|
||||
|
||||
|
||||
@pytest.mark.smoke2
|
||||
def test_smoke2_test():
|
||||
"""Test --test"""
|
||||
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)
|
||||
assert return_value == 0
|
||||
23
meshtastic/tests/test_smoke_wifi.py
Normal file
23
meshtastic/tests/test_smoke_wifi.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Meshtastic smoke tests a device setup with wifi.
|
||||
|
||||
Need to have run the following on an esp32 device:
|
||||
meshtastic --set wifi_ssid 'foo' --set wifi_password 'sekret'
|
||||
"""
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.smokewifi
|
||||
def test_smokewifi_info():
|
||||
"""Test --info"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info --host meshtastic.local')
|
||||
assert re.search(r'^Owner', out, re.MULTILINE)
|
||||
assert re.search(r'^My info', out, re.MULTILINE)
|
||||
assert re.search(r'^Nodes in mesh', out, re.MULTILINE)
|
||||
assert re.search(r'^Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'^Channels', out, re.MULTILINE)
|
||||
assert re.search(r'^ PRIMARY', out, re.MULTILINE)
|
||||
assert re.search(r'^Primary channel URL', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
14
meshtastic/tests/test_stream_interface.py
Normal file
14
meshtastic/tests/test_stream_interface.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""Meshtastic unit tests for stream_interface.py"""
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
from ..stream_interface import StreamInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_StreamInterface():
|
||||
"""Test that we can instantiate a StreamInterface"""
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
StreamInterface(noProto=True)
|
||||
assert pytest_wrapped_e.type == Exception
|
||||
26
meshtastic/tests/test_tcp_interface.py
Normal file
26
meshtastic/tests/test_tcp_interface.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Meshtastic unit tests for tcp_interface.py"""
|
||||
|
||||
import re
|
||||
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from ..tcp_interface import TCPInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_TCPInterface(capsys):
|
||||
"""Test that we can instantiate a TCPInterface"""
|
||||
with patch('socket.socket') as mock_socket:
|
||||
iface = TCPInterface(hostname='localhost', noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Owner: None \(None\)', out, re.MULTILINE)
|
||||
assert re.search(r'Nodes', out, re.MULTILINE)
|
||||
assert re.search(r'Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'Channels', out, re.MULTILINE)
|
||||
assert re.search(r'Primary channel URL', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
assert mock_socket.called
|
||||
iface.close()
|
||||
122
meshtastic/tests/test_util.py
Normal file
122
meshtastic/tests/test_util.py
Normal file
@@ -0,0 +1,122 @@
|
||||
"""Meshtastic unit tests for util.py"""
|
||||
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from meshtastic.util import fixme, stripnl, pskToString, our_exit, support_info, genPSK256, fromStr, fromPSK
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_genPSK256():
|
||||
"""Test genPSK256"""
|
||||
assert genPSK256() != ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fromStr():
|
||||
"""Test fromStr"""
|
||||
assert fromStr('') == b''
|
||||
assert fromStr('0x12') == b'\x12'
|
||||
assert fromStr('t')
|
||||
assert fromStr('T')
|
||||
assert fromStr('true')
|
||||
assert fromStr('True')
|
||||
assert fromStr('yes')
|
||||
assert fromStr('Yes')
|
||||
assert fromStr('f') is False
|
||||
assert fromStr('F') is False
|
||||
assert fromStr('false') is False
|
||||
assert fromStr('False') is False
|
||||
assert fromStr('no') is False
|
||||
assert fromStr('No') is False
|
||||
assert fromStr('100.01') == 100.01
|
||||
assert fromStr('123') == 123
|
||||
assert fromStr('abc') == 'abc'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fromPSK():
|
||||
"""Test fromPSK"""
|
||||
assert fromPSK('random') != ''
|
||||
assert fromPSK('none') == b'\x00'
|
||||
assert fromPSK('default') == b'\x01'
|
||||
assert fromPSK('simple22') == b'\x17'
|
||||
assert fromPSK('trash') == 'trash'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_stripnl():
|
||||
"""Test stripnl"""
|
||||
assert stripnl('') == ''
|
||||
assert stripnl('a\n') == 'a'
|
||||
assert stripnl(' a \n ') == 'a'
|
||||
assert stripnl('a\nb') == 'a b'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_empty_string():
|
||||
"""Test pskToString empty string"""
|
||||
assert pskToString('') == 'unencrypted'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_string():
|
||||
"""Test pskToString string"""
|
||||
assert pskToString('hunter123') == 'secret'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_one_byte_zero_value():
|
||||
"""Test pskToString one byte that is value of 0"""
|
||||
assert pskToString(bytes([0x00])) == 'unencrypted'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_one_byte_non_zero_value():
|
||||
"""Test pskToString one byte that is non-zero"""
|
||||
assert pskToString(bytes([0x01])) == 'default'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_many_bytes():
|
||||
"""Test pskToString many bytes"""
|
||||
assert pskToString(bytes([0x02, 0x01])) == 'secret'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_our_exit_zero_return_value():
|
||||
"""Test our_exit with a zero return value"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
our_exit("Warning: Some message", 0)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 0
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_our_exit_non_zero_return_value():
|
||||
"""Test our_exit with a non-zero return value"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
our_exit("Error: Some message", 1)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fixme():
|
||||
"""Test fixme"""
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
fixme("some exception")
|
||||
assert pytest_wrapped_e.type == Exception
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_support_info(capsys):
|
||||
"""Test support_info"""
|
||||
support_info()
|
||||
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 == ''
|
||||
Reference in New Issue
Block a user