@@ -640,6 +640,118 @@ def test_db_no_autocommit_executemany(sentry_init, client, capture_events):
640640 assert commit_span ["origin" ] == "auto.db.django"
641641
642642
643+ @pytest .mark .forked
644+ @pytest_mark_django_db_decorator (transaction = True , databases = ["postgres" ])
645+ def test_db_no_autocommit_rollback_execute (sentry_init , client , capture_events ):
646+ sentry_init (
647+ integrations = [DjangoIntegration ()],
648+ traces_sample_rate = 1.0 ,
649+ )
650+
651+ if "postgres" not in connections :
652+ pytest .skip ("postgres tests disabled" )
653+
654+ # trigger Django to open a new connection by marking the existing one as None.
655+ connections ["postgres" ].connection = None
656+
657+ events = capture_events ()
658+
659+ client .get (reverse ("postgres_insert_orm_no_autocommit_rollback" ))
660+
661+ (event ,) = events
662+
663+ # Ensure operation is rolled back
664+ assert not User .objects .using ("postgres" ).exists ()
665+
666+ assert event ["contexts" ]["trace" ]["origin" ] == "auto.http.django"
667+
668+ for span in event ["spans" ]:
669+ if span ["op" ] == "db" :
670+ assert span ["origin" ] == "auto.db.django"
671+ else :
672+ assert span ["origin" ] == "auto.http.django"
673+
674+ commit_spans = [
675+ span
676+ for span in event ["spans" ]
677+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
678+ ]
679+ assert len (commit_spans ) == 1
680+ commit_span = commit_spans [0 ]
681+ assert commit_span ["origin" ] == "auto.db.django"
682+
683+
684+ @pytest .mark .forked
685+ @pytest_mark_django_db_decorator (transaction = True )
686+ def test_db_no_autocommit_rollback_executemany (sentry_init , client , capture_events ):
687+ sentry_init (
688+ integrations = [DjangoIntegration ()],
689+ traces_sample_rate = 1.0 ,
690+ )
691+
692+ events = capture_events ()
693+
694+ if "postgres" not in connections :
695+ pytest .skip ("postgres tests disabled" )
696+
697+ with start_transaction (name = "test_transaction" ):
698+ from django .db import connection , transaction
699+
700+ cursor = connection .cursor ()
701+
702+ query = """INSERT INTO auth_user (
703+ password,
704+ is_superuser,
705+ username,
706+ first_name,
707+ last_name,
708+ email,
709+ is_staff,
710+ is_active,
711+ date_joined
712+ )
713+ VALUES ('password', false, %s, %s, %s, %s, false, true, %s);"""
714+
715+ query_list = (
716+ (
717+ "user1" ,
718+ "John" ,
719+ "Doe" ,
720+ 721+ datetime (1970 , 1 , 1 ),
722+ ),
723+ (
724+ "user2" ,
725+ "Max" ,
726+ "Mustermann" ,
727+ 728+ datetime (1970 , 1 , 1 ),
729+ ),
730+ )
731+
732+ transaction .set_autocommit (False )
733+ cursor .executemany (query , query_list )
734+ transaction .rollback ()
735+ transaction .set_autocommit (True )
736+
737+ (event ,) = events
738+
739+ # Ensure operation is rolled back
740+ assert not User .objects .exists ()
741+
742+ assert event ["contexts" ]["trace" ]["origin" ] == "manual"
743+ assert event ["spans" ][0 ]["origin" ] == "auto.db.django"
744+
745+ commit_spans = [
746+ span
747+ for span in event ["spans" ]
748+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
749+ ]
750+ assert len (commit_spans ) == 1
751+ commit_span = commit_spans [0 ]
752+ assert commit_span ["origin" ] == "auto.db.django"
753+
754+
643755@pytest .mark .forked
644756@pytest_mark_django_db_decorator (transaction = True , databases = ["postgres" ])
645757def test_db_atomic_execute (sentry_init , client , capture_events ):
@@ -743,3 +855,109 @@ def test_db_atomic_executemany(sentry_init, client, capture_events):
743855 assert len (commit_spans ) == 1
744856 commit_span = commit_spans [0 ]
745857 assert commit_span ["origin" ] == "auto.db.django"
858+
859+
860+ @pytest .mark .forked
861+ @pytest_mark_django_db_decorator (transaction = True , databases = ["postgres" ])
862+ def test_db_atomic_rollback_execute (sentry_init , client , capture_events ):
863+ sentry_init (
864+ integrations = [DjangoIntegration ()],
865+ send_default_pii = True ,
866+ traces_sample_rate = 1.0 ,
867+ )
868+
869+ if "postgres" not in connections :
870+ pytest .skip ("postgres tests disabled" )
871+
872+ # trigger Django to open a new connection by marking the existing one as None.
873+ connections ["postgres" ].connection = None
874+
875+ events = capture_events ()
876+
877+ client .get (reverse ("postgres_insert_orm_atomic_rollback" ))
878+
879+ (event ,) = events
880+
881+ # Ensure operation is rolled back
882+ assert not User .objects .using ("postgres" ).exists ()
883+
884+ assert event ["contexts" ]["trace" ]["origin" ] == "auto.http.django"
885+
886+ commit_spans = [
887+ span
888+ for span in event ["spans" ]
889+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
890+ ]
891+ assert len (commit_spans ) == 1
892+ commit_span = commit_spans [0 ]
893+ assert commit_span ["origin" ] == "auto.db.django"
894+
895+
896+ @pytest .mark .forked
897+ @pytest_mark_django_db_decorator (transaction = True )
898+ def test_db_atomic_rollback_executemany (sentry_init , client , capture_events ):
899+ sentry_init (
900+ integrations = [DjangoIntegration ()],
901+ send_default_pii = True ,
902+ traces_sample_rate = 1.0 ,
903+ )
904+
905+ if "postgres" not in connections :
906+ pytest .skip ("postgres tests disabled" )
907+
908+ # trigger Django to open a new connection by marking the existing one as None.
909+ connections ["postgres" ].connection = None
910+
911+ events = capture_events ()
912+
913+ with start_transaction (name = "test_transaction" ):
914+ with transaction .atomic ():
915+ cursor = connection .cursor ()
916+
917+ query = """INSERT INTO auth_user (
918+ password,
919+ is_superuser,
920+ username,
921+ first_name,
922+ last_name,
923+ email,
924+ is_staff,
925+ is_active,
926+ date_joined
927+ )
928+ VALUES ('password', false, %s, %s, %s, %s, false, true, %s);"""
929+
930+ query_list = (
931+ (
932+ "user1" ,
933+ "John" ,
934+ "Doe" ,
935+ 936+ datetime (1970 , 1 , 1 ),
937+ ),
938+ (
939+ "user2" ,
940+ "Max" ,
941+ "Mustermann" ,
942+ 943+ datetime (1970 , 1 , 1 ),
944+ ),
945+ )
946+ cursor .executemany (query , query_list )
947+ transaction .set_rollback (True )
948+
949+ (event ,) = events
950+
951+ # Ensure operation is rolled back
952+ assert not User .objects .exists ()
953+
954+ assert event ["contexts" ]["trace" ]["origin" ] == "manual"
955+
956+ commit_spans = [
957+ span
958+ for span in event ["spans" ]
959+ if span ["data" ].get (SPANDATA .DB_OPERATION ) == DBOPERATION .ROLLBACK
960+ ]
961+ assert len (commit_spans ) == 1
962+ commit_span = commit_spans [0 ]
963+ assert commit_span ["origin" ] == "auto.db.django"
0 commit comments