Isolate pytest env per file so fail-closed and setup stay script-accurate.
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Test Suite / pytest-backend (push) Successful in 2m50s
Test Suite / smoke-dev (push) Successful in 0s
Test Suite / frontend-build (push) Successful in 15s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Lars 2026-09-07 15:00:33 +02:00
parent 9d79e3e92f
commit 3c0213ae74
5 changed files with 57 additions and 29 deletions

View File

@ -54,7 +54,10 @@ jobs:
-e PYTHONUTF8=1 \ -e PYTHONUTF8=1 \
backend sh -lc ' backend sh -lc '
set -e set -e
unset KANSHO_DB_PATH unset KANSHO_DB_PATH KANSHO_FAKE_PROVIDER KANSHO_FAKE_DETECT
unset KANSHO_PROVIDER_KEY KANSHO_DETECT_PROVIDER_KEY
export KANSHO_PROVIDER_KEY=
export KANSHO_DETECT_PROVIDER_KEY=
pip install -q -r requirements-dev.txt pip install -q -r requirements-dev.txt
python -m pytest tests -m "not slow" -ra -vv --tb=short python -m pytest tests -m "not slow" -ra -vv --tb=short
' '

View File

@ -2,7 +2,8 @@
Each file stays one case (`main()`) until it is split into native pytest Each file stays one case (`main()`) until it is split into native pytest
functions. Integration files reset `kansho_test` only; `kansho_dev` is never functions. Integration files reset `kansho_test` only; `kansho_dev` is never
the test target. the test target. Provider keys and fake flags are restored per file so the
shared pytest process matches the old one-script-per-process isolation.
""" """
from __future__ import annotations from __future__ import annotations
@ -17,6 +18,7 @@ if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT))
from tests.harness import ( # noqa: E402 from tests.harness import ( # noqa: E402
apply_module_env,
is_postgres_test_database, is_postgres_test_database,
prepare_test_env, prepare_test_env,
reset_postgres_schema, reset_postgres_schema,
@ -56,34 +58,32 @@ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item
class KanshoScriptModule(pytest.Module): class KanshoScriptModule(pytest.Module):
def collect(self): def collect(self):
module = self.obj module = self.obj
main = getattr(module, "main", None)
def test_main() -> None: if main is None or not callable(main):
main = getattr(module, "main", None) pytest.fail(f"{self.path.name} has no callable main()")
if main is None or not callable(main): yield pytest.Function.from_parent(self, name="test_main", callobj=main)
pytest.fail(f"{self.path.name} has no callable main()")
main()
yield pytest.Function.from_parent(self, name="test_main", callobj=test_main)
@pytest.fixture(scope="module", autouse=True) @pytest.fixture(scope="module", autouse=True)
def _module_backend(request: pytest.FixtureRequest): def _module_backend(request: pytest.FixtureRequest):
stem = Path(str(request.path)).stem source = Path(str(request.path))
if stem in UNIT_MODULES: stem = source.stem
saved = dict(os.environ) saved = dict(os.environ)
try: try:
apply_module_env(source)
if stem in UNIT_MODULES:
yield yield
finally: return
os.environ.clear() if not is_postgres_test_database():
os.environ.update(saved) pytest.skip(
return "integration requires KANSHO_DB_BACKEND=postgres and DB_NAME ending _test "
if not is_postgres_test_database(): "(Gitea: kansho_test on the Dev Postgres, never kansho_dev)"
pytest.skip( )
"integration requires KANSHO_DB_BACKEND=postgres and DB_NAME ending _test " reset_postgres_schema()
"(Gitea: kansho_test on the Dev Postgres, never kansho_dev)" from db import init_db
)
reset_postgres_schema()
from db import init_db
init_db() init_db()
yield yield
finally:
os.environ.clear()
os.environ.update(saved)

View File

@ -39,9 +39,28 @@ def is_postgres_test_database() -> bool:
def prepare_test_env() -> None: def prepare_test_env() -> None:
os.environ.setdefault("KANSHO_PROVIDER_KEY", "") """Fail-closed defaults. Do not keep Compose provider keys or leftover fakes."""
os.environ.setdefault("KANSHO_DETECT_PROVIDER_KEY", "") os.environ["KANSHO_PROVIDER_KEY"] = ""
os.environ["KANSHO_DETECT_PROVIDER_KEY"] = ""
os.environ.pop("KANSHO_DB_PATH", None) os.environ.pop("KANSHO_DB_PATH", None)
os.environ.pop("KANSHO_FAKE_PROVIDER", None)
os.environ.pop("KANSHO_FAKE_DETECT", None)
def apply_module_env(source) -> None:
"""Restore per-file env so pytest does not leak fakes/keys across scripts."""
from pathlib import Path
prepare_test_env()
text = Path(source).read_text(encoding="utf-8")
if 'os.environ["KANSHO_FAKE_PROVIDER"] = "1"' in text or "os.environ['KANSHO_FAKE_PROVIDER'] = '1'" in text:
os.environ["KANSHO_FAKE_PROVIDER"] = "1"
if (
'os.environ["KANSHO_FAKE_DETECT"] = "1"' in text
or "os.environ['KANSHO_FAKE_DETECT'] = '1'" in text
or 'os.environ.setdefault("KANSHO_FAKE_DETECT", "1")' in text
):
os.environ["KANSHO_FAKE_DETECT"] = "1"
def _require_test_database() -> None: def _require_test_database() -> None:

View File

@ -209,6 +209,9 @@ def main() -> None:
test_compile_flags() test_compile_flags()
test_budget_omission_in_effective_trace() test_budget_omission_in_effective_trace()
from tests.harness import reset_postgres_schema
reset_postgres_schema()
init_db() init_db()
reset_debug() reset_debug()
with TestClient(app) as client: with TestClient(app) as client:

View File

@ -268,6 +268,9 @@ def test_later_semantic_seed_creates_successor() -> None:
def test_legacy_generate_trace_and_prompt() -> None: def test_legacy_generate_trace_and_prompt() -> None:
from tests.harness import reset_postgres_schema
reset_postgres_schema()
init_db() init_db()
client = TestClient(app) client = TestClient(app)
setup = client.post( setup = client.post(