SolarManager unter Versionsverwaltung

Erster Stand der Hintergrundprozesse, die auf der Synology unter
/volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler
je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der
AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins
Web-Verzeichnis.

Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die
nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie
von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot),
zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das
Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat.

Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py,
gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso
gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte.

Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein
pip, sie muessen neben den Skripten liegen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 20:46:59 +02:00
co-authored by Claude Opus 5
commit 79843aa2ae
968 changed files with 261182 additions and 0 deletions
View File
+89
View File
@@ -0,0 +1,89 @@
import asyncio
import socket
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port
client_id = 'asyncio-test'
class AsyncioHelper:
def __init__(self, loop, client):
self.loop = loop
self.client = client
self.client.on_socket_open = self.on_socket_open
self.client.on_socket_close = self.on_socket_close
self.client.on_socket_register_write = self.on_socket_register_write
self.client.on_socket_unregister_write = self.on_socket_unregister_write
def on_socket_open(self, client, userdata, sock):
def cb():
client.loop_read()
self.loop.add_reader(sock, cb)
self.misc = self.loop.create_task(self.misc_loop())
def on_socket_close(self, client, userdata, sock):
self.loop.remove_reader(sock)
self.misc.cancel()
def on_socket_register_write(self, client, userdata, sock):
def cb():
client.loop_write()
self.loop.add_writer(sock, cb)
def on_socket_unregister_write(self, client, userdata, sock):
self.loop.remove_writer(sock)
async def misc_loop(self):
while self.client.loop_misc() == mqtt.MQTT_ERR_SUCCESS:
try:
await asyncio.sleep(1)
except asyncio.CancelledError:
break
async def main():
loop = asyncio.get_event_loop()
payload = ""
def on_connect(client, obj, flags, rc):
client.subscribe("sub-test", 1)
def on_subscribe(client, obj, mid, granted_qos):
client.unsubscribe("unsub-test")
def on_unsubscribe(client, obj, mid):
nonlocal payload
payload = "message"
def on_message(client, obj, msg):
client.publish("asyncio", qos=1, payload=payload)
def on_publish(client, obj, mid):
client.disconnect()
def on_disconnect(client, userdata, rc):
disconnected.set_result(rc)
disconnected = loop.create_future()
client = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION1, client_id=client_id)
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish
client.on_subscribe = on_subscribe
client.on_unsubscribe = on_unsubscribe
client.on_disconnect = on_disconnect
_aioh = AsyncioHelper(loop, client)
client.connect('localhost', get_test_server_port(), 60)
client.socket().setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2048)
await disconnected
if __name__ == '__main__':
asyncio.run(main())
@@ -0,0 +1,42 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "decorators-test", clean_session=True)
payload = b""
@mqttc.connect_callback()
def on_connect(mqttc, obj, flags, rc):
mqttc.subscribe("sub-test", 1)
@mqttc.subscribe_callback()
def on_subscribe(mqttc, obj, mid, granted_qos):
mqttc.unsubscribe("unsub-test")
@mqttc.unsubscribe_callback()
def on_unsubscribe(mqttc, obj, mid):
global payload
payload = "message"
@mqttc.message_callback()
def on_message(mqttc, obj, msg):
global payload
mqttc.publish("decorators", qos=1, payload=payload)
@mqttc.publish_callback()
def on_publish(mqttc, obj, mid):
mqttc.disconnect()
@mqttc.disconnect_callback()
def on_disconnect(mqttc, obj, rc):
pass # TODO: should probably test that this gets called
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,14 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-keepalive-pingreq")
mqttc.on_connect = on_connect
mqttc.connect("localhost", get_test_server_port(), keepalive=4)
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,8 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-no-clean-session", clean_session=False)
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,16 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, wait_for_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
mqttc.publish("reconnect/test", "message")
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-reconnect-on-failure", reconnect_on_failure=False)
mqttc.on_connect = on_connect
with wait_for_keyboard_interrupt():
mqttc.connect("localhost", get_test_server_port())
mqttc.loop_forever()
exit(42) # this is expected by the test case
@@ -0,0 +1,9 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-unpwd-set")
mqttc.username_pw_set("uname", "")
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,9 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-unpwd-set")
mqttc.username_pw_set("", "")
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,9 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-unpwd-set")
mqttc.username_pw_set("uname", ";'[08gn=#")
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,12 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-unpwd-unicode-set")
username = "\u00fas\u00e9rn\u00e1m\u00e9-h\u00e9ll\u00f3"
password = "h\u00e9ll\u00f3"
mqttc.username_pw_set(username, password)
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,9 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-will-set")
mqttc.will_set("topic/on/unexpected/disconnect", "will message", 1, True)
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,10 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "01-will-unpwd-set")
mqttc.username_pw_set("oibvvwqw", "#'^2hg9a&nm38*us")
mqttc.will_set("will-topic", "will message", 2, False)
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,20 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.disconnect()
def on_disconnect(mqttc, obj, rc):
mqttc.loop()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "", clean_session=True, protocol=mqtt.MQTTv311)
mqttc.on_connect = on_connect
mqttc.on_disconnect = on_disconnect
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,20 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.subscribe("qos0/test", 0)
def on_subscribe(mqttc, obj, mid, granted_qos):
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "subscribe-qos0-test", clean_session=True)
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,20 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.subscribe("qos1/test", 1)
def on_subscribe(mqttc, obj, mid, granted_qos):
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "subscribe-qos1-test", clean_session=True)
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,20 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.subscribe("qos2/test", 2)
def on_subscribe(mqttc, obj, mid, granted_qos):
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "subscribe-qos2-test", clean_session=True)
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,20 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.unsubscribe("unsubscribe/test")
def on_unsubscribe(mqttc, obj, mid):
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "unsubscribe-test", clean_session=True)
mqttc.on_connect = on_connect
mqttc.on_unsubscribe = on_unsubscribe
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,25 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
expected_payload = b"message"
def on_message(mqttc, obj, msg):
assert msg.mid == 123, f"Invalid mid: ({msg.mid})"
assert msg.topic == "pub/qos1/receive", f"Invalid topic: ({msg.topic})"
assert msg.payload == expected_payload, f"Invalid payload: ({msg.payload})"
assert msg.qos == 1, f"Invalid qos: ({msg.qos})"
assert not msg.retain, f"Invalid retain: ({msg.retain})"
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos1-test")
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,28 @@
import logging
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
expected_payload = b"message"
def on_message(mqttc, obj, msg):
assert msg.mid == 13423, f"Invalid mid: ({msg.mid})"
assert msg.topic == "pub/qos2/receive", f"Invalid topic: ({msg.topic})"
assert msg.payload == expected_payload, f"Invalid payload: ({msg.payload})"
assert msg.qos == 2, f"Invalid qos: ({msg.qos})"
assert not msg.retain, f"Invalid retain: ({msg.retain})"
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
logging.basicConfig(level=logging.DEBUG)
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos2-test", clean_session=True)
mqttc.enable_logger()
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,33 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
sent_mid = -1
def on_connect(mqttc, obj, flags, rc):
global sent_mid
assert rc == 0, f"Connect failed ({rc})"
if sent_mid == -1:
res = mqttc.publish("pub/qos1/test", "message", 1)
sent_mid = res[1]
def on_disconnect(mqttc, obj, rc):
if rc != mqtt.MQTT_ERR_SUCCESS:
mqttc.reconnect()
def on_publish(mqttc, obj, mid):
global sent_mid
assert mid == sent_mid, f"Invalid mid: ({mid})"
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos1-test", clean_session=False)
mqttc.on_connect = on_connect
mqttc.on_disconnect = on_disconnect
mqttc.on_publish = on_publish
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,31 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
first_connection = 1
def on_connect(mqttc, obj, flags, rc):
global first_connection
assert rc == 0, f"Connect failed ({rc})"
if first_connection == 1:
mqttc.publish("pub/qos2/test", "message", 2)
first_connection = 0
def on_disconnect(mqttc, obj, rc):
if rc != 0:
mqttc.reconnect()
def on_publish(mqttc, obj, mid):
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos2-test", clean_session=False)
mqttc.on_connect = on_connect
mqttc.on_disconnect = on_disconnect
mqttc.on_publish = on_publish
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,39 @@
import logging
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def expected_payload(i: int) -> bytes:
return f"message{i}".encode()
def on_message(mqttc, obj, msg):
assert msg.mid == 123, f"Invalid mid: ({msg.mid})"
assert msg.topic == "pub/qos1/receive", f"Invalid topic: ({msg.topic})"
assert msg.payload == expected_payload, f"Invalid payload: ({msg.payload})"
assert msg.qos == 1, f"Invalid qos: ({msg.qos})"
assert msg.retain is not False, f"Invalid retain: ({msg.retain})"
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
for i in range(12):
mqttc.publish("topic", expected_payload(i), qos=1)
def on_disconnect(mqttc, rc, properties):
logging.info("disconnected")
mqttc.reconnect()
logging.basicConfig(level=logging.DEBUG)
logging.info(str(mqtt))
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos1-test")
mqttc.max_inflight_messages_set(10)
mqttc.on_connect = on_connect
mqttc.on_disconnect = on_disconnect
mqttc.on_message = on_message
mqttc.enable_logger()
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,15 @@
import paho.mqtt.client
import paho.mqtt.publish
from tests.paho_test import get_test_server_port, wait_for_keyboard_interrupt
with wait_for_keyboard_interrupt():
paho.mqtt.publish.single(
"pub/qos0/test",
"message",
qos=0,
hostname="localhost",
port=get_test_server_port(),
client_id="publish-helper-qos0-test",
protocol=paho.mqtt.client.MQTTv5,
)
@@ -0,0 +1,13 @@
import paho.mqtt.publish
from tests.paho_test import get_test_server_port, wait_for_keyboard_interrupt
with wait_for_keyboard_interrupt():
paho.mqtt.publish.single(
"pub/qos0/test",
"message",
qos=0,
hostname="localhost",
port=get_test_server_port(),
client_id="publish-helper-qos0-test",
)
@@ -0,0 +1,13 @@
import paho.mqtt.publish
from tests.paho_test import get_test_server_port, wait_for_keyboard_interrupt
with wait_for_keyboard_interrupt():
paho.mqtt.publish.single(
"pub/qos1/test",
"message",
qos=1,
hostname="localhost",
port=get_test_server_port(),
client_id="publish-helper-qos1-disconnect-test",
)
@@ -0,0 +1,24 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
sent_mid = -1
def on_connect(mqttc, obj, flags, rc):
global sent_mid
assert rc == 0, f"Connect failed ({rc})"
(res, sent_mid) = mqttc.publish("pub/qos0/no-payload/test")
def on_publish(mqttc, obj, mid):
if sent_mid == mid:
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos0-test-np", clean_session=True)
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,26 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
sent_mid = -1
def on_connect(mqttc, obj, flags, rc):
global sent_mid
assert rc == 0, f"Connect failed ({rc})"
res = mqttc.publish("pub/qos0/test", "message")
sent_mid = res[1]
def on_publish(mqttc, obj, mid):
global sent_mid, run
if sent_mid == mid:
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "publish-qos0-test", clean_session=True)
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,15 @@
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.publish("retain/qos0/test", "retained message", 0, True)
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "retain-qos0-test", clean_session=True)
mqttc.on_connect = on_connect
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,23 @@
import os
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "08-ssl-connect-alpn", clean_session=True)
mqttc.tls_set(
os.path.join(os.environ["PAHO_SSL_PATH"], "all-ca.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client.key"),
alpn_protocols=["paho-test-protocol"],
)
mqttc.on_connect = on_connect
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,23 @@
import os
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "08-ssl-connect-crt-auth-pw")
mqttc.tls_set(
os.path.join(os.environ["PAHO_SSL_PATH"], "all-ca.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client-pw.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client-pw.key"),
keyfile_password="password",
)
mqttc.on_connect = on_connect
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,22 @@
import os
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "08-ssl-connect-crt-auth")
mqttc.tls_set(
os.path.join(os.environ["PAHO_SSL_PATH"], "all-ca.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client.key"),
)
mqttc.on_connect = on_connect
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,18 @@
import os
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, loop_until_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
assert rc == 0, f"Connect failed ({rc})"
mqttc.disconnect()
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "08-ssl-connect-no-auth")
mqttc.tls_set(os.path.join(os.environ["PAHO_SSL_PATH"], "all-ca.crt"))
mqttc.on_connect = on_connect
mqttc.connect("localhost", get_test_server_port())
loop_until_keyboard_interrupt(mqttc)
@@ -0,0 +1,27 @@
import os
import ssl
import paho.mqtt.client as mqtt
from tests.paho_test import get_test_server_port, wait_for_keyboard_interrupt
def on_connect(mqttc, obj, flags, rc):
raise RuntimeError("Connection should have failed!")
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "08-ssl-fake-cacert")
mqttc.tls_set(
os.path.join(os.environ["PAHO_SSL_PATH"], "test-fake-root-ca.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client.crt"),
os.path.join(os.environ["PAHO_SSL_PATH"], "client.key"),
)
mqttc.on_connect = on_connect
with wait_for_keyboard_interrupt():
try:
mqttc.connect("localhost", get_test_server_port())
except ssl.SSLError as msg:
assert msg.errno == 1 and "certificate verify failed" in msg.strerror
else:
raise Exception("Expected SSLError")
+80
View File
@@ -0,0 +1,80 @@
import os
import signal
import subprocess
import sys
import pytest
from tests.consts import ssl_path, tests_path
from tests.paho_test import create_server_socket, create_server_socket_ssl, ssl
clients_path = tests_path / "lib" / "clients"
def _yield_server(monkeypatch, sockport):
sock, port = sockport
monkeypatch.setenv("PAHO_SERVER_PORT", str(port))
try:
yield sock
finally:
sock.close()
@pytest.fixture()
def server_socket(monkeypatch):
yield from _yield_server(monkeypatch, create_server_socket())
@pytest.fixture()
def ssl_server_socket(monkeypatch):
if ssl is None:
pytest.skip("no ssl module")
yield from _yield_server(monkeypatch, create_server_socket_ssl())
@pytest.fixture()
def alpn_ssl_server_socket(monkeypatch):
if ssl is None:
pytest.skip("no ssl module")
if not getattr(ssl, "HAS_ALPN", False):
pytest.skip("ALPN not supported in this version of Python")
yield from _yield_server(monkeypatch, create_server_socket_ssl(alpn_protocols=["paho-test-protocol"]))
def stop_process(proc: subprocess.Popen) -> None:
if sys.platform == "win32":
proc.send_signal(signal.CTRL_C_EVENT)
else:
proc.send_signal(signal.SIGINT)
try:
proc.wait(5)
except subprocess.TimeoutExpired:
proc.terminate()
@pytest.fixture()
def start_client(request: pytest.FixtureRequest):
def starter(name: str, expected_returncode: int = 0) -> None:
client_path = clients_path / name
if not client_path.exists():
raise FileNotFoundError(client_path)
env = dict(
os.environ,
PAHO_SSL_PATH=str(ssl_path),
PYTHONPATH=f"{tests_path}{os.pathsep}{os.environ.get('PYTHONPATH', '')}",
)
assert 'PAHO_SERVER_PORT' in env, "PAHO_SERVER_PORT must be set in the environment when starting a client"
proc = subprocess.Popen([ # noqa: S603
sys.executable,
str(client_path),
], env=env)
def fin():
stop_process(proc)
if proc.returncode != expected_returncode:
raise RuntimeError(f"Client {name} exited with code {proc.returncode}, expected {expected_returncode}")
request.addfinalizer(fin)
return proc
return starter
+45
View File
@@ -0,0 +1,45 @@
# Test whether asyncio works
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("asyncio-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
subscribe_packet = paho_test.gen_subscribe(mid=1, topic="sub-test", qos=1)
suback_packet = paho_test.gen_suback(mid=1, qos=1)
unsubscribe_packet = paho_test.gen_unsubscribe(mid=2, topic="unsub-test")
unsuback_packet = paho_test.gen_unsuback(mid=2)
publish_packet = paho_test.gen_publish("b2c", qos=0, payload="msg")
publish_packet_in = paho_test.gen_publish("asyncio", qos=1, mid=3, payload="message")
puback_packet_in = paho_test.gen_puback(mid=3)
disconnect_packet = paho_test.gen_disconnect()
def test_01_asyncio(server_socket, start_client):
proc = start_client("01-asyncio.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "subscribe", subscribe_packet)
conn.send(suback_packet)
paho_test.expect_packet(conn, "unsubscribe", unsubscribe_packet)
conn.send(unsuback_packet)
conn.send(publish_packet)
paho_test.expect_packet(conn, "publish", publish_packet_in)
conn.send(puback_packet_in)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
assert proc.wait() == 0
+44
View File
@@ -0,0 +1,44 @@
# Test whether callback decorators work
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("decorators-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
subscribe_packet = paho_test.gen_subscribe(mid=1, topic="sub-test", qos=1)
suback_packet = paho_test.gen_suback(mid=1, qos=1)
unsubscribe_packet = paho_test.gen_unsubscribe(mid=2, topic="unsub-test")
unsuback_packet = paho_test.gen_unsuback(mid=2)
publish_packet = paho_test.gen_publish("b2c", qos=0, payload="msg")
publish_packet_in = paho_test.gen_publish("decorators", qos=1, mid=3, payload="message")
puback_packet_in = paho_test.gen_puback(mid=3)
disconnect_packet = paho_test.gen_disconnect()
def test_01_decorators(server_socket, start_client):
start_client("01-decorators.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "subscribe", subscribe_packet)
conn.send(suback_packet)
paho_test.expect_packet(conn, "unsubscribe", unsubscribe_packet)
conn.send(unsuback_packet)
conn.send(publish_packet)
paho_test.expect_packet(conn, "publish", publish_packet_in)
conn.send(puback_packet_in)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,32 @@
# Test whether a client sends a pingreq after the keepalive time
# The client should connect with keepalive=4, clean session set,
# and client id 01-keepalive-pingreq
# The client should send a PINGREQ message after the appropriate amount of time
# (4 seconds after no traffic).
import time
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("01-keepalive-pingreq", keepalive=4)
connack_packet = paho_test.gen_connack(rc=0)
pingreq_packet = paho_test.gen_pingreq()
pingresp_packet = paho_test.gen_pingresp()
def test_01_keepalive_pingreq(server_socket, start_client):
start_client("01-keepalive-pingreq.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "pingreq", pingreq_packet)
time.sleep(1.0)
conn.send(pingresp_packet)
paho_test.expect_packet(conn, "pingreq", pingreq_packet)
@@ -0,0 +1,20 @@
# Test whether a client produces a correct connect with clean session not set.
# The client should connect with keepalive=60, clean session not
# set, and client id 01-no-clean-session.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("01-no-clean-session", clean_session=False, keepalive=60)
def test_01_no_clean_session(server_socket, start_client):
start_client("01-no-clean-session.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
@@ -0,0 +1,31 @@
# Test the reconnect_on_failure = False mode
import pytest
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("01-reconnect-on-failure", keepalive=60)
connack_packet_ok = paho_test.gen_connack(rc=0)
connack_packet_failure = paho_test.gen_connack(rc=1) # CONNACK_REFUSED_PROTOCOL_VERSION
publish_packet = paho_test.gen_publish(
"reconnect/test", qos=0, payload="message")
@pytest.mark.parametrize("ok_code", [False, True])
def test_01_reconnect_on_failure(server_socket, start_client, ok_code):
client = start_client("01-reconnect-on-failure.py", expected_returncode=42)
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
if ok_code:
conn.send(connack_packet_ok)
# Connection is a success, so we expect a publish
paho_test.expect_packet(conn, "publish", publish_packet)
else:
conn.send(connack_packet_failure)
conn.close()
# Expect the client to quit here due to socket being closed
client.wait(1)
assert client.returncode == 42
@@ -0,0 +1,21 @@
# Test whether a client produces a correct connect with a username and password.
# The client should connect with keepalive=60, clean session set,
# client id 01-unpwd-set, username set to uname and password set to empty string
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"01-unpwd-set", keepalive=60, username="uname", password="")
def test_01_unpwd_empty_password_set(server_socket, start_client):
start_client("01-unpwd-empty-password-set.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
@@ -0,0 +1,21 @@
# Test whether a client produces a correct connect with a username and password.
# The client should connect with keepalive=60, clean session set,
# client id 01-unpwd-set, username and password set to empty string.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"01-unpwd-set", keepalive=60, username="", password='')
def test_01_unpwd_empty_set(server_socket, start_client):
start_client("01-unpwd-empty-set.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
+21
View File
@@ -0,0 +1,21 @@
# Test whether a client produces a correct connect with a username and password.
# The client should connect with keepalive=60, clean session set,
# client id 01-unpwd-set, username set to uname and password set to ;'[08gn=#
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"01-unpwd-set", keepalive=60, username="uname", password=";'[08gn=#")
def test_01_unpwd_set(server_socket, start_client):
start_client("01-unpwd-set.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
@@ -0,0 +1,25 @@
# Test whether a client produces a correct connect with a unicode username and password.
# The client should connect with keepalive=60, clean session set,
# client id 01-unpwd-unicode-set, username and password from corresponding variables
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"01-unpwd-unicode-set",
keepalive=60,
username="\u00fas\u00e9rn\u00e1m\u00e9-h\u00e9ll\u00f3",
password="h\u00e9ll\u00f3",
)
def test_01_unpwd_unicode_set(server_socket, start_client):
start_client("01-unpwd-unicode-set.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
+21
View File
@@ -0,0 +1,21 @@
# Test whether a client produces a correct connect with a will.
# Will QoS=1, will retain=1.
# The client should connect with keepalive=60, clean session set,
# client id 01-will-set will topic set to topic/on/unexpected/disconnect , will
# payload set to "will message", will qos set to 1 and will retain set.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"01-will-set", keepalive=60, will_topic="topic/on/unexpected/disconnect",
will_qos=1, will_retain=True, will_payload="will message")
def test_01_will_set(server_socket, start_client):
start_client("01-will-set.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
@@ -0,0 +1,26 @@
# Test whether a client produces a correct connect with a will, username and password.
# The client should connect with keepalive=60, clean session set,
# client id 01-will-unpwd-set , will topic set to "will-topic", will payload
# set to "will message", will qos=2, will retain not set, username set to
# "oibvvwqw" and password set to "#'^2hg9a&nm38*us".
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"01-will-unpwd-set",
keepalive=60, username="oibvvwqw", password="#'^2hg9a&nm38*us",
will_topic="will-topic", will_qos=2, will_payload="will message",
)
def test_01_will_unpwd_set(server_socket, start_client):
start_client("01-will-unpwd-set.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.close()
@@ -0,0 +1,23 @@
# Test whether a client connects correctly with a zero length clientid.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("", keepalive=60, proto_ver=4)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
def test_01_zero_length_clientid(server_socket, start_client):
start_client("01-zero-length-clientid.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,40 @@
# Test whether a client sends a correct SUBSCRIBE to a topic with QoS 0.
# The client should connect with keepalive=60, clean session set,
# and client id subscribe-qos0-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a SUBSCRIBE
# message to subscribe to topic "qos0/test" with QoS=0. If rc!=0, the client
# should exit with an error.
# Upon receiving the correct SUBSCRIBE message, the test will reply with a
# SUBACK message with the accepted QoS set to 0. On receiving the SUBACK
# message, the client should send a DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("subscribe-qos0-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 1
subscribe_packet = paho_test.gen_subscribe(mid, "qos0/test", 0)
suback_packet = paho_test.gen_suback(mid, 0)
def test_02_subscribe_qos0(server_socket, start_client):
start_client("02-subscribe-qos0.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "subscribe", subscribe_packet)
conn.send(suback_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,40 @@
# Test whether a client sends a correct SUBSCRIBE to a topic with QoS 1.
# The client should connect with keepalive=60, clean session set,
# and client id subscribe-qos1-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a SUBSCRIBE
# message to subscribe to topic "qos1/test" with QoS=1. If rc!=0, the client
# should exit with an error.
# Upon receiving the correct SUBSCRIBE message, the test will reply with a
# SUBACK message with the accepted QoS set to 1. On receiving the SUBACK
# message, the client should send a DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("subscribe-qos1-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 1
subscribe_packet = paho_test.gen_subscribe(mid, "qos1/test", 1)
suback_packet = paho_test.gen_suback(mid, 1)
def test_02_subscribe_qos1(server_socket, start_client):
start_client("02-subscribe-qos1.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "subscribe", subscribe_packet)
conn.send(suback_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,40 @@
# Test whether a client sends a correct SUBSCRIBE to a topic with QoS 2.
# The client should connect with keepalive=60, clean session set,
# and client id subscribe-qos2-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a SUBSCRIBE
# message to subscribe to topic "qos2/test" with QoS=2. If rc!=0, the client
# should exit with an error.
# Upon receiving the correct SUBSCRIBE message, the test will reply with a
# SUBACK message with the accepted QoS set to 2. On receiving the SUBACK
# message, the client should send a DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("subscribe-qos2-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 1
subscribe_packet = paho_test.gen_subscribe(mid, "qos2/test", 2)
suback_packet = paho_test.gen_suback(mid, 2)
def test_02_subscribe_qos2(server_socket, start_client):
start_client("02-subscribe-qos2.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "subscribe", subscribe_packet)
conn.send(suback_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,30 @@
# Test whether a client sends a correct UNSUBSCRIBE packet.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("unsubscribe-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 1
unsubscribe_packet = paho_test.gen_unsubscribe(mid, "unsubscribe/test")
unsuback_packet = paho_test.gen_unsuback(mid)
def test_02_unsubscribe(server_socket, start_client):
start_client("02-unsubscribe.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "unsubscribe", unsubscribe_packet)
conn.send(unsuback_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,36 @@
# Test whether a client responds correctly to a PUBLISH with QoS 1.
# The client should connect with keepalive=60, clean session set,
# and client id publish-qos1-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK the client should verify that rc==0.
# The test will send the client a PUBLISH message with topic
# "pub/qos1/receive", payload of "message", QoS=1 and mid=123. The client
# should handle this as per the spec by sending a PUBACK message.
# The client should then exit with return code==0.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("publish-qos1-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 123
publish_packet = paho_test.gen_publish(
"pub/qos1/receive", qos=1, mid=mid, payload="message")
puback_packet = paho_test.gen_puback(mid)
def test_03_publish_b2c_qos1(server_socket, start_client):
start_client("03-publish-b2c-qos1.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
conn.send(publish_packet)
paho_test.expect_packet(conn, "puback", puback_packet)
conn.close()
@@ -0,0 +1,41 @@
# Test whether a client responds correctly to a PUBLISH with QoS 1.
# The client should connect with keepalive=60, clean session set,
# and client id publish-qos1-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK the client should verify that rc==0.
# The test will send the client a PUBLISH message with topic
# "pub/qos1/receive", payload of "message", QoS=1 and mid=123. The client
# should handle this as per the spec by sending a PUBACK message.
# The client should then exit with return code==0.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("publish-qos2-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 13423
publish_packet = paho_test.gen_publish(
"pub/qos2/receive", qos=2, mid=mid, payload="message")
pubrec_packet = paho_test.gen_pubrec(mid=mid)
pubrel_packet = paho_test.gen_pubrel(mid=mid)
pubcomp_packet = paho_test.gen_pubcomp(mid)
def test_03_publish_b2c_qos2(server_socket, start_client):
start_client("03-publish-b2c-qos2.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
conn.send(publish_packet)
paho_test.expect_packet(conn, "pubrec", pubrec_packet)
conn.send(pubrel_packet)
paho_test.expect_packet(conn, "pubcomp", pubcomp_packet)
conn.close()
@@ -0,0 +1,45 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 1, then responds correctly to a disconnect.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"publish-qos1-test", keepalive=60, clean_session=False,
)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 1
publish_packet = paho_test.gen_publish(
"pub/qos1/test", qos=1, mid=mid, payload="message")
publish_packet_dup = paho_test.gen_publish(
"pub/qos1/test", qos=1, mid=mid, payload="message", dup=True)
puback_packet = paho_test.gen_puback(mid)
def test_03_publish_c2b_qos1_disconnect(server_socket, start_client):
start_client("03-publish-c2b-qos1-disconnect.py")
(conn, address) = server_socket.accept()
conn.settimeout(15)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
# Disconnect client. It should reconnect.
conn.close()
(conn, address) = server_socket.accept()
conn.settimeout(15)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "retried publish", publish_packet_dup)
conn.send(puback_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,61 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 2 and responds to a disconnect.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"publish-qos2-test", keepalive=60, clean_session=False,
)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
mid = 1
publish_packet = paho_test.gen_publish(
"pub/qos2/test", qos=2, mid=mid, payload="message")
publish_dup_packet = paho_test.gen_publish(
"pub/qos2/test", qos=2, mid=mid, payload="message", dup=True)
pubrec_packet = paho_test.gen_pubrec(mid)
pubrel_packet = paho_test.gen_pubrel(mid)
pubcomp_packet = paho_test.gen_pubcomp(mid)
def test_03_publish_c2b_qos2_disconnect(server_socket, start_client):
start_client("03-publish-c2b-qos2-disconnect.py")
(conn, address) = server_socket.accept()
conn.settimeout(5)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
# Disconnect client. It should reconnect.
conn.close()
(conn, address) = server_socket.accept()
conn.settimeout(15)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "retried publish", publish_dup_packet)
conn.send(pubrec_packet)
paho_test.expect_packet(conn, "pubrel", pubrel_packet)
# Disconnect client. It should reconnect.
conn.close()
(conn, address) = server_socket.accept()
conn.settimeout(15)
# Complete connection and message flow.
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "retried pubrel", pubrel_packet)
conn.send(pubcomp_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,90 @@
# Test whether a client responds to max-inflight and reconnect when max-inflight is reached
# The client should connect with keepalive=60, clean session set,
# and client id publish-fill-inflight
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK the client should verify that rc==0.
# Then client should send 10 PUBLISH with QoS == 1. On client side 12 message will be
# submitted, so 2 will be queued.
# The test will wait 0.5 seconds after received the 10 PUBLISH. After this wait, it will
# disconnect the client.
# The client should re-connect and re-sent the first 10 messages.
# The test will PUBACK one message, it should receive another PUBLISH.
# The test will wait 0.5 seconds and expect no PUBLISH.
# The test will then PUBACK all message.
# The client should disconnect once everything is acked.
import pytest
import tests.paho_test as paho_test
def expected_payload(i: int) -> bytes:
return f"message{i}"
connect_packet = paho_test.gen_connect("publish-qos1-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
first_connection_publishs = [
paho_test.gen_publish(
"topic", qos=1, mid=i+1, payload=expected_payload(i),
)
for i in range(10)
]
second_connection_publishs = [
paho_test.gen_publish(
# I'm not sure we should have the mid+13.
# Currently on reconnection client will do two wrong thing:
# * it sent more than max_inflight packet
# * it re-send message both with mid = old_mid + 12 AND with mid = old_mid & dup=1
"topic", qos=1, mid=i+13, payload=expected_payload(i),
)
for i in range(12)
]
second_connection_pubacks = [
paho_test.gen_puback(i+13)
for i in range(12)
]
@pytest.mark.xfail
def test_03_publish_fill_inflight(server_socket, start_client):
start_client("03-publish-fill-inflight.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
for packet in first_connection_publishs:
paho_test.expect_packet(conn, "publish", packet)
paho_test.expect_no_packet(conn, 0.5)
conn.close()
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
for packet in second_connection_publishs[:10]:
paho_test.expect_packet(conn, "publish", packet)
paho_test.expect_no_packet(conn, 0.2)
conn.send(second_connection_pubacks[0])
paho_test.expect_packet(conn, "publish", second_connection_publishs[10])
paho_test.expect_no_packet(conn, 0.5)
for packet in second_connection_pubacks[1:11]:
conn.send(packet)
paho_test.expect_packet(conn, "publish", second_connection_publishs[11])
paho_test.expect_no_packet(conn, 0.5)
@@ -0,0 +1,40 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 0.
# Use paho.mqtt.publish helper for that.
# The client should connect with keepalive=60, clean session set,
# and client id publish-helper-qos0-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a PUBLISH message
# to topic "pub/qos0/test" with payload "message" and QoS=0. If rc!=0, the
# client should exit with an error.
# After sending the PUBLISH message, the client should send a
# DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"publish-helper-qos0-test", keepalive=60,
)
connack_packet = paho_test.gen_connack(rc=0)
publish_packet = paho_test.gen_publish(
"pub/qos0/test", qos=0, payload="message"
)
disconnect_packet = paho_test.gen_disconnect()
def test_03_publish_helper_qos0(server_socket, start_client):
start_client("03-publish-helper-qos0.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,40 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 0.
# Use paho.mqtt.publish helper for that.
# The client should connect with keepalive=60, clean session set,
# and client id publish-helper-qos0-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a PUBLISH message
# to topic "pub/qos0/test" with payload "message" and QoS=0. If rc!=0, the
# client should exit with an error.
# After sending the PUBLISH message, the client should send a
# DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"publish-helper-qos0-test", keepalive=60, proto_ver=5, properties=None
)
connack_packet = paho_test.gen_connack(rc=0, proto_ver=5)
publish_packet = paho_test.gen_publish(
"pub/qos0/test", qos=0, payload="message", proto_ver=5
)
disconnect_packet = paho_test.gen_disconnect()
def test_03_publish_helper_qos0_v5(server_socket, start_client):
start_client("03-publish-helper-qos0-v5.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,50 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 1,
# then responds correctly to a disconnect.
# Use paho.mqtt.publish helper for that.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect(
"publish-helper-qos1-disconnect-test", keepalive=60,
)
connack_packet = paho_test.gen_connack(rc=0)
mid = 1
publish_packet = paho_test.gen_publish(
"pub/qos1/test", qos=1, mid=mid, payload="message"
)
publish_packet_dup = paho_test.gen_publish(
"pub/qos1/test", qos=1, mid=mid, payload="message",
dup=True,
)
puback_packet = paho_test.gen_puback(mid)
disconnect_packet = paho_test.gen_disconnect()
def test_03_publish_helper_qos1_disconnect(server_socket, start_client):
start_client("03-publish-helper-qos1-disconnect.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
# Disconnect client. It should reconnect.
conn.close()
(conn, address) = server_socket.accept()
conn.settimeout(15)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "retried publish", publish_packet_dup)
conn.send(puback_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,33 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 0.
# The client should connect with keepalive=60, clean session set,
# and client id publish-qos0-test
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a PUBLISH message
# to topic "pub/qos0/test" with payload "message" and QoS=0. If rc!=0, the
# client should exit with an error.
# After sending the PUBLISH message, the client should send a DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("publish-qos0-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
publish_packet = paho_test.gen_publish("pub/qos0/test", qos=0, payload="message")
disconnect_packet = paho_test.gen_disconnect()
def test_03_publish_qos0(server_socket, start_client):
start_client("03-publish-qos0.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,34 @@
# Test whether a client sends a correct PUBLISH to a topic with QoS 0 and no payload.
# The client should connect with keepalive=60, clean session set,
# and client id publish-qos0-test-np
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a PUBLISH message
# to topic "pub/qos0/no-payload/test" with zero length payload and QoS=0. If
# rc!=0, the client should exit with an error.
# After sending the PUBLISH message, the client should send a DISCONNECT message.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("publish-qos0-test-np", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
publish_packet = paho_test.gen_publish("pub/qos0/no-payload/test", qos=0)
disconnect_packet = paho_test.gen_disconnect()
def test_03_publish_qos0_no_payload(server_socket, start_client):
start_client("03-publish-qos0-no-payload.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,25 @@
# Test whether a client sends a correct retained PUBLISH to a topic with QoS 0.
import tests.paho_test as paho_test
mid = 16
connect_packet = paho_test.gen_connect("retain-qos0-test", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
publish_packet = paho_test.gen_publish(
"retain/qos0/test", qos=0, payload="retained message", retain=True)
def test_04_retain_qos0(server_socket, start_client):
start_client("04-retain-qos0.py")
(conn, address) = server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "publish", publish_packet)
conn.close()
@@ -0,0 +1,8 @@
import paho.mqtt.client as mqtt
import pytest
def test_08_ssl_bad_cacert():
with pytest.raises(IOError):
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, "08-ssl-bad-cacert")
mqttc.tls_set("this/file/doesnt/exist")
@@ -0,0 +1,38 @@
# Test whether a client produces a correct connect and subsequent disconnect when using SSL.
# Client must provide a certificate.
#
# The client should connect with keepalive=60, clean session set,
# and client id 08-ssl-connect-alpn
# It should use the CA certificate ssl/all-ca.crt for verifying the server.
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a DISCONNECT
# message. If rc!=0, the client should exit with an error.
#
# Additionally, the secure socket must have been negotiated with the "paho-test-protocol"
from tests import paho_test
from tests.paho_test import ssl
def test_08_ssl_connect_alpn(alpn_ssl_server_socket, start_client):
connect_packet = paho_test.gen_connect("08-ssl-connect-alpn", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
start_client("08-ssl-connect-alpn.py")
(conn, address) = alpn_ssl_server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
if ssl.HAS_ALPN:
negotiated_protocol = conn.selected_alpn_protocol()
if negotiated_protocol != "paho-test-protocol":
raise Exception(f"Unexpected protocol '{negotiated_protocol}'")
conn.close()
@@ -0,0 +1,29 @@
# Test whether a client produces a correct connect and subsequent disconnect when using SSL.
# Client must provide a certificate.
#
# The client should connect with keepalive=60, clean session set,
# and client id 08-ssl-connect-crt-auth
# It should use the CA certificate ssl/all-ca.crt for verifying the server.
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a DISCONNECT
# message. If rc!=0, the client should exit with an error.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("08-ssl-connect-crt-auth", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
def test_08_ssl_connect_crt_auth(ssl_server_socket, start_client):
start_client("08-ssl-connect-cert-auth.py")
(conn, address) = ssl_server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,29 @@
# Test whether a client produces a correct connect and subsequent disconnect when using SSL.
# Client must provide a certificate - the private key is encrypted with a password.
#
# The client should connect with keepalive=60, clean session set,
# and client id 08-ssl-connect-crt-auth
# It should use the CA certificate ssl/all-ca.crt for verifying the server.
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a DISCONNECT
# message. If rc!=0, the client should exit with an error.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("08-ssl-connect-crt-auth-pw", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
def test_08_ssl_connect_crt_auth_pw(ssl_server_socket, start_client):
start_client("08-ssl-connect-cert-auth-pw.py")
(conn, address) = ssl_server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,26 @@
# Test whether a client produces a correct connect and subsequent disconnect when using SSL.
#
# The client should connect with keepalive=60, clean session set,# and client id 08-ssl-connect-no-auth
# It should use the CA certificate ssl/all-ca.crt for verifying the server.
# The test will send a CONNACK message to the client with rc=0. Upon receiving
# the CONNACK and verifying that rc=0, the client should send a DISCONNECT
# message. If rc!=0, the client should exit with an error.
import tests.paho_test as paho_test
connect_packet = paho_test.gen_connect("08-ssl-connect-no-auth", keepalive=60)
connack_packet = paho_test.gen_connack(rc=0)
disconnect_packet = paho_test.gen_disconnect()
def test_08_ssl_connect_no_auth(ssl_server_socket, start_client):
start_client("08-ssl-connect-no-auth.py")
(conn, address) = ssl_server_socket.accept()
conn.settimeout(10)
paho_test.expect_packet(conn, "connect", connect_packet)
conn.send(connack_packet)
paho_test.expect_packet(conn, "disconnect", disconnect_packet)
conn.close()
@@ -0,0 +1,10 @@
import pytest
from tests.paho_test import ssl
def test_08_ssl_fake_cacert(ssl_server_socket, start_client):
start_client("08-ssl-fake-cacert.py")
with pytest.raises(ssl.SSLError):
(conn, address) = ssl_server_socket.accept()
conn.close()