@@ -534,5 +534,114 @@ public void IsLambdaEnvironment_WhenEnvironmentHasValue_ReturnsTrue()
534534 }
535535
536536 #endregion
537+
538+ #region XRayTraceId Tests
539+
540+ [ Fact ]
541+ public void XRayTraceId_WhenLambdaTraceProviderAvailable_ReturnsTraceId ( )
542+ {
543+ ResetTraceProviderState ( ) ;
544+
545+ try
546+ {
547+ // Arrange
548+ var environment = Substitute . For < IPowertoolsEnvironment > ( ) ;
549+ var configurations = new PowertoolsConfigurations ( environment ) ;
550+
551+ // Act - LambdaTraceProvider is available in test env (Amazon.Lambda.Core 2.8.0)
552+ // Returns null/empty in test env (no active Lambda trace), but should not throw
553+ var result = configurations . XRayTraceId ;
554+
555+ // Assert - should not fall back to env var (provider was used instead)
556+ environment . DidNotReceive ( )
557+ . GetEnvironmentVariable ( Arg . Is < string > ( i => i == Constants . XrayTraceIdEnv ) ) ;
558+ }
559+ finally
560+ {
561+ ResetTraceProviderState ( ) ;
562+ }
563+ }
564+
565+ [ Fact ]
566+ public void XRayTraceId_WhenLambdaTraceProviderUnavailable_FallsBackToEnvironmentVariable ( )
567+ {
568+ ResetTraceProviderState ( ) ;
569+
570+ try
571+ {
572+ // Arrange
573+ var traceId = "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1" ;
574+ var environment = Substitute . For < IPowertoolsEnvironment > ( ) ;
575+ environment . GetEnvironmentVariable ( Constants . XrayTraceIdEnv ) . Returns ( traceId ) ;
576+ var configurations = new PowertoolsConfigurations ( environment ) ;
577+
578+ // Simulate LambdaTraceProvider not being available (older Amazon.Lambda.Core)
579+ SetTraceProviderState ( - 1 ) ;
580+
581+ // Act
582+ var result = configurations . XRayTraceId ;
583+
584+ // Assert
585+ environment . Received ( 1 )
586+ . GetEnvironmentVariable ( Arg . Is < string > ( i => i == Constants . XrayTraceIdEnv ) ) ;
587+ Assert . Equal ( traceId , result ) ;
588+ }
589+ finally
590+ {
591+ ResetTraceProviderState ( ) ;
592+ }
593+ }
594+
595+ [ Fact ]
596+ public void XRayTraceId_WhenProviderCachedUnavailable_UsesEnvVarOnSubsequentCalls ( )
597+ {
598+ ResetTraceProviderState ( ) ;
599+
600+ try
601+ {
602+ // Arrange
603+ var environment = Substitute . For < IPowertoolsEnvironment > ( ) ;
604+ var configurations = new PowertoolsConfigurations ( environment ) ;
605+
606+ // Simulate LambdaTraceProvider not being available (cached)
607+ SetTraceProviderState ( - 1 ) ;
608+
609+ var traceId1 = "Root=1-aaa;Parent=bbb;Sampled=1" ;
610+ var traceId2 = "Root=1-ccc;Parent=ddd;Sampled=1" ;
611+ environment . GetEnvironmentVariable ( Constants . XrayTraceIdEnv ) . Returns ( traceId1 , traceId2 ) ;
612+
613+ // Act
614+ var result1 = configurations . XRayTraceId ;
615+ var result2 = configurations . XRayTraceId ;
616+
617+ // Assert - should go straight to env var on both calls (cached unavailable)
618+ environment . Received ( 2 )
619+ . GetEnvironmentVariable ( Arg . Is < string > ( i => i == Constants . XrayTraceIdEnv ) ) ;
620+ Assert . Equal ( traceId1 , result1 ) ;
621+ Assert . Equal ( traceId2 , result2 ) ;
622+ }
623+ finally
624+ {
625+ ResetTraceProviderState ( ) ;
626+ }
627+ }
628+
629+ private static void ResetTraceProviderState ( )
630+ {
631+ var field = typeof ( PowertoolsConfigurations ) . GetField ( "_traceProviderState" ,
632+ System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Static ) ;
633+ Assert . NotNull ( field ) ;
634+ field . SetValue ( null , 0 ) ;
635+ }
636+
637+ private static void SetTraceProviderState ( int state )
638+ {
639+ var field = typeof ( PowertoolsConfigurations ) . GetField ( "_traceProviderState" ,
640+ System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Static ) ;
641+ Assert . NotNull ( field ) ;
642+ field . SetValue ( null , state ) ;
643+ }
644+
645+ #endregion
537646 }
538647}
0 commit comments