Sonar qube 3 (#166)
* add unittests for mqtt.py * add mock * move test requirements into a file * fix unit tests * fix formating * initial version * fix SonarQube warning
This commit is contained in:
11
.github/workflows/python-app.yml
vendored
11
.github/workflows/python-app.yml
vendored
@@ -36,6 +36,15 @@ jobs:
|
||||
timezoneLinux: "Europe/Berlin"
|
||||
timezoneMacos: "Europe/Berlin"
|
||||
timezoneWindows: "Europe/Berlin"
|
||||
# - name: Start Mosquitto
|
||||
# uses: namoshek/mosquitto-github-action@v1
|
||||
# with:
|
||||
# version: '1.6'
|
||||
# ports: '1883:1883 8883:8883'
|
||||
# certificates: ${{ github.workspace }}/.ci/tls-certificates
|
||||
# config: ${{ github.workspace }}/.ci/mosquitto.conf
|
||||
# password-file: ${{ github.workspace}}/.ci/mosquitto.passwd
|
||||
# container-name: 'mqtt'
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
@@ -46,7 +55,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install flake8 pytest pytest-asyncio pytest-cov coverage
|
||||
if [ -f requirements-test.txt ]; then pip install -r requirements-test.txt; fi
|
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||
- name: Lint with flake8
|
||||
run: |
|
||||
|
||||
6
app/requirements-test.txt
Normal file
6
app/requirements-test.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
flake8
|
||||
pytest
|
||||
pytest-asyncio
|
||||
pytest-cov
|
||||
mock
|
||||
coverage
|
||||
@@ -177,7 +177,7 @@ class Talent(Message):
|
||||
return
|
||||
|
||||
self.__build_header(0x70, 0x77)
|
||||
self._send_buffer += b'\x00\x01\xa3\x28' # fixme
|
||||
self._send_buffer += b'\x00\x01\xa3\x28' # magic ?
|
||||
self._send_buffer += struct.pack('!B', len(modbus_pdu))
|
||||
self._send_buffer += modbus_pdu
|
||||
self.__finish_send_msg()
|
||||
|
||||
157
app/src/mqtt.py
157
app/src/mqtt.py
@@ -2,10 +2,16 @@ import asyncio
|
||||
import logging
|
||||
import aiomqtt
|
||||
import traceback
|
||||
from modbus import Modbus
|
||||
from messages import Message
|
||||
from config import Config
|
||||
from singleton import Singleton
|
||||
if __name__ == "app.src.mqtt":
|
||||
from app.src.modbus import Modbus
|
||||
from app.src.messages import Message
|
||||
from app.src.config import Config
|
||||
from app.src.singleton import Singleton
|
||||
else: # pragma: no cover
|
||||
from modbus import Modbus
|
||||
from messages import Message
|
||||
from config import Config
|
||||
from singleton import Singleton
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
@@ -22,6 +28,14 @@ class Mqtt(metaclass=Singleton):
|
||||
self.task = loop.create_task(self.__loop())
|
||||
self.ha_restarts = 0
|
||||
|
||||
ha = Config.get('ha')
|
||||
self.ha_status_topic = f"{ha['auto_conf_prefix']}/status"
|
||||
self.mb_rated_topic = f"{ha['entity_prefix']}/+/rated_load"
|
||||
self.mb_out_coeff_topic = f"{ha['entity_prefix']}/+/out_coeff"
|
||||
self.mb_reads_topic = f"{ha['entity_prefix']}/+/modbus_read_regs"
|
||||
self.mb_inputs_topic = f"{ha['entity_prefix']}/+/modbus_read_inputs"
|
||||
self.mb_at_cmd_topic = f"{ha['entity_prefix']}/+/at_cmd"
|
||||
|
||||
@property
|
||||
def ha_restarts(self):
|
||||
return self._ha_restarts
|
||||
@@ -49,7 +63,6 @@ class Mqtt(metaclass=Singleton):
|
||||
|
||||
async def __loop(self) -> None:
|
||||
mqtt = Config.get('mqtt')
|
||||
ha = Config.get('ha')
|
||||
logger_mqtt.info(f'start MQTT: host:{mqtt["host"]} port:'
|
||||
f'{mqtt["port"]} '
|
||||
f'user:{mqtt["user"]}')
|
||||
@@ -59,12 +72,6 @@ class Mqtt(metaclass=Singleton):
|
||||
password=mqtt['passwd'])
|
||||
|
||||
interval = 5 # Seconds
|
||||
ha_status_topic = f"{ha['auto_conf_prefix']}/status"
|
||||
mb_rated_topic = "tsun/+/rated_load" # fixme
|
||||
mb_out_coeff_topic = "tsun/+/out_coeff" # fixme
|
||||
mb_reads_topic = "tsun/+/modbus_read_regs" # fixme
|
||||
mb_inputs_topic = "tsun/+/modbus_read_inputs" # fixme
|
||||
mb_at_cmd_topic = "tsun/+/at_cmd" # fixme
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -74,51 +81,15 @@ class Mqtt(metaclass=Singleton):
|
||||
if self.__cb_mqtt_is_up:
|
||||
await self.__cb_mqtt_is_up()
|
||||
|
||||
# async with self.__client.messages() as messages:
|
||||
await self.__client.subscribe(ha_status_topic)
|
||||
await self.__client.subscribe(mb_rated_topic)
|
||||
await self.__client.subscribe(mb_out_coeff_topic)
|
||||
await self.__client.subscribe(mb_reads_topic)
|
||||
await self.__client.subscribe(mb_inputs_topic)
|
||||
await self.__client.subscribe(mb_at_cmd_topic)
|
||||
await self.__client.subscribe(self.ha_status_topic)
|
||||
await self.__client.subscribe(self.mb_rated_topic)
|
||||
await self.__client.subscribe(self.mb_out_coeff_topic)
|
||||
await self.__client.subscribe(self.mb_reads_topic)
|
||||
await self.__client.subscribe(self.mb_inputs_topic)
|
||||
await self.__client.subscribe(self.mb_at_cmd_topic)
|
||||
|
||||
async for message in self.__client.messages:
|
||||
if message.topic.matches(ha_status_topic):
|
||||
status = message.payload.decode("UTF-8")
|
||||
logger_mqtt.info('Home-Assistant Status:'
|
||||
f' {status}')
|
||||
if status == 'online':
|
||||
self.ha_restarts += 1
|
||||
await self.__cb_mqtt_is_up()
|
||||
|
||||
if message.topic.matches(mb_rated_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
1, 0x2008)
|
||||
|
||||
if message.topic.matches(mb_out_coeff_topic):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
val = round(float(payload) * 1024/100)
|
||||
|
||||
if val < 0 or val > 1024:
|
||||
logger_mqtt.error('out_coeff: value must be in'
|
||||
'the range 0..100,'
|
||||
f' got: {payload}')
|
||||
else:
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
0, 0x202c, val)
|
||||
|
||||
if message.topic.matches(mb_reads_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.READ_REGS, 2)
|
||||
|
||||
if message.topic.matches(mb_inputs_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.READ_INPUTS, 2)
|
||||
|
||||
if message.topic.matches(mb_at_cmd_topic):
|
||||
await self.at_cmd(message)
|
||||
await self.dispatch_msg(message)
|
||||
|
||||
except aiomqtt.MqttError:
|
||||
if Config.is_default('mqtt'):
|
||||
@@ -142,46 +113,76 @@ class Mqtt(metaclass=Singleton):
|
||||
f"Exception:\n"
|
||||
f"{traceback.format_exc()}")
|
||||
|
||||
async def dispatch_msg(self, message):
|
||||
if message.topic.matches(self.ha_status_topic):
|
||||
status = message.payload.decode("UTF-8")
|
||||
logger_mqtt.info('Home-Assistant Status:'
|
||||
f' {status}')
|
||||
if status == 'online':
|
||||
self.ha_restarts += 1
|
||||
await self.__cb_mqtt_is_up()
|
||||
|
||||
if message.topic.matches(self.mb_rated_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
1, 0x2008)
|
||||
|
||||
if message.topic.matches(self.mb_out_coeff_topic):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
try:
|
||||
val = round(float(payload) * 1024/100)
|
||||
if val < 0 or val > 1024:
|
||||
logger_mqtt.error('out_coeff: value must be in'
|
||||
'the range 0..100,'
|
||||
f' got: {payload}')
|
||||
else:
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
0, 0x202c, val)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if message.topic.matches(self.mb_reads_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.READ_REGS, 2)
|
||||
|
||||
if message.topic.matches(self.mb_inputs_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.READ_INPUTS, 2)
|
||||
|
||||
if message.topic.matches(self.mb_at_cmd_topic):
|
||||
await self.at_cmd(message)
|
||||
|
||||
def each_inverter(self, message, func_name: str):
|
||||
topic = str(message.topic)
|
||||
node_id = topic.split('/')[1] + '/'
|
||||
found = False
|
||||
for m in Message:
|
||||
if m.server_side and (m.node_id == node_id):
|
||||
found = True
|
||||
logger_mqtt.debug(f'Found: {node_id}')
|
||||
fnc = getattr(m, func_name, None)
|
||||
if callable(fnc):
|
||||
yield fnc
|
||||
else:
|
||||
logger_mqtt.warning(f'Cmd not supported by: {node_id}')
|
||||
break
|
||||
|
||||
if not found:
|
||||
else:
|
||||
logger_mqtt.warning(f'Node_id: {node_id} not found')
|
||||
|
||||
async def modbus_cmd(self, message, func, params=0, addr=0, val=0):
|
||||
topic = str(message.topic)
|
||||
node_id = topic.split('/')[1] + '/'
|
||||
# refactor into a loop over a table
|
||||
payload = message.payload.decode("UTF-8")
|
||||
logger_mqtt.info(f'MODBUS via MQTT: {topic} = {payload}')
|
||||
for m in Message:
|
||||
if m.server_side and (m.node_id == node_id):
|
||||
logger_mqtt.debug(f'Found: {node_id}')
|
||||
fnc = getattr(m, "send_modbus_cmd", None)
|
||||
res = payload.split(',')
|
||||
if params > 0 and params != len(res):
|
||||
logger_mqtt.error(f'Parameter expected: {params}, '
|
||||
f'got: {len(res)}')
|
||||
return
|
||||
|
||||
if callable(fnc):
|
||||
if params == 1:
|
||||
val = int(payload)
|
||||
elif params == 2:
|
||||
addr = int(res[0], base=16)
|
||||
val = int(res[1]) # lenght
|
||||
await fnc(func, addr, val, logging.INFO)
|
||||
for fnc in self.each_inverter(message, "send_modbus_cmd"):
|
||||
res = payload.split(',')
|
||||
if params > 0 and params != len(res):
|
||||
logger_mqtt.error(f'Parameter expected: {params}, '
|
||||
f'got: {len(res)}')
|
||||
return
|
||||
if params == 1:
|
||||
val = int(payload)
|
||||
elif params == 2:
|
||||
addr = int(res[0], base=16)
|
||||
val = int(res[1]) # lenght
|
||||
await fnc(func, addr, val, logging.INFO)
|
||||
|
||||
async def at_cmd(self, message):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
|
||||
class Singleton(type):
|
||||
_instances = {}
|
||||
_instances = WeakValueDictionary()
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
# logger_mqtt.debug('singleton: __call__')
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton,
|
||||
cls).__call__(*args, **kwargs)
|
||||
instance = super(Singleton,
|
||||
cls).__call__(*args, **kwargs)
|
||||
cls._instances[cls] = instance
|
||||
|
||||
return cls._instances[cls]
|
||||
|
||||
250
app/tests/test_mqtt.py
Normal file
250
app/tests/test_mqtt.py
Normal file
@@ -0,0 +1,250 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
import asyncio
|
||||
import aiomqtt
|
||||
import logging
|
||||
|
||||
from mock import patch, Mock
|
||||
from app.src.mqtt import Mqtt
|
||||
from app.src.modbus import Modbus
|
||||
from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
from app.src.config import Config
|
||||
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def test_port():
|
||||
return 1883
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def test_hostname():
|
||||
# if getenv("GITHUB_ACTIONS") == "true":
|
||||
# return 'mqtt'
|
||||
# else:
|
||||
return 'test.mosquitto.org'
|
||||
|
||||
@pytest.fixture
|
||||
def config_mqtt_conn(test_hostname, test_port):
|
||||
Config.act_config = {'mqtt':{'host': test_hostname, 'port': test_port, 'user': '', 'passwd': ''},
|
||||
'ha':{'auto_conf_prefix': 'homeassistant','discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun'}
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def config_no_conn(test_port):
|
||||
Config.act_config = {'mqtt':{'host': "", 'port': test_port, 'user': '', 'passwd': ''},
|
||||
'ha':{'auto_conf_prefix': 'homeassistant','discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun'}
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def spy_at_cmd():
|
||||
conn = SolarmanV5(server_side=True, client_mode= False)
|
||||
conn.node_id = 'inv_2/'
|
||||
with patch.object(conn, 'send_at_cmd', wraps=conn.send_at_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
conn.close()
|
||||
|
||||
@pytest.fixture
|
||||
def spy_modbus_cmd():
|
||||
conn = SolarmanV5(server_side=True, client_mode= False)
|
||||
conn.node_id = 'inv_1/'
|
||||
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
conn.close()
|
||||
|
||||
@pytest.fixture
|
||||
def spy_modbus_cmd_client():
|
||||
conn = SolarmanV5(server_side=False, client_mode= False)
|
||||
conn.node_id = 'inv_1/'
|
||||
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
conn.close()
|
||||
|
||||
def test_native_client(test_hostname, test_port):
|
||||
"""Sanity check: Make sure the paho-mqtt client can connect to the test
|
||||
MQTT server.
|
||||
"""
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import threading
|
||||
|
||||
c = mqtt.Client()
|
||||
c.loop_start()
|
||||
try:
|
||||
# Just make sure the client connects successfully
|
||||
on_connect = threading.Event()
|
||||
c.on_connect = Mock(side_effect=lambda *_: on_connect.set())
|
||||
c.connect_async(test_hostname, test_port)
|
||||
assert on_connect.wait(5)
|
||||
finally:
|
||||
c.loop_stop()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_no_config(config_no_conn):
|
||||
_ = config_no_conn
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
on_connect = asyncio.Event()
|
||||
async def cb():
|
||||
on_connect.set()
|
||||
|
||||
try:
|
||||
m = Mqtt(cb)
|
||||
assert m.task
|
||||
await asyncio.sleep(1)
|
||||
assert not on_connect.is_set()
|
||||
try:
|
||||
await m.publish('homeassistant/status', 'online')
|
||||
assert False
|
||||
except Exception:
|
||||
pass
|
||||
except TimeoutError:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_connection(config_mqtt_conn):
|
||||
_ = config_mqtt_conn
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
on_connect = asyncio.Event()
|
||||
async def cb():
|
||||
on_connect.set()
|
||||
|
||||
try:
|
||||
m = Mqtt(cb)
|
||||
assert m.task
|
||||
assert await asyncio.wait_for(on_connect.wait(), 5)
|
||||
# await asyncio.sleep(1)
|
||||
assert 0 == m.ha_restarts
|
||||
await m.publish('homeassistant/status', 'online')
|
||||
except TimeoutError:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
await m.publish('homeassistant/status', 'online')
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_msg_dispatch(config_mqtt_conn, spy_modbus_cmd):
|
||||
_ = config_mqtt_conn
|
||||
spy = spy_modbus_cmd
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/rated_load', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x2008, 2, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'100', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 1024, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'50', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 512, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.READ_REGS, 0x3000, 10, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.READ_INPUTS, 0x3000, 10, logging.INFO)
|
||||
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_msg_dispatch_err(config_mqtt_conn, spy_modbus_cmd):
|
||||
_ = config_mqtt_conn
|
||||
spy = spy_modbus_cmd
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
# test out of range param
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'-1', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
# test unknown node_id
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_2/out_coeff', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
# test invalid fload param
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'2, 3', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10, 7', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_msg_ignore_client_conn(config_mqtt_conn, spy_modbus_cmd_client):
|
||||
'''don't call function if connnection is not in server mode'''
|
||||
_ = config_mqtt_conn
|
||||
spy = spy_modbus_cmd_client
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/rated_load', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ha_reconnect(config_mqtt_conn):
|
||||
_ = config_mqtt_conn
|
||||
on_connect = asyncio.Event()
|
||||
async def cb():
|
||||
on_connect.set()
|
||||
|
||||
try:
|
||||
m = Mqtt(cb)
|
||||
msg = aiomqtt.Message(topic= 'homeassistant/status', payload= b'offline', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
assert not on_connect.is_set()
|
||||
|
||||
msg = aiomqtt.Message(topic= 'homeassistant/status', payload= b'online', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
assert on_connect.is_set()
|
||||
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ignore_unknown_func(config_mqtt_conn):
|
||||
'''don't dispatch for unknwon function names'''
|
||||
_ = config_mqtt_conn
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/rated_load', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
for _ in m.each_inverter(msg, 'unkown_fnc'):
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_at_cmd_dispatch(config_mqtt_conn, spy_at_cmd):
|
||||
_ = config_mqtt_conn
|
||||
spy = spy_at_cmd
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_2/at_cmd', payload= b'AT+', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with('AT+')
|
||||
|
||||
finally:
|
||||
await m.close()
|
||||
18
app/tests/test_singleton.py
Normal file
18
app/tests/test_singleton.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# test_with_pytest.py
|
||||
import pytest
|
||||
from app.src.singleton import Singleton
|
||||
|
||||
class Test(metaclass=Singleton):
|
||||
def __init__(self):
|
||||
pass # is a dummy test class
|
||||
|
||||
def test_singleton_metaclass():
|
||||
a = Test()
|
||||
assert 1 == len(Singleton._instances)
|
||||
b = Test()
|
||||
assert 1 == len(Singleton._instances)
|
||||
assert a is b
|
||||
del a
|
||||
assert 1 == len(Singleton._instances)
|
||||
del b
|
||||
assert 0 == len(Singleton._instances)
|
||||
@@ -8,7 +8,7 @@ from app.src.gen3plus.solarman_v5 import SolarmanV5
|
||||
from app.src.config import Config
|
||||
from app.src.infos import Infos, Register
|
||||
from app.src.modbus import Modbus
|
||||
from app.src.messages import State
|
||||
from app.src.messages import State, Message
|
||||
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
@@ -773,7 +773,7 @@ def test_invalid_checksum(invalid_checksum, device_ind_msg):
|
||||
m.close()
|
||||
|
||||
def test_read_message_twice(config_no_tsun_inv1, device_ind_msg, device_rsp_msg):
|
||||
config_no_tsun_inv1
|
||||
_ = config_no_tsun_inv1
|
||||
m = MemoryStream(device_ind_msg, (0,))
|
||||
m.append_msg(device_ind_msg)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -815,7 +815,7 @@ def test_read_message_in_chunks(device_ind_msg):
|
||||
m.close()
|
||||
|
||||
def test_read_message_in_chunks2(config_tsun_inv1, device_ind_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(device_ind_msg, (4,10,0))
|
||||
m.read() # read 4 bytes, header incomplere
|
||||
assert not m.header_valid
|
||||
@@ -840,7 +840,7 @@ def test_read_message_in_chunks2(config_tsun_inv1, device_ind_msg):
|
||||
m.close()
|
||||
|
||||
def test_read_two_messages(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inverter_ind_msg, inverter_rsp_msg):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(device_ind_msg, (0,))
|
||||
m.append_msg(inverter_ind_msg)
|
||||
assert 0 == m.sensor_list
|
||||
@@ -869,7 +869,7 @@ def test_read_two_messages(config_tsun_allow_all, device_ind_msg, device_rsp_msg
|
||||
m.close()
|
||||
|
||||
def test_read_two_messages2(config_tsun_allow_all, inverter_ind_msg, inverter_ind_msg_81, inverter_rsp_msg, inverter_rsp_msg_81):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(inverter_ind_msg, (0,))
|
||||
m.append_msg(inverter_ind_msg_81)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -895,7 +895,7 @@ def test_read_two_messages2(config_tsun_allow_all, inverter_ind_msg, inverter_in
|
||||
m.close()
|
||||
|
||||
def test_unkown_message(config_tsun_inv1, unknown_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(unknown_msg, (0,))
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -913,7 +913,7 @@ def test_unkown_message(config_tsun_inv1, unknown_msg):
|
||||
m.close()
|
||||
|
||||
def test_device_rsp(config_tsun_inv1, device_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(device_rsp_msg, (0,), False)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -931,7 +931,7 @@ def test_device_rsp(config_tsun_inv1, device_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_inverter_rsp(config_tsun_inv1, inverter_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(inverter_rsp_msg, (0,), False)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -949,7 +949,7 @@ def test_inverter_rsp(config_tsun_inv1, inverter_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_heartbeat_ind(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(heartbeat_ind_msg, (0,))
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -966,7 +966,7 @@ def test_heartbeat_ind(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_heartbeat_ind2(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(heartbeat_ind_msg, (0,))
|
||||
m.no_forwarding = True
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -984,7 +984,7 @@ def test_heartbeat_ind2(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_heartbeat_rsp(config_tsun_inv1, heartbeat_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(heartbeat_rsp_msg, (0,), False)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1002,7 +1002,7 @@ def test_heartbeat_rsp(config_tsun_inv1, heartbeat_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_sync_start_ind(config_tsun_inv1, sync_start_ind_msg, sync_start_rsp_msg, sync_start_fwd_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(sync_start_ind_msg, (0,))
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1025,7 +1025,7 @@ def test_sync_start_ind(config_tsun_inv1, sync_start_ind_msg, sync_start_rsp_msg
|
||||
m.close()
|
||||
|
||||
def test_sync_start_rsp(config_tsun_inv1, sync_start_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(sync_start_rsp_msg, (0,), False)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1043,7 +1043,7 @@ def test_sync_start_rsp(config_tsun_inv1, sync_start_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_sync_end_ind(config_tsun_inv1, sync_end_ind_msg, sync_end_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(sync_end_ind_msg, (0,))
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1060,7 +1060,7 @@ def test_sync_end_ind(config_tsun_inv1, sync_end_ind_msg, sync_end_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_sync_end_rsp(config_tsun_inv1, sync_end_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(sync_end_rsp_msg, (0,), False)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
|
||||
@@ -1078,7 +1078,7 @@ def test_sync_end_rsp(config_tsun_inv1, sync_end_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_build_modell_600(config_tsun_allow_all, inverter_ind_msg):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(inverter_ind_msg, (0,))
|
||||
assert 0 == m.sensor_list
|
||||
assert 0 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||
@@ -1097,7 +1097,7 @@ def test_build_modell_600(config_tsun_allow_all, inverter_ind_msg):
|
||||
m.close()
|
||||
|
||||
def test_build_modell_1600(config_tsun_allow_all, inverter_ind_msg1600):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(inverter_ind_msg1600, (0,))
|
||||
assert 0 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||
assert None == m.db.get_db_value(Register.RATED_POWER, None)
|
||||
@@ -1109,7 +1109,7 @@ def test_build_modell_1600(config_tsun_allow_all, inverter_ind_msg1600):
|
||||
m.close()
|
||||
|
||||
def test_build_modell_1800(config_tsun_allow_all, inverter_ind_msg1800):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(inverter_ind_msg1800, (0,))
|
||||
assert 0 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||
assert None == m.db.get_db_value(Register.RATED_POWER, None)
|
||||
@@ -1121,7 +1121,7 @@ def test_build_modell_1800(config_tsun_allow_all, inverter_ind_msg1800):
|
||||
m.close()
|
||||
|
||||
def test_build_modell_2000(config_tsun_allow_all, inverter_ind_msg2000):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(inverter_ind_msg2000, (0,))
|
||||
assert 0 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||
assert None == m.db.get_db_value(Register.RATED_POWER, None)
|
||||
@@ -1133,7 +1133,7 @@ def test_build_modell_2000(config_tsun_allow_all, inverter_ind_msg2000):
|
||||
m.close()
|
||||
|
||||
def test_build_modell_800(config_tsun_allow_all, inverter_ind_msg800):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(inverter_ind_msg800, (0,))
|
||||
assert 0 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
|
||||
assert None == m.db.get_db_value(Register.RATED_POWER, None)
|
||||
@@ -1145,7 +1145,7 @@ def test_build_modell_800(config_tsun_allow_all, inverter_ind_msg800):
|
||||
m.close()
|
||||
|
||||
def test_build_logger_modell(config_tsun_allow_all, device_ind_msg):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(device_ind_msg, (0,))
|
||||
assert 0 == m.db.get_db_value(Register.COLLECTOR_FW_VERSION, 0)
|
||||
assert 'IGEN TECH' == m.db.get_db_value(Register.CHIP_TYPE, None)
|
||||
@@ -1156,6 +1156,7 @@ def test_build_logger_modell(config_tsun_allow_all, device_ind_msg):
|
||||
m.close()
|
||||
|
||||
def test_msg_iterator():
|
||||
Message._registry.clear()
|
||||
m1 = SolarmanV5(server_side=True, client_mode=False)
|
||||
m2 = SolarmanV5(server_side=True, client_mode=False)
|
||||
m3 = SolarmanV5(server_side=True, client_mode=False)
|
||||
@@ -1195,7 +1196,7 @@ def test_proxy_counter():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_msg_build_modbus_req(config_tsun_inv1, device_ind_msg, device_rsp_msg, inverter_ind_msg, inverter_rsp_msg, msg_modbus_cmd):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(device_ind_msg, (0,), True)
|
||||
m.read()
|
||||
assert m.control == 0x4110
|
||||
@@ -1241,7 +1242,7 @@ async def test_msg_build_modbus_req(config_tsun_inv1, device_ind_msg, device_rsp
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_at_cmd(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inverter_ind_msg, inverter_rsp_msg, at_command_ind_msg, at_command_rsp_msg):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(device_ind_msg, (0,), True)
|
||||
m.read() # read device ind
|
||||
assert m.control == 0x4110
|
||||
@@ -1298,7 +1299,7 @@ async def test_at_cmd(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inv
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_at_cmd_blocked(config_tsun_allow_all, device_ind_msg, device_rsp_msg, inverter_ind_msg, inverter_rsp_msg, at_command_ind_msg):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(device_ind_msg, (0,), True)
|
||||
m.read()
|
||||
assert m.control == 0x4110
|
||||
@@ -1336,7 +1337,7 @@ async def test_at_cmd_blocked(config_tsun_allow_all, device_ind_msg, device_rsp_
|
||||
m.close()
|
||||
|
||||
def test_at_cmd_ind(config_tsun_inv1, at_command_ind_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(at_command_ind_msg, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['AT_Command'] = 0
|
||||
@@ -1360,7 +1361,7 @@ def test_at_cmd_ind(config_tsun_inv1, at_command_ind_msg):
|
||||
m.close()
|
||||
|
||||
def test_at_cmd_ind_block(config_tsun_inv1, at_command_ind_msg_block):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(at_command_ind_msg_block, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['AT_Command'] = 0
|
||||
@@ -1384,7 +1385,7 @@ def test_at_cmd_ind_block(config_tsun_inv1, at_command_ind_msg_block):
|
||||
m.close()
|
||||
|
||||
def test_msg_at_command_rsp1(config_tsun_inv1, at_command_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(at_command_rsp_msg)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1403,7 +1404,7 @@ def test_msg_at_command_rsp1(config_tsun_inv1, at_command_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_msg_at_command_rsp2(config_tsun_inv1, at_command_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(at_command_rsp_msg)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1422,7 +1423,7 @@ def test_msg_at_command_rsp2(config_tsun_inv1, at_command_rsp_msg):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd, msg_modbus_cmd_fwd):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
m.snr = get_sn_int()
|
||||
m.sensor_list = 0x2b0
|
||||
@@ -1450,7 +1451,7 @@ def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd, msg_modbus_cmd_fwd):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd_crc_err):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
m.snr = get_sn_int()
|
||||
m.state = State.up
|
||||
@@ -1477,7 +1478,7 @@ def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd_crc_err):
|
||||
m.close()
|
||||
|
||||
def test_msg_unknown_cmd_req(config_tsun_inv1, msg_unknown_cmd):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_unknown_cmd, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['AT_Command'] = 0
|
||||
@@ -1500,7 +1501,7 @@ def test_msg_unknown_cmd_req(config_tsun_inv1, msg_unknown_cmd):
|
||||
|
||||
def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp):
|
||||
'''Modbus response without a valid Modbus request must be dropped'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_rsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1519,7 +1520,7 @@ def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp):
|
||||
|
||||
def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp):
|
||||
'''Modbus response with a valid Modbus request must be forwarded'''
|
||||
config_tsun_inv1 # setup config structure
|
||||
_ = config_tsun_inv1 # setup config structure
|
||||
m = MemoryStream(msg_modbus_rsp)
|
||||
|
||||
m.mb.rsp_handler = m._SolarmanV5__forward_msg
|
||||
@@ -1557,7 +1558,7 @@ def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp):
|
||||
|
||||
def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp):
|
||||
'''Modbus response with a valid Modbus request must be forwarded'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_rsp)
|
||||
|
||||
m.mb.rsp_handler = m._SolarmanV5__forward_msg
|
||||
@@ -1593,7 +1594,7 @@ def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_unknown_rsp(config_tsun_inv1, msg_unknown_cmd_rsp):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_unknown_cmd_rsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1611,7 +1612,7 @@ def test_msg_unknown_rsp(config_tsun_inv1, msg_unknown_cmd_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_invalid):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_invalid, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1625,7 +1626,7 @@ def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_invalid):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
# receive more bytes than expected (7 bytes from the next msg)
|
||||
m = MemoryStream(msg_modbus_rsp+b'\x00\x00\x00\x45\x10\x52\x31', (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -1651,7 +1652,7 @@ def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp_msg):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
assert asyncio.get_running_loop()
|
||||
m = MemoryStream(heartbeat_ind_msg, (0,))
|
||||
assert asyncio.get_running_loop() == m.mb_timer.loop
|
||||
@@ -1692,7 +1693,7 @@ async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_client_mode(config_tsun_inv1):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
assert asyncio.get_running_loop()
|
||||
m = MemoryStream(b'')
|
||||
assert m.state == State.init
|
||||
|
||||
@@ -541,7 +541,7 @@ def test_read_message(msg_contact_info):
|
||||
m.close()
|
||||
|
||||
def test_read_message_twice(config_no_tsun_inv1, msg_inverter_ind):
|
||||
config_no_tsun_inv1
|
||||
_ = config_no_tsun_inv1
|
||||
m = MemoryStream(msg_inverter_ind, (0,))
|
||||
m.append_msg(msg_inverter_ind)
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -622,7 +622,7 @@ def test_read_message_in_chunks2(msg_contact_info):
|
||||
m.close()
|
||||
|
||||
def test_read_two_messages(config_tsun_allow_all, msg2_contact_info,msg_contact_rsp,msg_contact_rsp2):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(msg2_contact_info, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -652,7 +652,7 @@ def test_read_two_messages(config_tsun_allow_all, msg2_contact_info,msg_contact_
|
||||
m.close()
|
||||
|
||||
def test_msg_contact_resp(config_tsun_inv1, msg_contact_rsp):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_contact_rsp, (0,), False)
|
||||
m.await_conn_resp_cnt = 1
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -672,7 +672,7 @@ def test_msg_contact_resp(config_tsun_inv1, msg_contact_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_contact_resp_2(config_tsun_inv1, msg_contact_rsp):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_contact_rsp, (0,), False)
|
||||
m.await_conn_resp_cnt = 0
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -692,7 +692,7 @@ def test_msg_contact_resp_2(config_tsun_inv1, msg_contact_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_contact_resp_3(config_tsun_inv1, msg_contact_rsp):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_contact_rsp, (0,), True)
|
||||
m.await_conn_resp_cnt = 0
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -712,7 +712,7 @@ def test_msg_contact_resp_3(config_tsun_inv1, msg_contact_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_contact_invalid(config_tsun_inv1, msg_contact_invalid):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_contact_invalid, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -730,7 +730,7 @@ def test_msg_contact_invalid(config_tsun_inv1, msg_contact_invalid):
|
||||
m.close()
|
||||
|
||||
def test_msg_get_time(config_tsun_inv1, msg_get_time):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_get_time, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -749,7 +749,7 @@ def test_msg_get_time(config_tsun_inv1, msg_get_time):
|
||||
m.close()
|
||||
|
||||
def test_msg_get_time_autark(config_no_tsun_inv1, msg_get_time):
|
||||
config_no_tsun_inv1
|
||||
_ = config_no_tsun_inv1
|
||||
m = MemoryStream(msg_get_time, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -768,7 +768,7 @@ def test_msg_get_time_autark(config_no_tsun_inv1, msg_get_time):
|
||||
m.close()
|
||||
|
||||
def test_msg_time_resp(config_tsun_inv1, msg_time_rsp):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_time_rsp, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -787,7 +787,7 @@ def test_msg_time_resp(config_tsun_inv1, msg_time_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_time_resp_autark(config_no_tsun_inv1, msg_time_rsp):
|
||||
config_no_tsun_inv1
|
||||
_ = config_no_tsun_inv1
|
||||
m = MemoryStream(msg_time_rsp, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -806,7 +806,7 @@ def test_msg_time_resp_autark(config_no_tsun_inv1, msg_time_rsp):
|
||||
m.close()
|
||||
|
||||
def test_msg_time_inv_resp(config_tsun_inv1, msg_time_rsp_inv):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_time_rsp_inv, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -825,7 +825,7 @@ def test_msg_time_inv_resp(config_tsun_inv1, msg_time_rsp_inv):
|
||||
m.close()
|
||||
|
||||
def test_msg_time_invalid(config_tsun_inv1, msg_time_invalid):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_time_invalid, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -844,7 +844,7 @@ def test_msg_time_invalid(config_tsun_inv1, msg_time_invalid):
|
||||
m.close()
|
||||
|
||||
def test_msg_time_invalid_autark(config_no_tsun_inv1, msg_time_invalid):
|
||||
config_no_tsun_inv1
|
||||
_ = config_no_tsun_inv1
|
||||
m = MemoryStream(msg_time_invalid, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -863,7 +863,7 @@ def test_msg_time_invalid_autark(config_no_tsun_inv1, msg_time_invalid):
|
||||
m.close()
|
||||
|
||||
def test_msg_cntrl_ind(config_tsun_inv1, msg_controller_ind, msg_controller_ind_ts_offs, msg_controller_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_controller_ind, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -886,7 +886,7 @@ def test_msg_cntrl_ind(config_tsun_inv1, msg_controller_ind, msg_controller_ind_
|
||||
m.close()
|
||||
|
||||
def test_msg_cntrl_ack(config_tsun_inv1, msg_controller_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_controller_ack, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -904,7 +904,7 @@ def test_msg_cntrl_ack(config_tsun_inv1, msg_controller_ack):
|
||||
m.close()
|
||||
|
||||
def test_msg_cntrl_invalid(config_tsun_inv1, msg_controller_invalid):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_controller_invalid, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -927,7 +927,7 @@ def test_msg_cntrl_invalid(config_tsun_inv1, msg_controller_invalid):
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_ind(config_tsun_inv1, msg_inverter_ind, msg_inverter_ind_ts_offs, msg_inverter_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(msg_inverter_ind, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -951,7 +951,7 @@ def test_msg_inv_ind(config_tsun_inv1, msg_inverter_ind, msg_inverter_ind_ts_off
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_ind1(config_tsun_inv1, msg_inverter_ind2, msg_inverter_ind_ts_offs, msg_inverter_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(msg_inverter_ind2, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -975,7 +975,7 @@ def test_msg_inv_ind1(config_tsun_inv1, msg_inverter_ind2, msg_inverter_ind_ts_o
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_ind2(config_tsun_inv1, msg_inverter_ind_new, msg_inverter_ind_ts_offs, msg_inverter_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(msg_inverter_ind_new, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -1003,7 +1003,7 @@ def test_msg_inv_ind2(config_tsun_inv1, msg_inverter_ind_new, msg_inverter_ind_t
|
||||
|
||||
def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack):
|
||||
'''test that after close the invert_status will be resetted if the grid power is <2W'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(msg_inverter_ind_0w, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -1030,7 +1030,7 @@ def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack):
|
||||
|
||||
|
||||
def test_msg_inv_ack(config_tsun_inv1, msg_inverter_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
tracer.setLevel(logging.ERROR)
|
||||
|
||||
m = MemoryStream(msg_inverter_ack, (0,), False)
|
||||
@@ -1050,7 +1050,7 @@ def test_msg_inv_ack(config_tsun_inv1, msg_inverter_ack):
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_invalid(config_tsun_inv1, msg_inverter_invalid):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_inverter_invalid, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.read() # read complete msg, and dispatch msg
|
||||
@@ -1073,7 +1073,7 @@ def test_msg_inv_invalid(config_tsun_inv1, msg_inverter_invalid):
|
||||
m.close()
|
||||
|
||||
def test_msg_ota_req(config_tsun_inv1, msg_ota_req):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_ota_req, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['OTA_Start_Msg'] = 0
|
||||
@@ -1098,7 +1098,7 @@ def test_msg_ota_req(config_tsun_inv1, msg_ota_req):
|
||||
m.close()
|
||||
|
||||
def test_msg_ota_ack(config_tsun_inv1, msg_ota_ack):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
tracer.setLevel(logging.ERROR)
|
||||
|
||||
m = MemoryStream(msg_ota_ack, (0,), False)
|
||||
@@ -1125,7 +1125,7 @@ def test_msg_ota_ack(config_tsun_inv1, msg_ota_ack):
|
||||
m.close()
|
||||
|
||||
def test_msg_ota_invalid(config_tsun_inv1, msg_ota_invalid):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_ota_invalid, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['OTA_Start_Msg'] = 0
|
||||
@@ -1268,7 +1268,7 @@ def test_proxy_counter():
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
m.id_str = b"R170000000000001"
|
||||
m.state = State.up
|
||||
@@ -1299,7 +1299,7 @@ def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
m.id_str = b"R170000000000001"
|
||||
|
||||
@@ -1329,7 +1329,7 @@ def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_req3(config_tsun_inv1, msg_modbus_cmd_crc_err):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'')
|
||||
m.id_str = b"R170000000000001"
|
||||
c = m.createClientStream(msg_modbus_cmd_crc_err)
|
||||
@@ -1358,7 +1358,7 @@ def test_msg_modbus_req3(config_tsun_inv1, msg_modbus_cmd_crc_err):
|
||||
|
||||
def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp):
|
||||
'''Modbus response without a valid Modbus request must be dropped'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_rsp)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1379,7 +1379,7 @@ def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp):
|
||||
|
||||
def test_msg_modbus_cloud_rsp(config_tsun_inv1, msg_modbus_rsp):
|
||||
'''Modbus response from TSUN without a valid Modbus request must be dropped'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_rsp, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Unknown_Msg'] = 0
|
||||
@@ -1402,7 +1402,7 @@ def test_msg_modbus_cloud_rsp(config_tsun_inv1, msg_modbus_rsp):
|
||||
|
||||
def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp20):
|
||||
'''Modbus response with a valid Modbus request must be forwarded'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_rsp20)
|
||||
m.append_msg(msg_modbus_rsp20)
|
||||
|
||||
@@ -1432,7 +1432,7 @@ def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp20):
|
||||
|
||||
def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp21):
|
||||
'''Modbus response with a valid Modbus request must be forwarded'''
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_rsp21)
|
||||
m.append_msg(msg_modbus_rsp21)
|
||||
|
||||
@@ -1461,7 +1461,7 @@ def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp21):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_inv):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(msg_modbus_inv, (0,), False)
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.db.stat['proxy']['Modbus_Command'] = 0
|
||||
@@ -1481,7 +1481,7 @@ def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_inv):
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp20):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
# receive more bytes than expected (7 bytes from the next msg)
|
||||
m = MemoryStream(msg_modbus_rsp20+b'\x00\x00\x00\x45\x10\x52\x31', (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -1513,7 +1513,7 @@ def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp20):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_msg_build_modbus_req(config_tsun_inv1, msg_modbus_cmd):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
m = MemoryStream(b'', (0,), True)
|
||||
m.id_str = b"R170000000000001"
|
||||
await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG)
|
||||
@@ -1539,7 +1539,7 @@ async def test_msg_build_modbus_req(config_tsun_inv1, msg_modbus_cmd):
|
||||
m.close()
|
||||
|
||||
def test_modbus_no_polling(config_no_modbus_poll, msg_get_time):
|
||||
config_no_modbus_poll
|
||||
_ = config_no_modbus_poll
|
||||
m = MemoryStream(msg_get_time, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
m.modbus_polling = False
|
||||
@@ -1560,7 +1560,7 @@ def test_modbus_no_polling(config_no_modbus_poll, msg_get_time):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modbus_polling(config_tsun_inv1, msg_inverter_ind):
|
||||
config_tsun_inv1
|
||||
_ = config_tsun_inv1
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
m = MemoryStream(msg_inverter_ind, (0,))
|
||||
@@ -1600,7 +1600,7 @@ async def test_modbus_polling(config_tsun_inv1, msg_inverter_ind):
|
||||
m.close()
|
||||
|
||||
def test_broken_recv_buf(config_tsun_allow_all, broken_recv_buf):
|
||||
config_tsun_allow_all
|
||||
_ = config_tsun_allow_all
|
||||
m = MemoryStream(broken_recv_buf, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
assert m.db.stat['proxy']['Invalid_Data_Type'] == 0
|
||||
|
||||
1
requirements-test.txt
Normal file
1
requirements-test.txt
Normal file
@@ -0,0 +1 @@
|
||||
-r ./app/requirements-test.txt
|
||||
Reference in New Issue
Block a user