@@ -128,6 +128,91 @@ describe("middleware-recursion-detection", () => {
128128 expect . hasAssertions ( ) ;
129129 } ) ;
130130
131+ it ( "should NOT overwrite existing traceparent or add tracestate/baggage from InvokeStore when traceparent is already set" , async ( ) => {
132+ const existingTraceparent = "00-abcdef1234567890abcdef1234567890-1234567890abcdef-01" ;
133+ const mockTraceparent = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" ;
134+ const mockTracestate = "congo=t61rcWkgMzE" ;
135+ const mockBaggage = "userId=alice,serverNode=DF%2028" ;
136+ vi . spyOn ( InvokeStore , "getInstanceAsync" ) . mockResolvedValue ( {
137+ getXRayTraceId : ( ) => undefined ,
138+ getTraceparent : ( ) => mockTraceparent ,
139+ getTracestate : ( ) => mockTracestate ,
140+ getBaggage : ( ) => mockBaggage ,
141+ } as any ) ;
142+
143+ const client = new Lambda ( {
144+ region : "us-west-2" ,
145+ } ) ;
146+
147+ // Add middleware that sets traceparent before recursion detection runs.
148+ // recursionDetectionMiddleware runs at build step with low priority,
149+ // so we add at build step with high priority to run first.
150+ client . middlewareStack . add (
151+ ( next ) => async ( args : any ) => {
152+ args . request . headers [ "traceparent" ] = existingTraceparent ;
153+ return next ( args ) ;
154+ } ,
155+ { step : "build" , priority : "high" , name : "testSetTraceparent" , override : true }
156+ ) ;
157+
158+ requireRequestsFrom ( client ) . toMatch ( {
159+ headers : {
160+ traceparent : new RegExp ( `^${ existingTraceparent . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) } $` ) ,
161+ tracestate : ( value : any ) => expect ( value ) . toBeUndefined ( ) ,
162+ baggage : ( value : any ) => expect ( value ) . toBeUndefined ( ) ,
163+ } ,
164+ } ) ;
165+
166+ await client . invoke ( {
167+ FunctionName : "my-function" ,
168+ } ) ;
169+
170+ expect . hasAssertions ( ) ;
171+ } ) ;
172+
173+ it ( "should preserve existing traceparent, tracestate, and baggage without overwriting from InvokeStore" , async ( ) => {
174+ const existingTraceparent = "00-abcdef1234567890abcdef1234567890-1234567890abcdef-01" ;
175+ const existingTracestate = "vendor1=opaqueValue1" ;
176+ const existingBaggage = "key1=value1" ;
177+ const mockTraceparent = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" ;
178+ const mockTracestate = "congo=t61rcWkgMzE" ;
179+ const mockBaggage = "userId=alice,serverNode=DF%2028" ;
180+ vi . spyOn ( InvokeStore , "getInstanceAsync" ) . mockResolvedValue ( {
181+ getXRayTraceId : ( ) => undefined ,
182+ getTraceparent : ( ) => mockTraceparent ,
183+ getTracestate : ( ) => mockTracestate ,
184+ getBaggage : ( ) => mockBaggage ,
185+ } as any ) ;
186+
187+ const client = new Lambda ( {
188+ region : "us-west-2" ,
189+ } ) ;
190+
191+ client . middlewareStack . add (
192+ ( next ) => async ( args : any ) => {
193+ args . request . headers [ "traceparent" ] = existingTraceparent ;
194+ args . request . headers [ "tracestate" ] = existingTracestate ;
195+ args . request . headers [ "baggage" ] = existingBaggage ;
196+ return next ( args ) ;
197+ } ,
198+ { step : "build" , priority : "high" , name : "testSetTraceHeaders" , override : true }
199+ ) ;
200+
201+ requireRequestsFrom ( client ) . toMatch ( {
202+ headers : {
203+ traceparent : new RegExp ( `^${ existingTraceparent . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) } $` ) ,
204+ tracestate : new RegExp ( `^${ existingTracestate . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) } $` ) ,
205+ baggage : new RegExp ( `^${ existingBaggage . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) } $` ) ,
206+ } ,
207+ } ) ;
208+
209+ await client . invoke ( {
210+ FunctionName : "my-function" ,
211+ } ) ;
212+
213+ expect . hasAssertions ( ) ;
214+ } ) ;
215+
131216 it ( "should NOT add W3C headers when InvokeStore has no traceparent" , async ( ) => {
132217 vi . spyOn ( InvokeStore , "getInstanceAsync" ) . mockResolvedValue ( {
133218 getXRayTraceId : ( ) => undefined ,
0 commit comments