Spaces:
Sleeping
Sleeping
File size: 15,478 Bytes
79d4fd5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | # 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."""
@pytest.fixture(autouse=True)
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."""
@pytest.fixture(autouse=True)
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."""
@pytest.fixture(autouse=True)
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"]
|