import sys import os import pytest from starlette.testclient import TestClient from sqlalchemy import create_engine, text from sqlalchemy.orm import sessionmaker from testcontainers.postgres import PostgresContainer import time sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # Add backend root to START of path os.environ["TESTING"] = "1" from main import app from src.models.base import Base # Import all models to ensure Base.metadata.create_all is aware of them from src.models.api_token import APIToken from src.models.activity import Activity from src.models.auth_status import AuthStatus from src.models.config import Configuration from src.models.health_metric import HealthMetric from src.models.sync_log import SyncLog from src.models.weight_record import WeightRecord from src.models.stream import ActivityStream from src.api.status import get_db @pytest.fixture(scope="session") def postgres_container(): """Spin up a Postgres container with PostGIS.""" print("DEBUG: Starting Postgres Container...") # Use postgis/postgis image postgres = PostgresContainer("postgis/postgis:15-3.4") postgres.start() print("DEBUG: Postgres Container Started.") try: yield postgres finally: postgres.stop() @pytest.fixture(scope="session") def db_engine(postgres_container): """Create a test database engine connected to the container.""" print("DEBUG: Configuring DB Engine...") # Ensure usage of psycopg2 driver db_url = postgres_container.get_connection_url().replace("postgresql://", "postgresql+psycopg2://") engine = create_engine(db_url) # Enable PostGIS extension with engine.connect() as conn: conn.execute(text("CREATE EXTENSION IF NOT EXISTS postgis")) conn.commit() # Create tables Base.metadata.create_all(bind=engine) yield engine # Teardown logic Base.metadata.drop_all(bind=engine) @pytest.fixture(scope="function") def db_session(db_engine): """Create a test database session.""" TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=db_engine) connection = db_engine.connect() transaction = connection.begin() session = TestingSessionLocal(bind=connection) yield session session.close() transaction.rollback() connection.close() @pytest.fixture(scope="function") def client(db_session): """Create a FastAPI test client.""" def override_get_db(): try: yield db_session finally: pass app.dependency_overrides[get_db] = override_get_db with TestClient(app) as c: yield c app.dependency_overrides.clear()