summaryrefslogtreecommitdiff
path: root/stacks/daemon/test_auth.py
diff options
context:
space:
mode:
authorinfo@mode42.com <info@mode42.com>2026-08-07 18:23:28 +0000
committerinfo@mode42.com <info@mode42.com>2026-08-07 18:23:28 +0000
commitfa05a5f8238e9e1417235711656e5062ccc843a7 (patch)
tree46fbbd18de54492b59307c16efcc7f3152723238 /stacks/daemon/test_auth.py
Initial push
Diffstat (limited to 'stacks/daemon/test_auth.py')
-rw-r--r--stacks/daemon/test_auth.py95
1 files changed, 95 insertions, 0 deletions
diff --git a/stacks/daemon/test_auth.py b/stacks/daemon/test_auth.py
new file mode 100644
index 0000000..263a2e5
--- /dev/null
+++ b/stacks/daemon/test_auth.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+"""TCP auth smoke test for max25d M25/1."""
+import socket
+import subprocess
+import sys
+import tempfile
+import time
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parents[2]
+DAEMON = ROOT / "stacks/daemon/max25d"
+BASE_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 main() -> int:
+ port = free_port()
+ password = "preview-secret"
+
+ with tempfile.NamedTemporaryFile("w", suffix=".ini", delete=False) as tmp:
+ tmp.write(BASE_INI.read_text())
+ tmp.write(f"\n[network]\ntcp_password = {password}\n")
+ ini_path = Path(tmp.name)
+
+ proc = subprocess.Popen(
+ [str(DAEMON), "--no-stack", "-c", str(ini_path), "--tcp-port", str(port)],
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.PIPE,
+ text=True,
+ )
+ time.sleep(0.6)
+ 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() == "AUTH required"
+
+ sock.sendall(b"AUTH wrong\n")
+ assert reader.read() == "ERR auth failed"
+ sock.close()
+
+ sock = socket.create_connection(("127.0.0.1", port), timeout=3)
+ reader = LineReader(sock)
+ assert reader.read() == "AUTH required"
+ sock.sendall(f"AUTH {password}\n".encode())
+ assert reader.read() == "OK"
+ status = reader.read()
+ assert status.startswith("STATUS ")
+
+ sock.sendall(b"PING\n")
+ assert reader.read() == "OK"
+
+ print("OK: max25d TCP auth smoke")
+ return 0
+ finally:
+ try:
+ sock.close()
+ except OSError:
+ pass
+ proc.terminate()
+ proc.wait(timeout=5)
+ ini_path.unlink(missing_ok=True)
+
+
+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