Spaces:
Sleeping
Sleeping
| # Tests for error handler module | |
| import pytest | |
| from unittest.mock import Mock, patch | |
| from src.integration.error_handler import ( | |
| ErrorHandler, | |
| ErrorType, | |
| ErrorContext, | |
| get_error_handler, | |
| reset_error_handler, | |
| handle_error, | |
| ) | |
| class TestErrorType: | |
| """Tests for ErrorType enum.""" | |
| def test_error_type_values(self): | |
| """Test error type enum values.""" | |
| assert ErrorType.DATABASE_CONNECTION.value == "database_connection" | |
| assert ErrorType.DATABASE_QUERY.value == "database_query" | |
| assert ErrorType.SQL_VALIDATION.value == "sql_validation" | |
| assert ErrorType.SQL_INJECTION.value == "sql_injection" | |
| assert ErrorType.DOCUMENT_RETRIEVAL.value == "document_retrieval" | |
| assert ErrorType.LLM_GENERATION.value == "llm_generation" | |
| assert ErrorType.TIMEOUT.value == "timeout" | |
| assert ErrorType.UNKNOWN.value == "unknown" | |
| def test_error_type_membership(self): | |
| """Test all expected error types exist.""" | |
| types = [t.value for t in ErrorType] | |
| assert "database_connection" in types | |
| assert "sql_injection" in types | |
| assert "timeout" in types | |
| assert "unknown" in types | |
| class TestErrorContext: | |
| """Tests for ErrorContext dataclass.""" | |
| def test_error_context_creation(self): | |
| """Test basic error context creation.""" | |
| context = ErrorContext( | |
| error_type=ErrorType.DATABASE_QUERY, | |
| message="Query failed", | |
| ) | |
| assert context.error_type == ErrorType.DATABASE_QUERY | |
| assert context.message == "Query failed" | |
| assert context.original_error is None | |
| assert context.query is None | |
| def test_error_context_with_all_fields(self): | |
| """Test error context with all fields.""" | |
| original = ValueError("test error") | |
| context = ErrorContext( | |
| error_type=ErrorType.SQL_VALIDATION, | |
| message="Validation failed", | |
| original_error=original, | |
| query="SELECT * FROM table", | |
| additional_info={"key": "value"}, | |
| ) | |
| assert context.original_error == original | |
| assert context.query == "SELECT * FROM table" | |
| assert context.additional_info["key"] == "value" | |
| def test_error_context_to_dict(self): | |
| """Test conversion to dictionary.""" | |
| original = ValueError("test") | |
| context = ErrorContext( | |
| error_type=ErrorType.TIMEOUT, | |
| message="Timed out", | |
| original_error=original, | |
| query="test query", | |
| additional_info={"timeout": 30}, | |
| ) | |
| result = context.to_dict() | |
| assert result["error_type"] == "timeout" | |
| assert result["message"] == "Timed out" | |
| assert result["query"] == "test query" | |
| assert result["original_error"] == "test" | |
| assert result["additional_info"]["timeout"] == 30 | |
| def test_error_context_to_dict_no_original(self): | |
| """Test to_dict with no original error.""" | |
| context = ErrorContext( | |
| error_type=ErrorType.UNKNOWN, | |
| message="Unknown error", | |
| ) | |
| result = context.to_dict() | |
| assert result["original_error"] is None | |
| class TestErrorHandler: | |
| """Tests for ErrorHandler class.""" | |
| def reset_handler(self): | |
| """Reset error handler before each test.""" | |
| reset_error_handler() | |
| yield | |
| reset_error_handler() | |
| def test_error_handler_creation(self): | |
| """Test basic handler creation.""" | |
| handler = ErrorHandler() | |
| assert handler.enable_fallback is True | |
| assert all(count == 0 for count in handler.error_counts.values()) | |
| def test_error_handler_fallback_disabled(self): | |
| """Test handler with fallback disabled.""" | |
| handler = ErrorHandler(enable_fallback=False) | |
| assert handler.enable_fallback is False | |
| def test_set_enable_fallback(self): | |
| """Test setting fallback enabled state.""" | |
| handler = ErrorHandler() | |
| handler.enable_fallback = False | |
| assert handler.enable_fallback is False | |
| def test_error_counts_returns_copy(self): | |
| """Test that error_counts returns a copy.""" | |
| handler = ErrorHandler() | |
| counts = handler.error_counts | |
| counts[ErrorType.UNKNOWN] = 999 | |
| assert handler.error_counts[ErrorType.UNKNOWN] == 0 | |
| def test_reset_counts(self): | |
| """Test resetting error counts.""" | |
| handler = ErrorHandler() | |
| handler.handle(ValueError("test")) | |
| assert sum(handler.error_counts.values()) > 0 | |
| handler.reset_counts() | |
| assert all(count == 0 for count in handler.error_counts.values()) | |
| def test_handle_basic_error(self): | |
| """Test handling basic error.""" | |
| handler = ErrorHandler() | |
| error = ValueError("test error") | |
| context = handler.handle(error) | |
| assert isinstance(context, ErrorContext) | |
| assert context.original_error == error | |
| assert context.message != "" | |
| def test_handle_with_error_type(self): | |
| """Test handling error with specified type.""" | |
| handler = ErrorHandler() | |
| error = Exception("test") | |
| context = handler.handle(error, error_type=ErrorType.DATABASE_CONNECTION) | |
| assert context.error_type == ErrorType.DATABASE_CONNECTION | |
| assert handler.error_counts[ErrorType.DATABASE_CONNECTION] == 1 | |
| def test_handle_with_query(self): | |
| """Test handling error with query context.""" | |
| handler = ErrorHandler() | |
| error = Exception("test") | |
| context = handler.handle(error, query="SELECT * FROM users") | |
| assert context.query == "SELECT * FROM users" | |
| def test_handle_increments_count(self): | |
| """Test that handling increments error count.""" | |
| handler = ErrorHandler() | |
| handler.handle(Exception("test1"), ErrorType.TIMEOUT) | |
| handler.handle(Exception("test2"), ErrorType.TIMEOUT) | |
| handler.handle(Exception("test3"), ErrorType.DATABASE_QUERY) | |
| assert handler.error_counts[ErrorType.TIMEOUT] == 2 | |
| assert handler.error_counts[ErrorType.DATABASE_QUERY] == 1 | |
| def test_get_user_message(self): | |
| """Test getting user-friendly messages.""" | |
| handler = ErrorHandler() | |
| message = handler.get_user_message(ErrorType.DATABASE_CONNECTION) | |
| assert "bağlantı" in message.lower() | |
| message = handler.get_user_message(ErrorType.TIMEOUT) | |
| assert "zaman" in message.lower() | |
| def test_get_most_frequent_error_none(self): | |
| """Test most frequent error when no errors.""" | |
| handler = ErrorHandler() | |
| assert handler.get_most_frequent_error() is None | |
| def test_get_most_frequent_error(self): | |
| """Test getting most frequent error type.""" | |
| handler = ErrorHandler() | |
| handler.handle(Exception("1"), ErrorType.TIMEOUT) | |
| handler.handle(Exception("2"), ErrorType.TIMEOUT) | |
| handler.handle(Exception("3"), ErrorType.TIMEOUT) | |
| handler.handle(Exception("4"), ErrorType.DATABASE_QUERY) | |
| assert handler.get_most_frequent_error() == ErrorType.TIMEOUT | |
| def test_register_fallback(self): | |
| """Test registering fallback handler.""" | |
| handler = ErrorHandler() | |
| fallback_fn = Mock(return_value="fallback result") | |
| handler.register_fallback(ErrorType.DATABASE_QUERY, fallback_fn) | |
| assert ErrorType.DATABASE_QUERY in handler._fallback_handlers | |
| def test_execute_with_fallback_success(self): | |
| """Test execute_with_fallback on success.""" | |
| handler = ErrorHandler() | |
| def success_fn(): | |
| return "success" | |
| result = handler.execute_with_fallback( | |
| success_fn, | |
| ErrorType.DATABASE_QUERY, | |
| fallback_value="fallback", | |
| ) | |
| assert result == "success" | |
| def test_execute_with_fallback_uses_fallback_value(self): | |
| """Test execute_with_fallback uses fallback value on error.""" | |
| handler = ErrorHandler() | |
| def failing_fn(): | |
| raise ValueError("test error") | |
| result = handler.execute_with_fallback( | |
| failing_fn, | |
| ErrorType.DATABASE_QUERY, | |
| fallback_value="fallback result", | |
| ) | |
| assert result == "fallback result" | |
| def test_execute_with_fallback_uses_registered_handler(self): | |
| """Test execute_with_fallback uses registered handler.""" | |
| handler = ErrorHandler() | |
| fallback_fn = Mock(return_value="custom fallback") | |
| handler.register_fallback(ErrorType.DATABASE_QUERY, fallback_fn) | |
| def failing_fn(): | |
| raise ValueError("test") | |
| result = handler.execute_with_fallback( | |
| failing_fn, | |
| ErrorType.DATABASE_QUERY, | |
| fallback_value="default", | |
| query="test query", | |
| ) | |
| assert result == "custom fallback" | |
| fallback_fn.assert_called_once() | |
| def test_execute_with_fallback_disabled(self): | |
| """Test execute_with_fallback when fallback disabled.""" | |
| handler = ErrorHandler(enable_fallback=False) | |
| fallback_fn = Mock(return_value="custom") | |
| handler.register_fallback(ErrorType.DATABASE_QUERY, fallback_fn) | |
| def failing_fn(): | |
| raise ValueError("test") | |
| result = handler.execute_with_fallback( | |
| failing_fn, | |
| ErrorType.DATABASE_QUERY, | |
| fallback_value="default", | |
| ) | |
| assert result == "default" | |
| fallback_fn.assert_not_called() | |
| class TestErrorTypeDetection: | |
| """Tests for automatic error type detection.""" | |
| def reset_handler(self): | |
| """Reset error handler before each test.""" | |
| reset_error_handler() | |
| yield | |
| reset_error_handler() | |
| def test_detect_connection_error(self): | |
| """Test detection of connection errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("Connection refused") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.DATABASE_CONNECTION | |
| def test_detect_timeout_error(self): | |
| """Test detection of timeout errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("Query timed out after 30 seconds") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.TIMEOUT | |
| def test_detect_injection_error(self): | |
| """Test detection of SQL injection errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("SQL injection detected, forbidden pattern") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.SQL_INJECTION | |
| def test_detect_validation_error(self): | |
| """Test detection of validation errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("Validation failed: invalid data") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.SQL_VALIDATION | |
| def test_detect_retrieval_error(self): | |
| """Test detection of document retrieval errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("Failed to retrieve documents") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.DOCUMENT_RETRIEVAL | |
| def test_detect_llm_error(self): | |
| """Test detection of LLM errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("LLM generation failed") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.LLM_GENERATION | |
| def test_detect_unknown_error(self): | |
| """Test detection of unknown errors.""" | |
| handler = ErrorHandler() | |
| error = Exception("Some random error") | |
| context = handler.handle(error) | |
| assert context.error_type == ErrorType.UNKNOWN | |
| class TestErrorHandlerSingleton: | |
| """Tests for error handler singleton functions.""" | |
| def reset_singleton(self): | |
| """Reset singleton before each test.""" | |
| reset_error_handler() | |
| yield | |
| reset_error_handler() | |
| def test_get_error_handler_creates_instance(self): | |
| """Test get_error_handler creates new instance.""" | |
| handler = get_error_handler() | |
| assert handler is not None | |
| assert isinstance(handler, ErrorHandler) | |
| def test_get_error_handler_returns_same_instance(self): | |
| """Test get_error_handler returns singleton.""" | |
| handler1 = get_error_handler() | |
| handler2 = get_error_handler() | |
| assert handler1 is handler2 | |
| def test_reset_error_handler(self): | |
| """Test reset_error_handler clears singleton.""" | |
| handler1 = get_error_handler() | |
| reset_error_handler() | |
| handler2 = get_error_handler() | |
| assert handler1 is not handler2 | |
| def test_handle_error_convenience_function(self): | |
| """Test handle_error convenience function.""" | |
| error = ValueError("test") | |
| context = handle_error(error, ErrorType.DATABASE_QUERY, "test query") | |
| assert context.error_type == ErrorType.DATABASE_QUERY | |
| assert context.query == "test query" | |
| def test_handle_error_uses_singleton(self): | |
| """Test handle_error uses singleton handler.""" | |
| handle_error(ValueError("test1"), ErrorType.TIMEOUT) | |
| handle_error(ValueError("test2"), ErrorType.TIMEOUT) | |
| handler = get_error_handler() | |
| assert handler.error_counts[ErrorType.TIMEOUT] == 2 | |
| class TestErrorMessages: | |
| """Tests for error message localization.""" | |
| def test_all_error_types_have_messages(self): | |
| """Test all error types have user messages.""" | |
| handler = ErrorHandler() | |
| for error_type in ErrorType: | |
| message = handler.get_user_message(error_type) | |
| assert message != "" | |
| assert len(message) > 10 | |
| def test_messages_are_turkish(self): | |
| """Test messages contain Turkish text.""" | |
| handler = ErrorHandler() | |
| message = handler.get_user_message(ErrorType.DATABASE_CONNECTION) | |
| turkish_chars = set("ğüşıöçĞÜŞİÖÇ") | |
| message_lower = message.lower() | |
| turkish_words = ["lütfen", "veritabanı", "sorgu", "hata", "işlem"] | |
| has_turkish = any(word in message_lower for word in turkish_words) | |
| assert has_turkish | |
| class TestErrorContext: | |
| """Additional tests for error context.""" | |
| def test_error_context_includes_traceback(self): | |
| """Test error context includes traceback in additional_info.""" | |
| handler = ErrorHandler() | |
| try: | |
| raise ValueError("test error") | |
| except Exception as e: | |
| context = handler.handle(e) | |
| assert context.additional_info is not None | |
| assert "traceback" in context.additional_info | |
| assert "ValueError" in context.additional_info["traceback"] | |