mirror of
https://github.com/meshtastic/python.git
synced 2025-12-30 11:27:53 -05:00
4143 lines
177 KiB
HTML
4143 lines
177 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
|
<meta name="generator" content="pdoc 0.10.0" />
|
|
<title>meshtastic.tests.test_node API documentation</title>
|
|
<meta name="description" content="Meshtastic unit tests for node.py" />
|
|
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
|
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
|
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
|
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
|
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
|
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
|
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<article id="content">
|
|
<header>
|
|
<h1 class="title">Module <code>meshtastic.tests.test_node</code></h1>
|
|
</header>
|
|
<section id="section-intro">
|
|
<p>Meshtastic unit tests for node.py</p>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">"""Meshtastic unit tests for node.py"""
|
|
|
|
import re
|
|
import logging
|
|
|
|
from unittest.mock import patch, MagicMock
|
|
import pytest
|
|
|
|
from ..node import Node
|
|
from ..serial_interface import SerialInterface
|
|
from ..admin_pb2 import AdminMessage
|
|
from ..channel_pb2 import Channel
|
|
from ..radioconfig_pb2 import RadioConfig
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_node(capsys):
|
|
"""Test that we can instantiate a Node"""
|
|
anode = Node('foo', 'bar')
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
anode.showChannels()
|
|
anode.showInfo()
|
|
out, err = capsys.readouterr()
|
|
assert re.search(r'Preferences', out)
|
|
assert re.search(r'Channels', out)
|
|
assert re.search(r'Primary channel URL', out)
|
|
assert err == ''
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_node_reqquestConfig():
|
|
"""Test run requestConfig"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
amesg = MagicMock(autospec=AdminMessage)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
|
|
anode = Node(mo, 'bar')
|
|
anode.requestConfig()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setOwner_and_team(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='Test123', short_name='123', team=1)
|
|
assert re.search(r'p.set_owner.long_name:Test123:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:123:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:1', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setOwner_no_short_name(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='Test123')
|
|
assert re.search(r'p.set_owner.long_name:Test123:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:Tst:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setOwner_no_short_name_and_long_name_is_short(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='Tnt')
|
|
assert re.search(r'p.set_owner.long_name:Tnt:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:Tnt:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setOwner_no_short_name_and_long_name_has_words(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='A B C', is_licensed=True)
|
|
assert re.search(r'p.set_owner.long_name:A B C:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:ABC:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:True', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_exitSimulator(caplog):
|
|
"""Test exitSimulator"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.exitSimulator()
|
|
assert re.search(r'in exitSimulator', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_reboot(caplog):
|
|
"""Test reboot"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.reboot()
|
|
assert re.search(r'Telling node to reboot', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setURL_empty_url():
|
|
"""Test reboot"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
|
anode.setURL('')
|
|
assert pytest_wrapped_e.type == SystemExit
|
|
assert pytest_wrapped_e.value.code == 1
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setURL_valid_URL(caplog):
|
|
"""Test setURL"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
url = "https://www.meshtastic.org/d/#CgUYAyIBAQ"
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode = Node(iface, 'bar', noProto=True)
|
|
anode.radioConfig = 'baz'
|
|
channels = ['zoo']
|
|
anode.channels = channels
|
|
anode.setURL(url)
|
|
assert re.search(r'Channel i:0', caplog.text, re.MULTILINE)
|
|
assert re.search(r'modem_config: Bw125Cr48Sf4096', caplog.text, re.MULTILINE)
|
|
assert re.search(r'psk: "\\001"', caplog.text, re.MULTILINE)
|
|
assert re.search(r'role: PRIMARY', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_setURL_valid_URL_but_no_settings(caplog):
|
|
"""Test setURL"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
url = "https://www.meshtastic.org/d/#"
|
|
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
|
anode = Node(iface, 'bar', noProto=True)
|
|
anode.radioConfig = 'baz'
|
|
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_getChannelByChannelIndex():
|
|
"""Test getChannelByChannelIndex()"""
|
|
anode = Node('foo', 'bar')
|
|
|
|
channel1 = Channel(index=1, role=1) # primary channel
|
|
channel2 = Channel(index=2, role=2) # secondary channel
|
|
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
|
|
|
|
# test primary
|
|
assert anode.getChannelByChannelIndex(0) is not None
|
|
# test secondary
|
|
assert anode.getChannelByChannelIndex(1) is not None
|
|
# test disabled
|
|
assert anode.getChannelByChannelIndex(2) is not None
|
|
# test invalid values
|
|
assert anode.getChannelByChannelIndex(-1) is None
|
|
assert anode.getChannelByChannelIndex(9) is None
|
|
|
|
|
|
@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_deleteChannel_secondary():
|
|
"""Try to delete a secondary channel."""
|
|
|
|
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 ]
|
|
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
anode.channels = channels
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'testing'
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
anode.deleteChannel(1)
|
|
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == ''
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_deleteChannel_secondary_with_admin_channel_after_testing():
|
|
"""Try to delete a secondary channel where there is an admin channel."""
|
|
|
|
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=2)
|
|
channel3.settings.name = 'admin'
|
|
|
|
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 ]
|
|
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
assert mo.localNode == anode
|
|
|
|
anode.channels = channels
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'testing'
|
|
assert channels[2].settings.name == 'admin'
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
anode.deleteChannel(1)
|
|
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'admin'
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_deleteChannel_secondary_with_admin_channel_before_testing():
|
|
"""Try to delete a secondary channel where there is an admin channel."""
|
|
|
|
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=2)
|
|
channel3.settings.name = 'testing'
|
|
|
|
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 ]
|
|
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
anode.channels = channels
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'admin'
|
|
assert channels[2].settings.name == 'testing'
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
anode.deleteChannel(2)
|
|
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'admin'
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
|
|
@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."""
|
|
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."""
|
|
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 == ''
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_writeConfig(caplog):
|
|
"""Test writeConfig"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.writeConfig()
|
|
assert re.search(r'Wrote config', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_requestChannel_not_localNode(caplog):
|
|
"""Test _requestChannel()"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode._requestChannel(0)
|
|
assert re.search(r'Requesting channel 0 info from remote node', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_requestChannel_localNode(caplog):
|
|
"""Test _requestChannel()"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode._requestChannel(0)
|
|
assert re.search(r'Requesting channel 0', caplog.text, re.MULTILINE)
|
|
assert not re.search(r'from remote node', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_onResponseRequestChannel(caplog):
|
|
"""Test onResponseRequestChannel()"""
|
|
|
|
channel1 = Channel(index=1, role=1)
|
|
channel1.settings.modem_config = 3
|
|
channel1.settings.psk = b'\x01'
|
|
|
|
msg1 = MagicMock(autospec=AdminMessage)
|
|
msg1.get_channel_response = channel1
|
|
|
|
msg2 = MagicMock(autospec=AdminMessage)
|
|
channel2 = Channel(index=2, role=0) # disabled
|
|
msg2.get_channel_response = channel2
|
|
|
|
# default primary channel
|
|
packet1 = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b':\t\x12\x05\x18\x03"\x01\x01\x18\x01',
|
|
'requestId': 2615094405,
|
|
'admin': {
|
|
'getChannelResponse': {
|
|
'settings': {
|
|
'modemConfig': 'Bw125Cr48Sf4096',
|
|
'psk': 'AQ=='
|
|
},
|
|
'role': 'PRIMARY'
|
|
},
|
|
'raw': msg1,
|
|
}
|
|
},
|
|
'id': 1692918436,
|
|
'hopLimit': 3,
|
|
'priority':
|
|
'RELIABLE',
|
|
'raw': 'fake',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
|
|
# no other channels
|
|
packet2 = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b':\x04\x08\x02\x12\x00',
|
|
'requestId': 743049663,
|
|
'admin': {
|
|
'getChannelResponse': {
|
|
'index': 2,
|
|
'settings': {}
|
|
},
|
|
'raw': msg2,
|
|
}
|
|
},
|
|
'id': 1692918456,
|
|
'rxTime': 1640202239,
|
|
'hopLimit': 3,
|
|
'priority': 'RELIABLE',
|
|
'raw': 'faked',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.requestConfig()
|
|
anode.onResponseRequestChannel(packet1)
|
|
assert re.search(r'Received channel', caplog.text, re.MULTILINE)
|
|
anode.onResponseRequestChannel(packet2)
|
|
assert re.search(r'Received channel', caplog.text, re.MULTILINE)
|
|
assert re.search(r'Finished downloading channels', caplog.text, re.MULTILINE)
|
|
assert len(anode.channels) == 8
|
|
assert anode.channels[0].settings.modem_config == 3
|
|
assert anode.channels[1].settings.name == ''
|
|
assert anode.channels[2].settings.name == ''
|
|
assert anode.channels[3].settings.name == ''
|
|
assert anode.channels[4].settings.name == ''
|
|
assert anode.channels[5].settings.name == ''
|
|
assert anode.channels[6].settings.name == ''
|
|
assert anode.channels[7].settings.name == ''
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_onResponseRequestSetting(caplog):
|
|
"""Test onResponseRequestSetting()"""
|
|
# Note: Split out the get_radio_response to a MagicMock
|
|
# so it could be "returned" (not really sure how to do that
|
|
# in a python dict.
|
|
amsg = MagicMock(autospec=AdminMessage)
|
|
amsg.get_radio_response = """{
|
|
preferences {
|
|
phone_timeout_secs: 900
|
|
ls_secs: 300
|
|
position_broadcast_smart: true
|
|
position_flags: 35
|
|
}
|
|
}"""
|
|
packet = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b'*\x0e\n\x0c0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#',
|
|
'requestId': 3145147848,
|
|
'admin': {
|
|
'getRadioResponse': {
|
|
'preferences': {
|
|
'phoneTimeoutSecs': 900,
|
|
'lsSecs': 300,
|
|
'positionBroadcastSmart': True,
|
|
'positionFlags': 35
|
|
}
|
|
},
|
|
'raw': amsg
|
|
},
|
|
'id': 365963704,
|
|
'rxTime': 1640195197,
|
|
'hopLimit': 3,
|
|
'priority': 'RELIABLE',
|
|
'raw': 'faked',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
}
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.onResponseRequestSettings(packet)
|
|
assert re.search(r'Received radio config, now fetching channels..', caplog.text, re.MULTILINE)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_onResponseRequestSetting_with_error(capsys):
|
|
"""Test onResponseRequestSetting() with an error"""
|
|
packet = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b'*\x0e\n\x0c0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#',
|
|
'requestId': 3145147848,
|
|
'routing': {
|
|
'errorReason': 'some made up error',
|
|
},
|
|
'admin': {
|
|
'getRadioResponse': {
|
|
'preferences': {
|
|
'phoneTimeoutSecs': 900,
|
|
'lsSecs': 300,
|
|
'positionBroadcastSmart': True,
|
|
'positionFlags': 35
|
|
}
|
|
},
|
|
},
|
|
'id': 365963704,
|
|
'rxTime': 1640195197,
|
|
'hopLimit': 3,
|
|
'priority': 'RELIABLE',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
}
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
anode.onResponseRequestSettings(packet)
|
|
out, err = capsys.readouterr()
|
|
assert re.search(r'Error on response', out)
|
|
assert err == ''</code></pre>
|
|
</details>
|
|
</section>
|
|
<section>
|
|
</section>
|
|
<section>
|
|
</section>
|
|
<section>
|
|
<h2 class="section-title" id="header-functions">Functions</h2>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.test_deleteChannel_secondary"><code class="name flex">
|
|
<span>def <span class="ident">test_deleteChannel_secondary</span></span>(<span>)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Try to delete a secondary channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_deleteChannel_secondary():
|
|
"""Try to delete a secondary channel."""
|
|
|
|
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 ]
|
|
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
anode.channels = channels
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'testing'
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
anode.deleteChannel(1)
|
|
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == ''
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_deleteChannel_secondary_with_admin_channel_after_testing"><code class="name flex">
|
|
<span>def <span class="ident">test_deleteChannel_secondary_with_admin_channel_after_testing</span></span>(<span>)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Try to delete a secondary channel where there is an admin channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_deleteChannel_secondary_with_admin_channel_after_testing():
|
|
"""Try to delete a secondary channel where there is an admin channel."""
|
|
|
|
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=2)
|
|
channel3.settings.name = 'admin'
|
|
|
|
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 ]
|
|
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
assert mo.localNode == anode
|
|
|
|
anode.channels = channels
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'testing'
|
|
assert channels[2].settings.name == 'admin'
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
anode.deleteChannel(1)
|
|
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'admin'
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_deleteChannel_secondary_with_admin_channel_before_testing"><code class="name flex">
|
|
<span>def <span class="ident">test_deleteChannel_secondary_with_admin_channel_before_testing</span></span>(<span>)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Try to delete a secondary channel where there is an admin channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_deleteChannel_secondary_with_admin_channel_before_testing():
|
|
"""Try to delete a secondary channel where there is an admin channel."""
|
|
|
|
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=2)
|
|
channel3.settings.name = 'testing'
|
|
|
|
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 ]
|
|
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
anode.channels = channels
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'admin'
|
|
assert channels[2].settings.name == 'testing'
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''
|
|
|
|
anode.deleteChannel(2)
|
|
|
|
assert len(anode.channels) == 8
|
|
assert channels[0].settings.modem_config == 3
|
|
assert channels[1].settings.name == 'admin'
|
|
assert channels[2].settings.name == ''
|
|
assert channels[3].settings.name == ''
|
|
assert channels[4].settings.name == ''
|
|
assert channels[5].settings.name == ''
|
|
assert channels[6].settings.name == ''
|
|
assert channels[7].settings.name == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_deleteChannel_try_to_delete_primary_channel"><code class="name flex">
|
|
<span>def <span class="ident">test_deleteChannel_try_to_delete_primary_channel</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Try to delete primary channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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 == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_exitSimulator"><code class="name flex">
|
|
<span>def <span class="ident">test_exitSimulator</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test exitSimulator</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_exitSimulator(caplog):
|
|
"""Test exitSimulator"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.exitSimulator()
|
|
assert re.search(r'in exitSimulator', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getAdminChannelIndex"><code class="name flex">
|
|
<span>def <span class="ident">test_getAdminChannelIndex</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Get the 'admin' channel index.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getAdminChannelIndex_when_no_admin_named_channel"><code class="name flex">
|
|
<span>def <span class="ident">test_getAdminChannelIndex_when_no_admin_named_channel</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Get the 'admin' channel when there is not one.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getChannelByChannelIndex"><code class="name flex">
|
|
<span>def <span class="ident">test_getChannelByChannelIndex</span></span>(<span>)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test getChannelByChannelIndex()</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_getChannelByChannelIndex():
|
|
"""Test getChannelByChannelIndex()"""
|
|
anode = Node('foo', 'bar')
|
|
|
|
channel1 = Channel(index=1, role=1) # primary channel
|
|
channel2 = Channel(index=2, role=2) # secondary channel
|
|
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
|
|
|
|
# test primary
|
|
assert anode.getChannelByChannelIndex(0) is not None
|
|
# test secondary
|
|
assert anode.getChannelByChannelIndex(1) is not None
|
|
# test disabled
|
|
assert anode.getChannelByChannelIndex(2) is not None
|
|
# test invalid values
|
|
assert anode.getChannelByChannelIndex(-1) is None
|
|
assert anode.getChannelByChannelIndex(9) is None</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getChannelByName"><code class="name flex">
|
|
<span>def <span class="ident">test_getChannelByName</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Get a channel by the name.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getChannelByName_invalid_name"><code class="name flex">
|
|
<span>def <span class="ident">test_getChannelByName_invalid_name</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Get a channel by the name but one that is not present.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getDisabledChannel"><code class="name flex">
|
|
<span>def <span class="ident">test_getDisabledChannel</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Get the first disabled channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_getDisabledChannel_where_all_channels_are_used"><code class="name flex">
|
|
<span>def <span class="ident">test_getDisabledChannel_where_all_channels_are_used</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Get the first disabled channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_node"><code class="name flex">
|
|
<span>def <span class="ident">test_node</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test that we can instantiate a Node</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_node(capsys):
|
|
"""Test that we can instantiate a Node"""
|
|
anode = Node('foo', 'bar')
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
anode.showChannels()
|
|
anode.showInfo()
|
|
out, err = capsys.readouterr()
|
|
assert re.search(r'Preferences', out)
|
|
assert re.search(r'Channels', out)
|
|
assert re.search(r'Primary channel URL', out)
|
|
assert err == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_node_reqquestConfig"><code class="name flex">
|
|
<span>def <span class="ident">test_node_reqquestConfig</span></span>(<span>)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test run requestConfig</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_node_reqquestConfig():
|
|
"""Test run requestConfig"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
amesg = MagicMock(autospec=AdminMessage)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
|
|
anode = Node(mo, 'bar')
|
|
anode.requestConfig()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_onResponseRequestChannel"><code class="name flex">
|
|
<span>def <span class="ident">test_onResponseRequestChannel</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test onResponseRequestChannel()</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_onResponseRequestChannel(caplog):
|
|
"""Test onResponseRequestChannel()"""
|
|
|
|
channel1 = Channel(index=1, role=1)
|
|
channel1.settings.modem_config = 3
|
|
channel1.settings.psk = b'\x01'
|
|
|
|
msg1 = MagicMock(autospec=AdminMessage)
|
|
msg1.get_channel_response = channel1
|
|
|
|
msg2 = MagicMock(autospec=AdminMessage)
|
|
channel2 = Channel(index=2, role=0) # disabled
|
|
msg2.get_channel_response = channel2
|
|
|
|
# default primary channel
|
|
packet1 = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b':\t\x12\x05\x18\x03"\x01\x01\x18\x01',
|
|
'requestId': 2615094405,
|
|
'admin': {
|
|
'getChannelResponse': {
|
|
'settings': {
|
|
'modemConfig': 'Bw125Cr48Sf4096',
|
|
'psk': 'AQ=='
|
|
},
|
|
'role': 'PRIMARY'
|
|
},
|
|
'raw': msg1,
|
|
}
|
|
},
|
|
'id': 1692918436,
|
|
'hopLimit': 3,
|
|
'priority':
|
|
'RELIABLE',
|
|
'raw': 'fake',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
|
|
# no other channels
|
|
packet2 = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b':\x04\x08\x02\x12\x00',
|
|
'requestId': 743049663,
|
|
'admin': {
|
|
'getChannelResponse': {
|
|
'index': 2,
|
|
'settings': {}
|
|
},
|
|
'raw': msg2,
|
|
}
|
|
},
|
|
'id': 1692918456,
|
|
'rxTime': 1640202239,
|
|
'hopLimit': 3,
|
|
'priority': 'RELIABLE',
|
|
'raw': 'faked',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.requestConfig()
|
|
anode.onResponseRequestChannel(packet1)
|
|
assert re.search(r'Received channel', caplog.text, re.MULTILINE)
|
|
anode.onResponseRequestChannel(packet2)
|
|
assert re.search(r'Received channel', caplog.text, re.MULTILINE)
|
|
assert re.search(r'Finished downloading channels', caplog.text, re.MULTILINE)
|
|
assert len(anode.channels) == 8
|
|
assert anode.channels[0].settings.modem_config == 3
|
|
assert anode.channels[1].settings.name == ''
|
|
assert anode.channels[2].settings.name == ''
|
|
assert anode.channels[3].settings.name == ''
|
|
assert anode.channels[4].settings.name == ''
|
|
assert anode.channels[5].settings.name == ''
|
|
assert anode.channels[6].settings.name == ''
|
|
assert anode.channels[7].settings.name == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_onResponseRequestSetting"><code class="name flex">
|
|
<span>def <span class="ident">test_onResponseRequestSetting</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test onResponseRequestSetting()</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_onResponseRequestSetting(caplog):
|
|
"""Test onResponseRequestSetting()"""
|
|
# Note: Split out the get_radio_response to a MagicMock
|
|
# so it could be "returned" (not really sure how to do that
|
|
# in a python dict.
|
|
amsg = MagicMock(autospec=AdminMessage)
|
|
amsg.get_radio_response = """{
|
|
preferences {
|
|
phone_timeout_secs: 900
|
|
ls_secs: 300
|
|
position_broadcast_smart: true
|
|
position_flags: 35
|
|
}
|
|
}"""
|
|
packet = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b'*\x0e\n\x0c0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#',
|
|
'requestId': 3145147848,
|
|
'admin': {
|
|
'getRadioResponse': {
|
|
'preferences': {
|
|
'phoneTimeoutSecs': 900,
|
|
'lsSecs': 300,
|
|
'positionBroadcastSmart': True,
|
|
'positionFlags': 35
|
|
}
|
|
},
|
|
'raw': amsg
|
|
},
|
|
'id': 365963704,
|
|
'rxTime': 1640195197,
|
|
'hopLimit': 3,
|
|
'priority': 'RELIABLE',
|
|
'raw': 'faked',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
}
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.onResponseRequestSettings(packet)
|
|
assert re.search(r'Received radio config, now fetching channels..', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_onResponseRequestSetting_with_error"><code class="name flex">
|
|
<span>def <span class="ident">test_onResponseRequestSetting_with_error</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test onResponseRequestSetting() with an error</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_onResponseRequestSetting_with_error(capsys):
|
|
"""Test onResponseRequestSetting() with an error"""
|
|
packet = {
|
|
'from': 2475227164,
|
|
'to': 2475227164,
|
|
'decoded': {
|
|
'portnum': 'ADMIN_APP',
|
|
'payload': b'*\x0e\n\x0c0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#',
|
|
'requestId': 3145147848,
|
|
'routing': {
|
|
'errorReason': 'some made up error',
|
|
},
|
|
'admin': {
|
|
'getRadioResponse': {
|
|
'preferences': {
|
|
'phoneTimeoutSecs': 900,
|
|
'lsSecs': 300,
|
|
'positionBroadcastSmart': True,
|
|
'positionFlags': 35
|
|
}
|
|
},
|
|
},
|
|
'id': 365963704,
|
|
'rxTime': 1640195197,
|
|
'hopLimit': 3,
|
|
'priority': 'RELIABLE',
|
|
'fromId': '!9388f81c',
|
|
'toId': '!9388f81c'
|
|
}
|
|
}
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
anode.onResponseRequestSettings(packet)
|
|
out, err = capsys.readouterr()
|
|
assert re.search(r'Error on response', out)
|
|
assert err == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_reboot"><code class="name flex">
|
|
<span>def <span class="ident">test_reboot</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test reboot</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_reboot(caplog):
|
|
"""Test reboot"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.reboot()
|
|
assert re.search(r'Telling node to reboot', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_requestChannel_localNode"><code class="name flex">
|
|
<span>def <span class="ident">test_requestChannel_localNode</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test _requestChannel()</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_requestChannel_localNode(caplog):
|
|
"""Test _requestChannel()"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
|
|
# Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
|
|
mo.localNode = anode
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode._requestChannel(0)
|
|
assert re.search(r'Requesting channel 0', caplog.text, re.MULTILINE)
|
|
assert not re.search(r'from remote node', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_requestChannel_not_localNode"><code class="name flex">
|
|
<span>def <span class="ident">test_requestChannel_not_localNode</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test _requestChannel()</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_requestChannel_not_localNode(caplog):
|
|
"""Test _requestChannel()"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
|
mo.localNode.getChannelByName.return_value = None
|
|
mo.myInfo.max_channels = 8
|
|
anode = Node(mo, 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode._requestChannel(0)
|
|
assert re.search(r'Requesting channel 0 info from remote node', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setOwner_and_team"><code class="name flex">
|
|
<span>def <span class="ident">test_setOwner_and_team</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test setOwner</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setOwner_and_team(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='Test123', short_name='123', team=1)
|
|
assert re.search(r'p.set_owner.long_name:Test123:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:123:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:1', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setOwner_no_short_name"><code class="name flex">
|
|
<span>def <span class="ident">test_setOwner_no_short_name</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test setOwner</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setOwner_no_short_name(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='Test123')
|
|
assert re.search(r'p.set_owner.long_name:Test123:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:Tst:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setOwner_no_short_name_and_long_name_has_words"><code class="name flex">
|
|
<span>def <span class="ident">test_setOwner_no_short_name_and_long_name_has_words</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test setOwner</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setOwner_no_short_name_and_long_name_has_words(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='A B C', is_licensed=True)
|
|
assert re.search(r'p.set_owner.long_name:A B C:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:ABC:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:True', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setOwner_no_short_name_and_long_name_is_short"><code class="name flex">
|
|
<span>def <span class="ident">test_setOwner_no_short_name_and_long_name_is_short</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test setOwner</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setOwner_no_short_name_and_long_name_is_short(caplog):
|
|
"""Test setOwner"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.setOwner(long_name ='Tnt')
|
|
assert re.search(r'p.set_owner.long_name:Tnt:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.short_name:Tnt:', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
|
assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setURL_empty_url"><code class="name flex">
|
|
<span>def <span class="ident">test_setURL_empty_url</span></span>(<span>)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test reboot</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setURL_empty_url():
|
|
"""Test reboot"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
|
anode.setURL('')
|
|
assert pytest_wrapped_e.type == SystemExit
|
|
assert pytest_wrapped_e.value.code == 1</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setURL_valid_URL"><code class="name flex">
|
|
<span>def <span class="ident">test_setURL_valid_URL</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test setURL</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setURL_valid_URL(caplog):
|
|
"""Test setURL"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
url = "https://www.meshtastic.org/d/#CgUYAyIBAQ"
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode = Node(iface, 'bar', noProto=True)
|
|
anode.radioConfig = 'baz'
|
|
channels = ['zoo']
|
|
anode.channels = channels
|
|
anode.setURL(url)
|
|
assert re.search(r'Channel i:0', caplog.text, re.MULTILINE)
|
|
assert re.search(r'modem_config: Bw125Cr48Sf4096', caplog.text, re.MULTILINE)
|
|
assert re.search(r'psk: "\\001"', caplog.text, re.MULTILINE)
|
|
assert re.search(r'role: PRIMARY', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_setURL_valid_URL_but_no_settings"><code class="name flex">
|
|
<span>def <span class="ident">test_setURL_valid_URL_but_no_settings</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test setURL</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_setURL_valid_URL_but_no_settings(caplog):
|
|
"""Test setURL"""
|
|
iface = MagicMock(autospec=SerialInterface)
|
|
url = "https://www.meshtastic.org/d/#"
|
|
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
|
anode = Node(iface, 'bar', noProto=True)
|
|
anode.radioConfig = 'baz'
|
|
anode.setURL(url)
|
|
assert pytest_wrapped_e.type == SystemExit
|
|
assert pytest_wrapped_e.value.code == 1</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_showChannels"><code class="name flex">
|
|
<span>def <span class="ident">test_showChannels</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test showChannels</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@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 == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_turnOffEncryptionOnPrimaryChannel"><code class="name flex">
|
|
<span>def <span class="ident">test_turnOffEncryptionOnPrimaryChannel</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Turn off encryption when there is a psk.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_turnOffEncryptionOnPrimaryChannel(capsys):
|
|
"""Turn off encryption when there is a psk."""
|
|
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 == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_writeConfig"><code class="name flex">
|
|
<span>def <span class="ident">test_writeConfig</span></span>(<span>caplog)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test writeConfig</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_writeConfig(caplog):
|
|
"""Test writeConfig"""
|
|
anode = Node('foo', 'bar', noProto=True)
|
|
radioConfig = RadioConfig()
|
|
anode.radioConfig = radioConfig
|
|
|
|
with caplog.at_level(logging.DEBUG):
|
|
anode.writeConfig()
|
|
assert re.search(r'Wrote config', caplog.text, re.MULTILINE)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.test_writeConfig_with_no_radioConfig"><code class="name flex">
|
|
<span>def <span class="ident">test_writeConfig_with_no_radioConfig</span></span>(<span>capsys)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Test writeConfig with no radioConfig.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@pytest.mark.unit
|
|
def test_writeConfig_with_no_radioConfig(capsys):
|
|
"""Test writeConfig with no radioConfig."""
|
|
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 == ''</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
</section>
|
|
<section>
|
|
<h2 class="section-title" id="header-classes">Classes</h2>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage"><code class="flex name class">
|
|
<span>class <span class="ident">AdminMessage</span></span>
|
|
<span>(</span><span>**kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
|
<p>Protocol message classes are almost always generated by the protocol
|
|
compiler.
|
|
These generated types subclass Message and implement the methods
|
|
shown below.</p></div>
|
|
<h3>Ancestors</h3>
|
|
<ul class="hlist">
|
|
<li>google.protobuf.message.Message</li>
|
|
</ul>
|
|
<h3>Class variables</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.CONFIRM_SET_CHANNEL_FIELD_NUMBER"><code class="name">var <span class="ident">CONFIRM_SET_CHANNEL_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.CONFIRM_SET_RADIO_FIELD_NUMBER"><code class="name">var <span class="ident">CONFIRM_SET_RADIO_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.EXIT_SIMULATOR_FIELD_NUMBER"><code class="name">var <span class="ident">EXIT_SIMULATOR_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.GET_CHANNEL_REQUEST_FIELD_NUMBER"><code class="name">var <span class="ident">GET_CHANNEL_REQUEST_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.GET_CHANNEL_RESPONSE_FIELD_NUMBER"><code class="name">var <span class="ident">GET_CHANNEL_RESPONSE_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.GET_OWNER_REQUEST_FIELD_NUMBER"><code class="name">var <span class="ident">GET_OWNER_REQUEST_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.GET_OWNER_RESPONSE_FIELD_NUMBER"><code class="name">var <span class="ident">GET_OWNER_RESPONSE_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.GET_RADIO_REQUEST_FIELD_NUMBER"><code class="name">var <span class="ident">GET_RADIO_REQUEST_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.GET_RADIO_RESPONSE_FIELD_NUMBER"><code class="name">var <span class="ident">GET_RADIO_RESPONSE_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.REBOOT_SECONDS_FIELD_NUMBER"><code class="name">var <span class="ident">REBOOT_SECONDS_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.SET_CHANNEL_FIELD_NUMBER"><code class="name">var <span class="ident">SET_CHANNEL_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.SET_OWNER_FIELD_NUMBER"><code class="name">var <span class="ident">SET_OWNER_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.SET_RADIO_FIELD_NUMBER"><code class="name">var <span class="ident">SET_RADIO_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
<h3>Static methods</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.FromString"><code class="name flex">
|
|
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def FromString(s):
|
|
message = cls()
|
|
message.MergeFromString(s)
|
|
return message</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.RegisterExtension"><code class="name flex">
|
|
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def RegisterExtension(extension_handle):
|
|
extension_handle.containing_type = cls.DESCRIPTOR
|
|
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
|
# pylint: disable=protected-access
|
|
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
|
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
<h3>Instance variables</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.confirm_set_channel"><code class="name">var <span class="ident">confirm_set_channel</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for confirm_set_channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.confirm_set_radio"><code class="name">var <span class="ident">confirm_set_radio</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for confirm_set_radio.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.exit_simulator"><code class="name">var <span class="ident">exit_simulator</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for exit_simulator.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.get_channel_request"><code class="name">var <span class="ident">get_channel_request</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for get_channel_request.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.get_channel_response"><code class="name">var <span class="ident">get_channel_response</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for get_channel_response.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.get_owner_request"><code class="name">var <span class="ident">get_owner_request</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for get_owner_request.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.get_owner_response"><code class="name">var <span class="ident">get_owner_response</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for get_owner_response.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.get_radio_request"><code class="name">var <span class="ident">get_radio_request</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for get_radio_request.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.get_radio_response"><code class="name">var <span class="ident">get_radio_response</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for get_radio_response.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.reboot_seconds"><code class="name">var <span class="ident">reboot_seconds</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for reboot_seconds.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.set_channel"><code class="name">var <span class="ident">set_channel</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for set_channel.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.set_owner"><code class="name">var <span class="ident">set_owner</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for set_owner.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.set_radio"><code class="name">var <span class="ident">set_radio</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for set_radio.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.ByteSize"><code class="name flex">
|
|
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ByteSize(self):
|
|
if not self._cached_byte_size_dirty:
|
|
return self._cached_byte_size
|
|
|
|
size = 0
|
|
descriptor = self.DESCRIPTOR
|
|
if descriptor.GetOptions().map_entry:
|
|
# Fields of map entry should always be serialized.
|
|
size = descriptor.fields_by_name['key']._sizer(self.key)
|
|
size += descriptor.fields_by_name['value']._sizer(self.value)
|
|
else:
|
|
for field_descriptor, field_value in self.ListFields():
|
|
size += field_descriptor._sizer(field_value)
|
|
for tag_bytes, value_bytes in self._unknown_fields:
|
|
size += len(tag_bytes) + len(value_bytes)
|
|
|
|
self._cached_byte_size = size
|
|
self._cached_byte_size_dirty = False
|
|
self._listener_for_children.dirty = False
|
|
return size</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.Clear"><code class="name flex">
|
|
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _Clear(self):
|
|
# Clear fields.
|
|
self._fields = {}
|
|
self._unknown_fields = ()
|
|
# pylint: disable=protected-access
|
|
if self._unknown_field_set is not None:
|
|
self._unknown_field_set._clear()
|
|
self._unknown_field_set = None
|
|
|
|
self._oneofs = {}
|
|
self._Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.ClearField"><code class="name flex">
|
|
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ClearField(self, field_name):
|
|
try:
|
|
field = message_descriptor.fields_by_name[field_name]
|
|
except KeyError:
|
|
try:
|
|
field = message_descriptor.oneofs_by_name[field_name]
|
|
if field in self._oneofs:
|
|
field = self._oneofs[field]
|
|
else:
|
|
return
|
|
except KeyError:
|
|
raise ValueError('Protocol message %s has no "%s" field.' %
|
|
(message_descriptor.name, field_name))
|
|
|
|
if field in self._fields:
|
|
# To match the C++ implementation, we need to invalidate iterators
|
|
# for map fields when ClearField() happens.
|
|
if hasattr(self._fields[field], 'InvalidateIterators'):
|
|
self._fields[field].InvalidateIterators()
|
|
|
|
# Note: If the field is a sub-message, its listener will still point
|
|
# at us. That's fine, because the worst than can happen is that it
|
|
# will call _Modified() and invalidate our byte size. Big deal.
|
|
del self._fields[field]
|
|
|
|
if self._oneofs.get(field.containing_oneof, None) is field:
|
|
del self._oneofs[field.containing_oneof]
|
|
|
|
# Always call _Modified() -- even if nothing was changed, this is
|
|
# a mutating method, and thus calling it should cause the field to become
|
|
# present in the parent message.
|
|
self._Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.DiscardUnknownFields"><code class="name flex">
|
|
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _DiscardUnknownFields(self):
|
|
self._unknown_fields = []
|
|
self._unknown_field_set = None # pylint: disable=protected-access
|
|
for field, value in self.ListFields():
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if _IsMapField(field):
|
|
if _IsMessageMapField(field):
|
|
for key in value:
|
|
value[key].DiscardUnknownFields()
|
|
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
for sub_message in value:
|
|
sub_message.DiscardUnknownFields()
|
|
else:
|
|
value.DiscardUnknownFields()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.FindInitializationErrors"><code class="name flex">
|
|
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>A list of strings.
|
|
Each string is a path to an uninitialized field from
|
|
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def FindInitializationErrors(self):
|
|
"""Finds required fields which are not initialized.
|
|
|
|
Returns:
|
|
A list of strings. Each string is a path to an uninitialized field from
|
|
the top-level message, e.g. "foo.bar[5].baz".
|
|
"""
|
|
|
|
errors = [] # simplify things
|
|
|
|
for field in required_fields:
|
|
if not self.HasField(field.name):
|
|
errors.append(field.name)
|
|
|
|
for field, value in self.ListFields():
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if field.is_extension:
|
|
name = '(%s)' % field.full_name
|
|
else:
|
|
name = field.name
|
|
|
|
if _IsMapField(field):
|
|
if _IsMessageMapField(field):
|
|
for key in value:
|
|
element = value[key]
|
|
prefix = '%s[%s].' % (name, key)
|
|
sub_errors = element.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
else:
|
|
# ScalarMaps can't have any initialization errors.
|
|
pass
|
|
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
for i in range(len(value)):
|
|
element = value[i]
|
|
prefix = '%s[%d].' % (name, i)
|
|
sub_errors = element.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
else:
|
|
prefix = name + '.'
|
|
sub_errors = value.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
|
|
return errors</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.HasField"><code class="name flex">
|
|
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def HasField(self, field_name):
|
|
try:
|
|
field = hassable_fields[field_name]
|
|
except KeyError:
|
|
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
|
|
|
if isinstance(field, descriptor_mod.OneofDescriptor):
|
|
try:
|
|
return HasField(self, self._oneofs[field].name)
|
|
except KeyError:
|
|
return False
|
|
else:
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
value = self._fields.get(field)
|
|
return value is not None and value._is_present_in_parent
|
|
else:
|
|
return field in self._fields</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.IsInitialized"><code class="name flex">
|
|
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>errors</code></strong></dt>
|
|
<dd>A list which, if provided, will be populated with the field
|
|
paths of all missing required fields.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>True iff the specified message has all required fields set.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def IsInitialized(self, errors=None):
|
|
"""Checks if all required fields of a message are set.
|
|
|
|
Args:
|
|
errors: A list which, if provided, will be populated with the field
|
|
paths of all missing required fields.
|
|
|
|
Returns:
|
|
True iff the specified message has all required fields set.
|
|
"""
|
|
|
|
# Performance is critical so we avoid HasField() and ListFields().
|
|
|
|
for field in required_fields:
|
|
if (field not in self._fields or
|
|
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
|
not self._fields[field]._is_present_in_parent)):
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
|
|
for field, value in list(self._fields.items()): # dict can change size!
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
if (field.message_type.has_options and
|
|
field.message_type.GetOptions().map_entry):
|
|
continue
|
|
for element in value:
|
|
if not element.IsInitialized():
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
elif value._is_present_in_parent and not value.IsInitialized():
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
|
|
return True</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.ListFields"><code class="name flex">
|
|
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ListFields(self):
|
|
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
|
all_fields.sort(key = lambda item: item[0].number)
|
|
return all_fields</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.MergeFrom"><code class="name flex">
|
|
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def MergeFrom(self, msg):
|
|
if not isinstance(msg, cls):
|
|
raise TypeError(
|
|
'Parameter to MergeFrom() must be instance of same class: '
|
|
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
|
_FullyQualifiedClassName(msg.__class__)))
|
|
|
|
assert msg is not self
|
|
self._Modified()
|
|
|
|
fields = self._fields
|
|
|
|
for field, value in msg._fields.items():
|
|
if field.label == LABEL_REPEATED:
|
|
field_value = fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
fields[field] = field_value
|
|
field_value.MergeFrom(value)
|
|
elif field.cpp_type == CPPTYPE_MESSAGE:
|
|
if value._is_present_in_parent:
|
|
field_value = fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
fields[field] = field_value
|
|
field_value.MergeFrom(value)
|
|
else:
|
|
self._fields[field] = value
|
|
if field.containing_oneof:
|
|
self._UpdateOneofState(field)
|
|
|
|
if msg._unknown_fields:
|
|
if not self._unknown_fields:
|
|
self._unknown_fields = []
|
|
self._unknown_fields.extend(msg._unknown_fields)
|
|
# pylint: disable=protected-access
|
|
if self._unknown_field_set is None:
|
|
self._unknown_field_set = containers.UnknownFieldSet()
|
|
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.MergeFromString"><code class="name flex">
|
|
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def MergeFromString(self, serialized):
|
|
serialized = memoryview(serialized)
|
|
length = len(serialized)
|
|
try:
|
|
if self._InternalParse(serialized, 0, length) != length:
|
|
# The only reason _InternalParse would return early is if it
|
|
# encountered an end-group tag.
|
|
raise message_mod.DecodeError('Unexpected end-group tag.')
|
|
except (IndexError, TypeError):
|
|
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
|
raise message_mod.DecodeError('Truncated message.')
|
|
except struct.error as e:
|
|
raise message_mod.DecodeError(e)
|
|
return length # Return this for legacy reasons.</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.SerializePartialToString"><code class="name flex">
|
|
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
|
out = BytesIO()
|
|
self._InternalSerialize(out.write, **kwargs)
|
|
return out.getvalue()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.SerializeToString"><code class="name flex">
|
|
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def SerializeToString(self, **kwargs):
|
|
# Check if the message has all of its required fields set.
|
|
if not self.IsInitialized():
|
|
raise message_mod.EncodeError(
|
|
'Message %s is missing required fields: %s' % (
|
|
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
|
return self.SerializePartialToString(**kwargs)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.SetInParent"><code class="name flex">
|
|
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
|
and propagates this to our listener iff this was a state change.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def Modified(self):
|
|
"""Sets the _cached_byte_size_dirty bit to true,
|
|
and propagates this to our listener iff this was a state change.
|
|
"""
|
|
|
|
# Note: Some callers check _cached_byte_size_dirty before calling
|
|
# _Modified() as an extra optimization. So, if this method is ever
|
|
# changed such that it does stuff even when _cached_byte_size_dirty is
|
|
# already true, the callers need to be updated.
|
|
if not self._cached_byte_size_dirty:
|
|
self._cached_byte_size_dirty = True
|
|
self._listener_for_children.dirty = True
|
|
self._is_present_in_parent = True
|
|
self._listener.Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.UnknownFields"><code class="name flex">
|
|
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _UnknownFields(self):
|
|
if self._unknown_field_set is None: # pylint: disable=protected-access
|
|
# pylint: disable=protected-access
|
|
self._unknown_field_set = containers.UnknownFieldSet()
|
|
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.AdminMessage.WhichOneof"><code class="name flex">
|
|
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def WhichOneof(self, oneof_name):
|
|
"""Returns the name of the currently set field inside a oneof, or None."""
|
|
try:
|
|
field = message_descriptor.oneofs_by_name[oneof_name]
|
|
except KeyError:
|
|
raise ValueError(
|
|
'Protocol message has no oneof "%s" field.' % oneof_name)
|
|
|
|
nested_field = self._oneofs.get(field, None)
|
|
if nested_field is not None and self.HasField(nested_field.name):
|
|
return nested_field.name
|
|
else:
|
|
return None</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel"><code class="flex name class">
|
|
<span>class <span class="ident">Channel</span></span>
|
|
<span>(</span><span>**kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
|
<p>Protocol message classes are almost always generated by the protocol
|
|
compiler.
|
|
These generated types subclass Message and implement the methods
|
|
shown below.</p></div>
|
|
<h3>Ancestors</h3>
|
|
<ul class="hlist">
|
|
<li>google.protobuf.message.Message</li>
|
|
</ul>
|
|
<h3>Class variables</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.Channel.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.DISABLED"><code class="name">var <span class="ident">DISABLED</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.INDEX_FIELD_NUMBER"><code class="name">var <span class="ident">INDEX_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.PRIMARY"><code class="name">var <span class="ident">PRIMARY</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.ROLE_FIELD_NUMBER"><code class="name">var <span class="ident">ROLE_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.Role"><code class="name">var <span class="ident">Role</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.SECONDARY"><code class="name">var <span class="ident">SECONDARY</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.SETTINGS_FIELD_NUMBER"><code class="name">var <span class="ident">SETTINGS_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
<h3>Static methods</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.Channel.FromString"><code class="name flex">
|
|
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def FromString(s):
|
|
message = cls()
|
|
message.MergeFromString(s)
|
|
return message</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.RegisterExtension"><code class="name flex">
|
|
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def RegisterExtension(extension_handle):
|
|
extension_handle.containing_type = cls.DESCRIPTOR
|
|
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
|
# pylint: disable=protected-access
|
|
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
|
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
<h3>Instance variables</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.Channel.index"><code class="name">var <span class="ident">index</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for index.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.role"><code class="name">var <span class="ident">role</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for role.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
# TODO(protobuf-team): This may be broken since there may not be
|
|
# default_value. Combine with has_default_value somehow.
|
|
return self._fields.get(field, default_value)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.settings"><code class="name">var <span class="ident">settings</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for settings.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.Channel.ByteSize"><code class="name flex">
|
|
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ByteSize(self):
|
|
if not self._cached_byte_size_dirty:
|
|
return self._cached_byte_size
|
|
|
|
size = 0
|
|
descriptor = self.DESCRIPTOR
|
|
if descriptor.GetOptions().map_entry:
|
|
# Fields of map entry should always be serialized.
|
|
size = descriptor.fields_by_name['key']._sizer(self.key)
|
|
size += descriptor.fields_by_name['value']._sizer(self.value)
|
|
else:
|
|
for field_descriptor, field_value in self.ListFields():
|
|
size += field_descriptor._sizer(field_value)
|
|
for tag_bytes, value_bytes in self._unknown_fields:
|
|
size += len(tag_bytes) + len(value_bytes)
|
|
|
|
self._cached_byte_size = size
|
|
self._cached_byte_size_dirty = False
|
|
self._listener_for_children.dirty = False
|
|
return size</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.Clear"><code class="name flex">
|
|
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _Clear(self):
|
|
# Clear fields.
|
|
self._fields = {}
|
|
self._unknown_fields = ()
|
|
# pylint: disable=protected-access
|
|
if self._unknown_field_set is not None:
|
|
self._unknown_field_set._clear()
|
|
self._unknown_field_set = None
|
|
|
|
self._oneofs = {}
|
|
self._Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.ClearField"><code class="name flex">
|
|
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ClearField(self, field_name):
|
|
try:
|
|
field = message_descriptor.fields_by_name[field_name]
|
|
except KeyError:
|
|
try:
|
|
field = message_descriptor.oneofs_by_name[field_name]
|
|
if field in self._oneofs:
|
|
field = self._oneofs[field]
|
|
else:
|
|
return
|
|
except KeyError:
|
|
raise ValueError('Protocol message %s has no "%s" field.' %
|
|
(message_descriptor.name, field_name))
|
|
|
|
if field in self._fields:
|
|
# To match the C++ implementation, we need to invalidate iterators
|
|
# for map fields when ClearField() happens.
|
|
if hasattr(self._fields[field], 'InvalidateIterators'):
|
|
self._fields[field].InvalidateIterators()
|
|
|
|
# Note: If the field is a sub-message, its listener will still point
|
|
# at us. That's fine, because the worst than can happen is that it
|
|
# will call _Modified() and invalidate our byte size. Big deal.
|
|
del self._fields[field]
|
|
|
|
if self._oneofs.get(field.containing_oneof, None) is field:
|
|
del self._oneofs[field.containing_oneof]
|
|
|
|
# Always call _Modified() -- even if nothing was changed, this is
|
|
# a mutating method, and thus calling it should cause the field to become
|
|
# present in the parent message.
|
|
self._Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.DiscardUnknownFields"><code class="name flex">
|
|
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _DiscardUnknownFields(self):
|
|
self._unknown_fields = []
|
|
self._unknown_field_set = None # pylint: disable=protected-access
|
|
for field, value in self.ListFields():
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if _IsMapField(field):
|
|
if _IsMessageMapField(field):
|
|
for key in value:
|
|
value[key].DiscardUnknownFields()
|
|
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
for sub_message in value:
|
|
sub_message.DiscardUnknownFields()
|
|
else:
|
|
value.DiscardUnknownFields()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.FindInitializationErrors"><code class="name flex">
|
|
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>A list of strings.
|
|
Each string is a path to an uninitialized field from
|
|
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def FindInitializationErrors(self):
|
|
"""Finds required fields which are not initialized.
|
|
|
|
Returns:
|
|
A list of strings. Each string is a path to an uninitialized field from
|
|
the top-level message, e.g. "foo.bar[5].baz".
|
|
"""
|
|
|
|
errors = [] # simplify things
|
|
|
|
for field in required_fields:
|
|
if not self.HasField(field.name):
|
|
errors.append(field.name)
|
|
|
|
for field, value in self.ListFields():
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if field.is_extension:
|
|
name = '(%s)' % field.full_name
|
|
else:
|
|
name = field.name
|
|
|
|
if _IsMapField(field):
|
|
if _IsMessageMapField(field):
|
|
for key in value:
|
|
element = value[key]
|
|
prefix = '%s[%s].' % (name, key)
|
|
sub_errors = element.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
else:
|
|
# ScalarMaps can't have any initialization errors.
|
|
pass
|
|
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
for i in range(len(value)):
|
|
element = value[i]
|
|
prefix = '%s[%d].' % (name, i)
|
|
sub_errors = element.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
else:
|
|
prefix = name + '.'
|
|
sub_errors = value.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
|
|
return errors</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.HasField"><code class="name flex">
|
|
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def HasField(self, field_name):
|
|
try:
|
|
field = hassable_fields[field_name]
|
|
except KeyError:
|
|
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
|
|
|
if isinstance(field, descriptor_mod.OneofDescriptor):
|
|
try:
|
|
return HasField(self, self._oneofs[field].name)
|
|
except KeyError:
|
|
return False
|
|
else:
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
value = self._fields.get(field)
|
|
return value is not None and value._is_present_in_parent
|
|
else:
|
|
return field in self._fields</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.IsInitialized"><code class="name flex">
|
|
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>errors</code></strong></dt>
|
|
<dd>A list which, if provided, will be populated with the field
|
|
paths of all missing required fields.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>True iff the specified message has all required fields set.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def IsInitialized(self, errors=None):
|
|
"""Checks if all required fields of a message are set.
|
|
|
|
Args:
|
|
errors: A list which, if provided, will be populated with the field
|
|
paths of all missing required fields.
|
|
|
|
Returns:
|
|
True iff the specified message has all required fields set.
|
|
"""
|
|
|
|
# Performance is critical so we avoid HasField() and ListFields().
|
|
|
|
for field in required_fields:
|
|
if (field not in self._fields or
|
|
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
|
not self._fields[field]._is_present_in_parent)):
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
|
|
for field, value in list(self._fields.items()): # dict can change size!
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
if (field.message_type.has_options and
|
|
field.message_type.GetOptions().map_entry):
|
|
continue
|
|
for element in value:
|
|
if not element.IsInitialized():
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
elif value._is_present_in_parent and not value.IsInitialized():
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
|
|
return True</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.ListFields"><code class="name flex">
|
|
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ListFields(self):
|
|
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
|
all_fields.sort(key = lambda item: item[0].number)
|
|
return all_fields</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.MergeFrom"><code class="name flex">
|
|
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def MergeFrom(self, msg):
|
|
if not isinstance(msg, cls):
|
|
raise TypeError(
|
|
'Parameter to MergeFrom() must be instance of same class: '
|
|
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
|
_FullyQualifiedClassName(msg.__class__)))
|
|
|
|
assert msg is not self
|
|
self._Modified()
|
|
|
|
fields = self._fields
|
|
|
|
for field, value in msg._fields.items():
|
|
if field.label == LABEL_REPEATED:
|
|
field_value = fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
fields[field] = field_value
|
|
field_value.MergeFrom(value)
|
|
elif field.cpp_type == CPPTYPE_MESSAGE:
|
|
if value._is_present_in_parent:
|
|
field_value = fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
fields[field] = field_value
|
|
field_value.MergeFrom(value)
|
|
else:
|
|
self._fields[field] = value
|
|
if field.containing_oneof:
|
|
self._UpdateOneofState(field)
|
|
|
|
if msg._unknown_fields:
|
|
if not self._unknown_fields:
|
|
self._unknown_fields = []
|
|
self._unknown_fields.extend(msg._unknown_fields)
|
|
# pylint: disable=protected-access
|
|
if self._unknown_field_set is None:
|
|
self._unknown_field_set = containers.UnknownFieldSet()
|
|
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.MergeFromString"><code class="name flex">
|
|
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def MergeFromString(self, serialized):
|
|
serialized = memoryview(serialized)
|
|
length = len(serialized)
|
|
try:
|
|
if self._InternalParse(serialized, 0, length) != length:
|
|
# The only reason _InternalParse would return early is if it
|
|
# encountered an end-group tag.
|
|
raise message_mod.DecodeError('Unexpected end-group tag.')
|
|
except (IndexError, TypeError):
|
|
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
|
raise message_mod.DecodeError('Truncated message.')
|
|
except struct.error as e:
|
|
raise message_mod.DecodeError(e)
|
|
return length # Return this for legacy reasons.</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.SerializePartialToString"><code class="name flex">
|
|
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
|
out = BytesIO()
|
|
self._InternalSerialize(out.write, **kwargs)
|
|
return out.getvalue()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.SerializeToString"><code class="name flex">
|
|
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def SerializeToString(self, **kwargs):
|
|
# Check if the message has all of its required fields set.
|
|
if not self.IsInitialized():
|
|
raise message_mod.EncodeError(
|
|
'Message %s is missing required fields: %s' % (
|
|
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
|
return self.SerializePartialToString(**kwargs)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.SetInParent"><code class="name flex">
|
|
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
|
and propagates this to our listener iff this was a state change.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def Modified(self):
|
|
"""Sets the _cached_byte_size_dirty bit to true,
|
|
and propagates this to our listener iff this was a state change.
|
|
"""
|
|
|
|
# Note: Some callers check _cached_byte_size_dirty before calling
|
|
# _Modified() as an extra optimization. So, if this method is ever
|
|
# changed such that it does stuff even when _cached_byte_size_dirty is
|
|
# already true, the callers need to be updated.
|
|
if not self._cached_byte_size_dirty:
|
|
self._cached_byte_size_dirty = True
|
|
self._listener_for_children.dirty = True
|
|
self._is_present_in_parent = True
|
|
self._listener.Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.UnknownFields"><code class="name flex">
|
|
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _UnknownFields(self):
|
|
if self._unknown_field_set is None: # pylint: disable=protected-access
|
|
# pylint: disable=protected-access
|
|
self._unknown_field_set = containers.UnknownFieldSet()
|
|
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.Channel.WhichOneof"><code class="name flex">
|
|
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def WhichOneof(self, oneof_name):
|
|
"""Returns the name of the currently set field inside a oneof, or None."""
|
|
try:
|
|
field = message_descriptor.oneofs_by_name[oneof_name]
|
|
except KeyError:
|
|
raise ValueError(
|
|
'Protocol message has no oneof "%s" field.' % oneof_name)
|
|
|
|
nested_field = self._oneofs.get(field, None)
|
|
if nested_field is not None and self.HasField(nested_field.name):
|
|
return nested_field.name
|
|
else:
|
|
return None</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig"><code class="flex name class">
|
|
<span>class <span class="ident">RadioConfig</span></span>
|
|
<span>(</span><span>**kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
|
<p>Protocol message classes are almost always generated by the protocol
|
|
compiler.
|
|
These generated types subclass Message and implement the methods
|
|
shown below.</p></div>
|
|
<h3>Ancestors</h3>
|
|
<ul class="hlist">
|
|
<li>google.protobuf.message.Message</li>
|
|
</ul>
|
|
<h3>Class variables</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.PREFERENCES_FIELD_NUMBER"><code class="name">var <span class="ident">PREFERENCES_FIELD_NUMBER</span></code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.UserPreferences"><code class="name">var <span class="ident">UserPreferences</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
|
<p>Protocol message classes are almost always generated by the protocol
|
|
compiler.
|
|
These generated types subclass Message and implement the methods
|
|
shown below.</p></div>
|
|
</dd>
|
|
</dl>
|
|
<h3>Static methods</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.FromString"><code class="name flex">
|
|
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def FromString(s):
|
|
message = cls()
|
|
message.MergeFromString(s)
|
|
return message</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.RegisterExtension"><code class="name flex">
|
|
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def RegisterExtension(extension_handle):
|
|
extension_handle.containing_type = cls.DESCRIPTOR
|
|
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
|
# pylint: disable=protected-access
|
|
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
|
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
<h3>Instance variables</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.preferences"><code class="name">var <span class="ident">preferences</span></code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Getter for preferences.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def getter(self):
|
|
field_value = self._fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
|
|
# Atomically check if another thread has preempted us and, if not, swap
|
|
# in the new object we just created. If someone has preempted us, we
|
|
# take that object and discard ours.
|
|
# WARNING: We are relying on setdefault() being atomic. This is true
|
|
# in CPython but we haven't investigated others. This warning appears
|
|
# in several other locations in this file.
|
|
field_value = self._fields.setdefault(field, field_value)
|
|
return field_value</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.ByteSize"><code class="name flex">
|
|
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ByteSize(self):
|
|
if not self._cached_byte_size_dirty:
|
|
return self._cached_byte_size
|
|
|
|
size = 0
|
|
descriptor = self.DESCRIPTOR
|
|
if descriptor.GetOptions().map_entry:
|
|
# Fields of map entry should always be serialized.
|
|
size = descriptor.fields_by_name['key']._sizer(self.key)
|
|
size += descriptor.fields_by_name['value']._sizer(self.value)
|
|
else:
|
|
for field_descriptor, field_value in self.ListFields():
|
|
size += field_descriptor._sizer(field_value)
|
|
for tag_bytes, value_bytes in self._unknown_fields:
|
|
size += len(tag_bytes) + len(value_bytes)
|
|
|
|
self._cached_byte_size = size
|
|
self._cached_byte_size_dirty = False
|
|
self._listener_for_children.dirty = False
|
|
return size</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.Clear"><code class="name flex">
|
|
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _Clear(self):
|
|
# Clear fields.
|
|
self._fields = {}
|
|
self._unknown_fields = ()
|
|
# pylint: disable=protected-access
|
|
if self._unknown_field_set is not None:
|
|
self._unknown_field_set._clear()
|
|
self._unknown_field_set = None
|
|
|
|
self._oneofs = {}
|
|
self._Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.ClearField"><code class="name flex">
|
|
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ClearField(self, field_name):
|
|
try:
|
|
field = message_descriptor.fields_by_name[field_name]
|
|
except KeyError:
|
|
try:
|
|
field = message_descriptor.oneofs_by_name[field_name]
|
|
if field in self._oneofs:
|
|
field = self._oneofs[field]
|
|
else:
|
|
return
|
|
except KeyError:
|
|
raise ValueError('Protocol message %s has no "%s" field.' %
|
|
(message_descriptor.name, field_name))
|
|
|
|
if field in self._fields:
|
|
# To match the C++ implementation, we need to invalidate iterators
|
|
# for map fields when ClearField() happens.
|
|
if hasattr(self._fields[field], 'InvalidateIterators'):
|
|
self._fields[field].InvalidateIterators()
|
|
|
|
# Note: If the field is a sub-message, its listener will still point
|
|
# at us. That's fine, because the worst than can happen is that it
|
|
# will call _Modified() and invalidate our byte size. Big deal.
|
|
del self._fields[field]
|
|
|
|
if self._oneofs.get(field.containing_oneof, None) is field:
|
|
del self._oneofs[field.containing_oneof]
|
|
|
|
# Always call _Modified() -- even if nothing was changed, this is
|
|
# a mutating method, and thus calling it should cause the field to become
|
|
# present in the parent message.
|
|
self._Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.DiscardUnknownFields"><code class="name flex">
|
|
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _DiscardUnknownFields(self):
|
|
self._unknown_fields = []
|
|
self._unknown_field_set = None # pylint: disable=protected-access
|
|
for field, value in self.ListFields():
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if _IsMapField(field):
|
|
if _IsMessageMapField(field):
|
|
for key in value:
|
|
value[key].DiscardUnknownFields()
|
|
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
for sub_message in value:
|
|
sub_message.DiscardUnknownFields()
|
|
else:
|
|
value.DiscardUnknownFields()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.FindInitializationErrors"><code class="name flex">
|
|
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>A list of strings.
|
|
Each string is a path to an uninitialized field from
|
|
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def FindInitializationErrors(self):
|
|
"""Finds required fields which are not initialized.
|
|
|
|
Returns:
|
|
A list of strings. Each string is a path to an uninitialized field from
|
|
the top-level message, e.g. "foo.bar[5].baz".
|
|
"""
|
|
|
|
errors = [] # simplify things
|
|
|
|
for field in required_fields:
|
|
if not self.HasField(field.name):
|
|
errors.append(field.name)
|
|
|
|
for field, value in self.ListFields():
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if field.is_extension:
|
|
name = '(%s)' % field.full_name
|
|
else:
|
|
name = field.name
|
|
|
|
if _IsMapField(field):
|
|
if _IsMessageMapField(field):
|
|
for key in value:
|
|
element = value[key]
|
|
prefix = '%s[%s].' % (name, key)
|
|
sub_errors = element.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
else:
|
|
# ScalarMaps can't have any initialization errors.
|
|
pass
|
|
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
for i in range(len(value)):
|
|
element = value[i]
|
|
prefix = '%s[%d].' % (name, i)
|
|
sub_errors = element.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
else:
|
|
prefix = name + '.'
|
|
sub_errors = value.FindInitializationErrors()
|
|
errors += [prefix + error for error in sub_errors]
|
|
|
|
return errors</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.HasField"><code class="name flex">
|
|
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def HasField(self, field_name):
|
|
try:
|
|
field = hassable_fields[field_name]
|
|
except KeyError:
|
|
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
|
|
|
if isinstance(field, descriptor_mod.OneofDescriptor):
|
|
try:
|
|
return HasField(self, self._oneofs[field].name)
|
|
except KeyError:
|
|
return False
|
|
else:
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
value = self._fields.get(field)
|
|
return value is not None and value._is_present_in_parent
|
|
else:
|
|
return field in self._fields</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.IsInitialized"><code class="name flex">
|
|
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>errors</code></strong></dt>
|
|
<dd>A list which, if provided, will be populated with the field
|
|
paths of all missing required fields.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>True iff the specified message has all required fields set.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def IsInitialized(self, errors=None):
|
|
"""Checks if all required fields of a message are set.
|
|
|
|
Args:
|
|
errors: A list which, if provided, will be populated with the field
|
|
paths of all missing required fields.
|
|
|
|
Returns:
|
|
True iff the specified message has all required fields set.
|
|
"""
|
|
|
|
# Performance is critical so we avoid HasField() and ListFields().
|
|
|
|
for field in required_fields:
|
|
if (field not in self._fields or
|
|
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
|
not self._fields[field]._is_present_in_parent)):
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
|
|
for field, value in list(self._fields.items()): # dict can change size!
|
|
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
|
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
|
if (field.message_type.has_options and
|
|
field.message_type.GetOptions().map_entry):
|
|
continue
|
|
for element in value:
|
|
if not element.IsInitialized():
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
elif value._is_present_in_parent and not value.IsInitialized():
|
|
if errors is not None:
|
|
errors.extend(self.FindInitializationErrors())
|
|
return False
|
|
|
|
return True</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.ListFields"><code class="name flex">
|
|
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def ListFields(self):
|
|
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
|
all_fields.sort(key = lambda item: item[0].number)
|
|
return all_fields</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.MergeFrom"><code class="name flex">
|
|
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def MergeFrom(self, msg):
|
|
if not isinstance(msg, cls):
|
|
raise TypeError(
|
|
'Parameter to MergeFrom() must be instance of same class: '
|
|
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
|
_FullyQualifiedClassName(msg.__class__)))
|
|
|
|
assert msg is not self
|
|
self._Modified()
|
|
|
|
fields = self._fields
|
|
|
|
for field, value in msg._fields.items():
|
|
if field.label == LABEL_REPEATED:
|
|
field_value = fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
fields[field] = field_value
|
|
field_value.MergeFrom(value)
|
|
elif field.cpp_type == CPPTYPE_MESSAGE:
|
|
if value._is_present_in_parent:
|
|
field_value = fields.get(field)
|
|
if field_value is None:
|
|
# Construct a new object to represent this field.
|
|
field_value = field._default_constructor(self)
|
|
fields[field] = field_value
|
|
field_value.MergeFrom(value)
|
|
else:
|
|
self._fields[field] = value
|
|
if field.containing_oneof:
|
|
self._UpdateOneofState(field)
|
|
|
|
if msg._unknown_fields:
|
|
if not self._unknown_fields:
|
|
self._unknown_fields = []
|
|
self._unknown_fields.extend(msg._unknown_fields)
|
|
# pylint: disable=protected-access
|
|
if self._unknown_field_set is None:
|
|
self._unknown_field_set = containers.UnknownFieldSet()
|
|
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.MergeFromString"><code class="name flex">
|
|
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def MergeFromString(self, serialized):
|
|
serialized = memoryview(serialized)
|
|
length = len(serialized)
|
|
try:
|
|
if self._InternalParse(serialized, 0, length) != length:
|
|
# The only reason _InternalParse would return early is if it
|
|
# encountered an end-group tag.
|
|
raise message_mod.DecodeError('Unexpected end-group tag.')
|
|
except (IndexError, TypeError):
|
|
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
|
raise message_mod.DecodeError('Truncated message.')
|
|
except struct.error as e:
|
|
raise message_mod.DecodeError(e)
|
|
return length # Return this for legacy reasons.</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.SerializePartialToString"><code class="name flex">
|
|
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
|
out = BytesIO()
|
|
self._InternalSerialize(out.write, **kwargs)
|
|
return out.getvalue()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.SerializeToString"><code class="name flex">
|
|
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def SerializeToString(self, **kwargs):
|
|
# Check if the message has all of its required fields set.
|
|
if not self.IsInitialized():
|
|
raise message_mod.EncodeError(
|
|
'Message %s is missing required fields: %s' % (
|
|
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
|
return self.SerializePartialToString(**kwargs)</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.SetInParent"><code class="name flex">
|
|
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
|
and propagates this to our listener iff this was a state change.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def Modified(self):
|
|
"""Sets the _cached_byte_size_dirty bit to true,
|
|
and propagates this to our listener iff this was a state change.
|
|
"""
|
|
|
|
# Note: Some callers check _cached_byte_size_dirty before calling
|
|
# _Modified() as an extra optimization. So, if this method is ever
|
|
# changed such that it does stuff even when _cached_byte_size_dirty is
|
|
# already true, the callers need to be updated.
|
|
if not self._cached_byte_size_dirty:
|
|
self._cached_byte_size_dirty = True
|
|
self._listener_for_children.dirty = True
|
|
self._is_present_in_parent = True
|
|
self._listener.Modified()</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.UnknownFields"><code class="name flex">
|
|
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def _UnknownFields(self):
|
|
if self._unknown_field_set is None: # pylint: disable=protected-access
|
|
# pylint: disable=protected-access
|
|
self._unknown_field_set = containers.UnknownFieldSet()
|
|
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
|
</details>
|
|
</dd>
|
|
<dt id="meshtastic.tests.test_node.RadioConfig.WhichOneof"><code class="name flex">
|
|
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def WhichOneof(self, oneof_name):
|
|
"""Returns the name of the currently set field inside a oneof, or None."""
|
|
try:
|
|
field = message_descriptor.oneofs_by_name[oneof_name]
|
|
except KeyError:
|
|
raise ValueError(
|
|
'Protocol message has no oneof "%s" field.' % oneof_name)
|
|
|
|
nested_field = self._oneofs.get(field, None)
|
|
if nested_field is not None and self.HasField(nested_field.name):
|
|
return nested_field.name
|
|
else:
|
|
return None</code></pre>
|
|
</details>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</section>
|
|
</article>
|
|
<nav id="sidebar">
|
|
<h1>Index</h1>
|
|
<div class="toc">
|
|
<ul></ul>
|
|
</div>
|
|
<ul id="index">
|
|
<li><h3>Super-module</h3>
|
|
<ul>
|
|
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li><h3><a href="#header-functions">Functions</a></h3>
|
|
<ul class="">
|
|
<li><code><a title="meshtastic.tests.test_node.test_deleteChannel_secondary" href="#meshtastic.tests.test_node.test_deleteChannel_secondary">test_deleteChannel_secondary</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_deleteChannel_secondary_with_admin_channel_after_testing" href="#meshtastic.tests.test_node.test_deleteChannel_secondary_with_admin_channel_after_testing">test_deleteChannel_secondary_with_admin_channel_after_testing</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_deleteChannel_secondary_with_admin_channel_before_testing" href="#meshtastic.tests.test_node.test_deleteChannel_secondary_with_admin_channel_before_testing">test_deleteChannel_secondary_with_admin_channel_before_testing</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_deleteChannel_try_to_delete_primary_channel" href="#meshtastic.tests.test_node.test_deleteChannel_try_to_delete_primary_channel">test_deleteChannel_try_to_delete_primary_channel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_exitSimulator" href="#meshtastic.tests.test_node.test_exitSimulator">test_exitSimulator</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getAdminChannelIndex" href="#meshtastic.tests.test_node.test_getAdminChannelIndex">test_getAdminChannelIndex</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getAdminChannelIndex_when_no_admin_named_channel" href="#meshtastic.tests.test_node.test_getAdminChannelIndex_when_no_admin_named_channel">test_getAdminChannelIndex_when_no_admin_named_channel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getChannelByChannelIndex" href="#meshtastic.tests.test_node.test_getChannelByChannelIndex">test_getChannelByChannelIndex</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getChannelByName" href="#meshtastic.tests.test_node.test_getChannelByName">test_getChannelByName</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getChannelByName_invalid_name" href="#meshtastic.tests.test_node.test_getChannelByName_invalid_name">test_getChannelByName_invalid_name</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getDisabledChannel" href="#meshtastic.tests.test_node.test_getDisabledChannel">test_getDisabledChannel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_getDisabledChannel_where_all_channels_are_used" href="#meshtastic.tests.test_node.test_getDisabledChannel_where_all_channels_are_used">test_getDisabledChannel_where_all_channels_are_used</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_node" href="#meshtastic.tests.test_node.test_node">test_node</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_node_reqquestConfig" href="#meshtastic.tests.test_node.test_node_reqquestConfig">test_node_reqquestConfig</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_onResponseRequestChannel" href="#meshtastic.tests.test_node.test_onResponseRequestChannel">test_onResponseRequestChannel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_onResponseRequestSetting" href="#meshtastic.tests.test_node.test_onResponseRequestSetting">test_onResponseRequestSetting</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_onResponseRequestSetting_with_error" href="#meshtastic.tests.test_node.test_onResponseRequestSetting_with_error">test_onResponseRequestSetting_with_error</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_reboot" href="#meshtastic.tests.test_node.test_reboot">test_reboot</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_requestChannel_localNode" href="#meshtastic.tests.test_node.test_requestChannel_localNode">test_requestChannel_localNode</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_requestChannel_not_localNode" href="#meshtastic.tests.test_node.test_requestChannel_not_localNode">test_requestChannel_not_localNode</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setOwner_and_team" href="#meshtastic.tests.test_node.test_setOwner_and_team">test_setOwner_and_team</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setOwner_no_short_name" href="#meshtastic.tests.test_node.test_setOwner_no_short_name">test_setOwner_no_short_name</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setOwner_no_short_name_and_long_name_has_words" href="#meshtastic.tests.test_node.test_setOwner_no_short_name_and_long_name_has_words">test_setOwner_no_short_name_and_long_name_has_words</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setOwner_no_short_name_and_long_name_is_short" href="#meshtastic.tests.test_node.test_setOwner_no_short_name_and_long_name_is_short">test_setOwner_no_short_name_and_long_name_is_short</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setURL_empty_url" href="#meshtastic.tests.test_node.test_setURL_empty_url">test_setURL_empty_url</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setURL_valid_URL" href="#meshtastic.tests.test_node.test_setURL_valid_URL">test_setURL_valid_URL</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_setURL_valid_URL_but_no_settings" href="#meshtastic.tests.test_node.test_setURL_valid_URL_but_no_settings">test_setURL_valid_URL_but_no_settings</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_showChannels" href="#meshtastic.tests.test_node.test_showChannels">test_showChannels</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_turnOffEncryptionOnPrimaryChannel" href="#meshtastic.tests.test_node.test_turnOffEncryptionOnPrimaryChannel">test_turnOffEncryptionOnPrimaryChannel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_writeConfig" href="#meshtastic.tests.test_node.test_writeConfig">test_writeConfig</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.test_writeConfig_with_no_radioConfig" href="#meshtastic.tests.test_node.test_writeConfig_with_no_radioConfig">test_writeConfig_with_no_radioConfig</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li><h3><a href="#header-classes">Classes</a></h3>
|
|
<ul>
|
|
<li>
|
|
<h4><code><a title="meshtastic.tests.test_node.AdminMessage" href="#meshtastic.tests.test_node.AdminMessage">AdminMessage</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.ByteSize" href="#meshtastic.tests.test_node.AdminMessage.ByteSize">ByteSize</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.CONFIRM_SET_CHANNEL_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.CONFIRM_SET_CHANNEL_FIELD_NUMBER">CONFIRM_SET_CHANNEL_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.CONFIRM_SET_RADIO_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.CONFIRM_SET_RADIO_FIELD_NUMBER">CONFIRM_SET_RADIO_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.Clear" href="#meshtastic.tests.test_node.AdminMessage.Clear">Clear</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.ClearField" href="#meshtastic.tests.test_node.AdminMessage.ClearField">ClearField</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.DESCRIPTOR" href="#meshtastic.tests.test_node.AdminMessage.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.DiscardUnknownFields" href="#meshtastic.tests.test_node.AdminMessage.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.EXIT_SIMULATOR_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.EXIT_SIMULATOR_FIELD_NUMBER">EXIT_SIMULATOR_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.FindInitializationErrors" href="#meshtastic.tests.test_node.AdminMessage.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.FromString" href="#meshtastic.tests.test_node.AdminMessage.FromString">FromString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.GET_CHANNEL_REQUEST_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.GET_CHANNEL_REQUEST_FIELD_NUMBER">GET_CHANNEL_REQUEST_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.GET_CHANNEL_RESPONSE_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.GET_CHANNEL_RESPONSE_FIELD_NUMBER">GET_CHANNEL_RESPONSE_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.GET_OWNER_REQUEST_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.GET_OWNER_REQUEST_FIELD_NUMBER">GET_OWNER_REQUEST_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.GET_OWNER_RESPONSE_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.GET_OWNER_RESPONSE_FIELD_NUMBER">GET_OWNER_RESPONSE_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.GET_RADIO_REQUEST_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.GET_RADIO_REQUEST_FIELD_NUMBER">GET_RADIO_REQUEST_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.GET_RADIO_RESPONSE_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.GET_RADIO_RESPONSE_FIELD_NUMBER">GET_RADIO_RESPONSE_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.HasField" href="#meshtastic.tests.test_node.AdminMessage.HasField">HasField</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.IsInitialized" href="#meshtastic.tests.test_node.AdminMessage.IsInitialized">IsInitialized</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.ListFields" href="#meshtastic.tests.test_node.AdminMessage.ListFields">ListFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.MergeFrom" href="#meshtastic.tests.test_node.AdminMessage.MergeFrom">MergeFrom</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.MergeFromString" href="#meshtastic.tests.test_node.AdminMessage.MergeFromString">MergeFromString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.REBOOT_SECONDS_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.REBOOT_SECONDS_FIELD_NUMBER">REBOOT_SECONDS_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.RegisterExtension" href="#meshtastic.tests.test_node.AdminMessage.RegisterExtension">RegisterExtension</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.SET_CHANNEL_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.SET_CHANNEL_FIELD_NUMBER">SET_CHANNEL_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.SET_OWNER_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.SET_OWNER_FIELD_NUMBER">SET_OWNER_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.SET_RADIO_FIELD_NUMBER" href="#meshtastic.tests.test_node.AdminMessage.SET_RADIO_FIELD_NUMBER">SET_RADIO_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.SerializePartialToString" href="#meshtastic.tests.test_node.AdminMessage.SerializePartialToString">SerializePartialToString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.SerializeToString" href="#meshtastic.tests.test_node.AdminMessage.SerializeToString">SerializeToString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.SetInParent" href="#meshtastic.tests.test_node.AdminMessage.SetInParent">SetInParent</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.UnknownFields" href="#meshtastic.tests.test_node.AdminMessage.UnknownFields">UnknownFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.WhichOneof" href="#meshtastic.tests.test_node.AdminMessage.WhichOneof">WhichOneof</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.confirm_set_channel" href="#meshtastic.tests.test_node.AdminMessage.confirm_set_channel">confirm_set_channel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.confirm_set_radio" href="#meshtastic.tests.test_node.AdminMessage.confirm_set_radio">confirm_set_radio</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.exit_simulator" href="#meshtastic.tests.test_node.AdminMessage.exit_simulator">exit_simulator</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.get_channel_request" href="#meshtastic.tests.test_node.AdminMessage.get_channel_request">get_channel_request</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.get_channel_response" href="#meshtastic.tests.test_node.AdminMessage.get_channel_response">get_channel_response</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.get_owner_request" href="#meshtastic.tests.test_node.AdminMessage.get_owner_request">get_owner_request</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.get_owner_response" href="#meshtastic.tests.test_node.AdminMessage.get_owner_response">get_owner_response</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.get_radio_request" href="#meshtastic.tests.test_node.AdminMessage.get_radio_request">get_radio_request</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.get_radio_response" href="#meshtastic.tests.test_node.AdminMessage.get_radio_response">get_radio_response</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.reboot_seconds" href="#meshtastic.tests.test_node.AdminMessage.reboot_seconds">reboot_seconds</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.set_channel" href="#meshtastic.tests.test_node.AdminMessage.set_channel">set_channel</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.set_owner" href="#meshtastic.tests.test_node.AdminMessage.set_owner">set_owner</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.AdminMessage.set_radio" href="#meshtastic.tests.test_node.AdminMessage.set_radio">set_radio</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="meshtastic.tests.test_node.Channel" href="#meshtastic.tests.test_node.Channel">Channel</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.ByteSize" href="#meshtastic.tests.test_node.Channel.ByteSize">ByteSize</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.Clear" href="#meshtastic.tests.test_node.Channel.Clear">Clear</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.ClearField" href="#meshtastic.tests.test_node.Channel.ClearField">ClearField</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.DESCRIPTOR" href="#meshtastic.tests.test_node.Channel.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.DISABLED" href="#meshtastic.tests.test_node.Channel.DISABLED">DISABLED</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.DiscardUnknownFields" href="#meshtastic.tests.test_node.Channel.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.FindInitializationErrors" href="#meshtastic.tests.test_node.Channel.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.FromString" href="#meshtastic.tests.test_node.Channel.FromString">FromString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.HasField" href="#meshtastic.tests.test_node.Channel.HasField">HasField</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.INDEX_FIELD_NUMBER" href="#meshtastic.tests.test_node.Channel.INDEX_FIELD_NUMBER">INDEX_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.IsInitialized" href="#meshtastic.tests.test_node.Channel.IsInitialized">IsInitialized</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.ListFields" href="#meshtastic.tests.test_node.Channel.ListFields">ListFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.MergeFrom" href="#meshtastic.tests.test_node.Channel.MergeFrom">MergeFrom</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.MergeFromString" href="#meshtastic.tests.test_node.Channel.MergeFromString">MergeFromString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.PRIMARY" href="#meshtastic.tests.test_node.Channel.PRIMARY">PRIMARY</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.ROLE_FIELD_NUMBER" href="#meshtastic.tests.test_node.Channel.ROLE_FIELD_NUMBER">ROLE_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.RegisterExtension" href="#meshtastic.tests.test_node.Channel.RegisterExtension">RegisterExtension</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.Role" href="#meshtastic.tests.test_node.Channel.Role">Role</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.SECONDARY" href="#meshtastic.tests.test_node.Channel.SECONDARY">SECONDARY</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.SETTINGS_FIELD_NUMBER" href="#meshtastic.tests.test_node.Channel.SETTINGS_FIELD_NUMBER">SETTINGS_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.SerializePartialToString" href="#meshtastic.tests.test_node.Channel.SerializePartialToString">SerializePartialToString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.SerializeToString" href="#meshtastic.tests.test_node.Channel.SerializeToString">SerializeToString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.SetInParent" href="#meshtastic.tests.test_node.Channel.SetInParent">SetInParent</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.UnknownFields" href="#meshtastic.tests.test_node.Channel.UnknownFields">UnknownFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.WhichOneof" href="#meshtastic.tests.test_node.Channel.WhichOneof">WhichOneof</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.index" href="#meshtastic.tests.test_node.Channel.index">index</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.role" href="#meshtastic.tests.test_node.Channel.role">role</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.Channel.settings" href="#meshtastic.tests.test_node.Channel.settings">settings</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="meshtastic.tests.test_node.RadioConfig" href="#meshtastic.tests.test_node.RadioConfig">RadioConfig</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.ByteSize" href="#meshtastic.tests.test_node.RadioConfig.ByteSize">ByteSize</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.Clear" href="#meshtastic.tests.test_node.RadioConfig.Clear">Clear</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.ClearField" href="#meshtastic.tests.test_node.RadioConfig.ClearField">ClearField</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.DESCRIPTOR" href="#meshtastic.tests.test_node.RadioConfig.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.DiscardUnknownFields" href="#meshtastic.tests.test_node.RadioConfig.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.FindInitializationErrors" href="#meshtastic.tests.test_node.RadioConfig.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.FromString" href="#meshtastic.tests.test_node.RadioConfig.FromString">FromString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.HasField" href="#meshtastic.tests.test_node.RadioConfig.HasField">HasField</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.IsInitialized" href="#meshtastic.tests.test_node.RadioConfig.IsInitialized">IsInitialized</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.ListFields" href="#meshtastic.tests.test_node.RadioConfig.ListFields">ListFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.MergeFrom" href="#meshtastic.tests.test_node.RadioConfig.MergeFrom">MergeFrom</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.MergeFromString" href="#meshtastic.tests.test_node.RadioConfig.MergeFromString">MergeFromString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.PREFERENCES_FIELD_NUMBER" href="#meshtastic.tests.test_node.RadioConfig.PREFERENCES_FIELD_NUMBER">PREFERENCES_FIELD_NUMBER</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.RegisterExtension" href="#meshtastic.tests.test_node.RadioConfig.RegisterExtension">RegisterExtension</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.SerializePartialToString" href="#meshtastic.tests.test_node.RadioConfig.SerializePartialToString">SerializePartialToString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.SerializeToString" href="#meshtastic.tests.test_node.RadioConfig.SerializeToString">SerializeToString</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.SetInParent" href="#meshtastic.tests.test_node.RadioConfig.SetInParent">SetInParent</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.UnknownFields" href="#meshtastic.tests.test_node.RadioConfig.UnknownFields">UnknownFields</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.UserPreferences" href="#meshtastic.tests.test_node.RadioConfig.UserPreferences">UserPreferences</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.WhichOneof" href="#meshtastic.tests.test_node.RadioConfig.WhichOneof">WhichOneof</a></code></li>
|
|
<li><code><a title="meshtastic.tests.test_node.RadioConfig.preferences" href="#meshtastic.tests.test_node.RadioConfig.preferences">preferences</a></code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</main>
|
|
<footer id="footer">
|
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
|
</footer>
|
|
</body>
|
|
</html> |