amqtt.client is not working correctly. Using gmqtt instead
This commit is contained in:
parent
72dcf9af20
commit
6a58d8fb7f
9 changed files with 249 additions and 308 deletions
|
|
@ -5,7 +5,8 @@ import socket
|
|||
import sys
|
||||
|
||||
from bumper.db import revoke_expired_oauths, revoke_expired_tokens
|
||||
from bumper.mqttserver import MQTTHelperBot, MQTTServer
|
||||
from bumper.mqtt.helper_bot import HelperBot
|
||||
from bumper.mqttserver import MQTTServer
|
||||
from bumper.util import get_logger, log_to_stdout
|
||||
from bumper.web.server import WebServer, WebserverBinding
|
||||
from bumper.xmppserver import XMPPServer
|
||||
|
|
@ -50,7 +51,7 @@ token_validity_seconds = 3600 # 1 hour
|
|||
oauth_validity_days = 15
|
||||
|
||||
mqtt_server: MQTTServer
|
||||
mqtt_helperbot: MQTTHelperBot
|
||||
mqtt_helperbot: HelperBot
|
||||
web_server: WebServer
|
||||
xmpp_server: XMPPServer
|
||||
|
||||
|
|
@ -103,7 +104,7 @@ async def start():
|
|||
global mqtt_server
|
||||
mqtt_server = MQTTServer(bumper_listen, mqtt_listen_port)
|
||||
global mqtt_helperbot
|
||||
mqtt_helperbot = MQTTHelperBot(bumper_listen, mqtt_listen_port)
|
||||
mqtt_helperbot = HelperBot(bumper_listen, mqtt_listen_port)
|
||||
global web_server
|
||||
web_server = WebServer(web_server_bindings)
|
||||
global xmpp_server
|
||||
|
|
|
|||
1
bumper/mqtt/__init__.py
Normal file
1
bumper/mqtt/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""Mqtt module."""
|
||||
149
bumper/mqtt/helper_bot.py
Normal file
149
bumper/mqtt/helper_bot.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
"""Helper bot module."""
|
||||
import asyncio
|
||||
import json
|
||||
import ssl
|
||||
from typing import Any, MutableMapping, Union
|
||||
|
||||
from cachetools import TTLCache
|
||||
from gmqtt import Client, Subscription
|
||||
from gmqtt.mqtt.constants import MQTTv311
|
||||
|
||||
from bumper.util import get_logger
|
||||
|
||||
_LOGGER = get_logger("helperbot")
|
||||
|
||||
|
||||
class CommandDto:
|
||||
"""Command DTO."""
|
||||
|
||||
def __init__(self, payload_type: str) -> None:
|
||||
self._payload_type = payload_type
|
||||
self._event = asyncio.Event()
|
||||
self._response: Union[str, bytes]
|
||||
|
||||
async def wait_for_response(self) -> Union[str, dict[str, Any]]:
|
||||
"""Wait for the response to be received."""
|
||||
await self._event.wait()
|
||||
if self._payload_type == "j":
|
||||
return json.loads(self._response) # type:ignore[no-any-return]
|
||||
|
||||
return str(self._response)
|
||||
|
||||
def add_response(self, response: Union[str, bytes]) -> None:
|
||||
"""Add received response."""
|
||||
self._response = response
|
||||
self._event.set()
|
||||
|
||||
|
||||
class HelperBot:
|
||||
"""Helper bot, which converts commands from the rest api to mqtt ones."""
|
||||
|
||||
def __init__(self, host: str, port: int, timeout: float = 60):
|
||||
self._commands: MutableMapping[str, CommandDto] = TTLCache(
|
||||
maxsize=timeout * 60, ttl=timeout * 1.1
|
||||
)
|
||||
self._host = host
|
||||
self._port = port
|
||||
self._client_id = "helperbot@bumper/helperbot"
|
||||
self._timeout = timeout
|
||||
self._client = Client("helperbot@bumper/helperbot")
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
async def _on_message(
|
||||
client: Client, topic: str, payload: bytes, qos: int, properties: dict
|
||||
) -> None:
|
||||
_LOGGER.debug("Got message: topic=%s; payload=%s;", topic, payload.decode())
|
||||
topic_split = topic.split("/")
|
||||
data_decoded = str(payload.decode())
|
||||
if topic_split[10] in self._commands:
|
||||
self._commands[topic_split[10]].add_response(data_decoded)
|
||||
|
||||
self._client.on_message = _on_message
|
||||
|
||||
@property
|
||||
def is_connected(self) -> bool:
|
||||
"""Return True if client is connected successfully."""
|
||||
return self._client.is_connected # type: ignore[no-any-return]
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Connect and subscribe helper bot."""
|
||||
try:
|
||||
if self.is_connected:
|
||||
return
|
||||
|
||||
ssl_ctx = ssl.create_default_context()
|
||||
ssl_ctx.check_hostname = False
|
||||
ssl_ctx.verify_mode = ssl.CERT_NONE
|
||||
await self._client.connect(
|
||||
self._host, self._port, ssl=ssl_ctx, version=MQTTv311
|
||||
)
|
||||
self._client.subscribe(
|
||||
Subscription("iot/p2p/+/+/+/+/helperbot/bumper/helperbot/+/+/+")
|
||||
)
|
||||
except Exception:
|
||||
_LOGGER.exception("An exception occurred during startup", exc_info=True)
|
||||
raise
|
||||
|
||||
async def _wait_for_resp(
|
||||
self, command_dto: CommandDto, request_id: str
|
||||
) -> dict[str, Any]:
|
||||
try:
|
||||
payload = await asyncio.wait_for(
|
||||
command_dto.wait_for_response(), timeout=self._timeout
|
||||
)
|
||||
return {"id": request_id, "ret": "ok", "resp": payload}
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.debug("wait_for_resp timeout reached")
|
||||
except asyncio.CancelledError:
|
||||
_LOGGER.debug("wait_for_resp cancelled by asyncio", exc_info=True)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("An unknown error occurred", exc_info=True)
|
||||
|
||||
return {
|
||||
"id": request_id,
|
||||
"errno": 500,
|
||||
"ret": "fail",
|
||||
"debug": "wait for response timed out",
|
||||
}
|
||||
|
||||
async def send_command(
|
||||
self, cmdjson: dict[str, Any], request_id: str
|
||||
) -> dict[str, Any]:
|
||||
"""Send command over MQTT."""
|
||||
if not self.is_connected:
|
||||
await self.start()
|
||||
|
||||
try:
|
||||
topic = (
|
||||
f"iot/p2p/{cmdjson['cmdName']}/helperbot/bumper/helperbot/{cmdjson['toId']}/"
|
||||
f"{cmdjson['toType']}/{cmdjson['toRes']}/q/{request_id}/{cmdjson['payloadType']}"
|
||||
)
|
||||
|
||||
if cmdjson["payloadType"] == "j":
|
||||
payload = json.dumps(cmdjson["payload"])
|
||||
else:
|
||||
payload = str(cmdjson["payload"])
|
||||
|
||||
command_dto = CommandDto(cmdjson["payloadType"])
|
||||
self._commands[request_id] = command_dto
|
||||
|
||||
_LOGGER.debug("Sending message %s", topic)
|
||||
self._client.publish(topic, payload.encode())
|
||||
|
||||
resp = await self._wait_for_resp(command_dto, request_id)
|
||||
return resp
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Could not send command.", exc_info=True)
|
||||
return {
|
||||
"id": request_id,
|
||||
"errno": 500,
|
||||
"ret": "fail",
|
||||
"debug": "exception occurred please check bumper logs",
|
||||
}
|
||||
finally:
|
||||
self._commands.pop(request_id, None)
|
||||
|
||||
async def disconnect(self) -> None:
|
||||
"""Disconnect client."""
|
||||
if self.is_connected:
|
||||
await self._client.disconnect()
|
||||
|
|
@ -1,18 +1,12 @@
|
|||
"""Mqtt module."""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from asyncio import Task
|
||||
from typing import Any, MutableMapping, Optional, Union
|
||||
from typing import Any
|
||||
|
||||
import amqtt
|
||||
import pkg_resources
|
||||
from amqtt.broker import Broker, BrokerContext
|
||||
from amqtt.client import MQTTClient
|
||||
from amqtt.mqtt.constants import QOS_0
|
||||
from amqtt.session import IncomingApplicationMessage, Session
|
||||
from cachetools import TTLCache
|
||||
from passlib.apps import custom_app_context as pwd_context
|
||||
|
||||
import bumper
|
||||
|
|
@ -32,164 +26,6 @@ helperbotlog = get_logger("helperbot")
|
|||
boterrorlog = get_logger("boterror")
|
||||
|
||||
|
||||
class CommandDto:
|
||||
"""Command DTO."""
|
||||
|
||||
def __init__(self, payload_type: str) -> None:
|
||||
self._payload_type = payload_type
|
||||
self._event = asyncio.Event()
|
||||
self._response: Union[str, bytes]
|
||||
|
||||
async def wait_for_response(self) -> Union[str, dict[str, Any]]:
|
||||
"""Wait for the response to be received."""
|
||||
await self._event.wait()
|
||||
if self._payload_type == "j":
|
||||
return json.loads(self._response) # type:ignore[no-any-return]
|
||||
|
||||
return str(self._response)
|
||||
|
||||
def add_response(self, response: Union[str, bytes]) -> None:
|
||||
"""Add received response."""
|
||||
self._response = response
|
||||
self._event.set()
|
||||
|
||||
|
||||
class MQTTHelperBot:
|
||||
"""Helper bot, which converts commands from the rest api to mqtt ones."""
|
||||
|
||||
def __init__(self, host: str, port: int, timeout: float = 60):
|
||||
self._commands: MutableMapping[str, CommandDto] = TTLCache(
|
||||
maxsize=timeout * 60, ttl=timeout * 1.1
|
||||
)
|
||||
self._host = host
|
||||
self._port = port
|
||||
self._client_id = "helperbot@bumper/helperbot"
|
||||
self._timeout = timeout
|
||||
self._client: Optional[MQTTClient] = None
|
||||
self._new_messages_task: Optional[Task] = None
|
||||
|
||||
@property
|
||||
def is_connected(self) -> bool:
|
||||
"""Return True if client is connected successfully."""
|
||||
return (
|
||||
self._client is not None
|
||||
and self._client.session.transitions.state == "connected"
|
||||
)
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Connect and subscribe helper bot."""
|
||||
try:
|
||||
if self._client is None:
|
||||
self._client = MQTTClient(
|
||||
client_id=self._client_id,
|
||||
config={"check_hostname": False, "reconnect_retries": 20},
|
||||
)
|
||||
|
||||
await self._client.connect(
|
||||
f"mqtts://{self._host}:{self._port}/", cafile=bumper.ca_cert
|
||||
)
|
||||
await self._client.subscribe(
|
||||
[
|
||||
("iot/p2p/+/+/+/+/helperbot/bumper/helperbot/+/+/+", QOS_0),
|
||||
]
|
||||
)
|
||||
self._new_messages_task = asyncio.create_task(
|
||||
self._check_for_new_messages()
|
||||
)
|
||||
except Exception:
|
||||
mqttserverlog.exception(
|
||||
"An exception occurred during startup", exc_info=True
|
||||
)
|
||||
raise
|
||||
|
||||
async def _check_for_new_messages(self) -> None:
|
||||
assert self._client is not None
|
||||
while True:
|
||||
try:
|
||||
message: Optional[
|
||||
IncomingApplicationMessage
|
||||
] = await self._client.deliver_message()
|
||||
if message is not None:
|
||||
topic_split = str(message.topic).split("/")
|
||||
data_decoded = str(message.data.decode("utf-8"))
|
||||
if topic_split[10] in self._commands:
|
||||
self._commands[topic_split[10]].add_response(data_decoded)
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except Exception: # pylint: disable=broad-except
|
||||
helperbotlog.error(
|
||||
"An exception occurred during handling new messages", exc_info=True
|
||||
)
|
||||
|
||||
async def _wait_for_resp(
|
||||
self, command_dto: CommandDto, request_id: str
|
||||
) -> dict[str, Any]:
|
||||
try:
|
||||
payload = await asyncio.wait_for(
|
||||
command_dto.wait_for_response(), timeout=self._timeout
|
||||
)
|
||||
return {"id": request_id, "ret": "ok", "resp": payload}
|
||||
except asyncio.TimeoutError:
|
||||
helperbotlog.debug("wait_for_resp timeout reached")
|
||||
except asyncio.CancelledError:
|
||||
helperbotlog.debug("wait_for_resp cancelled by asyncio", exc_info=True)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
helperbotlog.exception("An unknown error occurred", exc_info=True)
|
||||
|
||||
return {
|
||||
"id": request_id,
|
||||
"errno": 500,
|
||||
"ret": "fail",
|
||||
"debug": "wait for response timed out",
|
||||
}
|
||||
|
||||
async def send_command(
|
||||
self, cmdjson: dict[str, Any], request_id: str
|
||||
) -> dict[str, Any]:
|
||||
"""Send command over MQTT."""
|
||||
if self._client is None:
|
||||
await self.start()
|
||||
assert self._client is not None
|
||||
|
||||
try:
|
||||
topic = (
|
||||
f"iot/p2p/{cmdjson['cmdName']}/helperbot/bumper/helperbot/{cmdjson['toId']}/"
|
||||
f"{cmdjson['toType']}/{cmdjson['toRes']}/q/{request_id}/{cmdjson['payloadType']}"
|
||||
)
|
||||
command_dto = CommandDto(cmdjson["payloadType"])
|
||||
self._commands[request_id] = command_dto
|
||||
|
||||
if cmdjson["payloadType"] == "j":
|
||||
payload = json.dumps(cmdjson["payload"])
|
||||
else:
|
||||
payload = str(cmdjson["payload"])
|
||||
|
||||
await self._client.publish(topic, payload.encode(), QOS_0)
|
||||
|
||||
resp = await self._wait_for_resp(command_dto, request_id)
|
||||
return resp
|
||||
except Exception: # pylint: disable=broad-except
|
||||
helperbotlog.exception("Could not send command.", exc_info=True)
|
||||
return {
|
||||
"id": request_id,
|
||||
"errno": 500,
|
||||
"ret": "fail",
|
||||
"debug": "exception occurred please check bumper logs",
|
||||
}
|
||||
finally:
|
||||
self._commands.pop(request_id, None)
|
||||
|
||||
async def disconnect(self) -> None:
|
||||
"""Disconnect client."""
|
||||
if self._new_messages_task is not None:
|
||||
self._new_messages_task.cancel()
|
||||
self._new_messages_task = None
|
||||
|
||||
if self._client is not None:
|
||||
await self._client.disconnect()
|
||||
self._client = None
|
||||
|
||||
|
||||
class MQTTServer:
|
||||
"""Mqtt server."""
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ def get_logger(name: str, rotate: RotatingFileHandler = None) -> logging.Logger:
|
|||
) # Ignore this logger
|
||||
get_logger("amqtt.broker", rotate)
|
||||
get_logger("amqtt.mqtt.protocol", rotate)
|
||||
get_logger("amqtt.client", rotate)
|
||||
get_logger("gmqtt", rotate)
|
||||
|
||||
return logger
|
||||
|
||||
|
|
|
|||
|
|
@ -2,5 +2,6 @@ aiohttp==3.8.1
|
|||
aiohttp-jinja2==1.5
|
||||
amqtt==0.10.0
|
||||
cachetools==5.0.0
|
||||
gmqtt==0.6.11
|
||||
Jinja2==3.0.3
|
||||
tinydb==4.6.1
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import asyncio
|
||||
import ssl
|
||||
|
||||
import pytest
|
||||
from amqtt.client import MQTTClient
|
||||
from gmqtt import Client
|
||||
from gmqtt.mqtt.constants import MQTTv311
|
||||
|
||||
import bumper
|
||||
from bumper import MQTTServer, WebserverBinding
|
||||
from bumper import HelperBot, MQTTServer, WebserverBinding
|
||||
from tests import HOST, MQTT_PORT, WEBSERVER_PORT
|
||||
|
||||
|
||||
|
|
@ -16,26 +18,40 @@ async def mqtt_server():
|
|||
while not mqtt_server.state == "started":
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
yield
|
||||
yield mqtt_server
|
||||
|
||||
await mqtt_server.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mqtt_server")
|
||||
@pytest.fixture
|
||||
async def mqtt_client():
|
||||
client = MQTTClient(
|
||||
client_id="helperbot@bumper/test",
|
||||
config={"check_hostname": False, "auto_reconnect": False},
|
||||
)
|
||||
async def mqtt_client(mqtt_server: MQTTServer):
|
||||
assert mqtt_server.state == "started"
|
||||
|
||||
await client.connect(f"mqtts://{HOST}:{MQTT_PORT}/", cafile=bumper.ca_cert)
|
||||
client = Client("helperbot@bumper/test")
|
||||
ssl_ctx = ssl.create_default_context()
|
||||
ssl_ctx.check_hostname = False
|
||||
ssl_ctx.verify_mode = ssl.CERT_NONE
|
||||
await client.connect(HOST, MQTT_PORT, ssl=ssl_ctx, version=MQTTv311)
|
||||
|
||||
yield client
|
||||
|
||||
await client.disconnect()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def helper_bot(mqtt_server: MQTTServer):
|
||||
assert mqtt_server.state == "started"
|
||||
|
||||
helper_bot = HelperBot(HOST, MQTT_PORT, 0.1)
|
||||
bumper.mqtt_helperbot = helper_bot
|
||||
await helper_bot.start()
|
||||
assert helper_bot.is_connected
|
||||
|
||||
yield helper_bot
|
||||
|
||||
await helper_bot.disconnect()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def webserver_client(aiohttp_client):
|
||||
webserver = bumper.WebServer(WebserverBinding(HOST, WEBSERVER_PORT, False))
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
import asyncio
|
||||
import os
|
||||
import ssl
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from amqtt.client import MQTTClient
|
||||
from amqtt.mqtt.constants import QOS_0
|
||||
from gmqtt import Client
|
||||
from gmqtt.mqtt.constants import MQTTv311
|
||||
from testfixtures import LogCapture
|
||||
|
||||
import bumper
|
||||
from bumper import MQTTHelperBot, MQTTServer, ca_cert, db
|
||||
from bumper import MQTTServer, db
|
||||
from bumper.mqtt.helper_bot import HelperBot
|
||||
from tests import HOST, MQTT_PORT
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mqtt_server")
|
||||
async def test_helperbot_message(mqtt_client: MQTTClient):
|
||||
async def test_helperbot_message(mqtt_client: Client):
|
||||
with LogCapture() as l:
|
||||
|
||||
# Test broadcast message
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
mqtt_helperbot = HelperBot(HOST, MQTT_PORT)
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
msg_payload = "<ctl ts='1547822804960' td='DustCaseST' st='0'/>"
|
||||
msg_topic_name = "iot/atr/DustCaseST/bot_serial/ls1ok3/wC3g/x"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
|
@ -37,12 +36,12 @@ async def test_helperbot_message(mqtt_client: MQTTClient):
|
|||
await mqtt_helperbot.disconnect()
|
||||
|
||||
# Send command to bot
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
mqtt_helperbot = HelperBot(HOST, MQTT_PORT)
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
msg_payload = "{}"
|
||||
msg_topic_name = "iot/p2p/GetWKVer/helperbot/bumper/helperbot/bot_serial/ls1ok3/wC3g/q/iCmuqp/j"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
|
@ -57,12 +56,12 @@ async def test_helperbot_message(mqtt_client: MQTTClient):
|
|||
await mqtt_helperbot.disconnect()
|
||||
|
||||
# Received response to command
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
mqtt_helperbot = HelperBot(HOST, MQTT_PORT)
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
msg_payload = '{"ret":"ok","ver":"0.13.5"}'
|
||||
msg_topic_name = "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helperbot/bumper/helperbot/p/iCmuqp/j"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
|
@ -77,12 +76,12 @@ async def test_helperbot_message(mqtt_client: MQTTClient):
|
|||
await mqtt_helperbot.disconnect()
|
||||
|
||||
# Received unknown message
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
mqtt_helperbot = HelperBot(HOST, MQTT_PORT)
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
msg_payload = "test"
|
||||
msg_topic_name = "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/TESTBAD/bumper/helperbot/p/iCmuqp/j"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
|
@ -97,12 +96,12 @@ async def test_helperbot_message(mqtt_client: MQTTClient):
|
|||
await mqtt_helperbot.disconnect()
|
||||
|
||||
# Received error message
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
mqtt_helperbot = HelperBot(HOST, MQTT_PORT)
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
msg_payload = "<ctl ts='1560904925396' td='errors' old='' new='110'/>"
|
||||
msg_topic_name = "iot/atr/errors/bot_serial/ls1ok3/wC3g/x"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
|
@ -117,15 +116,7 @@ async def test_helperbot_message(mqtt_client: MQTTClient):
|
|||
await mqtt_helperbot.disconnect()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mqtt_server")
|
||||
async def test_helperbot_expire_message(mqtt_client: MQTTClient):
|
||||
timeout = 0.1
|
||||
# Test broadcast message
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT, timeout)
|
||||
bumper.mqtt_helperbot = mqtt_helperbot
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
|
||||
async def test_helperbot_expire_message(mqtt_client: Client, helper_bot: HelperBot):
|
||||
expire_msg_payload = '{"ret":"ok","ver":"0.13.5"}'
|
||||
expire_msg_topic_name = "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helperbot/bumper/helperbot/p/testgood/j"
|
||||
currenttime = time.time()
|
||||
|
|
@ -136,32 +127,23 @@ async def test_helperbot_expire_message(mqtt_client: MQTTClient):
|
|||
"payload": expire_msg_payload,
|
||||
}
|
||||
|
||||
mqtt_helperbot._commands[request_id] = data
|
||||
helper_bot._commands[request_id] = data
|
||||
|
||||
assert mqtt_helperbot._commands[request_id] == data
|
||||
assert helper_bot._commands[request_id] == data
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
msg_payload = "<ctl ts='1547822804960' td='DustCaseST' st='0'/>"
|
||||
msg_topic_name = "iot/atr/DustCaseST/bot_serial/ls1ok3/wC3g/x"
|
||||
await mqtt_client.publish(
|
||||
msg_topic_name, msg_payload.encode(), QOS_0
|
||||
mqtt_client.publish(
|
||||
msg_topic_name, msg_payload.encode()
|
||||
) # Send another message to force get_msg
|
||||
|
||||
await asyncio.sleep(timeout * 2)
|
||||
await asyncio.sleep(0.1 * 2)
|
||||
|
||||
assert mqtt_helperbot._commands.get(request_id, None) == None
|
||||
|
||||
await mqtt_helperbot.disconnect()
|
||||
assert helper_bot._commands.get(request_id, None) == None
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mqtt_server")
|
||||
async def test_helperbot_sendcommand(mqtt_client: MQTTClient):
|
||||
timeout = 0.1
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT, timeout)
|
||||
bumper.mqtt_helperbot = mqtt_helperbot
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
|
||||
async def test_helperbot_sendcommand(mqtt_client: Client, helper_bot: HelperBot):
|
||||
cmdjson = {
|
||||
"toType": "ls1ok3",
|
||||
"payloadType": "j",
|
||||
|
|
@ -178,7 +160,7 @@ async def test_helperbot_sendcommand(mqtt_client: MQTTClient):
|
|||
"realm": "ecouser.net",
|
||||
},
|
||||
}
|
||||
commandresult = await mqtt_helperbot.send_command(cmdjson, "testfail")
|
||||
commandresult = await helper_bot.send_command(cmdjson, "testfail")
|
||||
# Don't send a response, ensure timeout
|
||||
assert commandresult == {
|
||||
"debug": "wait for response timed out",
|
||||
|
|
@ -190,9 +172,10 @@ async def test_helperbot_sendcommand(mqtt_client: MQTTClient):
|
|||
# Send response beforehand
|
||||
msg_payload = '{"ret":"ok","ver":"0.13.5"}'
|
||||
msg_topic_name = "iot/p2p/GetWKVer/bot_serial/ls1ok3/wC3g/helperbot/bumper/helperbot/p/testgood/j"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.call_soon(lambda: mqtt_client.publish(msg_topic_name, msg_payload.encode()))
|
||||
|
||||
commandresult = await mqtt_helperbot.send_command(cmdjson, "testgood")
|
||||
commandresult = await helper_bot.send_command(cmdjson, "testgood")
|
||||
assert commandresult == {
|
||||
"id": "testgood",
|
||||
"resp": {"ret": "ok", "ver": "0.13.5"},
|
||||
|
|
@ -222,9 +205,9 @@ async def test_helperbot_sendcommand(mqtt_client: MQTTClient):
|
|||
# Send response beforehand
|
||||
msg_payload = "<ctl ret='ok' type='Brush' left='4142' total='18000'/>"
|
||||
msg_topic_name = "iot/p2p/GetLifeSpan/bot_serial/ls1ok3/wC3g/helperbot/bumper/helperbot/p/testx/q"
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
commandresult = await mqtt_helperbot.send_command(cmdjson, "testx")
|
||||
commandresult = await helper_bot.send_command(cmdjson, "testx")
|
||||
assert commandresult == {
|
||||
"id": "testx",
|
||||
"resp": "<ctl ret='ok' type='Brush' left='4142' total='18000'/>",
|
||||
|
|
@ -257,9 +240,9 @@ async def test_helperbot_sendcommand(mqtt_client: MQTTClient):
|
|||
msg_topic_name = (
|
||||
"iot/p2p/getStats/bot_serial/ls1ok3/wC3g/helperbot/bumper/helperbot/p/testj/j"
|
||||
)
|
||||
await mqtt_client.publish(msg_topic_name, msg_payload.encode(), QOS_0)
|
||||
mqtt_client.publish(msg_topic_name, msg_payload.encode())
|
||||
|
||||
commandresult = await mqtt_helperbot.send_command(cmdjson, "testj")
|
||||
commandresult = await helper_bot.send_command(cmdjson, "testj")
|
||||
|
||||
assert commandresult == {
|
||||
"id": "testj",
|
||||
|
|
@ -287,8 +270,6 @@ async def test_helperbot_sendcommand(mqtt_client: MQTTClient):
|
|||
"ret": "ok",
|
||||
}
|
||||
|
||||
await mqtt_helperbot.disconnect()
|
||||
|
||||
|
||||
async def test_mqttserver():
|
||||
if os.path.exists("tests/tmp.db"):
|
||||
|
|
@ -302,7 +283,7 @@ async def test_mqttserver():
|
|||
|
||||
try:
|
||||
# Test helperbot connect
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
mqtt_helperbot = HelperBot(HOST, MQTT_PORT)
|
||||
await mqtt_helperbot.start()
|
||||
assert mqtt_helperbot.is_connected
|
||||
await mqtt_helperbot.disconnect()
|
||||
|
|
@ -311,60 +292,35 @@ async def test_mqttserver():
|
|||
db.user_add("user_123") # Add user to db
|
||||
db.client_add("user_123", "ecouser.net", "resource_123") # Add client to db
|
||||
|
||||
client = MQTTClient(
|
||||
client_id="user_123@ecouser.net/resource_123",
|
||||
config={"check_hostname": False},
|
||||
)
|
||||
|
||||
await client.connect(
|
||||
f"mqtts://{HOST}:{MQTT_PORT}/",
|
||||
cafile=ca_cert,
|
||||
)
|
||||
assert client._connected_state._value == True # Check client is connected
|
||||
ssl_ctx = ssl.create_default_context()
|
||||
ssl_ctx.check_hostname = False
|
||||
ssl_ctx.verify_mode = ssl.CERT_NONE
|
||||
client = Client("user_123@ecouser.net/resource_123")
|
||||
await client.connect(HOST, MQTT_PORT, ssl=ssl_ctx, version=MQTTv311)
|
||||
assert client.is_connected
|
||||
await client.disconnect()
|
||||
assert client._connected_state._value == False # Check client is disconnected
|
||||
assert not client.is_connected
|
||||
|
||||
# Test fake_bot connect
|
||||
client = MQTTClient(
|
||||
client_id="bot_serial@ls1ok3/wC3g", config={"check_hostname": False}
|
||||
)
|
||||
|
||||
await client.connect(
|
||||
f"mqtts://{HOST}:{MQTT_PORT}/",
|
||||
cafile=ca_cert,
|
||||
)
|
||||
assert client._connected_state._value == True # Check fake_bot is connected
|
||||
client = Client("bot_serial@ls1ok3/wC3g")
|
||||
await client.connect(HOST, MQTT_PORT, ssl=ssl_ctx, version=MQTTv311)
|
||||
assert client.is_connected
|
||||
await client.disconnect()
|
||||
|
||||
# Test file auth client connect
|
||||
client = MQTTClient(
|
||||
client_id="test-file-auth",
|
||||
config={
|
||||
"check_hostname": False,
|
||||
"auto_reconnect": False,
|
||||
"reconnect_retries": 1,
|
||||
},
|
||||
)
|
||||
|
||||
# good user/pass
|
||||
await client.connect(
|
||||
f"mqtts://test-client:abc123!@{HOST}:{MQTT_PORT}/",
|
||||
cafile=ca_cert,
|
||||
cleansession=True,
|
||||
)
|
||||
|
||||
assert client._connected_state._value == True # Check client is connected
|
||||
client = Client("test-file-auth")
|
||||
client.set_auth_credentials("test-client", "abc123!")
|
||||
await client.connect(HOST, MQTT_PORT, ssl=ssl_ctx, version=MQTTv311)
|
||||
assert client.is_connected
|
||||
await client.disconnect()
|
||||
assert client._connected_state._value == False # Check client is disconnected
|
||||
assert not client.is_connected
|
||||
|
||||
# bad password
|
||||
with LogCapture() as l:
|
||||
|
||||
await client.connect(
|
||||
f"mqtts://test-client:notvalid!@{HOST}:{MQTT_PORT}/",
|
||||
cafile=ca_cert,
|
||||
cleansession=True,
|
||||
)
|
||||
client.set_auth_credentials("test-client", "notvalid!")
|
||||
await client.connect(HOST, MQTT_PORT, ssl=ssl_ctx, version=MQTTv311)
|
||||
await client.disconnect()
|
||||
|
||||
l.check_present(
|
||||
(
|
||||
|
|
@ -377,11 +333,9 @@ async def test_mqttserver():
|
|||
l.clear()
|
||||
|
||||
# no username in file
|
||||
await client.connect(
|
||||
f"mqtts://test-client-noexist:notvalid!@{HOST}:{MQTT_PORT}/",
|
||||
cafile=ca_cert,
|
||||
cleansession=True,
|
||||
)
|
||||
client.set_auth_credentials("test-client-noexist", "notvalid!")
|
||||
await client.connect(HOST, MQTT_PORT, ssl=ssl_ctx, version=MQTTv311)
|
||||
await client.disconnect()
|
||||
|
||||
l.check_present(
|
||||
(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from unittest import mock
|
|||
import pytest
|
||||
|
||||
import bumper
|
||||
from bumper import MQTTHelperBot, WebServer, WebserverBinding, XMPPServer, db
|
||||
from bumper import HelperBot, WebServer, WebserverBinding, XMPPServer, db
|
||||
from bumper.models import ERR_TOKEN_INVALID, RETURN_API_SUCCESS
|
||||
from tests import HOST, MQTT_PORT, WEBSERVER_PORT
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ async def test_webserver_no_ssl():
|
|||
await webserver.start()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mqtt_server")
|
||||
@pytest.mark.usefixtures("helper_bot")
|
||||
async def test_base(webserver_client):
|
||||
remove_existing_db()
|
||||
|
||||
|
|
@ -46,20 +46,13 @@ async def test_base(webserver_client):
|
|||
bumper.xmpp_server = xmpp_server
|
||||
await xmpp_server.start_async_server()
|
||||
|
||||
# Start Helperbot
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
bumper.mqtt_helperbot = mqtt_helperbot
|
||||
await mqtt_helperbot.start()
|
||||
|
||||
resp = await webserver_client.get("/")
|
||||
assert resp.status == 200
|
||||
|
||||
await mqtt_helperbot.disconnect()
|
||||
|
||||
bumper.xmpp_server.disconnect()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mqtt_server")
|
||||
@pytest.mark.usefixtures("helper_bot")
|
||||
async def test_restartService(webserver_client):
|
||||
remove_existing_db()
|
||||
|
||||
|
|
@ -69,11 +62,6 @@ async def test_restartService(webserver_client):
|
|||
bumper.xmpp_server = xmpp_server
|
||||
await xmpp_server.start_async_server()
|
||||
|
||||
# Start Helperbot
|
||||
mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
bumper.mqtt_helperbot = mqtt_helperbot
|
||||
await mqtt_helperbot.start()
|
||||
|
||||
resp = await webserver_client.get("/restart_Helperbot")
|
||||
assert resp.status == 200
|
||||
|
||||
|
|
@ -83,8 +71,6 @@ async def test_restartService(webserver_client):
|
|||
resp = await webserver_client.get("/restart_XMPPServer")
|
||||
assert resp.status == 200
|
||||
|
||||
await mqtt_helperbot.disconnect()
|
||||
|
||||
xmpp_server.disconnect()
|
||||
|
||||
|
||||
|
|
@ -718,12 +704,11 @@ async def test_appsvr_api(webserver_client):
|
|||
assert jsonresp["ret"] == "ok"
|
||||
|
||||
|
||||
async def test_lg_logs(webserver_client):
|
||||
async def test_lg_logs(webserver_client, helper_bot: HelperBot):
|
||||
remove_existing_db()
|
||||
db.bot_add("sn_1234", "did_1234", "ls1ok3", "res_1234", "eco-ng")
|
||||
db.bot_set_mqtt("did_1234", True)
|
||||
confserver = create_webserver()
|
||||
bumper.mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
|
||||
# Test return get status
|
||||
command_getstatus_resp = {
|
||||
|
|
@ -731,7 +716,7 @@ async def test_lg_logs(webserver_client):
|
|||
"resp": "<ctl ret='ok' status='idle'/>",
|
||||
"ret": "ok",
|
||||
}
|
||||
bumper.mqtt_helperbot.send_command = mock.MagicMock(
|
||||
helper_bot.send_command = mock.MagicMock(
|
||||
return_value=async_return(command_getstatus_resp)
|
||||
)
|
||||
|
||||
|
|
@ -775,10 +760,9 @@ async def test_postLookup(webserver_client):
|
|||
assert test_resp["result"] == "ok"
|
||||
|
||||
|
||||
async def test_devmgr(webserver_client):
|
||||
async def test_devmgr(webserver_client, helper_bot: HelperBot):
|
||||
remove_existing_db()
|
||||
confserver = create_webserver()
|
||||
bumper.mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
|
||||
# Test PollSCResult
|
||||
postbody = {"td": "PollSCResult"}
|
||||
|
|
@ -808,7 +792,7 @@ async def test_devmgr(webserver_client):
|
|||
"resp": "<ctl ret='ok' status='idle'/>",
|
||||
"ret": "ok",
|
||||
}
|
||||
bumper.mqtt_helperbot.send_command = mock.MagicMock(
|
||||
helper_bot.send_command = mock.MagicMock(
|
||||
return_value=async_return(command_getstatus_resp)
|
||||
)
|
||||
resp = await webserver_client.post("/api/iot/devmanager.do", json=postbody)
|
||||
|
|
@ -819,7 +803,7 @@ async def test_devmgr(webserver_client):
|
|||
|
||||
# Test return fail timeout
|
||||
command_timeout_resp = {"id": "resp_1234", "errno": "timeout", "ret": "fail"}
|
||||
bumper.mqtt_helperbot.send_command = mock.MagicMock(
|
||||
helper_bot.send_command = mock.MagicMock(
|
||||
return_value=async_return(command_timeout_resp)
|
||||
)
|
||||
resp = await webserver_client.post("/api/iot/devmanager.do", json=postbody)
|
||||
|
|
@ -829,10 +813,9 @@ async def test_devmgr(webserver_client):
|
|||
assert test_resp["ret"] == "fail"
|
||||
|
||||
|
||||
async def test_dim_devmanager(webserver_client):
|
||||
async def test_dim_devmanager(webserver_client, helper_bot: HelperBot):
|
||||
remove_existing_db()
|
||||
confserver = create_webserver()
|
||||
bumper.mqtt_helperbot = MQTTHelperBot(HOST, MQTT_PORT)
|
||||
|
||||
# Test PollSCResult
|
||||
postbody = {"td": "PollSCResult"}
|
||||
|
|
@ -862,7 +845,7 @@ async def test_dim_devmanager(webserver_client):
|
|||
"resp": "<ctl ret='ok' status='idle'/>",
|
||||
"ret": "ok",
|
||||
}
|
||||
bumper.mqtt_helperbot.send_command = mock.MagicMock(
|
||||
helper_bot.send_command = mock.MagicMock(
|
||||
return_value=async_return(command_getstatus_resp)
|
||||
)
|
||||
resp = await webserver_client.post("/api/dim/devmanager.do", json=postbody)
|
||||
|
|
@ -873,7 +856,7 @@ async def test_dim_devmanager(webserver_client):
|
|||
|
||||
# Test return fail timeout
|
||||
command_timeout_resp = {"id": "resp_1234", "errno": "timeout", "ret": "fail"}
|
||||
bumper.mqtt_helperbot.send_command = mock.MagicMock(
|
||||
helper_bot.send_command = mock.MagicMock(
|
||||
return_value=async_return(command_timeout_resp)
|
||||
)
|
||||
resp = await webserver_client.post("/api/dim/devmanager.do", json=postbody)
|
||||
|
|
@ -885,7 +868,7 @@ async def test_dim_devmanager(webserver_client):
|
|||
|
||||
# Set bot not on mqtt
|
||||
db.bot_set_mqtt("did_1234", False)
|
||||
bumper.mqtt_helperbot.send_command = mock.MagicMock(
|
||||
helper_bot.send_command = mock.MagicMock(
|
||||
return_value=async_return(command_getstatus_resp)
|
||||
)
|
||||
resp = await webserver_client.post("/api/dim/devmanager.do", json=postbody)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue