@@ -150,6 +150,131 @@ def test_db_no_autocommit_executemany(sentry_init, client, capture_events):
150150 ) or conn_params .get ("dbname" )
151151
152152
153+ @pytest .mark .forked
154+ @pytest_mark_django_db_decorator (transaction = True )
155+ def test_db_no_autocommit_rollback_execute (sentry_init , client , capture_events ):
156+ sentry_init (
157+ integrations = [DjangoIntegration ()],
158+ traces_sample_rate = 1.0 ,
159+ )
160+
161+ if "postgres" not in connections :
162+ pytest .skip ("postgres tests disabled" )
163+
164+ # trigger Django to open a new connection by marking the existing one as None.
165+ connections ["postgres" ].connection = None
166+
167+ events = capture_events ()
168+
169+ client .get (reverse ("postgres_insert_orm_no_autocommit_rollback" ))
170+
171+ (event ,) = events
172+
173+ # Ensure operation is rolled back
174+ assert not User .objects .using ("postgres" ).exists ()
175+
176+ assert event ["contexts" ]["trace" ]["origin" ] == "auto.http.django"
177+
178+ commit_spans = [
179+ span
180+ for span in event ["spans" ]
181+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
182+ ]
183+ assert len (commit_spans ) == 1
184+ commit_span = commit_spans [0 ]
185+ assert commit_span ["origin" ] == "auto.db.django"
186+
187+ # Verify other database attributes
188+ assert commit_span ["data" ].get (SPANDATA .DB_SYSTEM ) == "postgresql"
189+ conn_params = connections ["postgres" ].get_connection_params ()
190+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) is not None
191+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) == conn_params .get (
192+ "database"
193+ ) or conn_params .get ("dbname" )
194+ assert commit_span ["data" ].get (SPANDATA .SERVER_ADDRESS ) == os .environ .get (
195+ "SENTRY_PYTHON_TEST_POSTGRES_HOST" , "localhost"
196+ )
197+ assert commit_span ["data" ].get (SPANDATA .SERVER_PORT ) == os .environ .get (
198+ "SENTRY_PYTHON_TEST_POSTGRES_PORT" , "5432"
199+ )
200+
201+
202+ @pytest .mark .forked
203+ @pytest_mark_django_db_decorator (transaction = True )
204+ def test_db_no_autocommit_rollback_executemany (sentry_init , client , capture_events ):
205+ sentry_init (
206+ integrations = [DjangoIntegration ()],
207+ traces_sample_rate = 1.0 ,
208+ )
209+
210+ events = capture_events ()
211+
212+ with start_transaction (name = "test_transaction" ):
213+ from django .db import connection , transaction
214+
215+ cursor = connection .cursor ()
216+
217+ query = """INSERT INTO auth_user (
218+ password,
219+ is_superuser,
220+ username,
221+ first_name,
222+ last_name,
223+ email,
224+ is_staff,
225+ is_active,
226+ date_joined
227+ )
228+ VALUES ('password', false, %s, %s, %s, %s, false, true, %s);"""
229+
230+ query_list = (
231+ (
232+ "user1" ,
233+ "John" ,
234+ "Doe" ,
235+ 236+ datetime (1970 , 1 , 1 ),
237+ ),
238+ (
239+ "user2" ,
240+ "Max" ,
241+ "Mustermann" ,
242+ 243+ datetime (1970 , 1 , 1 ),
244+ ),
245+ )
246+
247+ transaction .set_autocommit (False )
248+ cursor .executemany (query , query_list )
249+ transaction .rollback ()
250+ transaction .set_autocommit (True )
251+
252+ (event ,) = events
253+
254+ # Ensure operation is rolled back
255+ assert not User .objects .exists ()
256+
257+ assert event ["contexts" ]["trace" ]["origin" ] == "manual"
258+ assert event ["spans" ][0 ]["origin" ] == "auto.db.django"
259+
260+ commit_spans = [
261+ span
262+ for span in event ["spans" ]
263+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
264+ ]
265+ assert len (commit_spans ) == 1
266+ commit_span = commit_spans [0 ]
267+ assert commit_span ["origin" ] == "auto.db.django"
268+
269+ # Verify other database attributes
270+ assert commit_span ["data" ].get (SPANDATA .DB_SYSTEM ) == "sqlite"
271+ conn_params = connection .get_connection_params ()
272+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) is not None
273+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) == conn_params .get (
274+ "database"
275+ ) or conn_params .get ("dbname" )
276+
277+
153278@pytest .mark .forked
154279@pytest_mark_django_db_decorator (transaction = True )
155280def test_db_atomic_execute (sentry_init , client , capture_events ):
@@ -270,3 +395,127 @@ def test_db_atomic_executemany(sentry_init, client, capture_events):
270395 assert commit_span ["data" ].get (SPANDATA .DB_NAME ) == conn_params .get (
271396 "database"
272397 ) or conn_params .get ("dbname" )
398+
399+
400+ @pytest .mark .forked
401+ @pytest_mark_django_db_decorator (transaction = True )
402+ def test_db_atomic_rollback_execute (sentry_init , client , capture_events ):
403+ sentry_init (
404+ integrations = [DjangoIntegration ()],
405+ send_default_pii = True ,
406+ traces_sample_rate = 1.0 ,
407+ )
408+
409+ if "postgres" not in connections :
410+ pytest .skip ("postgres tests disabled" )
411+
412+ # trigger Django to open a new connection by marking the existing one as None.
413+ connections ["postgres" ].connection = None
414+
415+ events = capture_events ()
416+
417+ client .get (reverse ("postgres_insert_orm_atomic_rollback" ))
418+
419+ (event ,) = events
420+
421+ # Ensure operation is rolled back
422+ assert not User .objects .using ("postgres" ).exists ()
423+
424+ assert event ["contexts" ]["trace" ]["origin" ] == "auto.http.django"
425+
426+ commit_spans = [
427+ span
428+ for span in event ["spans" ]
429+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
430+ ]
431+ assert len (commit_spans ) == 1
432+ commit_span = commit_spans [0 ]
433+ assert commit_span ["origin" ] == "auto.db.django"
434+
435+ # Verify other database attributes
436+ assert commit_span ["data" ].get (SPANDATA .DB_SYSTEM ) == "postgresql"
437+ conn_params = connections ["postgres" ].get_connection_params ()
438+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) is not None
439+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) == conn_params .get (
440+ "database"
441+ ) or conn_params .get ("dbname" )
442+ assert commit_span ["data" ].get (SPANDATA .SERVER_ADDRESS ) == os .environ .get (
443+ "SENTRY_PYTHON_TEST_POSTGRES_HOST" , "localhost"
444+ )
445+ assert commit_span ["data" ].get (SPANDATA .SERVER_PORT ) == os .environ .get (
446+ "SENTRY_PYTHON_TEST_POSTGRES_PORT" , "5432"
447+ )
448+
449+
450+ @pytest .mark .forked
451+ @pytest_mark_django_db_decorator (transaction = True )
452+ def test_db_atomic_rollback_executemany (sentry_init , client , capture_events ):
453+ sentry_init (
454+ integrations = [DjangoIntegration ()],
455+ send_default_pii = True ,
456+ traces_sample_rate = 1.0 ,
457+ )
458+
459+ events = capture_events ()
460+
461+ with start_transaction (name = "test_transaction" ):
462+ from django .db import connection , transaction
463+
464+ with transaction .atomic ():
465+ cursor = connection .cursor ()
466+
467+ query = """INSERT INTO auth_user (
468+ password,
469+ is_superuser,
470+ username,
471+ first_name,
472+ last_name,
473+ email,
474+ is_staff,
475+ is_active,
476+ date_joined
477+ )
478+ VALUES ('password', false, %s, %s, %s, %s, false, true, %s);"""
479+
480+ query_list = (
481+ (
482+ "user1" ,
483+ "John" ,
484+ "Doe" ,
485+ 486+ datetime (1970 , 1 , 1 ),
487+ ),
488+ (
489+ "user2" ,
490+ "Max" ,
491+ "Mustermann" ,
492+ 493+ datetime (1970 , 1 , 1 ),
494+ ),
495+ )
496+ cursor .executemany (query , query_list )
497+ transaction .set_rollback (True )
498+
499+ (event ,) = events
500+
501+ # Ensure operation is rolled back
502+ assert not User .objects .exists ()
503+
504+ assert event ["contexts" ]["trace" ]["origin" ] == "manual"
505+
506+ commit_spans = [
507+ span
508+ for span in event ["spans" ]
509+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
510+ ]
511+ assert len (commit_spans ) == 1
512+ commit_span = commit_spans [0 ]
513+ assert commit_span ["origin" ] == "auto.db.django"
514+
515+ # Verify other database attributes
516+ assert commit_span ["data" ].get (SPANDATA .DB_SYSTEM ) == "sqlite"
517+ conn_params = connection .get_connection_params ()
518+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) is not None
519+ assert commit_span ["data" ].get (SPANDATA .DB_NAME ) == conn_params .get (
520+ "database"
521+ ) or conn_params .get ("dbname" )
0 commit comments