import pytest import json from datetime import datetime from flask import Flask, request from werkzeug.exceptions import NotFound from ..core.exceptions import ( ValidationException, InputValidationError, AuthenticationException, InvalidCredentialsError, DatabaseException, QueryError, ResourceNotFoundError, BusinessRuleViolation ) from ..core.error_handlers import init_error_handlers, handle_errors, validate_request from ..core.validators import Validators, validate from ..core.monitoring import error_metrics, alert_manager from ..middleware.error_middleware import ErrorHandlingMiddleware @pytest.fixture def app(): app = Flask(__name__) app.config['TESTING'] = True app.config['SECRET_KEY'] = 'test-secret-key' init_error_handlers(app) ErrorHandlingMiddleware(app) @app.route('/test-validation-error') def test_validation_error(): raise InputValidationError( field='email', message='Invalid email format', value='not-an-email' ) @app.route('/test-auth-error') def test_auth_error(): raise InvalidCredentialsError('testuser') @app.route('/test-db-error') def test_db_error(): raise QueryError( message='Column not found', query='SELECT * FROM users', error_code='42703' ) @app.route('/test-not-found') def test_not_found(): raise ResourceNotFoundError('User', 123) @app.route('/test-generic-error') def test_generic_error(): raise Exception('Something went wrong') @app.route('/test-validate', methods=['POST']) @validate({ 'email': {'type': 'email', 'required': True}, 'age': {'type': 'integer', 'required': True, 'min_value': 18}, 'username': {'type': 'username', 'required': False} }) def test_validate(): return {'success': True, 'data': request.validated_data} @app.route('/test-handle-errors') @handle_errors( catch=(ValueError,), message='Value error occurred', user_message='Ungültiger Wert' ) def test_handle_errors(): raise ValueError('Invalid value') return app @pytest.fixture def client(app): return app.test_client() class TestExceptions: def test_validation_exception(self): exc = ValidationException( message='Test validation error', field='test_field', value='test_value', user_message='Test user message' ) assert exc.code == 'VALIDATION_ERROR' assert exc.status_code == 400 assert exc.details['field'] == 'test_field' assert exc.details['value'] == 'test_value' assert exc.user_message == 'Test user message' def test_input_validation_error(self): exc = InputValidationError( field='email', message='Invalid format', value='not-email', expected_type='email' ) assert exc.code == 'VALIDATION_ERROR' assert exc.status_code == 400 assert exc.details['field'] == 'email' assert exc.details['expected_type'] == 'email' def test_business_rule_violation(self): exc = BusinessRuleViolation( rule='max_licenses', message='License limit exceeded', context={'current': 10, 'max': 5} ) assert exc.details['rule'] == 'max_licenses' assert exc.details['context']['current'] == 10 def test_authentication_exceptions(self): exc = InvalidCredentialsError('testuser') assert exc.status_code == 401 assert exc.details['username'] == 'testuser' def test_database_exceptions(self): exc = QueryError( message='Syntax error', query='SELECT * FORM users', error_code='42601' ) assert exc.code == 'DATABASE_ERROR' assert exc.status_code == 500 assert 'query_hash' in exc.details assert exc.details['error_code'] == '42601' def test_resource_not_found(self): exc = ResourceNotFoundError( resource_type='License', resource_id='ABC123', search_criteria={'customer_id': 1} ) assert exc.status_code == 404 assert exc.details['resource_type'] == 'License' assert exc.details['resource_id'] == 'ABC123' assert exc.details['search_criteria']['customer_id'] == 1 class TestErrorHandlers: def test_validation_error_json_response(self, client): response = client.get( '/test-validation-error', headers={'Accept': 'application/json'} ) assert response.status_code == 400 data = json.loads(response.data) assert 'error' in data assert data['error']['code'] == 'VALIDATION_ERROR' assert 'request_id' in data['error'] def test_validation_error_html_response(self, client): response = client.get('/test-validation-error') assert response.status_code == 400 assert b'Ungültiger Wert für Feld' in response.data def test_auth_error_response(self, client): response = client.get( '/test-auth-error', headers={'Accept': 'application/json'} ) assert response.status_code == 401 data = json.loads(response.data) assert data['error']['code'] == 'AUTHENTICATION_ERROR' def test_db_error_response(self, client): response = client.get( '/test-db-error', headers={'Accept': 'application/json'} ) assert response.status_code == 500 data = json.loads(response.data) assert data['error']['code'] == 'DATABASE_ERROR' def test_not_found_response(self, client): response = client.get('/test-not-found') assert response.status_code == 404 assert b'User nicht gefunden' in response.data def test_generic_error_response(self, client): response = client.get( '/test-generic-error', headers={'Accept': 'application/json'} ) assert response.status_code == 500 data = json.loads(response.data) assert data['error']['code'] == 'INTERNAL_ERROR' def test_validate_decorator_success(self, client): response = client.post( '/test-validate', json={'email': 'test@example.com', 'age': 25, 'username': 'testuser'} ) assert response.status_code == 200 data = json.loads(response.data) assert data['success'] is True assert data['data']['email'] == 'test@example.com' assert data['data']['age'] == 25 def test_validate_decorator_failure(self, client): response = client.post( '/test-validate', json={'email': 'invalid-email', 'age': 15} ) assert response.status_code == 400 data = json.loads(response.data) assert data['error']['code'] == 'VALIDATION_ERROR' def test_handle_errors_decorator(self, client): response = client.get('/test-handle-errors') assert response.status_code == 500 assert b'Ungültiger Wert' in response.data class TestValidators: def test_email_validator(self): assert Validators.email('test@example.com') == 'test@example.com' assert Validators.email('TEST@EXAMPLE.COM') == 'test@example.com' with pytest.raises(InputValidationError): Validators.email('invalid-email') with pytest.raises(InputValidationError): Validators.email('') def test_phone_validator(self): assert Validators.phone('+1-234-567-8900') == '+12345678900' assert Validators.phone('(123) 456-7890') == '1234567890' with pytest.raises(InputValidationError): Validators.phone('123') def test_license_key_validator(self): assert Validators.license_key('abcd-1234-efgh-5678') == 'ABCD-1234-EFGH-5678' with pytest.raises(InputValidationError): Validators.license_key('invalid-key') def test_integer_validator(self): assert Validators.integer('123') == 123 assert Validators.integer(456) == 456 assert Validators.integer('10', min_value=5, max_value=15) == 10 with pytest.raises(InputValidationError): Validators.integer('abc') with pytest.raises(InputValidationError): Validators.integer('3', min_value=5) with pytest.raises(InputValidationError): Validators.integer('20', max_value=15) def test_string_validator(self): assert Validators.string('test', min_length=2, max_length=10) == 'test' with pytest.raises(InputValidationError): Validators.string('a', min_length=2) with pytest.raises(InputValidationError): Validators.string('a' * 20, max_length=10) with pytest.raises(InputValidationError): Validators.string('test