okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

dawne2e: give each exclusive test a fresh daemon beside the shared one, keep test daemons offline, and reuse connections5bf3cbb

main
1.6 KiB50 linesraw
1"""One scratch directory per test process, removed when the process exits.
2
3Every Python suite works inside ``<root>/<name>-<pid>``, where root is
4``$ALBEDO_TEST_TMP`` or ``/tmp/albedo-tests``. Claiming it points tempfile's
5default directory and ``TMPDIR`` there, so daemons, their kernels and any
6temporary directory a test forgets are removed together instead of piling up in
7/tmp or in each nix shell's own TMPDIR. A run that died before cleaning up is
8swept by the next one. The root is fixed rather than taken from TMPDIR, so
9locks under it hold across shells and unix socket paths below it stay short.
10"""
11
12import atexit
13import os
14from pathlib import Path
15import shutil
16import tempfile
17
18ROOT = Path(os.environ.get("ALBEDO_TEST_TMP", "/tmp/albedo-tests"))
19
20
21def claim(name: str) -> Path:
22    """This process's scratch directory, created on first use."""
23    path = ROOT / f"{name}-{os.getpid()}"
24    if tempfile.tempdir == str(path):
25        return path
26    ROOT.mkdir(parents=True, exist_ok=True)
27    sweep()
28    path.mkdir(exist_ok=True)
29    tempfile.tempdir = str(path)
30    os.environ["TMPDIR"] = str(path)
31    atexit.register(shutil.rmtree, path, ignore_errors=True)
32    return path
33
34
35def sweep() -> None:
36    """Remove the directories of test processes that no longer exist."""
37    for entry in ROOT.iterdir():
38        pid = entry.name.rpartition("-")[2]
39        if entry.is_dir() and pid.isdigit() and not alive(int(pid)):
40            shutil.rmtree(entry, ignore_errors=True)
41
42
43def alive(pid: int) -> bool:
44    try:
45        os.kill(pid, 0)
46    except ProcessLookupError:
47        return False
48    except PermissionError:
49        return True
50    return True