mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-06 06:52:20 +02:00
Four more tests in the same family as the /tmp ones this change already
fixes, and they hide for the same reason: the failure depends on how
long $TMPDIR happens to be.
tests/test_shell_routes.py::TestHostDockerAccess (three) and
tests/test_cookbook_docker_access.py::test_container_opt_in_with_unix_
socket_is_allowed each bind an AF_UNIX socket at tmp_path/"docker.sock".
macOS gives sun_path 104 bytes including the terminator. pytest roots
tmp_path at $TMPDIR, which on a stock Mac is a 49-character
/var/folders/<2>/<30>/T/; add pytest-of-<user>/pytest-<n>/ and the
test's own name and the bind path is 115 bytes before the filename.
OSError: AF_UNIX path too long
Linux allows 108 and roots $TMPDIR at /tmp, so CI never sees it. Under a
shortened $TMPDIR the path lands at exactly 103 and passes — until
pytest's run counter reaches two digits and it becomes 104. That is why
the ledger's counts did not include these: they were measured somewhere
the path fit.
Adds tests/helpers/unix_sockets.bound_unix_socket, which binds under a
short directory and asserts the length before it tries, so the next
socket fixture fails with a sentence rather than an errno. Records the
trap in KNOWN_FAILURES.md along with the instruction to re-measure with
the default $TMPDIR.
47 lines
2.0 KiB
Python
47 lines
2.0 KiB
Python
"""Bind an AF_UNIX socket at a path the kernel will actually accept.
|
|
|
|
``sun_path`` is 104 bytes on macOS, terminator included, so a bind path longer
|
|
than 103 characters fails with ``OSError: AF_UNIX path too long``. pytest's
|
|
``tmp_path`` is rooted at ``$TMPDIR``, which on stock macOS is a 49-character
|
|
``/var/folders/<2>/<30>/T/`` path; adding ``pytest-of-<user>/pytest-<n>/`` and
|
|
the test's own (truncated) name spends the rest of the budget before the
|
|
filename is appended.
|
|
|
|
That is why this reads as flaky rather than broken. Linux allows 108 bytes and
|
|
roots ``$TMPDIR`` at ``/tmp``, so it never bites there; on macOS whether it
|
|
bites depends on the length of ``$TMPDIR``, the test's name, and how many
|
|
digits pytest's run counter is currently using. A run under a shortened
|
|
``$TMPDIR`` passes, the same checkout under the default one does not.
|
|
|
|
The path is resolved before it is handed back, for the same reason the rest of
|
|
this change resolves temp paths: on macOS ``/tmp`` is a symlink to
|
|
``/private/tmp``, and a test that binds one spelling and asserts on the other
|
|
is comparing two names for the same socket.
|
|
"""
|
|
|
|
import os
|
|
import shutil
|
|
import socket
|
|
import tempfile
|
|
from contextlib import contextmanager
|
|
|
|
# Short enough to leave room for the socket's own name under every platform's
|
|
# sun_path budget. A relative root would depend on the working directory.
|
|
_SHORT_ROOT = os.path.realpath(tempfile.gettempdir() if os.name == "nt" else "/tmp")
|
|
|
|
|
|
@contextmanager
|
|
def bound_unix_socket(name="docker.sock"):
|
|
"""Yield the path of a listening AF_UNIX socket, cleaned up on exit."""
|
|
directory = os.path.realpath(tempfile.mkdtemp(prefix="odysseus-sock-", dir=_SHORT_ROOT))
|
|
path = os.path.join(directory, name)
|
|
if len(path) > 103: # pragma: no cover - guards the guard
|
|
raise AssertionError(f"socket path is {len(path)} bytes, over the limit: {path}")
|
|
sock = socket.socket(socket.AF_UNIX)
|
|
try:
|
|
sock.bind(path)
|
|
yield path
|
|
finally:
|
|
sock.close()
|
|
shutil.rmtree(directory, ignore_errors=True)
|