developed files

This commit is contained in:
2025-08-02 20:51:59 -04:00
parent c9f25ea149
commit 2d6c3bff56
24 changed files with 2660 additions and 220 deletions

View File

@@ -1,34 +1,32 @@
# Test configuration for Job Forge
"""
Updated test configuration for Job Forge that matches the actual project structure
"""
import pytest
import asyncio
import asyncpg
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from fastapi.testclient import TestClient
from httpx import AsyncClient
import os
from typing import AsyncGenerator
from unittest.mock import AsyncMock
from unittest.mock import AsyncMock, Mock
import uuid
from app.main import app
from app.core.database import get_db, Base
from app.core.security import create_access_token
from app.models.user import User
from app.models.application import Application
# Fix import paths to match actual structure
from src.backend.main import app
from src.backend.core.database import get_db, Base
from src.backend.models.user import User
from src.backend.api.auth import create_access_token, hash_password
# Test database URL
# Test database URL (use a separate test database)
TEST_DATABASE_URL = os.getenv(
"TEST_DATABASE_URL",
"postgresql+asyncpg://jobforge:jobforge123@localhost:5432/jobforge_test"
"postgresql+asyncpg://jobforge_user:jobforge_password@localhost:5432/jobforge_test"
)
# Test engine and session factory
# Test engine
test_engine = create_async_engine(TEST_DATABASE_URL, echo=False)
TestSessionLocal = sessionmaker(
test_engine, class_=AsyncSession, expire_on_commit=False
)
TestSessionLocal = sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False)
@pytest.fixture(scope="session")
def event_loop():
@@ -37,28 +35,13 @@ def event_loop():
yield loop
loop.close()
@pytest.fixture(scope="session")
async def setup_test_db():
"""Set up test database tables."""
# Create all tables
async with test_engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await conn.run_sync(Base.metadata.create_all)
# Enable RLS and create policies
await conn.execute("""
ALTER TABLE applications ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS applications_user_isolation ON applications;
CREATE POLICY applications_user_isolation ON applications
FOR ALL TO authenticated
USING (user_id = current_setting('app.current_user_id')::UUID);
-- Create vector extension if needed
CREATE EXTENSION IF NOT EXISTS vector;
""")
yield
@@ -66,22 +49,18 @@ async def setup_test_db():
async with test_engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
@pytest.fixture
async def test_db(setup_test_db) -> AsyncGenerator[AsyncSession, None]:
"""Create a test database session."""
async with TestSessionLocal() as session:
try:
yield session
finally:
await session.rollback()
@pytest.fixture
def override_get_db(test_db: AsyncSession):
"""Override the get_db dependency for testing."""
def _override_get_db():
return test_db
@@ -89,147 +68,72 @@ def override_get_db(test_db: AsyncSession):
yield
app.dependency_overrides.clear()
@pytest.fixture
def test_client(override_get_db):
"""Create a test client."""
with TestClient(app) as client:
yield client
@pytest.fixture
async def async_client(override_get_db):
"""Create an async test client."""
async with AsyncClient(app=app, base_url="http://test") as client:
yield client
@pytest.fixture
async def test_user(test_db: AsyncSession):
"""Create a test user."""
from app.crud.user import create_user
from app.schemas.user import UserCreate
user_data = UserCreate(
user = User(
email="test@jobforge.com",
password="testpassword123",
first_name="Test",
last_name="User"
password_hash=hash_password("testpassword123"),
full_name="Test User"
)
user = await create_user(test_db, user_data)
test_db.add(user)
await test_db.commit()
await test_db.refresh(user)
return user
@pytest.fixture
def test_user_token(test_user):
"""Create a JWT token for test user."""
token_data = {"sub": str(test_user.id), "email": test_user.email}
token_data = {"sub": str(test_user.id)}
return create_access_token(data=token_data)
@pytest.fixture
async def test_application(test_db: AsyncSession, test_user):
"""Create a test job application."""
from app.crud.application import create_application
from app.schemas.application import ApplicationCreate
app_data = ApplicationCreate(
company_name="Test Corp",
role_title="Software Developer",
job_description="Python developer position with FastAPI experience",
status="draft"
)
application = await create_application(test_db, app_data, test_user.id)
await test_db.commit()
return application
@pytest.fixture
def mock_claude_service():
"""Mock Claude AI service."""
mock = AsyncMock()
mock.generate_cover_letter.return_value = """
Dear Hiring Manager,
I am writing to express my strong interest in the Software Developer position at Test Corp.
With my experience in Python development and FastAPI expertise, I am confident I would be
a valuable addition to your team.
Thank you for your consideration.
Sincerely,
Test User
"""
def mock_ai_service():
"""Mock AI service for testing."""
mock = Mock()
mock.generate_cover_letter = AsyncMock(return_value={
"content": "Dear Hiring Manager,\n\nI am writing to express my interest...\n\nBest regards,\nTest User",
"model_used": "mock-ai",
"prompt": "Mock prompt for testing"
})
mock.generate_resume_optimization = AsyncMock(return_value={
"content": "Optimized Resume\n\nTest User\nSoftware Engineer\n\nExperience optimized for target role...",
"model_used": "mock-ai",
"prompt": "Mock resume optimization prompt"
})
return mock
@pytest.fixture
def mock_openai_service():
"""Mock OpenAI service."""
mock = AsyncMock()
mock.create_embedding.return_value = [0.1] * 1536 # Mock embedding vector
mock.test_connection.return_value = True
return mock
@pytest.fixture
async def multiple_test_users(test_db: AsyncSession):
"""Create multiple test users for isolation testing."""
from app.crud.user import create_user
from app.schemas.user import UserCreate
"""Create multiple test users for testing."""
users = []
for i in range(3):
user_data = UserCreate(
user = User(
email=f"user{i}@test.com",
password="password123",
first_name=f"User{i}",
last_name="Test"
password_hash=hash_password("password123"),
full_name=f"User {i} Test"
)
user = await create_user(test_db, user_data)
test_db.add(user)
users.append(user)
await test_db.commit()
for user in users:
await test_db.refresh(user)
return users
@pytest.fixture
async def applications_for_users(test_db: AsyncSession, multiple_test_users):
"""Create applications for multiple users to test isolation."""
from app.crud.application import create_application
from app.schemas.application import ApplicationCreate
all_applications = []
for i, user in enumerate(multiple_test_users):
for j in range(2): # 2 applications per user
app_data = ApplicationCreate(
company_name=f"Company{i}-{j}",
role_title=f"Role{i}-{j}",
job_description=f"Job description for user {i}, application {j}",
status="draft"
)
application = await create_application(test_db, app_data, user.id)
all_applications.append(application)
await test_db.commit()
return all_applications
# Test data factories
class TestDataFactory:
"""Factory for creating test data."""
@@ -239,87 +143,46 @@ class TestDataFactory:
"""Create user test data."""
return {
"email": email or "test@example.com",
"password": "testpassword123",
"password": "testpassword123",
"first_name": "Test",
"last_name": "User",
**kwargs
}
@staticmethod
def application_data(company_name: str = None, **kwargs):
"""Create application test data."""
def cover_letter_request(**kwargs):
"""Create cover letter request data."""
return {
"company_name": company_name or "Test Company",
"role_title": "Software Developer",
"job_description": "Python developer position",
"status": "draft",
"job_description": "We are looking for a Software Engineer with Python experience",
"company_name": "Test Company",
"role_title": "Software Engineer",
**kwargs
}
@staticmethod
def ai_response():
"""Create mock AI response."""
return """
Dear Hiring Manager,
I am excited to apply for this position. My background in software development
and passion for technology make me an ideal candidate.
Best regards,
Test User
"""
def resume_optimization_request(**kwargs):
"""Create resume optimization request data."""
return {
"current_resume": "John Doe\nSoftware Engineer\n\nExperience:\n- Python development\n- Web applications",
"job_description": "Senior Python Developer role requiring FastAPI experience",
"role_title": "Senior Python Developer",
**kwargs
}
# Database utilities for testing
# Helper functions
async def create_test_user_and_token(db: AsyncSession, email: str):
"""Helper to create a user and return auth token."""
from app.crud.user import create_user
from app.schemas.user import UserCreate
user_data = UserCreate(
user = User(
email=email,
password="password123",
first_name="Test",
last_name="User"
password_hash=hash_password("password123"),
full_name="Test User"
)
user = await create_user(db, user_data)
db.add(user)
await db.commit()
await db.refresh(user)
token_data = {"sub": str(user.id), "email": user.email}
token_data = {"sub": str(user.id)}
token = create_access_token(data=token_data)
return user, token
async def set_rls_context(db: AsyncSession, user_id: str):
"""Set RLS context for testing multi-tenancy."""
await db.execute(f"SET app.current_user_id = '{user_id}'")
# Performance testing helpers
@pytest.fixture
def benchmark_db_operations():
"""Benchmark database operations."""
import time
class BenchmarkContext:
def __init__(self):
self.start_time = None
self.end_time = None
def __enter__(self):
self.start_time = time.time()
return self
def __exit__(self, *args):
self.end_time = time.time()
@property
def duration(self):
return self.end_time - self.start_time if self.end_time else None
return BenchmarkContext
return user, token