"""Real-fd regression canary. Drives a real socket code path (the TCP reachability probe) in a tight loop and asserts the process's open-fd count doesn't grow. If someone reintroduces a socket leak in the probe path — the class of bug behind the Errno 24 lockups — this fails in CI instead of in production. Uses real descriptors, not fakes, so the assertion has teeth. """ import asyncio import os import pytest from steward.monitors.ping import tcp_check _ITERATIONS = 100 def _fd_count() -> int | None: try: return len(os.listdir("/proc/self/fd")) except OSError: return None async def _hammer_tcp_check() -> None: # 127.0.0.1:1 has no listener → connection refused immediately. Each call must # fully release its socket; a leak would add ~one fd per iteration. for _ in range(_ITERATIONS): await tcp_check("127.0.0.1", 1) def test_tcp_check_does_not_leak_fds(): if _fd_count() is None: pytest.skip("/proc/self/fd unavailable on this platform") asyncio.run(_hammer_tcp_check()) # warm up (lazy imports, caches) before = _fd_count() asyncio.run(_hammer_tcp_check()) after = _fd_count() # Small slack for interpreter-internal fds; a genuine leak over 100 iterations # would be far larger than this. assert after - before <= 5, ( f"open fds grew {before}->{after} over {_ITERATIONS} tcp_check calls " "— possible socket leak")