Skip to content

Commit cb7e107

Browse files
committed
tests
1 parent 06b0703 commit cb7e107

File tree

2 files changed

+157
-2
lines changed

2 files changed

+157
-2
lines changed

sentry_sdk/integrations/django/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,9 @@ def _cache_database_configurations():
652652
"engine": db_config.get("ENGINE"),
653653
}
654654

655-
db_wrapper = connections.get(alias)
656-
if db_wrapper is None:
655+
try:
656+
db_wrapper = connections[alias]
657+
except (KeyError, Exception):
657658
continue
658659

659660
if hasattr(db_wrapper, "vendor"):

tests/integrations/django/test_db_query_data.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import threading
23

34
import pytest
45
from datetime import datetime
@@ -8,6 +9,7 @@
89
from django.core.exceptions import ImproperlyConfigured
910
from django.db import connections
1011

12+
1113
try:
1214
from django.urls import reverse
1315
except ImportError:
@@ -17,10 +19,12 @@
1719

1820
from sentry_sdk import start_transaction
1921
from sentry_sdk.consts import SPANDATA
22+
from sentry_sdk.integrations import django as django_integration
2023
from sentry_sdk.integrations.django import (
2124
DjangoIntegration,
2225
_set_db_data,
2326
_cached_db_configs,
27+
_cache_database_configurations,
2428
)
2529
from sentry_sdk.tracing_utils import record_sql_queries
2630

@@ -986,3 +990,153 @@ def test_set_db_data_empty_cached_values(sentry_init):
986990

987991
for call in not_expected_calls:
988992
assert call not in span.set_data.call_args_list
993+
994+
995+
def test_cache_database_configurations_basic(sentry_init):
996+
"""Test _cache_database_configurations caches Django database settings."""
997+
sentry_init(integrations=[DjangoIntegration()])
998+
999+
_cached_db_configs.clear()
1000+
django_integration._cache_initialized = False
1001+
1002+
_cache_database_configurations()
1003+
1004+
# Verify cache was populated
1005+
assert django_integration._cache_initialized is True
1006+
assert len(_cached_db_configs) > 0
1007+
1008+
# Verify default database was cached
1009+
assert "default" in _cached_db_configs
1010+
default_config = _cached_db_configs["default"]
1011+
1012+
# Check expected keys exist
1013+
expected_keys = ["db_name", "host", "port", "unix_socket", "engine"]
1014+
for key in expected_keys:
1015+
assert key in default_config
1016+
1017+
# Verify the vendor was added from the database wrapper
1018+
if "vendor" in default_config:
1019+
assert isinstance(default_config["vendor"], str)
1020+
1021+
1022+
def test_cache_database_configurations_idempotent(sentry_init):
1023+
"""Test _cache_database_configurations is idempotent and thread-safe."""
1024+
sentry_init(integrations=[DjangoIntegration()])
1025+
1026+
_cached_db_configs.clear()
1027+
django_integration._cache_initialized = False
1028+
1029+
_cache_database_configurations()
1030+
first_call_result = dict(_cached_db_configs)
1031+
first_call_initialized = django_integration._cache_initialized
1032+
1033+
_cache_database_configurations()
1034+
second_call_result = dict(_cached_db_configs)
1035+
second_call_initialized = django_integration._cache_initialized
1036+
1037+
# Verify idempotency
1038+
assert first_call_initialized is True
1039+
assert second_call_initialized is True
1040+
assert first_call_result == second_call_result
1041+
1042+
1043+
def test_cache_database_configurations_thread_safety(sentry_init):
1044+
"""Test _cache_database_configurations is thread-safe."""
1045+
sentry_init(integrations=[DjangoIntegration()])
1046+
1047+
_cached_db_configs.clear()
1048+
django_integration._cache_initialized = False
1049+
1050+
results = []
1051+
exceptions = []
1052+
1053+
def cache_in_thread():
1054+
try:
1055+
_cache_database_configurations()
1056+
results.append(dict(_cached_db_configs))
1057+
except Exception as e:
1058+
exceptions.append(e)
1059+
1060+
threads = []
1061+
for _ in range(5):
1062+
thread = threading.Thread(target=cache_in_thread)
1063+
threads.append(thread)
1064+
1065+
for thread in threads:
1066+
thread.start()
1067+
1068+
for thread in threads:
1069+
thread.join()
1070+
1071+
assert len(exceptions) == 0, f"Exceptions occurred: {exceptions}"
1072+
1073+
assert len(results) == 5
1074+
first_result = results[0]
1075+
for result in results[1:]:
1076+
assert result == first_result
1077+
1078+
assert django_integration._cache_initialized is True
1079+
1080+
1081+
def test_cache_database_configurations_with_custom_settings(sentry_init):
1082+
"""Test _cache_database_configurations handles custom database settings."""
1083+
sentry_init(integrations=[DjangoIntegration()])
1084+
1085+
# Mock custom database settings
1086+
with mock.patch("django.conf.settings") as mock_settings:
1087+
mock_settings.DATABASES = {
1088+
"custom_db": {
1089+
"NAME": "test_db",
1090+
"HOST": "db.example.com",
1091+
"PORT": 5432,
1092+
"ENGINE": "django.db.backends.postgresql",
1093+
"OPTIONS": {"unix_socket": "/tmp/postgres.sock"},
1094+
},
1095+
"empty_db": {}, # Should be skipped
1096+
}
1097+
1098+
# Mock connections to avoid actual database access
1099+
with mock.patch("django.db.connections") as mock_connections:
1100+
mock_wrapper = mock.Mock()
1101+
mock_wrapper.vendor = "postgresql"
1102+
mock_connections.__getitem__.return_value = mock_wrapper
1103+
1104+
# Reset cache and call function
1105+
_cached_db_configs.clear()
1106+
django_integration._cache_initialized = False
1107+
1108+
_cache_database_configurations()
1109+
1110+
# Verify custom database was cached correctly
1111+
assert "custom_db" in _cached_db_configs
1112+
custom_config = _cached_db_configs["custom_db"]
1113+
1114+
assert custom_config["db_name"] == "test_db"
1115+
assert custom_config["host"] == "db.example.com"
1116+
assert custom_config["port"] == 5432
1117+
assert custom_config["unix_socket"] == "/tmp/postgres.sock"
1118+
assert custom_config["engine"] == "django.db.backends.postgresql"
1119+
assert custom_config["vendor"] == "postgresql"
1120+
1121+
# Verify empty database was skipped
1122+
assert "empty_db" not in _cached_db_configs
1123+
1124+
1125+
def test_cache_database_configurations_exception_handling(sentry_init):
1126+
"""Test _cache_database_configurations handles exceptions gracefully."""
1127+
sentry_init(integrations=[DjangoIntegration()])
1128+
1129+
# Mock settings to raise an exception
1130+
with mock.patch("django.conf.settings") as mock_settings:
1131+
mock_settings.DATABASES.items.side_effect = Exception("Settings error")
1132+
1133+
# Reset cache and call function
1134+
_cached_db_configs.clear()
1135+
django_integration._cache_initialized = False
1136+
1137+
# Should not raise an exception
1138+
_cache_database_configurations()
1139+
1140+
# Verify cache was cleared on exception
1141+
assert _cached_db_configs == {}
1142+
assert django_integration._cache_initialized is False

0 commit comments

Comments
 (0)