diff --git a/tests/conftest.py b/tests/conftest.py index 3211ab8b9..292fdadf2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -351,7 +351,8 @@ def context_probe_ledger(_no_context_window_network_probe): return _no_context_window_network_probe -@pytest.hookimpl(specname="pytest_configure") +# Before pytest's tmpdir plugin reads the basetemp this sets. +@pytest.hookimpl(specname="pytest_configure", tryfirst=True) def pytest_configure_worker_runtime(config): configure_runtime(config, _runtime_environment) diff --git a/tests/helpers/worker_runtime.py b/tests/helpers/worker_runtime.py index d745ff607..44a76bc4c 100644 --- a/tests/helpers/worker_runtime.py +++ b/tests/helpers/worker_runtime.py @@ -14,7 +14,7 @@ def bootstrap_runtime(): if os.environ.get("APP_PORT") and not worker: return None runtime = isolated_runtime(worker or "main") - runtime.__enter__() + runtime.root = runtime.__enter__() return runtime @@ -22,6 +22,12 @@ 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 /pytest-of-/pytest- beneath the + # private TMPDIR, plus xdist's popen-gw, 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. diff --git a/tests/test_worker_runtime.py b/tests/test_worker_runtime.py index 5ff9e87d4..a91157902 100644 --- a/tests/test_worker_runtime.py +++ b/tests/test_worker_runtime.py @@ -1,6 +1,7 @@ """The default namespace must protect callers and simultaneous pytest runs.""" import os +import socket import subprocess import sys import tempfile @@ -70,3 +71,11 @@ def test_subprocess_inherits_private_temp_and_data_directories(): assert (root / "data" / "child").read_text() == "data" assert (root / "tmp" / "child").read_text() == "temp" assert not root.exists() + + +@pytest.mark.skipif(not hasattr(socket, "AF_UNIX"), reason="requires AF_UNIX") +def test_tmp_path_under_private_runtime_fits_unix_socket(tmp_path): + # pytest truncates this name to 30 characters, as for the real-tmux + # witness. A nested pytest-of- basetemp made it 110 bytes under xdist. + with socket.socket(socket.AF_UNIX) as sock: + sock.bind(str(tmp_path / "tmux.sock"))