""" V2 API Test Configuration and Fixtures Provides test fixtures for authentication, database, and API testing """ import pytest from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool # IMPORTANT: Monkey patch database module BEFORE importing app # This prevents the app from connecting to production database import app.core.database as db_module # Create a test engine for the entire test session _test_engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) # Replace the global engine and SessionLocal db_module.engine = _test_engine db_module.SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=_test_engine) # Now safely import app (it will use our test database) from app.main import app from app.core.database import Base, get_db from app.core.security import create_access_token from app.models.user import User from app.models.task import Task @pytest.fixture(scope="function") def engine(): """Get test database engine and reset tables for each test""" Base.metadata.drop_all(bind=_test_engine) Base.metadata.create_all(bind=_test_engine) yield _test_engine # Tables will be dropped at the start of next test @pytest.fixture(scope="function") def db(engine): """Create test database session""" TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) db = TestingSessionLocal() try: yield db finally: db.close() @pytest.fixture(scope="function") def client(db): """Create FastAPI test client with test database""" # Override get_db to use the same session as the test def override_get_db(): try: yield db finally: # Don't close the session, it's managed by the db fixture pass app.dependency_overrides[get_db] = override_get_db with TestClient(app) as test_client: yield test_client app.dependency_overrides.clear() @pytest.fixture def test_user(db): """Create a test user""" # Ensure test_user is always created first by checking if it exists user = db.query(User).filter(User.email == "test@example.com").first() if not user: user = User( email="test@example.com", display_name="Test User", is_active=True ) db.add(user) db.commit() db.refresh(user) return user @pytest.fixture def admin_user(db): """Create an admin user""" user = db.query(User).filter(User.email == "ymirliu@panjit.com.tw").first() if not user: user = User( email="ymirliu@panjit.com.tw", display_name="Admin User", is_active=True ) db.add(user) db.commit() db.refresh(user) return user @pytest.fixture def auth_token(test_user): """Create authentication token for test user""" token_data = { "sub": str(test_user.id), "email": test_user.email } return create_access_token(token_data) @pytest.fixture def admin_token(admin_user): """Create authentication token for admin user""" token_data = { "sub": str(admin_user.id), "email": admin_user.email } return create_access_token(token_data) @pytest.fixture def test_task(test_user, db): """Create a test task (depends on test_user to ensure user exists first)""" task = Task( user_id=test_user.id, task_id="test-task-123", filename="test.pdf", file_type="application/pdf", status="pending" ) db.add(task) db.commit() db.refresh(task) return task