sync: workflow CI self-contained + imagen Harbor t-<short> (ADR-061)
Workflow <app>-build.yaml self-contained — sin uses: cross-repo al repo privado coralware/IDP. requirements-dev.txt inline. image.repository apunta al proyecto Harbor dedicado del tenant t-<tenant-id-short> (ADR-019 D-03). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,32 +1,47 @@
|
||||
"""
|
||||
Fixtures para los tests del shape.
|
||||
Fixtures para los tests del shape web-backend/python.
|
||||
|
||||
Levanta una MariaDB efímera con testcontainers para que los tests corran
|
||||
contra una BD real (no mocks). El reusable workflow ADR-038 garantiza que
|
||||
Docker está disponible en el runner.
|
||||
Los tests corren contra una BD SQLite efímera en archivo temporal — el runner
|
||||
CI (executor=host, ADR-043) no tiene Docker daemon, por lo que no se usa
|
||||
testcontainers (ADR-061). El deploy real usa MariaDB (claim-mariadb.yaml + hook
|
||||
Alembic); los tests del scaffold solo ejercen /health, /demo y /metrics, sin
|
||||
tocar Alembic ni modelos de dominio. Al añadir modelos reales, agrega tests de
|
||||
integración contra tu propia infra.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from collections.abc import Iterator
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from testcontainers.mariadb import MariaDbContainer
|
||||
|
||||
# La configuración debe existir ANTES de importar app.settings: Settings() exige
|
||||
# DATABASE_URL al cargar el módulo. Se usa un archivo SQLite temporal (no
|
||||
# :memory:) para evitar problemas de hilos con el TestClient.
|
||||
_DB_FD, _DB_PATH = tempfile.mkstemp(suffix=".sqlite", prefix="webapp-test-")
|
||||
os.close(_DB_FD)
|
||||
_SQLITE_URL = f"sqlite:///{_DB_PATH}"
|
||||
os.environ.setdefault("DATABASE_URL", _SQLITE_URL)
|
||||
os.environ.setdefault("MIGRATION_DATABASE_URL", _SQLITE_URL)
|
||||
# El frontend estático /demo se sirve desde el árbol del repo durante los tests.
|
||||
_DEMO_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "app", "static", "demo"))
|
||||
os.environ.setdefault("STATIC_DEMO_PATH", _DEMO_DIR)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def mariadb_url() -> Iterator[str]:
|
||||
"""MariaDB efímera por sesión de tests; URL exportada como DATABASE_URL."""
|
||||
with MariaDbContainer("mariadb:11") as mdb:
|
||||
url = mdb.get_connection_url().replace("mysql://", "mysql+pymysql://", 1)
|
||||
os.environ["DATABASE_URL"] = url
|
||||
os.environ["MIGRATION_DATABASE_URL"] = url
|
||||
yield url
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def _cleanup_sqlite() -> Iterator[None]:
|
||||
"""Borra el archivo SQLite temporal al terminar la sesión de tests."""
|
||||
yield
|
||||
try:
|
||||
os.unlink(_DB_PATH)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(mariadb_url: str) -> Iterator[TestClient]:
|
||||
"""TestClient con la app cargada contra la BD efímera."""
|
||||
def client() -> Iterator[TestClient]:
|
||||
"""TestClient con la app cargada contra la BD SQLite efímera."""
|
||||
from app.main import create_app
|
||||
|
||||
app = create_app()
|
||||
|
||||
Reference in New Issue
Block a user