From 8006702ee7191be157b93ac2d0714a7abd00e899 Mon Sep 17 00:00:00 2001 From: didericis Date: Fri, 26 Jun 2026 20:35:19 -0400 Subject: [PATCH] test: isolate HOME for the unit suite (hermetic audit/queue/state) The unit suite could write to and flock the real ~/.bot-bottle: state, queue, and audit dirs all derive from supervise.bot_bottle_root() -> Path.home(). A test taking a flock on the real audit log blocks indefinitely when a live bottle's supervise sidecar holds that lock (observed: a `coverage run` hung at 0% CPU), and unisolated tests otherwise pollute the developer's home dir. Point HOME at a throwaway temp dir for the whole tests/unit package (restored + cleaned at exit). Tests that set their own HOME now restore to the isolated dir, not the real one; tests that patch bot_bottle_root directly are unaffected. Closes #302 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NkwFXLFff9PYPy4wgVBJp9 --- tests/unit/__init__.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index e69de29..da5784b 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -0,0 +1,37 @@ +"""Unit-test package init. + +Isolates ``HOME`` to a throwaway directory for the entire unit suite so +no test ever reads or writes the real ``~/.bot-bottle`` (state, queue, +and audit dirs all derive from ``supervise.bot_bottle_root()`` → +``Path.home()``). Without this, a test that takes a ``flock`` on the +real audit log can **block indefinitely** when a live bottle's supervise +sidecar holds that lock — observed as a hung ``coverage run`` at 0% CPU — +and unisolated tests otherwise pollute the developer's home dir. + +Individual tests that need their own ``HOME`` still override +``os.environ['HOME']`` and restore it; they now restore to this isolated +dir rather than the real one, so isolation holds either way. Tests that +patch ``supervise.bot_bottle_root`` directly are unaffected. +""" + +from __future__ import annotations + +import atexit +import os +import shutil +import tempfile + +_real_home = os.environ.get("HOME") +_tmp_home = tempfile.mkdtemp(prefix="bot-bottle-unit-home.") +os.environ["HOME"] = _tmp_home + + +def _restore_home() -> None: + if _real_home is None: + os.environ.pop("HOME", None) + else: + os.environ["HOME"] = _real_home + shutil.rmtree(_tmp_home, ignore_errors=True) + + +atexit.register(_restore_home) -- 2.52.0