todo-backend / Chatbot /tests /integration /test_add_task_integration.py
Fizu123's picture
BACKEND FIX: Filter by credential provider during login
08af9fd
"""
Integration test for add_task tool to verify user association and data isolation.
"""
import pytest
import asyncio
from sqlmodel import Session, create_engine, select
from backend.models.task import Task
from backend.mcp_server.tools.add_task import add_task
@pytest.fixture
def test_engine():
"""Create a test database engine."""
engine = create_engine("sqlite:///:memory:", echo=False)
return engine
@pytest.fixture
def session(test_engine):
"""Create a test database session."""
from sqlmodel import SQLModel
SQLModel.metadata.create_all(test_engine)
with Session(test_engine) as session:
yield session
SQLModel.metadata.drop_all(test_engine)
def test_task_created_with_correct_user_association(session, test_engine):
"""Test that a task is created with the correct user_id association."""
# Mock the database engine to use test engine
from unittest.mock import patch
with patch('backend.mcp_server.tools.add_task.get_engine', return_value=test_engine):
result = add_task(
user_id="user_abc123",
title="Buy groceries",
description="Milk, eggs, bread"
)
# Verify success response
assert result["success"] is True
assert result["data"]["task_id"] is not None
assert result["data"]["status"] == "created"
assert result["data"]["title"] == "Buy groceries"
# Verify task in database with correct user association
task = session.get(Task, result["data"]["task_id"])
assert task is not None
assert task.user_id == "user_abc123"
assert task.title == "Buy groceries"
assert task.description == "Milk, eggs, bread"
assert task.completed is False
def test_data_isolation_different_users(session, test_engine):
"""Test that users can only access their own tasks (data isolation)."""
from unittest.mock import patch
# User 1 creates a task
with patch('backend.mcp_server.tools.add_task.get_engine', return_value=test_engine):
user1_result = add_task(
user_id="user_abc123",
title="User 1 Task",
description="Only for user 1"
)
user2_result = add_task(
user_id="user_xyz456",
title="User 2 Task",
description="Only for user 2"
)
# Verify both tasks created
assert user1_result["success"] is True
assert user2_result["success"] is True
# Query tasks for each user
user1_tasks = session.exec(select(Task).where(Task.user_id == "user_abc123")).all()
user2_tasks = session.exec(select(Task).where(Task.user_id == "user_xyz456")).all()
# Verify isolation
assert len(user1_tasks) == 1
assert len(user2_tasks) == 1
assert user1_tasks[0].title == "User 1 Task"
assert user2_tasks[0].title == "User 2 Task"
# Verify user1 cannot see user2's tasks
assert len([t for t in user1_tasks if t.title == "User 2 Task"]) == 0
def test_task_creation_persists_across_sessions(session, test_engine):
"""Test that a created task persists across different database sessions."""
from unittest.mock import patch
# Create task in session 1
with patch('backend.mcp_server.tools.add_task.get_engine', return_value=test_engine):
result = add_task(
user_id="user_abc123",
title="Persistent Task",
description="Should survive session close"
)
task_id = result["data"]["task_id"]
# Close and create new session to simulate server restart
session.close()
with Session(test_engine) as new_session:
# Verify task still exists
task = new_session.get(Task, task_id)
assert task is not None
assert task.title == "Persistent Task"
assert task.user_id == "user_abc123"
def test_multiple_tasks_same_user(session, test_engine):
"""Test creating multiple tasks for the same user."""
from unittest.mock import patch
task_ids = []
with patch('backend.mcp_server.tools.add_task.get_engine', return_value=test_engine):
# Create 3 tasks for same user
for i in range(3):
result = add_task(
user_id="user_abc123",
title=f"Task {i+1}",
description=f"Description {i+1}"
)
task_ids.append(result["data"]["task_id"])
# Verify all tasks exist and are associated with user
tasks = session.exec(select(Task).where(Task.user_id == "user_abc123")).all()
assert len(tasks) == 3
# Verify task details
for i, task in enumerate(tasks):
assert task.title == f"Task {i+1}"
assert task.description == f"Description {i+1}"
assert task.completed is False
def test_task_without_description(session, test_engine):
"""Test that tasks can be created without optional description."""
from unittest.mock import patch
with patch('backend.mcp_server.tools.add_task.get_engine', return_value=test_engine):
result = add_task(
user_id="user_abc123",
title="No Description Task"
)
assert result["success"] is True
# Verify task in database
task = session.get(Task, result["data"]["task_id"])
assert task is not None
assert task.title == "No Description Task"
assert task.description is None
def test_task_user_id_cannot_be_modified(session, test_engine):
"""Test that user_id is correctly set and isolated."""
from unittest.mock import patch
with patch('backend.mcp_server.tools.add_task.get_engine', return_value=test_engine):
result = add_task(
user_id="user_abc123",
title="User Specific Task"
)
# Verify task has correct user_id
task = session.get(Task, result["data"]["task_id"])
assert task is not None
assert task.user_id == "user_abc123"
# Try to update user_id directly in database (shouldn't happen in production)
task.user_id = "another_user"
session.add(task)
session.commit()
# Verify we can distinguish tasks by user_id
user_tasks = session.exec(select(Task).where(Task.user_id == "user_abc123")).all()
other_user_tasks = session.exec(select(Task).where(Task.user_id == "another_user")).all()
# This demonstrates the importance of filtering by user_id in all queries
assert len(other_user_tasks) == 1