def test_sentry_integration(client, monkeypatch, caplog, mocker): """ Tests the sentry integration """ from sentry_sdk.scope import Scope from django_guid.integrations import SentryIntegration from django_guid.config import settings as guid_settings monkeypatch.setattr(guid_settings, 'INTEGRATIONS', [SentryIntegration()]) mock_scope = mocker.patch.object(Scope, 'set_tag') client.get('/api', **{'HTTP_Correlation-ID': '97c304252fd14b25b72d6aee31565842'}) expected = [ (None, 'Correlation-ID found in the header: 97c304252fd14b25b72d6aee31565842'), (None, '97c304252fd14b25b72d6aee31565842 is a valid GUID'), ('97c304252fd14b25b72d6aee31565842', 'Running integration: `SentryIntegration`'), ('97c304252fd14b25b72d6aee31565842', 'Setting Sentry transaction_id to 97c304252fd14b25b72d6aee31565842'), ('97c304252fd14b25b72d6aee31565842', 'This is a DRF view log, and should have a GUID.'), ('97c304252fd14b25b72d6aee31565842', 'Some warning in a function'), ('97c304252fd14b25b72d6aee31565842', 'Running tear down for integration: `SentryIntegration`'), ('97c304252fd14b25b72d6aee31565842', 'Received signal `request_finished`'), ('97c304252fd14b25b72d6aee31565842', 'Deleting 97c304252fd14b25b72d6aee31565842 from _guid'), ] mock_scope.assert_called_with('transaction_id', '97c304252fd14b25b72d6aee31565842') assert [(x.correlation_id, x.message) for x in caplog.records] == expected
def test_non_callable_methods(monkeypatch, subtests): """ Tests that an exception is raised when any of the integration base methods are non-callable. """ from django_guid.integrations import SentryIntegration from django.conf import settings from django_guid.config import Settings mock_integration = SentryIntegration() to_test = [ { 'function_name': 'cleanup', 'error': 'Integration method `cleanup` needs to be made callable for `SentryIntegration`.', }, { 'function_name': 'run', 'error': 'Integration method `run` needs to be made callable for `SentryIntegration`.', }, { 'function_name': 'setup', 'error': 'Integration method `setup` needs to be made callable for `SentryIntegration`.', }, ] for test in to_test: setattr(mock_integration, test.get('function_name'), 'test') monkeypatch.setattr(settings, 'DJANGO_GUID', {'INTEGRATIONS': [mock_integration]}) with subtests.test(msg=f'Testing function {test.get("function_name")}'): with pytest.raises(ImproperlyConfigured, match=test.get('error')): Settings()
def test_missing_identifier(monkeypatch): """ Tests that an exception is raised when identifier is missing. """ from django_guid.integrations import SentryIntegration monkeypatch.setattr(SentryIntegration, 'identifier', None) with pytest.raises(ImproperlyConfigured, match='`identifier` cannot be None'): SentryIntegration()
def test_missing_run_method(monkeypatch, client): """ Tests that an exception is raised when the run method has not been defined. """ from django_guid.config import settings as guid_settings from django_guid.integrations import SentryIntegration monkeypatch.delattr(SentryIntegration, 'run') monkeypatch.setattr(guid_settings, 'INTEGRATIONS', [SentryIntegration()]) with pytest.raises(ImproperlyConfigured, match='The integration `SentryIntegration` is missing a `run` method'): client.get('/api')
def test_sentry_validation(client, monkeypatch): """ Tests that the package handles multiple header values by defaulting to one and logging a warning. """ import sys from django_guid.integrations import SentryIntegration from django_guid.config import Settings from django.conf import settings # Mock away the sentry_sdk dependency sys.modules['sentry_sdk'] = None monkeypatch.setattr(settings, 'DJANGO_GUID', {'INTEGRATIONS': [SentryIntegration()]}) with pytest.raises( ImproperlyConfigured, match='The package `sentry-sdk` is required for extending your tracing IDs to Sentry. ' 'Please run `pip install sentry-sdk` if you wish to include this integration.', ): Settings()
def validate(self) -> None: if not isinstance(self.use_django_logging, bool): raise ImproperlyConfigured( 'The CeleryIntegration use_django_logging setting must be a boolean.' ) if not isinstance(self.log_parent, bool): raise ImproperlyConfigured( 'The CeleryIntegration log_parent setting must be a boolean.') if type(self.uuid_length ) is not int or not 1 <= self.uuid_length <= 32: raise ImproperlyConfigured( 'The CeleryIntegration uuid_length setting must be an integer.' ) if not isinstance(self.sentry_integration, bool): raise ImproperlyConfigured( 'The CeleryIntegration sentry_integration setting must be a boolean.' ) if self.sentry_integration: SentryIntegration().setup()
def test_missing_run_method(monkeypatch, client): """ Tests that an exception is raised when the run method has not been defined. """ from django_guid.integrations import SentryIntegration monkeypatch.delattr(SentryIntegration, 'run') mocked_settings = deepcopy(django_settings.DJANGO_GUID) mocked_settings['INTEGRATIONS'] = [SentryIntegration()] with override_settings(DJANGO_GUID=mocked_settings): settings = Settings() monkeypatch.setattr('django_guid.middleware.settings', settings) with pytest.raises( ImproperlyConfigured, match= 'The integration `SentryIntegration` is missing a `run` method' ): client.get('/api')
import sys from django.core.exceptions import ImproperlyConfigured from django.test import override_settings import pytest from sentry_sdk.scope import Scope from django_guid.config import Settings from django_guid.integrations import SentryIntegration mocked_settings = { 'GUID_HEADER_NAME': 'Correlation-ID', 'VALIDATE_GUID': True, 'INTEGRATIONS': [SentryIntegration()], 'IGNORE_URLS': ['no-guid'], } def test_sentry_integration(client, caplog, mocker, monkeypatch): """ Tests the sentry integration """ mock_scope = mocker.patch.object(Scope, 'set_tag') with override_settings(DJANGO_GUID=mocked_settings): settings = Settings() monkeypatch.setattr('django_guid.middleware.settings', settings) client.get( '/api', **{'HTTP_Correlation-ID': '97c304252fd14b25b72d6aee31565842'}) expected = [
}, ] # fmt: off # OBS: No setting in Django GUID is required. These are example settings. DJANGO_GUID = { 'GUID_HEADER_NAME': 'Correlation-ID', 'VALIDATE_GUID': True, 'INTEGRATIONS': [ CeleryIntegration( use_django_logging=True, log_parent=True, uuid_length=10 ), SentryIntegration() ], 'IGNORE_URLS': ['no-guid'], } # Set up logging for the project LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'correlation_id': {'()': 'django_guid.log_filters.CorrelationId'}, # <-- Add correlation ID 'celery_tracing': {'()': 'django_guid.integrations.celery.log_filters.CeleryTracing'}, # <-- Add celery IDs }, 'formatters': { # Basic log format without django-guid filters 'basic_format': {'format': '%(levelname)s %(asctime)s %(name)s - %(message)s'},