- Added tests for OAuth provider admin and consent endpoints covering edge cases. - Extended agent-related tests to handle incorrect project associations and lifecycle state transitions. - Introduced tests for sprint status transitions and validation checks. - Improved multiline formatting consistency across all test functions.
276 lines
8.9 KiB
Python
276 lines
8.9 KiB
Python
# tests/models/syndarix/test_project.py
|
|
"""
|
|
Unit tests for the Project model.
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
import pytest
|
|
from sqlalchemy.exc import IntegrityError
|
|
|
|
from app.models.syndarix import (
|
|
AutonomyLevel,
|
|
Project,
|
|
ProjectStatus,
|
|
)
|
|
|
|
|
|
class TestProjectModel:
|
|
"""Tests for Project model creation and fields."""
|
|
|
|
def test_create_project_with_required_fields(self, db_session):
|
|
"""Test creating a project with only required fields."""
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Test Project",
|
|
slug="test-project",
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = db_session.query(Project).filter_by(slug="test-project").first()
|
|
|
|
assert retrieved is not None
|
|
assert retrieved.name == "Test Project"
|
|
assert retrieved.slug == "test-project"
|
|
assert retrieved.autonomy_level == AutonomyLevel.MILESTONE # Default
|
|
assert retrieved.status == ProjectStatus.ACTIVE # Default
|
|
assert retrieved.settings == {} # Default empty dict
|
|
assert retrieved.description is None
|
|
assert retrieved.owner_id is None
|
|
|
|
def test_create_project_with_all_fields(self, db_session):
|
|
"""Test creating a project with all optional fields."""
|
|
project_id = uuid.uuid4()
|
|
owner_id = uuid.uuid4()
|
|
|
|
project = Project(
|
|
id=project_id,
|
|
name="Full Project",
|
|
slug="full-project",
|
|
description="A complete project with all fields",
|
|
autonomy_level=AutonomyLevel.AUTONOMOUS,
|
|
status=ProjectStatus.PAUSED,
|
|
settings={"webhook_url": "https://example.com/webhook"},
|
|
owner_id=owner_id,
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = db_session.query(Project).filter_by(id=project_id).first()
|
|
|
|
assert retrieved.name == "Full Project"
|
|
assert retrieved.slug == "full-project"
|
|
assert retrieved.description == "A complete project with all fields"
|
|
assert retrieved.autonomy_level == AutonomyLevel.AUTONOMOUS
|
|
assert retrieved.status == ProjectStatus.PAUSED
|
|
assert retrieved.settings == {"webhook_url": "https://example.com/webhook"}
|
|
assert retrieved.owner_id == owner_id
|
|
|
|
def test_project_unique_slug_constraint(self, db_session):
|
|
"""Test that projects cannot have duplicate slugs."""
|
|
project1 = Project(
|
|
id=uuid.uuid4(),
|
|
name="Project One",
|
|
slug="duplicate-slug",
|
|
)
|
|
db_session.add(project1)
|
|
db_session.commit()
|
|
|
|
project2 = Project(
|
|
id=uuid.uuid4(),
|
|
name="Project Two",
|
|
slug="duplicate-slug", # Same slug
|
|
)
|
|
db_session.add(project2)
|
|
|
|
with pytest.raises(IntegrityError):
|
|
db_session.commit()
|
|
|
|
db_session.rollback()
|
|
|
|
def test_project_timestamps(self, db_session):
|
|
"""Test that timestamps are automatically set."""
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Timestamp Project",
|
|
slug="timestamp-project",
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = (
|
|
db_session.query(Project).filter_by(slug="timestamp-project").first()
|
|
)
|
|
|
|
assert isinstance(retrieved.created_at, datetime)
|
|
assert isinstance(retrieved.updated_at, datetime)
|
|
|
|
def test_project_update(self, db_session):
|
|
"""Test updating project fields."""
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Original Name",
|
|
slug="original-slug",
|
|
status=ProjectStatus.ACTIVE,
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
original_created_at = project.created_at
|
|
|
|
# Update fields
|
|
project.name = "Updated Name"
|
|
project.status = ProjectStatus.COMPLETED
|
|
project.settings = {"new_setting": "value"}
|
|
db_session.commit()
|
|
|
|
retrieved = db_session.query(Project).filter_by(slug="original-slug").first()
|
|
|
|
assert retrieved.name == "Updated Name"
|
|
assert retrieved.status == ProjectStatus.COMPLETED
|
|
assert retrieved.settings == {"new_setting": "value"}
|
|
assert retrieved.created_at == original_created_at
|
|
assert retrieved.updated_at > original_created_at
|
|
|
|
def test_project_delete(self, db_session):
|
|
"""Test deleting a project."""
|
|
project_id = uuid.uuid4()
|
|
project = Project(
|
|
id=project_id,
|
|
name="Delete Me",
|
|
slug="delete-me",
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
db_session.delete(project)
|
|
db_session.commit()
|
|
|
|
deleted = db_session.query(Project).filter_by(id=project_id).first()
|
|
assert deleted is None
|
|
|
|
def test_project_string_representation(self, db_session):
|
|
"""Test the string representation of a project."""
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Repr Project",
|
|
slug="repr-project",
|
|
status=ProjectStatus.ACTIVE,
|
|
)
|
|
|
|
assert str(project) == "<Project Repr Project (repr-project) status=active>"
|
|
assert repr(project) == "<Project Repr Project (repr-project) status=active>"
|
|
|
|
|
|
class TestProjectEnums:
|
|
"""Tests for Project enum fields."""
|
|
|
|
def test_all_autonomy_levels(self, db_session):
|
|
"""Test that all autonomy levels can be stored."""
|
|
for level in AutonomyLevel:
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name=f"Project {level.value}",
|
|
slug=f"project-{level.value}",
|
|
autonomy_level=level,
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = (
|
|
db_session.query(Project)
|
|
.filter_by(slug=f"project-{level.value}")
|
|
.first()
|
|
)
|
|
assert retrieved.autonomy_level == level
|
|
|
|
def test_all_project_statuses(self, db_session):
|
|
"""Test that all project statuses can be stored."""
|
|
for status in ProjectStatus:
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name=f"Project {status.value}",
|
|
slug=f"project-status-{status.value}",
|
|
status=status,
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = (
|
|
db_session.query(Project)
|
|
.filter_by(slug=f"project-status-{status.value}")
|
|
.first()
|
|
)
|
|
assert retrieved.status == status
|
|
|
|
|
|
class TestProjectSettings:
|
|
"""Tests for Project JSON settings field."""
|
|
|
|
def test_complex_json_settings(self, db_session):
|
|
"""Test storing complex JSON in settings."""
|
|
complex_settings = {
|
|
"mcp_servers": ["gitea", "slack", "file-system"],
|
|
"webhook_urls": {
|
|
"on_issue_created": "https://example.com/issue",
|
|
"on_sprint_completed": "https://example.com/sprint",
|
|
},
|
|
"notification_settings": {
|
|
"email": True,
|
|
"slack_channel": "#syndarix-updates",
|
|
},
|
|
"tags": ["important", "client-a"],
|
|
}
|
|
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Complex Settings Project",
|
|
slug="complex-settings",
|
|
settings=complex_settings,
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = db_session.query(Project).filter_by(slug="complex-settings").first()
|
|
|
|
assert retrieved.settings == complex_settings
|
|
assert retrieved.settings["mcp_servers"] == ["gitea", "slack", "file-system"]
|
|
assert (
|
|
retrieved.settings["webhook_urls"]["on_issue_created"]
|
|
== "https://example.com/issue"
|
|
)
|
|
assert "important" in retrieved.settings["tags"]
|
|
|
|
def test_empty_settings(self, db_session):
|
|
"""Test that empty settings defaults correctly."""
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Empty Settings",
|
|
slug="empty-settings",
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
retrieved = db_session.query(Project).filter_by(slug="empty-settings").first()
|
|
assert retrieved.settings == {}
|
|
|
|
def test_update_settings(self, db_session):
|
|
"""Test updating settings field."""
|
|
project = Project(
|
|
id=uuid.uuid4(),
|
|
name="Update Settings",
|
|
slug="update-settings",
|
|
settings={"initial": "value"},
|
|
)
|
|
db_session.add(project)
|
|
db_session.commit()
|
|
|
|
# Update settings
|
|
project.settings = {"updated": "new_value", "additional": "data"}
|
|
db_session.commit()
|
|
|
|
retrieved = db_session.query(Project).filter_by(slug="update-settings").first()
|
|
assert retrieved.settings == {"updated": "new_value", "additional": "data"}
|