Systematic rename of all semantic anchors (#region, [DEF], @RELATION) across 1400+ files — backend Python, frontend Svelte/TS, specs, docs: - Flat anchors become Namespace.Module.Entity - @RELATION references updated to match new anchor paths - Zero business logic changes
80 lines
3.8 KiB
Python
80 lines
3.8 KiB
Python
# #region Test.Alembic.TaskRecordsUserId [C:3] [TYPE Module] [SEMANTICS test,alembic,migration,task,postgres]
|
|
# @BRIEF Verifies the real PostgreSQL upgrade that adds task_records.user_id.
|
|
# @RELATION BINDS_TO -> [EXT:Alembic:MigrationChain]
|
|
# @TEST_FIXTURE: migration_revisions -> INLINE_JSON
|
|
# @TEST_EDGE: missing_field -> Pre-user-id schema does not expose task_records.user_id.
|
|
# @TEST_EDGE: invalid_type -> Upgrade is addressed by a concrete Alembic revision.
|
|
# @TEST_EDGE: external_fail -> PostgreSQL DDL failures propagate instead of being masked.
|
|
# @TEST_INVARIANT: task_records_user_id_upgrade -> VERIFIED_BY: [Test.Alembic.TestUserIdMigrationAddsColumn]
|
|
# @RATIONALE SQLite and metadata.create_all() cannot expose an unapplied PostgreSQL migration;
|
|
# an isolated Testcontainers database exercises Alembic's actual DDL path.
|
|
# @REJECTED Stamping the revision or applying raw ALTER TABLE was rejected because each can
|
|
# conceal a migration chain failure while falsely marking the schema current.
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import pytest
|
|
|
|
from sqlalchemy import create_engine, inspect
|
|
|
|
|
|
# #region Test.Alembic.MigrationDatabaseUrl [C:2] [TYPE Function]
|
|
# @BRIEF Provide a pristine isolated database created via db_factory in the shared PG container.
|
|
# @POST Returns a host-accessible connection URL for an empty database.
|
|
# @RATIONALE Uses db_factory from the shared Postgres container instead of starting
|
|
# a separate PostgreSQL container. This is faster and uses fewer Docker resources.
|
|
# The database is created as a fresh, empty database — no tables exist, no Alembic
|
|
# has been run. This preserves the pristine-schema semantics required for testing
|
|
# Alembic migrations from a clean state.
|
|
# @REJECTED Starting a separate PostgresContainer was rejected — it adds ~5s per test
|
|
# and unnecessary Docker overhead when the shared container is already running.
|
|
@pytest.fixture
|
|
def migration_database_url(db_factory) -> str:
|
|
"""Provide a pristine PostgreSQL database from the shared container via db_factory.
|
|
|
|
Returns a host-accessible Postgres URL. The database is empty (no tables).
|
|
"""
|
|
result = db_factory["create_db"]("_alembic_test")
|
|
return result["host_url"]
|
|
|
|
|
|
# #endregion Test.Alembic.MigrationDatabaseUrl
|
|
|
|
|
|
# #region Test.Alembic.TestUserIdMigrationAddsColumn [C:2] [TYPE Function] [SEMANTICS test,alembic,migration,task,postgres]
|
|
# @BRIEF Upgrades a pristine PostgreSQL schema through the task_records.user_id revision.
|
|
def test_user_id_migration_adds_column(monkeypatch: pytest.MonkeyPatch, migration_database_url: str) -> None:
|
|
"""Alembic adds user_id after the predecessor revision without runtime schema creation."""
|
|
monkeypatch.setenv("DATABASE_URL", migration_database_url)
|
|
_run_alembic_upgrade("b2a3c4d5e6f7")
|
|
|
|
engine = create_engine(migration_database_url)
|
|
try:
|
|
before_columns = {column["name"] for column in inspect(engine).get_columns("task_records")}
|
|
assert "user_id" not in before_columns
|
|
|
|
_run_alembic_upgrade("c3d4e5f6a7b8")
|
|
after_columns = {column["name"] for column in inspect(engine).get_columns("task_records")}
|
|
assert "user_id" in after_columns
|
|
finally:
|
|
engine.dispose()
|
|
# #endregion Test.Alembic.TestUserIdMigrationAddsColumn
|
|
|
|
|
|
# #region _run_alembic_upgrade [C:1] [TYPE Function]
|
|
def _run_alembic_upgrade(revision: str) -> None:
|
|
"""Run a named revision against the DATABASE_URL injected for this test."""
|
|
from alembic.config import Config
|
|
|
|
from alembic import command
|
|
|
|
backend_dir = Path(__file__).parents[2]
|
|
config = Config(str(backend_dir / "alembic.ini"))
|
|
config.set_main_option("script_location", str(backend_dir / "alembic"))
|
|
config.set_main_option("sqlalchemy.url", os.environ["DATABASE_URL"])
|
|
command.upgrade(config, revision)
|
|
# #endregion _run_alembic_upgrade
|
|
|
|
|
|
# #endregion Test.Alembic.TaskRecordsUserId
|