Skip to main content
Glama
test_metadata_schema.py18.3 kB
""" Comprehensive tests for todo metadata schema validation. Tests the standardized metadata schema for: - Schema validation works correctly - Backward compatibility is maintained - Error handling for invalid data - Edge cases and boundary conditions """ import pytest import time from uuid import uuid4 from typing import Dict, Any from pydantic import ValidationError # Import the schemas we're testing from src.Omnispindle.schemas.todo_metadata_schema import ( TodoMetadata, TodoSchema, TodoCreateRequest, TodoUpdateRequest, PriorityLevel, StatusLevel, ComplexityLevel, validate_todo_metadata, validate_todo ) class TestTodoMetadata: """Test TodoMetadata schema validation.""" def test_minimal_valid_metadata(self): """Test minimal valid metadata (all fields optional).""" metadata = TodoMetadata() assert metadata is not None assert metadata.files is None assert metadata.custom is None def test_full_valid_metadata(self): """Test metadata with all fields populated.""" metadata_data = { "files": ["src/test.py", "docs/readme.md"], "components": ["UserComponent", "AuthComponent"], "commit_hash": "abc123def456", "branch": "feature/test-branch", "phase": "implementation", "epic": "user-management", "tags": ["bug", "high-priority", "backend"], "current_state": "needs_testing", "target_state": "fully_tested", "blockers": ["uuid-1", "uuid-2"], "deliverables": ["test_file.py", "documentation.md"], "acceptance_criteria": [ "All unit tests pass", "Code coverage > 90%", "Documentation updated" ], "complexity": "High", "confidence": 4, "custom": {"team": "backend", "reviewer": "john@example.com"}, "completed_by": "test@example.com", "completion_comment": "Completed with minor issues resolved" } metadata = TodoMetadata(**metadata_data) # Verify all fields are set correctly assert metadata.files == ["src/test.py", "docs/readme.md"] assert metadata.components == ["UserComponent", "AuthComponent"] assert metadata.commit_hash == "abc123def456" assert metadata.branch == "feature/test-branch" assert metadata.phase == "implementation" assert metadata.epic == "user-management" assert metadata.tags == ["bug", "high-priority", "backend"] assert metadata.current_state == "needs_testing" assert metadata.target_state == "fully_tested" assert metadata.blockers == ["uuid-1", "uuid-2"] assert metadata.deliverables == ["test_file.py", "documentation.md"] assert metadata.acceptance_criteria == [ "All unit tests pass", "Code coverage > 90%", "Documentation updated" ] assert metadata.complexity == ComplexityLevel.HIGH assert metadata.confidence == 4 assert metadata.custom == {"team": "backend", "reviewer": "john@example.com"} assert metadata.completed_by == "test@example.com" assert metadata.completion_comment == "Completed with minor issues resolved" def test_array_validation_removes_empty_strings(self): """Test that array validators remove empty strings.""" metadata = TodoMetadata( files=["valid_file.py", "", " ", "another_file.py"], tags=["valid-tag", "", " \t ", "another-tag"], deliverables=["", "valid_deliverable.md", " "], acceptance_criteria=["Valid criteria", "", " ", "Another criteria"] ) # Empty strings should be filtered out assert metadata.files == ["valid_file.py", "another_file.py"] assert metadata.tags == ["valid-tag", "another-tag"] assert metadata.deliverables == ["valid_deliverable.md"] assert metadata.acceptance_criteria == ["Valid criteria", "Another criteria"] def test_confidence_validation_valid_range(self): """Test confidence validation for valid values (1-5).""" for confidence in [1, 2, 3, 4, 5]: metadata = TodoMetadata(confidence=confidence) assert metadata.confidence == confidence def test_confidence_validation_invalid_range(self): """Test confidence validation rejects invalid values.""" with pytest.raises(ValidationError, match="Input should be greater than or equal to 1"): TodoMetadata(confidence=0) with pytest.raises(ValidationError, match="Input should be less than or equal to 5"): TodoMetadata(confidence=6) with pytest.raises(ValidationError, match="Input should be greater than or equal to 1"): TodoMetadata(confidence=-1) def test_complexity_enum_validation(self): """Test complexity enum validation.""" valid_complexities = ["Low", "Medium", "High", "Complex"] for complexity in valid_complexities: metadata = TodoMetadata(complexity=complexity) assert metadata.complexity == ComplexityLevel(complexity) # Test invalid complexity with pytest.raises(ValidationError): TodoMetadata(complexity="Invalid") class TestTodoSchema: """Test TodoSchema validation.""" def test_minimal_valid_todo(self): """Test minimal valid todo with required fields only.""" todo_data = { "id": str(uuid4()), "description": "Test todo", "project": "test-project", "created_at": int(time.time()) } todo = TodoSchema(**todo_data) assert todo.id == todo_data["id"] assert todo.description == "Test todo" assert todo.project == "test-project" assert todo.priority == PriorityLevel.MEDIUM # default assert todo.status == StatusLevel.PENDING # default assert todo.target_agent == "user" # default assert todo.created_at == todo_data["created_at"] assert todo.metadata is not None # default_factory=dict def test_full_valid_todo(self): """Test todo with all fields populated.""" created_time = int(time.time()) completed_time = created_time + 3600 metadata = TodoMetadata( files=["test.py"], tags=["testing"], complexity="High", confidence=5 ) todo_data = { "id": str(uuid4()), "description": "Complete integration test", "project": "omnispindle", "priority": "High", "status": "completed", "target_agent": "claude", "created_at": created_time, "updated_at": completed_time, "completed_at": completed_time, "completed_by": "test@example.com", "completion_comment": "All tests passed", "duration_sec": 3600, "metadata": metadata } todo = TodoSchema(**todo_data) assert todo.id == todo_data["id"] assert todo.description == "Complete integration test" assert todo.project == "omnispindle" assert todo.priority == PriorityLevel.HIGH assert todo.status == StatusLevel.COMPLETED assert todo.target_agent == "claude" assert todo.created_at == created_time assert todo.updated_at == completed_time assert todo.completed_at == completed_time assert todo.completed_by == "test@example.com" assert todo.completion_comment == "All tests passed" assert todo.duration_sec == 3600 assert todo.metadata == metadata def test_description_validation(self): """Test description validation.""" base_todo = { "id": str(uuid4()), "project": "test-project", "created_at": int(time.time()) } # Empty description should fail with pytest.raises(ValidationError, match="description cannot be empty"): TodoSchema(**{**base_todo, "description": ""}) with pytest.raises(ValidationError, match="description cannot be empty"): TodoSchema(**{**base_todo, "description": " "}) # Valid description should work todo = TodoSchema(**{**base_todo, "description": " Valid description "}) assert todo.description == "Valid description" # stripped def test_project_validation(self): """Test project validation and normalization.""" base_todo = { "id": str(uuid4()), "description": "Test todo", "created_at": int(time.time()) } # Empty project should fail with pytest.raises(ValidationError, match="project cannot be empty"): TodoSchema(**{**base_todo, "project": ""}) with pytest.raises(ValidationError, match="project cannot be empty"): TodoSchema(**{**base_todo, "project": " "}) # Project should be normalized to lowercase todo = TodoSchema(**{**base_todo, "project": " TEST-PROJECT "}) assert todo.project == "test-project" def test_enum_validation(self): """Test enum field validation.""" base_todo = { "id": str(uuid4()), "description": "Test todo", "project": "test-project", "created_at": int(time.time()) } # Valid priority values valid_priorities = ["Critical", "High", "Medium", "Low"] for priority in valid_priorities: todo = TodoSchema(**{**base_todo, "priority": priority}) assert todo.priority == PriorityLevel(priority) # Invalid priority should fail with pytest.raises(ValidationError): TodoSchema(**{**base_todo, "priority": "Invalid"}) # Valid status values valid_statuses = ["pending", "in_progress", "completed", "blocked"] for status in valid_statuses: todo = TodoSchema(**{**base_todo, "status": status}) assert todo.status == StatusLevel(status) # Invalid status should fail with pytest.raises(ValidationError): TodoSchema(**{**base_todo, "status": "invalid"}) class TestTodoCreateRequest: """Test TodoCreateRequest schema.""" def test_minimal_create_request(self): """Test minimal create request.""" request = TodoCreateRequest( description="New todo", project="test-project" ) assert request.description == "New todo" assert request.project == "test-project" assert request.priority == PriorityLevel.MEDIUM # default assert request.target_agent == "user" # default assert request.metadata is None # default def test_full_create_request(self): """Test create request with all fields.""" metadata = TodoMetadata(tags=["feature"], complexity="Medium") request = TodoCreateRequest( description="Complex todo", project="omnispindle", priority="High", target_agent="claude", metadata=metadata ) assert request.description == "Complex todo" assert request.project == "omnispindle" assert request.priority == PriorityLevel.HIGH assert request.target_agent == "claude" assert request.metadata == metadata class TestTodoUpdateRequest: """Test TodoUpdateRequest schema.""" def test_empty_update_request(self): """Test update request with no fields (all optional).""" request = TodoUpdateRequest() assert request.description is None assert request.project is None assert request.priority is None assert request.status is None assert request.target_agent is None assert request.metadata is None def test_partial_update_request(self): """Test update request with some fields.""" metadata = TodoMetadata(files=["updated.py"]) request = TodoUpdateRequest( description="Updated description", status="completed", metadata=metadata, completion_comment="Done!" ) assert request.description == "Updated description" assert request.project is None # not updated assert request.status == StatusLevel.COMPLETED assert request.metadata == metadata assert request.completion_comment == "Done!" class TestValidationFunctions: """Test standalone validation functions.""" def test_validate_todo_metadata_function(self): """Test validate_todo_metadata function.""" # Valid metadata metadata_dict = { "files": ["test.py"], "tags": ["testing"], "complexity": "Medium", "confidence": 3 } metadata = validate_todo_metadata(metadata_dict) assert isinstance(metadata, TodoMetadata) assert metadata.files == ["test.py"] assert metadata.tags == ["testing"] assert metadata.complexity == ComplexityLevel.MEDIUM assert metadata.confidence == 3 # Invalid metadata should raise ValidationError with pytest.raises(ValidationError): validate_todo_metadata({"confidence": 10}) # invalid range def test_validate_todo_function(self): """Test validate_todo function.""" # Valid todo todo_dict = { "id": str(uuid4()), "description": "Test todo", "project": "test-project", "created_at": int(time.time()), "metadata": { "tags": ["testing"], "complexity": "Low" } } todo = validate_todo(todo_dict) assert isinstance(todo, TodoSchema) assert todo.description == "Test todo" assert todo.project == "test-project" assert isinstance(todo.metadata, TodoMetadata) # Invalid todo should raise ValidationError with pytest.raises(ValidationError): validate_todo({"id": str(uuid4())}) # missing required fields class TestBackwardCompatibility: """Test backward compatibility with legacy metadata formats.""" def test_legacy_metadata_fields(self): """Test that legacy fields are still supported.""" metadata = TodoMetadata( completed_by="legacy@example.com", completion_comment="Legacy completion" ) assert metadata.completed_by == "legacy@example.com" assert metadata.completion_comment == "Legacy completion" def test_mixed_legacy_and_new_fields(self): """Test mixing legacy and new metadata fields.""" metadata = TodoMetadata( # New standardized fields files=["new_file.py"], tags=["new-feature"], complexity="High", confidence=4, # Legacy fields completed_by="user@example.com", completion_comment="Mixed metadata test" ) assert metadata.files == ["new_file.py"] assert metadata.tags == ["new-feature"] assert metadata.complexity == ComplexityLevel.HIGH assert metadata.confidence == 4 assert metadata.completed_by == "user@example.com" assert metadata.completion_comment == "Mixed metadata test" def test_custom_fields_preserve_arbitrary_data(self): """Test that custom fields preserve arbitrary legacy data.""" custom_data = { "legacy_field": "some_value", "nested_legacy": { "sub_field": "sub_value", "numbers": [1, 2, 3] }, "random_metadata": True } metadata = TodoMetadata(custom=custom_data) assert metadata.custom == custom_data class TestEdgeCases: """Test edge cases and boundary conditions.""" def test_maximum_description_length(self): """Test description length validation.""" # Exactly 500 characters should work long_description = "a" * 500 todo = TodoSchema( id=str(uuid4()), description=long_description, project="test", created_at=int(time.time()) ) assert len(todo.description) == 500 # 501 characters should fail with pytest.raises(ValidationError): TodoSchema( id=str(uuid4()), description="a" * 501, project="test", created_at=int(time.time()) ) def test_unicode_support(self): """Test Unicode support in text fields.""" unicode_description = "测试 Unicode 支持 🚀 émojis and special chars" todo = TodoSchema( id=str(uuid4()), description=unicode_description, project="unicode-test", created_at=int(time.time()) ) assert todo.description == unicode_description assert todo.project == "unicode-test" def test_very_large_metadata(self): """Test handling of large metadata objects.""" large_files_list = [f"file_{i}.py" for i in range(100)] large_tags_list = [f"tag_{i}" for i in range(50)] large_criteria_list = [f"Criterion {i} must be satisfied" for i in range(20)] metadata = TodoMetadata( files=large_files_list, tags=large_tags_list, acceptance_criteria=large_criteria_list ) assert len(metadata.files) == 100 assert len(metadata.tags) == 50 assert len(metadata.acceptance_criteria) == 20 def test_none_vs_empty_arrays(self): """Test distinction between None and empty arrays.""" # None should remain None metadata_none = TodoMetadata(files=None, tags=None) assert metadata_none.files is None assert metadata_none.tags is None # Empty arrays should remain empty arrays metadata_empty = TodoMetadata(files=[], tags=[]) assert metadata_empty.files == [] assert metadata_empty.tags == [] if __name__ == "__main__": pytest.main([__file__, "-v"])

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/MadnessEngineering/fastmcp-todo-server'

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