apac-ops-bot/backend/tests/test_models.py
SamoilenkoVadym a8151fbe66 Add comprehensive backend test suite and Phase 1 foundation
Backend Tests:
- Add pytest configuration with async support (conftest.py)
- Add model tests: User, Conversation, Message, TokenUsage, Session, UserMemory
- Add configuration tests: Settings validation and environment variables
- Add API tests: Health endpoint and future endpoint stubs
- Add database tests: Connection, transactions, query execution

Phase 1 Foundation:
- FastAPI application structure with main.py
- SQLAlchemy async models for all entities
- Alembic migrations setup
- Configuration management via Pydantic Settings
- Logging system (English only)
- Docker multi-stage builds for backend
- Docker Compose orchestration (PostgreSQL, Redis, backend)
- Frontend React + TypeScript structure
- Dark & Gold theme CSS implementation
- Environment configuration examples

All code and comments in English as per requirements.
Tests cover model relationships, cascade deletes, and constraints.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-27 14:24:59 +00:00

253 lines
6.8 KiB
Python

"""
Tests for SQLAlchemy models
Tests model creation, relationships, and constraints
"""
import pytest
from datetime import datetime
from sqlalchemy import select
from app.models.user import User
from app.models.conversation import Conversation
from app.models.message import Message
from app.models.token_usage import TokenUsage
from app.models.session import Session
from app.models.user_memory import UserMemory
@pytest.mark.asyncio
async def test_create_user(db_session):
"""Test creating a user"""
user = User(
azure_ad_id="test-azure-id-123",
email="test@example.com",
display_name="Test User",
given_name="Test",
surname="User",
role="user",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
assert user.id is not None
assert user.email == "test@example.com"
assert user.azure_ad_id == "test-azure-id-123"
assert user.is_active is True
assert user.role == "user"
assert isinstance(user.created_at, datetime)
@pytest.mark.asyncio
async def test_user_conversation_relationship(db_session):
"""Test user-conversation relationship"""
# Create user
user = User(
azure_ad_id="test-azure-id-456",
email="user@example.com",
display_name="User Test",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
# Create conversation
conversation = Conversation(
user_id=user.id,
title="Test Conversation",
)
db_session.add(conversation)
await db_session.commit()
await db_session.refresh(conversation)
# Verify relationship
assert conversation.user_id == user.id
assert conversation.title == "Test Conversation"
assert isinstance(conversation.created_at, datetime)
@pytest.mark.asyncio
async def test_conversation_message_relationship(db_session):
"""Test conversation-message relationship"""
# Create user and conversation
user = User(
azure_ad_id="test-azure-id-789",
email="messages@example.com",
display_name="Message User",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
conversation = Conversation(user_id=user.id, title="Message Test")
db_session.add(conversation)
await db_session.commit()
await db_session.refresh(conversation)
# Create messages
user_message = Message(
conversation_id=conversation.id,
role="user",
content="Hello, bot!",
token_count=3,
)
assistant_message = Message(
conversation_id=conversation.id,
role="assistant",
content="Hello! How can I help you?",
token_count=7,
)
db_session.add_all([user_message, assistant_message])
await db_session.commit()
# Fetch conversation with messages
result = await db_session.execute(
select(Conversation).where(Conversation.id == conversation.id)
)
conv = result.scalar_one()
assert len(conv.messages) == 2
assert conv.messages[0].role == "user"
assert conv.messages[1].role == "assistant"
@pytest.mark.asyncio
async def test_token_usage_tracking(db_session):
"""Test token usage model"""
user = User(
azure_ad_id="test-token-user",
email="token@example.com",
display_name="Token User",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
# Create token usage record
token_usage = TokenUsage(
user_id=user.id,
prompt_tokens=100,
completion_tokens=50,
total_tokens=150,
model="gpt-5-nano-2025-08-07",
cost_usd=0.015,
operation_type="chat",
)
db_session.add(token_usage)
await db_session.commit()
await db_session.refresh(token_usage)
assert token_usage.prompt_tokens == 100
assert token_usage.completion_tokens == 50
assert token_usage.total_tokens == 150
assert token_usage.model == "gpt-5-nano-2025-08-07"
assert float(token_usage.cost_usd) == 0.015
@pytest.mark.asyncio
async def test_user_memory(db_session):
"""Test user memory model"""
user = User(
azure_ad_id="test-memory-user",
email="memory@example.com",
display_name="Memory User",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
# Create memory
memory = UserMemory(
user_id=user.id,
memory_key="office_location",
memory_value="Sydney office",
importance_score=0.8,
)
db_session.add(memory)
await db_session.commit()
await db_session.refresh(memory)
assert memory.memory_key == "office_location"
assert memory.memory_value == "Sydney office"
assert float(memory.importance_score) == 0.8
@pytest.mark.asyncio
async def test_session_creation(db_session):
"""Test session model"""
user = User(
azure_ad_id="test-session-user",
email="session@example.com",
display_name="Session User",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
# Create session
from datetime import timedelta
session = Session(
user_id=user.id,
access_token_hash="hashed_token_123",
expires_at=datetime.utcnow() + timedelta(hours=1),
ip_address="127.0.0.1",
user_agent="Test Agent",
)
db_session.add(session)
await db_session.commit()
await db_session.refresh(session)
assert session.user_id == user.id
assert session.access_token_hash == "hashed_token_123"
assert session.is_active is True
assert session.ip_address == "127.0.0.1"
@pytest.mark.asyncio
async def test_cascade_delete(db_session):
"""Test cascade delete functionality"""
# Create user with conversation and messages
user = User(
azure_ad_id="test-cascade-user",
email="cascade@example.com",
display_name="Cascade User",
)
db_session.add(user)
await db_session.commit()
await db_session.refresh(user)
conversation = Conversation(user_id=user.id, title="Cascade Test")
db_session.add(conversation)
await db_session.commit()
await db_session.refresh(conversation)
message = Message(
conversation_id=conversation.id,
role="user",
content="Test message",
)
db_session.add(message)
await db_session.commit()
# Delete user - should cascade
await db_session.delete(user)
await db_session.commit()
# Verify conversation is deleted
result = await db_session.execute(
select(Conversation).where(Conversation.id == conversation.id)
)
assert result.scalar_one_or_none() is None
# Verify message is deleted
result = await db_session.execute(
select(Message).where(Message.id == message.id)
)
assert result.scalar_one_or_none() is None