- Add AGENTS.md with repo-specific conventions, build steps, and quirks - Add PATCHES_AND_MODULES.md documenting every upstream deviation - Add tests/ with pytest/slixmpp integration suite for core, MUC, vnctalk extensions, and infrastructure verification - Include pytest.ini and .gitignore Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
109 lines
4.4 KiB
Python
109 lines
4.4 KiB
Python
"""Infrastructure tests: telnet, healthcheck, ports, TLS."""
|
|
import asyncio
|
|
import os
|
|
import subprocess
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
class TestAdminTelnet:
|
|
|
|
async def test_telnet_port_open(self, xmpp_config):
|
|
"""Admin telnet port 5582 must accept TCP connections."""
|
|
import socket
|
|
host = xmpp_config["admin_telnet_host"]
|
|
port = xmpp_config["admin_telnet_port"]
|
|
try:
|
|
reader, writer = await asyncio.wait_for(
|
|
asyncio.open_connection(host, port), timeout=5
|
|
)
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
except ConnectionRefusedError:
|
|
if xmpp_config.get("skip_live"):
|
|
pytest.skip("No server running (skip-live mode)")
|
|
raise
|
|
except (OSError, asyncio.TimeoutError) as e:
|
|
pytest.fail(f"Cannot connect to admin telnet {host}:{port}: {e}")
|
|
|
|
async def test_telnet_banner(self, xmpp_config):
|
|
"""Telnet should send a banner with null byte."""
|
|
host = xmpp_config["admin_telnet_host"]
|
|
port = xmpp_config["admin_telnet_port"]
|
|
try:
|
|
reader, writer = await asyncio.wait_for(
|
|
asyncio.open_connection(host, port), timeout=5
|
|
)
|
|
data = await asyncio.wait_for(reader.read(1024), timeout=5)
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
assert b"Prosody" in data or b"\x00" in data, "Unexpected telnet banner"
|
|
except ConnectionRefusedError:
|
|
if xmpp_config.get("skip_live"):
|
|
pytest.skip("No server running (skip-live mode)")
|
|
raise
|
|
except (OSError, asyncio.TimeoutError) as e:
|
|
pytest.fail(f"Telnet banner check failed: {e}")
|
|
|
|
|
|
class TestHealthcheck:
|
|
"""Verify healthcheck.sh semantics."""
|
|
|
|
def test_healthcheck_script_exists(self):
|
|
script = os.path.join(os.path.dirname(__file__), "..", "config", "healthcheck.sh")
|
|
assert os.path.exists(script), "healthcheck.sh not found"
|
|
|
|
def test_healthcheck_exits_two_on_cert_mismatch(self, tmp_path, monkeypatch):
|
|
"""Simulate cert mismatch scenario: script must exit 2."""
|
|
# We cannot easily run the real script without the container layout,
|
|
# but we verify the script source contains the exit-2 logic.
|
|
script_path = os.path.join(os.path.dirname(__file__), "..", "config", "healthcheck.sh")
|
|
with open(script_path) as f:
|
|
source = f.read()
|
|
assert "exit 2" in source, "healthcheck.sh must exit 2 on cert mismatch"
|
|
assert "md5sum" in source or "sha" in source, "healthcheck should compare cert hashes"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
class TestPorts:
|
|
|
|
async def test_c2s_port_open(self, xmpp_config):
|
|
"""XMPP C2S port must accept TCP."""
|
|
import socket
|
|
host = xmpp_config["host"]
|
|
port = xmpp_config["port"]
|
|
try:
|
|
reader, writer = await asyncio.wait_for(
|
|
asyncio.open_connection(host, port), timeout=5
|
|
)
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
except (ConnectionRefusedError, OSError, asyncio.TimeoutError) as e:
|
|
if xmpp_config.get("skip_live") and ("Connect call failed" in str(e) or isinstance(e, ConnectionRefusedError)):
|
|
pytest.skip("No server running (skip-live mode)")
|
|
pytest.fail(f"C2S port not reachable {host}:{port}: {e}")
|
|
|
|
async def test_http_port_open(self, xmpp_config):
|
|
"""HTTP port (BOSH/WebSocket) must accept TCP."""
|
|
import aiohttp
|
|
# Try BOSH URL host:port if given, else skip
|
|
url = xmpp_config.get("bosh_url") or xmpp_config.get("ws_url")
|
|
if not url:
|
|
pytest.skip("No HTTP URL configured")
|
|
from urllib.parse import urlparse
|
|
parsed = urlparse(url)
|
|
host = parsed.hostname
|
|
port = parsed.port or (443 if parsed.scheme == "https" else 80)
|
|
try:
|
|
reader, writer = await asyncio.wait_for(
|
|
asyncio.open_connection(host, port), timeout=5
|
|
)
|
|
writer.close()
|
|
await writer.wait_closed()
|
|
except ConnectionRefusedError:
|
|
if xmpp_config.get("skip_live"):
|
|
pytest.skip("No server running (skip-live mode)")
|
|
raise
|
|
except (OSError, asyncio.TimeoutError) as e:
|
|
pytest.fail(f"HTTP port not reachable {host}:{port}: {e}")
|