test(issue31): keep every claude tmp root candidate inside the test
The adapter's fixed /tmp fallback is now a module constant. The new tests point it, TMPDIR, TMP and TEMP at the test's own dirs, in the test process and (through a sitecustomize on PYTHONPATH) in every python a test starts, so no test lists the real /tmp/claude-<uid> any more (Mac review, PR #59). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6f4f40a4ad
commit
26fb1c4130
2 files changed
+40
-5
No files matched your search
@@ -22,6 +22,10 @@ def _projects_dirs(ctx: DiscoveryContext) -> list:
|
|||||||
return dirs
|
return dirs
|
||||||
|
|
||||||
|
|
||||||
|
# Node's os.tmpdir() when no TMPDIR/TMP/TEMP is set; tests point it elsewhere.
|
||||||
|
_SYSTEM_TMP = "/tmp"
|
||||||
|
|
||||||
|
|
||||||
def _tmp_roots() -> list:
|
def _tmp_roots() -> list:
|
||||||
"""The per-uid temp roots claude may have used: ${CLAUDE_CODE_TMPDIR:-
|
"""The per-uid temp roots claude may have used: ${CLAUDE_CODE_TMPDIR:-
|
||||||
os.tmpdir()}/claude-<uid>. A sandboxed tool shell sets CLAUDE_CODE_TMPDIR
|
os.tmpdir()}/claude-<uid>. A sandboxed tool shell sets CLAUDE_CODE_TMPDIR
|
||||||
@@ -36,9 +40,9 @@ def _tmp_roots() -> list:
|
|||||||
cands.append(override)
|
cands.append(override)
|
||||||
# Node's os.tmpdir() on POSIX, not tempfile.gettempdir() (which probes
|
# Node's os.tmpdir() on POSIX, not tempfile.gettempdir() (which probes
|
||||||
# writability and falls back to the cwd).
|
# writability and falls back to the cwd).
|
||||||
tmp = os.environ.get("TMPDIR") or os.environ.get("TMP") or os.environ.get("TEMP") or "/tmp"
|
tmp = os.environ.get("TMPDIR") or os.environ.get("TMP") or os.environ.get("TEMP") or _SYSTEM_TMP
|
||||||
cands.append(os.path.join(tmp.rstrip("/") or "/", name))
|
cands.append(os.path.join(tmp.rstrip("/") or "/", name))
|
||||||
cands.append(os.path.join("/tmp", name))
|
cands.append(os.path.join(_SYSTEM_TMP, name))
|
||||||
roots, seen = [], set()
|
roots, seen = [], set()
|
||||||
for c in cands:
|
for c in cands:
|
||||||
real = os.path.realpath(c)
|
real = os.path.realpath(c)
|
||||||
|
|||||||
@@ -47,6 +47,29 @@ def _fresh_id() -> str:
|
|||||||
return ident
|
return ident
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def own_tmp_roots(tmp_path, monkeypatch):
|
||||||
|
"""Every tmp root the claude adapter may look in stays inside the test:
|
||||||
|
TMP/TEMP/TMPDIR and the fixed /tmp fallback, here and in every python a
|
||||||
|
test starts (a sitecustomize on PYTHONPATH sets the fallback there)."""
|
||||||
|
from lib_py.agents.adapters import claude as claude_mod
|
||||||
|
sys_tmp, tmpdir, shim = tmp_path / "systmp", tmp_path / "tmpdir", tmp_path / "pyshim"
|
||||||
|
for d in (sys_tmp, tmpdir, shim):
|
||||||
|
d.mkdir()
|
||||||
|
monkeypatch.setattr(claude_mod, "_SYSTEM_TMP", str(sys_tmp))
|
||||||
|
monkeypatch.setenv("TMPDIR", str(tmpdir))
|
||||||
|
monkeypatch.delenv("TMP", raising=False)
|
||||||
|
monkeypatch.delenv("TEMP", raising=False)
|
||||||
|
(shim / "sitecustomize.py").write_text(
|
||||||
|
"try:\n"
|
||||||
|
" from lib_py.agents.adapters import claude\n"
|
||||||
|
f" claude._SYSTEM_TMP = {str(sys_tmp)!r}\n"
|
||||||
|
"except Exception:\n"
|
||||||
|
" pass\n")
|
||||||
|
monkeypatch.setenv("PYTHONPATH", f"{shim}:{os.environ.get('PYTHONPATH', '')}")
|
||||||
|
return sys_tmp
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def conv() -> str:
|
def conv() -> str:
|
||||||
return _fresh_id()
|
return _fresh_id()
|
||||||
@@ -411,14 +434,14 @@ def test_a_job_dir_that_cannot_be_emptied_keeps_its_state_json(home, tmp_path, m
|
|||||||
assert adapter.residual_artifacts(conv, ctx) == []
|
assert adapter.residual_artifacts(conv, ctx) == []
|
||||||
|
|
||||||
|
|
||||||
def test_claude_tmp_root_rules(tmp_path, monkeypatch):
|
def test_claude_tmp_root_rules(tmp_path, monkeypatch, own_tmp_roots):
|
||||||
from lib_py.agents.adapters.claude import _tmp_roots
|
from lib_py.agents.adapters.claude import _tmp_roots
|
||||||
name = f"claude-{UID}"
|
name = f"claude-{UID}"
|
||||||
x, y, z = tmp_path / "x", tmp_path / "y", tmp_path / "z"
|
x, y, z = tmp_path / "x", tmp_path / "y", tmp_path / "z"
|
||||||
for d in (x / name, y / name, z / name):
|
for d in (x / name, y / name, z / name, own_tmp_roots / name):
|
||||||
d.mkdir(parents=True)
|
d.mkdir(parents=True)
|
||||||
real = lambda roots: [os.path.realpath(r) for r in roots] # noqa: E731
|
real = lambda roots: [os.path.realpath(r) for r in roots] # noqa: E731
|
||||||
sys_tmp = [os.path.realpath(f"/tmp/{name}")] if os.path.isdir(f"/tmp/{name}") else []
|
sys_tmp = [os.path.realpath(str(own_tmp_roots / name))]
|
||||||
|
|
||||||
monkeypatch.setenv("CLAUDE_CODE_TMPDIR", str(x))
|
monkeypatch.setenv("CLAUDE_CODE_TMPDIR", str(x))
|
||||||
monkeypatch.setenv("TMPDIR", str(z) + "/")
|
monkeypatch.setenv("TMPDIR", str(z) + "/")
|
||||||
@@ -438,6 +461,14 @@ def test_claude_tmp_root_rules(tmp_path, monkeypatch):
|
|||||||
assert real(_tmp_roots()) == [str(z / name)] + sys_tmp
|
assert real(_tmp_roots()) == [str(z / name)] + sys_tmp
|
||||||
|
|
||||||
|
|
||||||
|
def test_tests_never_reach_the_real_tmp_root(tmp_path, own_tmp_roots):
|
||||||
|
from lib_py.agents.adapters.claude import _tmp_roots
|
||||||
|
assert all(os.path.realpath(r).startswith(os.path.realpath(str(tmp_path))) for r in _tmp_roots())
|
||||||
|
res = subprocess.run([sys.executable, "-c", "from lib_py.agents.adapters import claude; print(claude._SYSTEM_TMP)"],
|
||||||
|
capture_output=True, text=True, env=_env(), timeout=30)
|
||||||
|
assert res.stdout.strip() == str(own_tmp_roots), res.stdout + res.stderr
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# in-use CLI and the stop gate
|
# in-use CLI and the stop gate
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in new issue
Block a user