test: harden session-state isolation for #594 decision-lock suite

Pin per-test durable session-state so patch.dict(clear=True) cannot adopt
host ~/.cache review-decision locks, and clear the merge-test ledger in
setUp. Keeps active #332 hard-stop coverage while making TestMergePR
deterministic without manual host cache cleanup.

Aligned with #590 / PR #592 isolation approach.
This commit is contained in:
2026-07-09 15:24:41 -04:00
parent 86651a3d05
commit b98e8dfa1a
2 changed files with 38 additions and 1 deletions
+35 -1
View File
@@ -1,4 +1,5 @@
"""Shared pytest fixtures for the Gitea-Tools test suite.""" """Shared pytest fixtures for the Gitea-Tools test suite."""
import os
import sys import sys
import pytest import pytest
@@ -16,13 +17,41 @@ def _reset_mutation_authority(monkeypatch):
the next test. It must never replace verify_mutation_authority with a the next test. It must never replace verify_mutation_authority with a
no-op: individual tests that need a specific authority state set it up no-op: individual tests that need a specific authority state set it up
explicitly. explicitly.
Session-state isolation (#559 / #590 / #594): many tests use
``patch.dict(os.environ, ..., clear=True)``, which drops
``GITEA_MCP_SESSION_STATE_DIR``. Pin ``default_state_dir`` /
``DEFAULT_STATE_DIR`` to a per-test temp dir so durable load/save never
touches host state even after env clears.
""" """
monkeypatch.delenv("GITEA_SESSION_PROFILE_LOCK", raising=False) monkeypatch.delenv("GITEA_SESSION_PROFILE_LOCK", raising=False)
# Isolate durable session-state files so tests never share host cache (#559). # Isolate durable session-state files so tests never share host cache (#559).
import tempfile import tempfile
_state_tmp = tempfile.TemporaryDirectory(prefix="gitea-session-state-") _state_tmp = tempfile.TemporaryDirectory(prefix="gitea-session-state-")
monkeypatch.setenv("GITEA_MCP_SESSION_STATE_DIR", _state_tmp.name) state_dir = _state_tmp.name
monkeypatch.setenv("GITEA_MCP_SESSION_STATE_DIR", state_dir)
try:
import mcp_session_state
except Exception:
mcp_session_state = None
if mcp_session_state is not None:
monkeypatch.setattr(
mcp_session_state, "DEFAULT_STATE_DIR", state_dir, raising=False
)
def _isolated_default_state_dir(
_fallback: str = state_dir,
_env_key: str = mcp_session_state.STATE_DIR_ENV,
) -> str:
raw = (os.environ.get(_env_key) or "").strip()
return raw or _fallback
monkeypatch.setattr(
mcp_session_state,
"default_state_dir",
_isolated_default_state_dir,
)
try: try:
import mcp_server import mcp_server
except Exception: except Exception:
@@ -40,6 +69,11 @@ def _reset_mutation_authority(monkeypatch):
monkeypatch.setattr(mcp_server, "_preflight_capability_baseline_porcelain", None) monkeypatch.setattr(mcp_server, "_preflight_capability_baseline_porcelain", None)
monkeypatch.setattr(mcp_server, "_preflight_resolved_task", None) monkeypatch.setattr(mcp_server, "_preflight_resolved_task", None)
monkeypatch.setattr(mcp_server, "_preflight_reviewer_violation_files", []) monkeypatch.setattr(mcp_server, "_preflight_reviewer_violation_files", [])
monkeypatch.setattr(
mcp_server,
"_check_mcp_runtimes_diagnostics",
lambda *args, **kwargs: [],
)
try: try:
import review_workflow_load import review_workflow_load
review_workflow_load._REVIEW_WORKFLOW_LOAD = None review_workflow_load._REVIEW_WORKFLOW_LOAD = None
+3
View File
@@ -774,6 +774,9 @@ class TestMergePR(unittest.TestCase):
def setUp(self): def setUp(self):
import reviewer_pr_lease import reviewer_pr_lease
# Clean ledger each merge test so residual/host durable #332 state
# cannot short-circuit eligibility gates (#590 / #594).
mcp_server._save_review_decision_lock(None)
mcp_server.gitea_load_review_workflow() mcp_server.gitea_load_review_workflow()
self._lease_patch = _install_owned_reviewer_lease(8) self._lease_patch = _install_owned_reviewer_lease(8)
self._lease_patch.start() self._lease_patch.start()