11import os
22import pytest
3+ import itertools
34from datetime import datetime
45
56from django .db import connections
@@ -27,7 +28,9 @@ def client():
2728
2829@pytest .mark .forked
2930@pytest_mark_django_db_decorator (transaction = True )
30- def test_db_no_autocommit_execute (sentry_init , client , capture_events ):
31+ def test_db_transaction_spans_disabled_no_autocommit (
32+ sentry_init , client , capture_events
33+ ):
3134 sentry_init (
3235 integrations = [DjangoIntegration ()],
3336 traces_sample_rate = 1.0 ,
@@ -43,6 +46,151 @@ def test_db_no_autocommit_execute(sentry_init, client, capture_events):
4346
4447 client .get (reverse ("postgres_insert_orm_no_autocommit" ))
4548
49+ with start_transaction (name = "test_transaction" ):
50+ from django .db import connection , transaction
51+
52+ cursor = connection .cursor ()
53+
54+ query = """INSERT INTO auth_user (
55+ password,
56+ is_superuser,
57+ username,
58+ first_name,
59+ last_name,
60+ email,
61+ is_staff,
62+ is_active,
63+ date_joined
64+ )
65+ VALUES ('password', false, %s, %s, %s, %s, false, true, %s);"""
66+
67+ query_list = (
68+ (
69+ "user1" ,
70+ "John" ,
71+ "Doe" ,
72+ 73+ datetime (1970 , 1 , 1 ),
74+ ),
75+ (
76+ "user2" ,
77+ "Max" ,
78+ "Mustermann" ,
79+ 80+ datetime (1970 , 1 , 1 ),
81+ ),
82+ )
83+
84+ transaction .set_autocommit (False )
85+ cursor .executemany (query , query_list )
86+ transaction .commit ()
87+ transaction .set_autocommit (True )
88+
89+ (postgres_spans , sqlite_spans ) = events
90+
91+ # Ensure operation is persisted
92+ assert User .objects .using ("postgres" ).exists ()
93+
94+ assert postgres_spans ["contexts" ]["trace" ]["origin" ] == "auto.http.django"
95+ assert sqlite_spans ["contexts" ]["trace" ]["origin" ] == "manual"
96+
97+ commit_spans = [
98+ span
99+ for span in itertools .chain (postgres_spans ["spans" ], sqlite_spans ["spans" ])
100+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .COMMIT
101+ ]
102+ assert len (commit_spans ) == 0
103+
104+
105+ @pytest .mark .forked
106+ @pytest_mark_django_db_decorator (transaction = True )
107+ def test_db_transaction_spans_disabled_atomic (sentry_init , client , capture_events ):
108+ sentry_init (
109+ integrations = [DjangoIntegration ()],
110+ traces_sample_rate = 1.0 ,
111+ )
112+
113+ if "postgres" not in connections :
114+ pytest .skip ("postgres tests disabled" )
115+
116+ # trigger Django to open a new connection by marking the existing one as None.
117+ connections ["postgres" ].connection = None
118+
119+ events = capture_events ()
120+
121+ client .get (reverse ("postgres_insert_orm_atomic" ))
122+
123+ with start_transaction (name = "test_transaction" ):
124+ from django .db import connection , transaction
125+
126+ with transaction .atomic ():
127+ cursor = connection .cursor ()
128+
129+ query = """INSERT INTO auth_user (
130+ password,
131+ is_superuser,
132+ username,
133+ first_name,
134+ last_name,
135+ email,
136+ is_staff,
137+ is_active,
138+ date_joined
139+ )
140+ VALUES ('password', false, %s, %s, %s, %s, false, true, %s);"""
141+
142+ query_list = (
143+ (
144+ "user1" ,
145+ "John" ,
146+ "Doe" ,
147+ 148+ datetime (1970 , 1 , 1 ),
149+ ),
150+ (
151+ "user2" ,
152+ "Max" ,
153+ "Mustermann" ,
154+ 155+ datetime (1970 , 1 , 1 ),
156+ ),
157+ )
158+ cursor .executemany (query , query_list )
159+
160+ (postgres_spans , sqlite_spans ) = events
161+
162+ # Ensure operation is persisted
163+ assert User .objects .using ("postgres" ).exists ()
164+
165+ assert postgres_spans ["contexts" ]["trace" ]["origin" ] == "auto.http.django"
166+ assert sqlite_spans ["contexts" ]["trace" ]["origin" ] == "manual"
167+
168+ commit_spans = [
169+ span
170+ for span in itertools .chain (postgres_spans ["spans" ], postgres_spans ["spans" ])
171+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .COMMIT
172+ ]
173+ assert len (commit_spans ) == 0
174+
175+
176+ @pytest .mark .forked
177+ @pytest_mark_django_db_decorator (transaction = True )
178+ def test_db_no_autocommit_execute (sentry_init , client , capture_events ):
179+ sentry_init (
180+ integrations = [DjangoIntegration (database_transaction_spans = True )],
181+ traces_sample_rate = 1.0 ,
182+ )
183+
184+ if "postgres" not in connections :
185+ pytest .skip ("postgres tests disabled" )
186+
187+ # trigger Django to open a new connection by marking the existing one as None.
188+ connections ["postgres" ].connection = None
189+
190+ events = capture_events ()
191+
192+ client .get (reverse ("postgres_insert_orm_no_autocommit" ))
193+
46194 (event ,) = events
47195
48196 # Ensure operation is persisted
@@ -87,7 +235,7 @@ def test_db_no_autocommit_execute(sentry_init, client, capture_events):
87235@pytest_mark_django_db_decorator (transaction = True )
88236def test_db_no_autocommit_executemany (sentry_init , client , capture_events ):
89237 sentry_init (
90- integrations = [DjangoIntegration ()],
238+ integrations = [DjangoIntegration (database_transaction_spans = True )],
91239 traces_sample_rate = 1.0 ,
92240 )
93241
@@ -171,7 +319,7 @@ def test_db_no_autocommit_executemany(sentry_init, client, capture_events):
171319@pytest_mark_django_db_decorator (transaction = True )
172320def test_db_atomic_execute (sentry_init , client , capture_events ):
173321 sentry_init (
174- integrations = [DjangoIntegration ()],
322+ integrations = [DjangoIntegration (database_transaction_spans = True )],
175323 traces_sample_rate = 1.0 ,
176324 )
177325
@@ -229,7 +377,7 @@ def test_db_atomic_execute(sentry_init, client, capture_events):
229377@pytest_mark_django_db_decorator (transaction = True )
230378def test_db_atomic_executemany (sentry_init , client , capture_events ):
231379 sentry_init (
232- integrations = [DjangoIntegration ()],
380+ integrations = [DjangoIntegration (database_transaction_spans = True )],
233381 send_default_pii = True ,
234382 traces_sample_rate = 1.0 ,
235383 )
0 commit comments