test(issue-20): record and drop the ambient control-plane binding before collection; per-test default registry and audit-log roots
pytest_configure records WORKSPACE_ROOT, AGENT_SESSIONS_YAML, MAM_JOBS_DIR and DELEGATE_JOB_LOGS_DIR and drops the last three, plus WORKSPACE_ROOT when it names another checkout: a worktree creator's pane carries all four at the live main checkout, and each wins over a test's own WORKSPACE_ROOT. It runs before collection because test_orc_onboard copies os.environ at import. Every test then defaults MAM_JOBS_DIR and DELEGATE_JOB_LOGS_DIR to tmp_path/.mam-test-state; mam_sandbox and a test's own monkeypatch still override. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sdga4A8i1iSc8DaaW9iKU2
This commit is contained in:
1 parent
b1e313be04
commit
3433ffdc41
1 file changed
+59
@@ -109,6 +109,65 @@ def _pid_alive(pid):
|
|||||||
return bool(state) and not state.startswith("Z")
|
return bool(state) and not state.startswith("Z")
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Issue #20: test state stays out of every real control plane.
|
||||||
|
#
|
||||||
|
# An agent pane can carry a control-plane binding: a worktree creator's pane
|
||||||
|
# gets WORKSPACE_ROOT, AGENT_SESSIONS_YAML, MAM_JOBS_DIR and
|
||||||
|
# DELEGATE_JOB_LOGS_DIR pointing at the live main checkout (create/resume
|
||||||
|
# forward the row's control_plane), and each of them wins over a test's own
|
||||||
|
# WORKSPACE_ROOT (mqtt_common.default_registry_dir/get_logs_dir, lib.sh's
|
||||||
|
# AGENT_SESSIONS_YAML). pytest_configure records the binding and drops it
|
||||||
|
# before collection - a session fixture is too late for a module that copies
|
||||||
|
# os.environ at import (test_orc_onboard.SCRUBBED_ENV). WORKSPACE_ROOT is
|
||||||
|
# dropped only when it names another checkout; naming this one, it is what
|
||||||
|
# lib.sh derives anyway. Every test then defaults to a registry and an
|
||||||
|
# audit-log root under its own tmp_path, and a session guard (next to the #19
|
||||||
|
# one) reports new entries in the recorded control planes.
|
||||||
|
# ==============================================================================
|
||||||
|
_REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
_BINDING_VARS = ("WORKSPACE_ROOT", "AGENT_SESSIONS_YAML", "MAM_JOBS_DIR", "DELEGATE_JOB_LOGS_DIR")
|
||||||
|
_RECORDED_BINDING = {}
|
||||||
|
_DROPPED_BINDING = pytest.StashKey[dict]()
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_configure(config):
|
||||||
|
_RECORDED_BINDING.clear()
|
||||||
|
_RECORDED_BINDING.update({k: os.environ[k] for k in _BINDING_VARS if os.environ.get(k)})
|
||||||
|
dropped = {k: os.environ.pop(k) for k in ("AGENT_SESSIONS_YAML", "MAM_JOBS_DIR", "DELEGATE_JOB_LOGS_DIR")
|
||||||
|
if k in os.environ}
|
||||||
|
ws = os.environ.get("WORKSPACE_ROOT")
|
||||||
|
if ws and os.path.realpath(ws) != str(_REPO_ROOT):
|
||||||
|
dropped["WORKSPACE_ROOT"] = os.environ.pop("WORKSPACE_ROOT")
|
||||||
|
config.stash[_DROPPED_BINDING] = dropped
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_unconfigure(config):
|
||||||
|
# Back for callers that run pytest.main() in-process.
|
||||||
|
os.environ.update(config.stash.get(_DROPPED_BINDING, {}))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def _ambient_control_plane():
|
||||||
|
"""The binding pytest_configure recorded (and dropped), as a copy."""
|
||||||
|
return dict(_RECORDED_BINDING)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _isolate_mam_state_dirs(_ambient_control_plane, tmp_path, monkeypatch):
|
||||||
|
"""Default registry and audit-log roots under this test's tmp_path; only
|
||||||
|
the env is set, nothing is created. mam_sandbox and a test's own
|
||||||
|
setenv/delenv run after this autouse fixture and win, and the shared
|
||||||
|
function-scope monkeypatch undoes them in LIFO order. A hidden directory,
|
||||||
|
so tests that use tmp_path/"jobs" as their own registry or list tmp_path
|
||||||
|
are unaffected. Takes _ambient_control_plane to state the order, not to
|
||||||
|
rely on it."""
|
||||||
|
state = tmp_path / ".mam-test-state"
|
||||||
|
monkeypatch.setenv("MAM_JOBS_DIR", str(state / "jobs"))
|
||||||
|
monkeypatch.setenv("DELEGATE_JOB_LOGS_DIR", str(state / "delegate_job_logs"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mam_sandbox(tmp_path, monkeypatch, request):
|
def mam_sandbox(tmp_path, monkeypatch, request):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in new issue
Block a user