import os from datetime import UTC, datetime, timedelta from uuid import uuid4 # Must be set before importing db (which calls create_engine at module level) os.environ.setdefault("DATABASE_URL", "sqlite://") import pytest from fastapi.testclient import TestClient from sqlmodel import Session, SQLModel, create_engine from sqlmodel.pool import StaticPool import db as db_module from db import get_session from innercontext.api.auth_deps import get_current_user from innercontext.auth import CurrentUser, IdentityData, TokenClaims from innercontext.models import Role from main import app @pytest.fixture() def session(monkeypatch): """Per-test fresh SQLite in-memory database with full isolation.""" engine = create_engine( "sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) # Patch before TestClient triggers lifespan (which calls create_db_and_tables) monkeypatch.setattr(db_module, "engine", engine) import innercontext.models # noqa: F401 — populate SQLModel.metadata SQLModel.metadata.create_all(engine) with Session(engine) as s: yield s # monkeypatch auto-restores db_module.engine after test @pytest.fixture() def current_user() -> CurrentUser: claims = TokenClaims( issuer="https://auth.test", subject="test-user", audience=("innercontext-web",), expires_at=datetime.now(UTC) + timedelta(hours=1), groups=("innercontext-admin",), raw_claims={"iss": "https://auth.test", "sub": "test-user"}, ) return CurrentUser( user_id=uuid4(), role=Role.ADMIN, identity=IdentityData.from_claims(claims), claims=claims, ) @pytest.fixture() def client(session, monkeypatch, current_user): """TestClient using the per-test session for every request.""" def _override(): yield session def _current_user_override(): return current_user app.dependency_overrides[get_session] = _override app.dependency_overrides[get_current_user] = _current_user_override with TestClient(app) as c: yield c app.dependency_overrides.clear() # ---- Shared data fixtures ---- @pytest.fixture() def product_data(): return { "name": "CeraVe Moisturising Cream", "brand": "CeraVe", "category": "moisturizer", "recommended_time": "both", "leave_on": True, } @pytest.fixture() def created_product(client, product_data): r = client.post("/products", json=product_data) assert r.status_code == 201 return r.json() @pytest.fixture() def medication_data(): return {"kind": "prescription", "product_name": "Epiduo"} @pytest.fixture() def created_medication(client, medication_data): r = client.post("/health/medications", json=medication_data) assert r.status_code == 201 return r.json() @pytest.fixture() def created_routine(client): r = client.post( "/routines", json={"routine_date": "2026-02-26", "part_of_day": "am"} ) assert r.status_code == 201 return r.json()