@@ -2408,6 +2408,38 @@ def test_create_inferred_span(mock_span_finish, source, expect):
24082408 assert mock_span_finish .call_count == 0
24092409
24102410
2411+ @patch ("ddtrace.trace.Span.finish" , autospec = True )
2412+ def test_authorizer_span_no_negative_duration_when_clock_skew (mock_span_finish ):
2413+ """
2414+ Simulate the case where requestTimeEpoch + integrationLatency < parentSpanFinishTime
2415+ (i.e., API Gateway's reported end is before the authorizer lambda's self-reported finish).
2416+ This 1ms discrepancy would produce a negative duration.
2417+ """
2418+ with open (f"{ event_samples } authorizer-request-api-gateway-v1.json" ) as f :
2419+ event = json .load (f )
2420+
2421+ authorizer_ctx = json .loads (
2422+ base64 .b64decode (event ["requestContext" ]["authorizer" ]["_datadog" ])
2423+ )
2424+ parent_finish_time_ns = authorizer_ctx ["x-datadog-parent-span-finish-time" ]
2425+ request_time_epoch_ms = event ["requestContext" ]["requestTimeEpoch" ]
2426+ # Set integrationLatency 1ms below the parent span's finish time to simulate clock skew.
2427+ event ["requestContext" ]["authorizer" ]["integrationLatency" ] = (
2428+ parent_finish_time_ns // 1_000_000 - request_time_epoch_ms - 1
2429+ )
2430+
2431+ ctx = get_mock_context (aws_request_id = "123" )
2432+ create_inferred_span (event , ctx )
2433+
2434+ args = mock_span_finish .call_args_list [0 ].args
2435+ authorizer_span , finish_time = args [0 ], args [1 ]
2436+
2437+ assert finish_time >= authorizer_span .start , (
2438+ f"Authorizer span has negative duration: "
2439+ f"finish_time={ finish_time } < start={ authorizer_span .start } "
2440+ )
2441+
2442+
24112443class TestInferredSpans (unittest .TestCase ):
24122444 @patch ("datadog_lambda.tracing.submit_errors_metric" )
24132445 def test_mark_trace_as_error_for_5xx_responses_getting_400_response_code (
0 commit comments