Files
odysseus/tests/helpers/worker_runtime.py
T
Alexandre Teixeira 256beebb3d test: keep pytest basetemp within the AF_UNIX path limit
Moving TMPDIR into the private runtime root left pytest's default
<TMPDIR>/pytest-of-<user>/pytest-<n> beneath it. With xdist's popen-gw<n>
the real-tmux witness bound a 110-byte socket path, over Linux's 107-byte
sun_path limit, so it failed under every worker count while passing
serially.

The controller now roots basetemp at the private root's pytest directory;
xdist hands workers popen-gw<n> beneath it. An explicit --basetemp wins.
A tmux-independent witness binds a socket at the same path budget.
2026-10-03 03:46:52 +01:00

71 lines
3.0 KiB
Python

"""Private filesystem defaults established before application imports."""
import os
import tempfile
from contextlib import contextmanager
from pathlib import Path
import pytest
def bootstrap_runtime():
"""Establish defaults before collection; APP_PORT opts into live smoke."""
worker = os.environ.get("PYTEST_XDIST_WORKER")
if os.environ.get("APP_PORT") and not worker:
return None
runtime = isolated_runtime(worker or "main")
runtime.root = runtime.__enter__()
return runtime
def configure_runtime(config, runtime):
"""Register ownership even when configuration or collection fails."""
if runtime is not None:
config.add_cleanup(lambda: runtime.__exit__(None, None, None))
# pytest's default <TMPDIR>/pytest-of-<user>/pytest-<n> beneath the
# private TMPDIR, plus xdist's popen-gw<n>, overflows the 107-byte
# AF_UNIX limit for sockets in tmp_path. Workers inherit a basetemp
# under the controller's; an explicit --basetemp still wins.
if config.option.basetemp is None and not hasattr(config, "workerinput"):
config.option.basetemp = str(runtime.root / "pytest")
parallel = bool(getattr(config.option, "numprocesses", None)) or hasattr(config, "workerinput")
# This consumes the existing test option; its public read and documented
# source location remain in the static-server fixture.
port_variable = "ODYSSEUS_TEST_STATIC_PORT"
if parallel and int(os.environ.get(port_variable) or 0):
raise pytest.UsageError(
"parallel tests require an ephemeral static-server port; "
"unset ODYSSEUS_TEST_STATIC_PORT or use -n 0"
)
@contextmanager
def isolated_runtime(worker="main"):
"""Own mutable defaults for one pytest process, including subprocesses.
The random suffix separates simultaneous runs, even with the same worker
name. Test-specific monkeypatches and function-scoped databases still own
their resources; this is a fallback namespace, not a shared DB fixture.
"""
with tempfile.TemporaryDirectory(prefix=f"ody-{worker}-") as directory:
root = Path(directory)
with pytest.MonkeyPatch.context() as patcher:
paths = {
"ODYSSEUS_DATA_DIR": root / "data",
"ODYSSEUS_MAIL_ATTACHMENTS_DIR": root / "mail",
"FASTEMBED_CACHE_PATH": root / "fastembed",
"XDG_RUNTIME_DIR": root / "runtime",
}
for name, path in paths.items():
path.mkdir(mode=0o700)
patcher.setenv(name, str(path))
# Browser resolution falls back to our XDG runtime directory.
patcher.delenv("AGENT_BROWSER_SOCKET_DIR", raising=False)
tmp = root / "tmp"
tmp.mkdir(mode=0o700)
for name in ("TMPDIR", "TMP", "TEMP"):
patcher.setenv(name, str(tmp))
# tempfile may already have cached the caller's directory.
patcher.setattr(tempfile, "tempdir", str(tmp))
yield root