summaryrefslogtreecommitdiff
path: root/stacks/daemon/test_proto.py
diff options
context:
space:
mode:
Diffstat (limited to 'stacks/daemon/test_proto.py')
-rw-r--r--stacks/daemon/test_proto.py106
1 files changed, 106 insertions, 0 deletions
diff --git a/stacks/daemon/test_proto.py b/stacks/daemon/test_proto.py
new file mode 100644
index 0000000..50ced93
--- /dev/null
+++ b/stacks/daemon/test_proto.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+"""Offline smoke test for max25d M25/1 protocol."""
+import socket
+import subprocess
+import sys
+import time
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[2]
+DAEMON = ROOT / "stacks/daemon/max25d"
+INI = ROOT / "share/max25/max25d.ini.example"
+
+
+class LineReader:
+ def __init__(self, sock: socket.socket) -> None:
+ self.sock = sock
+ self.buf = b""
+
+ def read(self, timeout: float = 5.0) -> str:
+ self.sock.settimeout(timeout)
+ while b"\n" not in self.buf:
+ chunk = self.sock.recv(4096)
+ if not chunk:
+ raise RuntimeError("connection closed")
+ self.buf += chunk
+ line, self.buf = self.buf.split(b"\n", 1)
+ return line.decode("utf-8")
+
+
+def free_port() -> int:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.bind(("127.0.0.1", 0))
+ port = sock.getsockname()[1]
+ sock.close()
+ return port
+
+
+def wait_for_port(port: int, proc: subprocess.Popen[str], timeout: float = 8.0) -> bool:
+ deadline = time.time() + timeout
+ while time.time() < deadline:
+ if proc.poll() is not None:
+ return False
+ try:
+ probe = socket.create_connection(("127.0.0.1", port), timeout=0.25)
+ probe.close()
+ return True
+ except OSError:
+ time.sleep(0.1)
+ return False
+
+
+def main() -> int:
+ port = free_port()
+ proc = subprocess.Popen(
+ [str(DAEMON), "--no-stack", "--no-serial", "-c", str(INI), "--tcp-port", str(port)],
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.PIPE,
+ text=True,
+ )
+ if not wait_for_port(port, proc):
+ err = proc.stderr.read() if proc.stderr else ""
+ proc.terminate()
+ proc.wait(timeout=3)
+ print(f"FAIL: max25d not listening on {port}: {err.strip()}", file=sys.stderr)
+ return 1
+ try:
+ sock = socket.create_connection(("127.0.0.1", port), timeout=3)
+ except OSError as exc:
+ proc.terminate()
+ proc.wait(timeout=3)
+ print(f"FAIL: connect: {exc}", file=sys.stderr)
+ return 1
+
+ reader = LineReader(sock)
+ try:
+ assert reader.read() == "OK"
+ status = reader.read()
+ assert status.startswith("STATUS ")
+
+ sock.sendall(b"SET CALLERID DG1ABC\n")
+ assert reader.read() == "OK"
+
+ sock.sendall(b"CONNECT\n")
+ assert reader.read() == "EVENT connected"
+ assert reader.read() == "OK"
+
+ sock.sendall(b"SEND 73\n")
+ rx = reader.read()
+ assert rx.startswith("RX ")
+ assert reader.read() == "OK"
+
+ sock.sendall(b"GET STATUS\n")
+ st = reader.read()
+ assert "callerid=DG1ABC" in st
+ assert reader.read() == "OK"
+
+ print("OK: max25d protocol smoke")
+ return 0
+ finally:
+ sock.close()
+ proc.terminate()
+ proc.wait(timeout=5)
+
+
+if __name__ == "__main__":
+ sys.exit(main())
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com