mirror of
https://github.com/rommapp/romm.git
synced 2026-10-11 22:40:04 +00:00
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:
co-authored by
Claude Opus 5.5
parent
c63f44133d
commit
503c9b290b
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user