44from pydantic import ValidationError as PydanticValidationError
55from urllib3 import BaseHTTPResponse
66
7+ from sentry .seer .sentry_data_models import Span , TraceData , Transaction
78from sentry .tasks .llm_issue_detection import (
89 IssueDetectionResponse ,
910 detect_llm_issues_for_project ,
@@ -129,42 +130,59 @@ def test_detect_llm_issues_no_traces(self, mock_seer_api):
129130
130131 mock_seer_api .assert_not_called ()
131132
133+ @patch ("sentry.tasks.llm_issue_detection.get_trace_for_transaction" )
134+ @patch ("sentry.tasks.llm_issue_detection.get_transactions_for_project" )
135+ @patch ("sentry.tasks.llm_issue_detection.sentry_sdk.capture_exception" )
132136 @patch ("sentry.tasks.llm_issue_detection.logger" )
133137 def test_detect_llm_issues_multiple_transactions_partial_errors (
134- self , mock_logger , mock_seer_api
138+ self ,
139+ mock_logger ,
140+ mock_capture_exception ,
141+ mock_get_transactions ,
142+ mock_get_trace ,
143+ mock_seer_api ,
135144 ):
136145 """Test that errors in some transactions don't block processing of others."""
137146 transaction1_name = "transaction_1"
138147 trace_id_1 = uuid .uuid4 ().hex
139- spans1 = [
140- self .create_span (
141- {
142- "description" : "span-1" ,
143- "sentry_tags" : {"transaction" : transaction1_name },
144- "trace_id" : trace_id_1 ,
145- "parent_span_id" : None ,
146- "is_segment" : True ,
147- },
148- start_ts = self .ten_mins_ago ,
149- )
150- ]
151-
152148 transaction2_name = "transaction_2"
153149 trace_id_2 = uuid .uuid4 ().hex
154- spans2 = [
155- self .create_span (
156- {
157- "description" : "span-2" ,
158- "sentry_tags" : {"transaction" : transaction2_name },
159- "trace_id" : trace_id_2 ,
160- "parent_span_id" : None ,
161- "is_segment" : True ,
162- },
163- start_ts = self .ten_mins_ago ,
164- )
150+
151+ mock_get_transactions .return_value = [
152+ Transaction (name = transaction1_name , project_id = self .project .id ),
153+ Transaction (name = transaction2_name , project_id = self .project .id ),
165154 ]
166155
167- self .store_spans (spans1 + spans2 , is_eap = True )
156+ mock_get_trace .side_effect = [
157+ TraceData (
158+ trace_id = trace_id_1 ,
159+ project_id = self .project .id ,
160+ transaction_name = transaction1_name ,
161+ total_spans = 1 ,
162+ spans = [
163+ Span (
164+ span_id = "span1" ,
165+ parent_span_id = None ,
166+ span_op = "http" ,
167+ span_description = "test" ,
168+ )
169+ ],
170+ ),
171+ TraceData (
172+ trace_id = trace_id_2 ,
173+ project_id = self .project .id ,
174+ transaction_name = transaction2_name ,
175+ total_spans = 1 ,
176+ spans = [
177+ Span (
178+ span_id = "span2" ,
179+ parent_span_id = None ,
180+ span_op = "http" ,
181+ span_description = "test" ,
182+ )
183+ ],
184+ ),
185+ ]
168186
169187 error_response = Mock (spec = BaseHTTPResponse )
170188 error_response .status = 500
@@ -189,6 +207,13 @@ def test_detect_llm_issues_multiple_transactions_partial_errors(
189207 detect_llm_issues_for_project (self .project .id )
190208
191209 assert mock_seer_api .call_count == 2
210+ assert mock_capture_exception .call_count == 1
211+
212+ captured_exception = mock_capture_exception .call_args [0 ][0 ]
213+ assert captured_exception .project_id == self .project .id
214+ assert captured_exception .trace_id == trace_id_1
215+ assert captured_exception .status == 500
216+
192217 success_log_calls = [
193218 call
194219 for call in mock_logger .info .call_args_list
0 commit comments