Skip to main content
Glama
test_living_reports_models.py11.2 kB
"""Tests for living reports data models.""" from __future__ import annotations import uuid from datetime import UTC, datetime import pytest from igloo_mcp.living_reports.models import ( AuditEvent, IndexEntry, Insight, Outline, ReportId, Section, ) class TestReportId: """Test ReportId class.""" def test_new_creates_uuid(self) -> None: """Test creating a new ReportId generates a valid UUID.""" report_id = ReportId.new() assert isinstance(report_id.uuid, uuid.UUID) assert str(report_id) def test_from_string_valid(self) -> None: """Test creating ReportId from valid UUID string.""" test_uuid = "550e8400-e29b-41d4-a716-446655440000" report_id = ReportId(test_uuid) assert str(report_id) == test_uuid assert report_id.uuid == uuid.UUID(test_uuid) def test_from_string_invalid(self) -> None: """Test creating ReportId from invalid string raises ValueError.""" with pytest.raises(ValueError, match="Invalid UUID string"): ReportId("not-a-uuid") def test_from_uuid_object(self) -> None: """Test creating ReportId from UUID object.""" test_uuid = uuid.uuid4() report_id = ReportId(test_uuid) assert report_id.uuid == test_uuid def test_equality(self) -> None: """Test ReportId equality.""" uuid_str = "550e8400-e29b-41d4-a716-446655440000" id1 = ReportId(uuid_str) id2 = ReportId(uuid_str) id3 = ReportId.new() assert id1 == id2 assert id1 != id3 assert id1 != "not-a-report-id" class TestInsight: """Test Insight model.""" def test_valid_insight(self) -> None: """Test creating a valid insight.""" insight = Insight( insight_id="550e8400-e29b-41d4-a716-446655440000", importance=8, summary="Test insight summary", ) assert insight.insight_id == "550e8400-e29b-41d4-a716-446655440000" assert insight.importance == 8 assert insight.summary == "Test insight summary" assert insight.status == "active" assert insight.supporting_queries == [] def test_invalid_insight_id(self) -> None: """Test insight with invalid UUID raises ValueError.""" with pytest.raises(ValueError, match="insight_id must be valid UUID string"): Insight( insight_id="not-a-uuid", importance=5, summary="Test", ) def test_importance_bounds(self) -> None: """Test importance score validation.""" # Valid range Insight(insight_id=str(uuid.uuid4()), importance=0, summary="Test") Insight(insight_id=str(uuid.uuid4()), importance=10, summary="Test") # Invalid range with pytest.raises(ValueError): Insight(insight_id=str(uuid.uuid4()), importance=-1, summary="Test") with pytest.raises(ValueError): Insight(insight_id=str(uuid.uuid4()), importance=11, summary="Test") def test_status_validation(self) -> None: """Test status field validation.""" # Valid statuses Insight(insight_id=str(uuid.uuid4()), importance=5, summary="Test", status="active") Insight( insight_id=str(uuid.uuid4()), importance=5, summary="Test", status="archived", ) Insight(insight_id=str(uuid.uuid4()), importance=5, summary="Test", status="killed") # Invalid status with pytest.raises(ValueError): Insight( insight_id=str(uuid.uuid4()), importance=5, summary="Test", status="invalid", ) class TestSection: """Test Section model.""" def test_valid_section(self) -> None: """Test creating a valid section.""" section = Section( section_id="550e8400-e29b-41d4-a716-446655440000", title="Test Section", order=1, ) assert section.section_id == "550e8400-e29b-41d4-a716-446655440000" assert section.title == "Test Section" assert section.order == 1 assert section.insight_ids == [] assert section.notes is None def test_invalid_section_id(self) -> None: """Test section with invalid UUID raises ValueError.""" with pytest.raises(ValueError, match="section_id must be valid UUID string"): Section( section_id="not-a-uuid", title="Test", order=0, ) def test_order_validation(self) -> None: """Test order field validation.""" Section(section_id=str(uuid.uuid4()), title="Test", order=0) Section(section_id=str(uuid.uuid4()), title="Test", order=100) with pytest.raises(ValueError): Section(section_id=str(uuid.uuid4()), title="Test", order=-1) class TestOutline: """Test Outline model.""" def test_valid_outline(self) -> None: """Test creating a valid outline.""" now = datetime.now(UTC).isoformat() outline = Outline( report_id="550e8400-e29b-41d4-a716-446655440000", title="Test Report", created_at=now, updated_at=now, sections=[ Section( section_id=str(uuid.uuid4()), title="Section 1", order=0, ) ], insights=[ Insight( insight_id=str(uuid.uuid4()), importance=7, summary="Test insight", ) ], ) assert outline.report_id == "550e8400-e29b-41d4-a716-446655440000" assert outline.title == "Test Report" assert len(outline.sections) == 1 assert len(outline.insights) == 1 def test_invalid_report_id(self) -> None: """Test outline with invalid report ID raises ValueError.""" now = datetime.now(UTC).isoformat() with pytest.raises(ValueError, match="report_id must be valid ReportId"): Outline( report_id="not-a-uuid", title="Test", created_at=now, updated_at=now, ) def test_get_insight(self) -> None: """Test getting insight by ID.""" now = datetime.now(UTC).isoformat() insight_id = str(uuid.uuid4()) outline = Outline( report_id=str(ReportId.new()), title="Test", created_at=now, updated_at=now, insights=[ Insight( insight_id=insight_id, importance=5, summary="Test insight", ) ], ) insight = outline.get_insight(insight_id) assert insight.insight_id == insight_id with pytest.raises(ValueError, match="Insight not found"): outline.get_insight(str(uuid.uuid4())) def test_get_section(self) -> None: """Test getting section by ID.""" now = datetime.now(UTC).isoformat() section_id = str(uuid.uuid4()) outline = Outline( report_id=str(ReportId.new()), title="Test", created_at=now, updated_at=now, sections=[ Section( section_id=section_id, title="Test Section", order=0, ) ], ) section = outline.get_section(section_id) assert section.section_id == section_id with pytest.raises(ValueError, match="Section not found"): outline.get_section(str(uuid.uuid4())) class TestAuditEvent: """Test AuditEvent model.""" def test_valid_audit_event(self) -> None: """Test creating a valid audit event.""" now = datetime.now(UTC).isoformat() event = AuditEvent( action_id=str(uuid.uuid4()), report_id=str(ReportId.new()), ts=now, actor="cli", action_type="create", ) assert event.actor == "cli" assert event.action_type == "create" assert event.payload == {} def test_invalid_actor(self) -> None: """Test audit event with invalid actor raises ValueError.""" now = datetime.now(UTC).isoformat() with pytest.raises(ValueError): AuditEvent( action_id=str(uuid.uuid4()), report_id=str(ReportId.new()), ts=now, actor="invalid", action_type="create", ) def test_invalid_action_type(self) -> None: """Test audit event with invalid action type raises ValueError.""" now = datetime.now(UTC).isoformat() with pytest.raises(ValueError): AuditEvent( action_id=str(uuid.uuid4()), report_id=str(ReportId.new()), ts=now, actor="cli", action_type="invalid", ) class TestIndexEntry: """Test IndexEntry model.""" def test_valid_index_entry(self) -> None: """Test creating a valid index entry.""" now = datetime.now(UTC).isoformat() entry = IndexEntry( report_id=str(ReportId.new()), current_title="Test Report", created_at=now, updated_at=now, path="by_id/550e8400-e29b-41d4-a716-446655440000", ) assert entry.current_title == "Test Report" assert entry.status == "active" assert entry.tags == [] def test_invalid_report_id(self) -> None: """Test index entry with invalid report ID raises ValueError.""" now = datetime.now(UTC).isoformat() with pytest.raises(ValueError, match="report_id must be valid ReportId"): IndexEntry( report_id="not-a-uuid", current_title="Test", created_at=now, updated_at=now, path="test", ) def test_status_validation(self) -> None: """Test status field validation.""" now = datetime.now(UTC).isoformat() # Valid statuses IndexEntry( report_id=str(ReportId.new()), current_title="Test", created_at=now, updated_at=now, path="test", status="active", ) IndexEntry( report_id=str(ReportId.new()), current_title="Test", created_at=now, updated_at=now, path="test", status="archived", ) # Invalid status with pytest.raises(ValueError): IndexEntry( report_id=str(ReportId.new()), current_title="Test", created_at=now, updated_at=now, path="test", status="invalid", )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Evan-Kim2028/igloo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server