"""Unit tests for event schemas.""" import pytest from pydantic import ValidationError from src.schemas import ( AdjustmentFileInitializeEvent, AdjustmentFileInitializeEventDetail, ) class TestOutboxEventDetail: """Tests for OutboxEventDetail schema.""" def test_valid_event_detail_with_all_fields(self): """Test OutboxEventDetail with all fields.""" detail = AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': 123, 'correlation_id': 'corr-456', }, data={'upload_type': 'adjustments'}, ) assert detail.metadata.target_type == 'file_upload' assert detail.metadata.target_id == 123 assert detail.metadata.correlation_id == 'corr-456' def test_valid_event_detail_without_correlation_id(self): """Test OutboxEventDetail without optional correlation_id.""" detail = AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': 789, 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) assert detail.metadata.target_type == 'file_upload' assert detail.metadata.target_id == 789 assert detail.metadata.correlation_id is None def test_missing_required_field_raises_error(self): """Test missing required fields raise ValidationError.""" with pytest.raises(ValidationError) as exc_info: AdjustmentFileInitializeEventDetail( metadata={ 'target_id': 123, 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) assert 'target_type' in str(exc_info.value) def test_invalid_target_id_type_raises_error(self): """Test invalid target_id type raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': 'not-an-int', 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) errors = exc_info.value.errors() assert any('target_id' in str(error) for error in errors) def test_outbox_detail_with_large_target_id(self): """Test OutboxEventDetail with maximum integer target_id.""" # Test with maximum 32-bit signed integer large_id = 2147483647 detail = AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': large_id, 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) assert detail.metadata.target_id == large_id def test_outbox_detail_with_negative_target_id(self): """Test OutboxEventDetail rejects negative target_id.""" # Negative IDs should be invalid for target_id # Pydantic may coerce this depending on schema, or reject it # This test documents the expected behavior try: detail = AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': -1, 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) # If it allows negative, ensure it's stored correctly assert detail.metadata.target_id == -1 except ValidationError: # If validation rejects negative IDs, that's also acceptable pass def test_outbox_detail_with_special_characters(self): """Test OutboxEventDetail with special characters in correlation_id.""" special_chars_id = 'corr-123_abc-def.xyz/test@domain:8080#section?query=value' detail = AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': 123, 'correlation_id': special_chars_id, 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) assert detail.metadata.correlation_id == special_chars_id def test_outbox_detail_with_unicode_correlation_id(self): """Test OutboxEventDetail with Unicode characters in correlation_id.""" unicode_id = 'corr-测试-🔥-éàü' detail = AdjustmentFileInitializeEventDetail( metadata={ 'target_type': 'file_upload', 'target_id': 123, 'correlation_id': unicode_id, 'outbox_event_id': 1, }, data={'upload_type': 'adjustments'}, ) assert detail.metadata.correlation_id == unicode_id class TestAdjustmentFileInitializeEvent: """Tests for AdjustmentFileInitializeEvent schema.""" def test_valid_event_with_all_fields(self): """Test valid event with all fields.""" event = AdjustmentFileInitializeEvent( detail_type='file_upload.completed', detail={ 'metadata': { 'target_type': 'file_upload', 'target_id': 123, 'correlation_id': 'corr-789', 'outbox_event_id': 1, }, 'data': {'upload_type': 'adjustments'}, }, ) assert event.detail_type == 'file_upload.completed' assert event.detail.metadata.target_type == 'file_upload' assert event.detail.metadata.target_id == 123 assert event.detail.metadata.correlation_id == 'corr-789' def test_valid_event_with_dict_detail(self): """Test event accepts detail as dict.""" event = AdjustmentFileInitializeEvent( detail_type='file_upload.completed', detail={ 'metadata': { 'target_type': 'file_upload', 'target_id': 456, 'correlation_id': 'corr-abc', 'outbox_event_id': 1, }, 'data': {'upload_type': 'adjustments'}, }, ) assert event.detail.metadata.target_type == 'file_upload' assert event.detail.metadata.target_id == 456 def test_event_ignores_extra_fields(self): """Test event ignores extra fields (extra='ignore').""" event = AdjustmentFileInitializeEvent( detail_type='file_upload.completed', detail={ 'metadata': { 'target_type': 'file_upload', 'target_id': 123, 'outbox_event_id': 1, }, 'data': {'upload_type': 'adjustments'}, }, extra_field='should_be_ignored', another_field=999, ) assert event.detail.metadata.target_type == 'file_upload' # Extra fields are ignored, not stored assert not hasattr(event, 'extra_field') def test_missing_detail_raises_error(self): """Test missing detail field raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: AdjustmentFileInitializeEvent() assert 'detail' in str(exc_info.value) def test_invalid_detail_type_raises_error(self): """Test invalid detail type raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: AdjustmentFileInitializeEvent(detail='not-a-dict') errors = exc_info.value.errors() assert any('detail' in str(error) for error in errors) def test_event_with_nested_validation_error(self): """Test event with invalid nested detail raises ValidationError.""" with pytest.raises(ValidationError) as exc_info: AdjustmentFileInitializeEvent( # Missing detail_type detail={ 'metadata': { 'target_type': 'file_upload', # Missing target_id } } ) errors = exc_info.value.errors() assert any('target_id' in str(error) for error in errors) assert any('detail-type' in str(error) for error in errors)