test(db): give worktree runs their own temporary test database (#5074)

* test(db): give worktree runs their own temporary test database

Checkouts share romm_test, so a worktree on another branch can migrate it
to a revision the current branch lacks, and every test then errors in
setup with "Can't locate revision". ROMM_TEST_DB_TAG gives a run its own
romm_test_<tag> databases (one per xdist worker) that are dropped when
the session ends. AGENTS.md tells worktree sessions to use it.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* test(db): address Greptile review on temporary test databases

- Prefix tagged databases with tmp_ so they can never share a name with
  an untagged xdist worker database that teardown would then drop.
- Normalize the tag to [A-Za-z0-9_] so tags like my-worktree work.
- Drop the temporary database even when the migration fails.
- Shorten the new comment to two lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Georges-Antoine Assi
2026-10-03 11:28:24 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent c63f44133d
commit 503c9b290b
3 changed files with 47 additions and 2 deletions
+10
View File
@@ -78,6 +78,16 @@ callers of anything whose signature or behavior you changed (`grep` for the symb
CI runs the whole suite on the PR (`pytest.yml`, MariaDB + PostgreSQL). That is the
place for full-suite coverage; local runs stay scoped.
**In a git worktree, run tests against a temporary database.** Every checkout shares
`romm_test`, and one on another branch can migrate it to a revision yours lacks, so
every test errors in setup with `Can't locate revision`. Set `ROMM_TEST_DB_TAG` to a
tag unique to the worktree: the run creates and migrates `romm_test_tmp_<tag>` (one per
xdist worker), then drops it at the end. Never `stamp` or downgrade the shared `romm_test`.
```bash
ROMM_TEST_DB_TAG=my_worktree uv run pytest -n auto tests/handler/
```
---
## Environment setup
+7 -1
View File
@@ -1,4 +1,5 @@
import os
import re
# Tests must never inherit DB_NAME from the ambient environment (e.g. a
# sourced .env pointing at a real dev/prod database) -- the autouse
@@ -12,5 +13,10 @@ import os
#
# The Redis cache needs no equivalent handling: under pytest it is an in-process
# FakeRedis, so each worker process is already isolated.
#
# ROMM_TEST_DB_TAG runs use temporary databases that tests/conftest.py drops at
# session end; the `tmp_` prefix keeps them apart from the untagged worker names.
_tag = re.sub(r"[^A-Za-z0-9_]", "_", os.environ.get("ROMM_TEST_DB_TAG", ""))
_base = f"romm_test_tmp_{_tag}" if _tag else "romm_test"
_xdist_worker = os.environ.get("PYTEST_XDIST_WORKER")
os.environ["DB_NAME"] = f"romm_test_{_xdist_worker}" if _xdist_worker else "romm_test"
os.environ["DB_NAME"] = f"{_base}_{_xdist_worker}" if _xdist_worker else _base
+30 -1
View File
@@ -133,6 +133,30 @@ def _ensure_database_exists() -> None:
admin_engine.dispose()
def _drop_database() -> None:
"""Drop the temporary database a ROMM_TEST_DB_TAG run created."""
url = ConfigManager.get_db_engine()
db_name = url.database
if not db_name or not re.fullmatch(r"[A-Za-z0-9_]+", db_name):
return
engine.dispose()
sync_engine.dispose()
if ROMM_DB_DRIVER in ("mariadb", "mysql"):
admin_engine = create_engine(url.set(database="information_schema"))
with admin_engine.begin() as conn:
conn.execute(text(f"DROP DATABASE IF EXISTS `{db_name}`"))
elif ROMM_DB_DRIVER == "postgresql":
admin_engine = create_engine(
url.set(database="postgres"), isolation_level="AUTOCOMMIT"
)
with admin_engine.connect() as conn:
conn.execute(text(f'DROP DATABASE IF EXISTS "{db_name}" WITH (FORCE)'))
else:
return
admin_engine.dispose()
@pytest.fixture(autouse=True)
def raise_on_response_mismatch(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(response_validation, "RAISE_ON_MISMATCH", True)
@@ -151,7 +175,12 @@ def lenient(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
@pytest.fixture(scope="session", autouse=True)
def setup_database():
_ensure_database_exists()
alembic.config.main(argv=["upgrade", "head"])
try:
alembic.config.main(argv=["upgrade", "head"])
yield
finally:
if os.environ.get("ROMM_TEST_DB_TAG"):
_drop_database()
@pytest.fixture(autouse=True)