1313# limitations under the License.
1414
1515import pytest
16-
17- from newrelic .api .background_task import background_task
18- from newrelic .api .function_trace import FunctionTrace
19- from newrelic .api .time_trace import notice_error
20- from newrelic .api .transaction import current_transaction
21- from newrelic .api .application import application_instance
22-
23- from newrelic .common .object_names import callable_name
24-
2516from testing_support .fixtures import (
2617 override_application_settings ,
2718 reset_core_stats_engine ,
2819 validate_error_event_attributes_outside_transaction ,
2920 validate_error_event_sample_data ,
3021 validate_error_trace_attributes_outside_transaction ,
22+ validate_time_metrics_outside_transaction ,
3123 validate_transaction_error_trace_attributes ,
3224 validate_transaction_errors ,
3325 validate_transaction_metrics ,
3426)
3527
28+ from newrelic .api .application import application_instance
29+ from newrelic .api .background_task import background_task
30+ from newrelic .api .time_trace import notice_error
31+ from newrelic .api .transaction import current_transaction
32+ from newrelic .common .object_names import callable_name
3633
3734_runtime_error_name = callable_name (RuntimeError )
3835_error_message = "Test error message."
4643ignore_runtime_error_settings = {
4744 "error_collector.ignore_classes" : [_runtime_error_name ]
4845}
49- combined_runtime_error_settings = {}
50- combined_runtime_error_settings .update (expected_runtime_error_settings )
51- combined_runtime_error_settings .update (ignore_runtime_error_settings )
5246
5347# Status code settings
5448expected_status_code_settings = {"error_collector.expected_status_codes" : [418 ]}
5549ignore_status_code_settings = {"error_collector.ignore_status_codes" : [418 ]}
56- combined_status_code_settings = {}
57- combined_status_code_settings .update (expected_status_code_settings )
58- combined_status_code_settings .update (ignore_status_code_settings )
5950
6051_test_runtime_error = [(_runtime_error_name , _error_message )]
6152_intrinsic_attributes = {
6455 "error.expected" : False ,
6556 "transactionName" : "OtherTransaction/Function/test" ,
6657}
67- _metrics_normal = [
68- ("Errors/all" , 1 ),
69- ("Errors/OtherTransaction/Function/test" , 1 ),
70- ("Errors/allOther" , 1 ),
71- ]
72-
7358
74- # =============== Test ignored/expected classes within transaction ===============
59+ # =============== Test ignored/expected classes ===============
7560
7661classes_settings_matrix = [
7762 ({}, False , False ),
7863 (ignore_runtime_error_settings , False , True ),
7964 (expected_runtime_error_settings , True , False ),
80- (combined_runtime_error_settings , False , True ),
8165]
8266override_expected_matrix = (True , False , None )
8367
8468
85- def exercise (expected = None , ignore = None , status_code = None ):
69+ def exercise (expected = None , ignore = None , status_code = None , application = None ):
8670 try :
8771 raise RuntimeError (_error_message )
8872 except RuntimeError :
89- if current_transaction () is not None :
73+ if current_transaction () is None :
9074 # Record exception inside transaction
91- notice_error (
92- expected = expected ,
93- ignore = ignore ,
94- status_code = status_code ,
95- )
96- else :
97- # Record exception outside context of transaction
98- application_instance ().notice_error (
99- expected = expected ,
100- ignore = ignore ,
101- status_code = status_code ,
102- )
75+ application = application or application_instance ()
10376
77+ notice_error (
78+ expected = expected ,
79+ ignore = ignore ,
80+ status_code = status_code ,
81+ application = application ,
82+ )
10483
105- @pytest .mark .parametrize ("settings,expected,ignore" , classes_settings_matrix )
106- @pytest .mark .parametrize ("override_expected" , override_expected_matrix )
107- def test_classes_error_event_inside_transaction (
108- settings , expected , ignore , override_expected
109- ):
110- expected = override_expected if override_expected is not None else expected
11184
85+ @pytest .mark .parametrize ("settings,expected,ignore" , classes_settings_matrix )
86+ def test_classes_error_event_inside_transaction (settings , expected , ignore ):
11287 # Update attributes with parameters
11388 attributes = _intrinsic_attributes .copy ()
11489 attributes ["error.expected" ] = expected
@@ -125,21 +100,13 @@ def test_classes_error_event_inside_transaction(
125100 @background_task (name = "test" )
126101 @override_application_settings (settings )
127102 def _test ():
128- exercise (override_expected )
103+ exercise ()
129104
130105 _test ()
131106
132107
133- # =============== Test ignored/expected classes outside transaction ===============
134-
135-
136108@pytest .mark .parametrize ("settings,expected,ignore" , classes_settings_matrix )
137- @pytest .mark .parametrize ("override_expected" , override_expected_matrix )
138- def test_classes_error_event_outside_transaction (
139- settings , expected , ignore , override_expected
140- ):
141- expected = override_expected if override_expected is not None else expected
142-
109+ def test_classes_error_event_outside_transaction (settings , expected , ignore ):
143110 # Update attributes with parameters
144111 attributes = _intrinsic_attributes .copy ()
145112 attributes ["error.expected" ] = expected
@@ -154,12 +121,15 @@ def test_classes_error_event_outside_transaction(
154121 )
155122 @override_application_settings (settings )
156123 def _test ():
157- exercise (override_expected )
124+ exercise ()
158125
159126 _test ()
160127
161128
162129# =============== Test error trace attributes ===============
130+ # Override testing is required to ensure the proper handling of
131+ # overrides. First attempt at implementation did not correctly handle this
132+ # and resulted in discrepancies between error events and traced errors.
163133
164134
165135error_trace_settings_matrix = [
@@ -213,8 +183,7 @@ def test_error_trace_attributes_outside_transaction(
213183
214184 @reset_core_stats_engine ()
215185 @validate_error_trace_attributes_outside_transaction (
216- _runtime_error_name ,
217- exact_attrs = error_trace_attributes
186+ _runtime_error_name , exact_attrs = error_trace_attributes
218187 )
219188 @override_application_settings (settings )
220189 def _test ():
@@ -226,18 +195,40 @@ def _test():
226195# =============== Test metrics not incremented ===============
227196
228197
229- @pytest .mark .skip ()
230- @pytest .mark .parametrize ("settings,expected,ignore" , classes_settings_matrix )
231- @pytest .mark .parametrize ("override_expected" , override_expected_matrix )
232- def test_classes_exception_metrics (settings , expected , ignore , override_expected ):
233- expected = override_expected or expected
234- metrics = _metrics_normal if not (expected or ignore ) else []
198+ @pytest .mark .parametrize ("expected" , override_expected_matrix )
199+ def test_error_metrics_inside_transaction (expected ):
200+ normal_metrics_count = None if expected else 1
201+ expected_metrics_count = 1 if expected else None
202+ metrics_payload = [
203+ ("Errors/all" , normal_metrics_count ),
204+ ("Errors/OtherTransaction/Function/test" , normal_metrics_count ),
205+ ("Errors/allOther" , normal_metrics_count ),
206+ ("ErrorsExpected/all" , expected_metrics_count ),
207+ ]
235208
236- @override_application_settings (settings )
237- @validate_transaction_metrics ("test" , background_task = True , rollup_metrics = metrics )
209+ @validate_transaction_metrics (
210+ "test" , background_task = True , rollup_metrics = metrics_payload
211+ )
238212 @background_task (name = "test" )
239213 def _test ():
240- exercise (override_expected )
214+ exercise (expected )
215+
216+ _test ()
217+
218+
219+ @pytest .mark .parametrize ("expected" , override_expected_matrix )
220+ def test_error_metrics_outside_transaction (expected ):
221+ normal_metrics_count = None if expected else 1
222+ expected_metrics_count = 1 if expected else None
223+ metrics_payload = [
224+ ("Errors/all" , normal_metrics_count ),
225+ ("ErrorsExpected/all" , expected_metrics_count ),
226+ ]
227+
228+ @reset_core_stats_engine ()
229+ @validate_time_metrics_outside_transaction (metrics_payload )
230+ def _test ():
231+ exercise (expected )
241232
242233 _test ()
243234
@@ -261,25 +252,19 @@ def retrieve_status_code(exc, value, tb):
261252 ({}, False , False ),
262253 (ignore_status_code_settings , False , True ),
263254 (expected_status_code_settings , True , False ),
264- (combined_status_code_settings , False , True ),
265255]
266256
267257status_code_matrix = [None , 418 , retrieve_status_code ]
268258
269259
270260@pytest .mark .parametrize ("settings,expected,ignore" , status_codes_settings_matrix )
271- @pytest .mark .parametrize ("override_expected" , override_expected_matrix )
272261@pytest .mark .parametrize ("status_code" , status_code_matrix )
273- def test_status_codes_inside_transaction (
274- settings , expected , ignore , override_expected , status_code
275- ):
262+ def test_status_codes_inside_transaction (settings , expected , ignore , status_code ):
276263 if status_code is None :
277264 # Override all settings
278265 ignore = False
279266 expected = False
280267
281- expected = override_expected if override_expected is not None else expected
282-
283268 # Update attributes with parameters
284269 attributes = _intrinsic_attributes .copy ()
285270 attributes ["error.expected" ] = expected
@@ -300,24 +285,19 @@ def _test():
300285 try :
301286 raise TeapotError (_error_message )
302287 except :
303- notice_error (expected = override_expected , status_code = status_code )
288+ notice_error (status_code = status_code )
304289
305290 _test ()
306291
307292
308293@pytest .mark .parametrize ("settings,expected,ignore" , status_codes_settings_matrix )
309- @pytest .mark .parametrize ("override_expected" , override_expected_matrix )
310294@pytest .mark .parametrize ("status_code" , status_code_matrix )
311- def test_status_codes_outside_transaction (
312- settings , expected , ignore , override_expected , status_code
313- ):
295+ def test_status_codes_outside_transaction (settings , expected , ignore , status_code ):
314296 if status_code is None :
315297 # Override all settings
316298 ignore = False
317299 expected = False
318300
319- expected = override_expected if override_expected is not None else expected
320-
321301 # Update attributes with parameters
322302 attributes = _intrinsic_attributes .copy ()
323303 attributes ["error.expected" ] = expected
@@ -336,24 +316,33 @@ def _test():
336316 try :
337317 raise TeapotError (_error_message )
338318 except :
339- notice_error (expected = override_expected , status_code = status_code )
319+ notice_error (status_code = status_code )
340320
341321 _test ()
342322
343323
344324# =============== Test mixed ignored and expected settings ===============
345325
326+ # Aggregate settings
346327ignore_status_code_expected_class_settings = {}
347328ignore_status_code_expected_class_settings .update (ignore_status_code_settings )
348329ignore_status_code_expected_class_settings .update (expected_runtime_error_settings )
349330expected_status_code_ignore_class_settings = {}
350331expected_status_code_ignore_class_settings .update (expected_status_code_settings )
351332expected_status_code_ignore_class_settings .update (ignore_runtime_error_settings )
333+ combined_runtime_error_settings = {}
334+ combined_runtime_error_settings .update (expected_runtime_error_settings )
335+ combined_runtime_error_settings .update (ignore_runtime_error_settings )
336+ combined_status_code_settings = {}
337+ combined_status_code_settings .update (expected_status_code_settings )
338+ combined_status_code_settings .update (ignore_status_code_settings )
352339
353340mixed_settings_matrix = [
354341 ({}, False , False ),
355342 (ignore_status_code_expected_class_settings , True , True ),
356343 (expected_status_code_ignore_class_settings , True , True ),
344+ (combined_runtime_error_settings , True , True ),
345+ (combined_status_code_settings , True , True ),
357346]
358347override_expected_matrix = (True , False , None )
359348override_ignore_matrix = (True , False , None )
0 commit comments