Files
gh-christianlouis-docuelevate/tests/conftest.py
T
copilot-swe-agent[bot] 388bde2ff0 Fix SQLAlchemy model registration and database session injection in tests
- Import all models (DocumentMetadata, FileRecord, ProcessingLog) in conftest.py to register them with SQLAlchemy Base
- Override all three get_db functions used across the app (app.database, app.api.common, app.views.base) to ensure tests use the test database
- Fixes 21 of 24 failing tests (from "no such table" errors to passing)

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-07 17:54:05 +00:00

197 lines
5.1 KiB
Python

"""
Pytest configuration and shared fixtures for DocuElevate tests.
"""
import os
import tempfile
import pytest
from typing import Generator
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
# Set test environment variables before importing app
os.environ["DATABASE_URL"] = "sqlite:///:memory:"
os.environ["REDIS_URL"] = "redis://localhost:6379/1"
os.environ["OPENAI_API_KEY"] = "test-key"
os.environ["AZURE_AI_KEY"] = "test-key"
os.environ["AZURE_REGION"] = "test"
os.environ["AZURE_ENDPOINT"] = "https://test.cognitiveservices.azure.com/"
os.environ["GOTENBERG_URL"] = "http://localhost:3000"
os.environ["WORKDIR"] = "/tmp"
os.environ["AUTH_ENABLED"] = "False"
os.environ["SESSION_SECRET"] = "test_secret_key_for_testing_must_be_at_least_32_characters_long"
from app.database import Base, get_db
from app.main import app as fastapi_app
# Import models to register them with SQLAlchemy Base
from app.models import DocumentMetadata, FileRecord, ProcessingLog
@pytest.fixture(scope="session")
def test_workdir() -> Generator[str, None, None]:
"""Create a temporary work directory for tests."""
with tempfile.TemporaryDirectory() as tmpdir:
yield tmpdir
@pytest.fixture(scope="function")
def db_session():
"""Create a fresh database session for each test."""
# Create an in-memory SQLite database
engine = create_engine(
"sqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
# Create all tables
Base.metadata.create_all(bind=engine)
# Create a session
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = TestingSessionLocal()
try:
yield session
finally:
session.close()
Base.metadata.drop_all(bind=engine)
@pytest.fixture(scope="function")
def client(db_session) -> TestClient:
"""Create a test client with a fresh database."""
# Import all the different get_db functions used across the app
from app.api.common import get_db as api_get_db
from app.views.base import get_db as views_get_db
# Override the get_db dependency to use our test database
def override_get_db():
try:
yield db_session
finally:
pass
# Override all variants of get_db
fastapi_app.dependency_overrides[get_db] = override_get_db
fastapi_app.dependency_overrides[api_get_db] = override_get_db
fastapi_app.dependency_overrides[views_get_db] = override_get_db
# Use base_url to satisfy TrustedHostMiddleware
with TestClient(fastapi_app, base_url="http://localhost") as test_client:
yield test_client
# Clean up
fastapi_app.dependency_overrides.clear()
@pytest.fixture
def sample_pdf_path(test_workdir) -> str:
"""Create a sample PDF file for testing."""
pdf_path = os.path.join(test_workdir, "test.pdf")
# Create a minimal valid PDF
pdf_content = b"""%PDF-1.4
1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
>>
endobj
2 0 obj
<<
/Type /Pages
/Kids [3 0 R]
/Count 1
>>
endobj
3 0 obj
<<
/Type /Page
/Parent 2 0 R
/MediaBox [0 0 612 792]
>>
endobj
xref
0 4
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
trailer
<<
/Size 4
/Root 1 0 R
>>
startxref
197
%%EOF
"""
with open(pdf_path, 'wb') as f:
f.write(pdf_content)
return pdf_path
@pytest.fixture
def sample_text_file(test_workdir) -> str:
"""Create a sample text file for testing."""
text_path = os.path.join(test_workdir, "test.txt")
with open(text_path, 'w') as f:
f.write("This is a test document.\nWith multiple lines.\n")
return text_path
@pytest.fixture
def mock_openai_response():
"""Mock OpenAI API response for testing."""
return {
"choices": [{
"message": {
"content": '{"document_type": "invoice", "summary": "Test invoice", "tags": ["test", "invoice"]}'
}
}]
}
@pytest.fixture
def mock_azure_response():
"""Mock Azure Document Intelligence API response for testing."""
return {
"analyzeResult": {
"content": "Test document content extracted by OCR",
"pages": [{"pageNumber": 1}]
}
}
# Markers for categorizing tests
def pytest_configure(config):
"""Configure custom pytest markers."""
config.addinivalue_line(
"markers", "unit: Unit tests for individual functions/methods"
)
config.addinivalue_line(
"markers", "integration: Integration tests for API endpoints and workflows"
)
config.addinivalue_line(
"markers", "slow: Tests that take significant time to run"
)
config.addinivalue_line(
"markers", "security: Security-related tests"
)
config.addinivalue_line(
"markers", "requires_external: Tests requiring external services"
)
config.addinivalue_line(
"markers", "requires_db: Tests requiring database"
)
config.addinivalue_line(
"markers", "requires_redis: Tests requiring Redis"
)