Skip to content

Commit 4969e6e

Browse files
committed
more code coverage
1 parent ec5d23a commit 4969e6e

File tree

2 files changed

+243
-0
lines changed

2 files changed

+243
-0
lines changed

libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/EntityLevelSanitizationTests.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,100 @@ public void SanitizeEntityHttpInformation_WithNullHttp_HandlesGracefully()
281281
Assert.Fail($"EndSubsegment with null HTTP info should not throw: {ex.Message}");
282282
}
283283
}
284+
285+
[Fact]
286+
public void SanitizeEntityAnnotations_WithAnnotationSanitizationError_HandlesGracefully()
287+
{
288+
// Arrange
289+
var mockAwsXRayRecorder = Substitute.For<IAWSXRayRecorder>();
290+
var mockConfigurations = Substitute.For<IPowertoolsConfigurations>();
291+
mockConfigurations.IsLambdaEnvironment.Returns(true);
292+
293+
// Create a subsegment with annotations that will be sanitized
294+
var subsegment = new Subsegment("TestSegment");
295+
subsegment.AddAnnotation("test_key", "test_value");
296+
297+
var mockTraceContext = Substitute.For<Amazon.XRay.Recorder.Core.Internal.Context.ITraceContext>();
298+
mockTraceContext.GetEntity().Returns(subsegment);
299+
mockAwsXRayRecorder.TraceContext.Returns(mockTraceContext);
300+
301+
var recorder = new XRayRecorder(mockAwsXRayRecorder, mockConfigurations);
302+
303+
// Act & Assert - Should not throw even if annotation sanitization encounters issues
304+
try
305+
{
306+
recorder.EndSubsegment();
307+
308+
// Verify that EndSubsegment was called
309+
mockAwsXRayRecorder.Received(1).EndSubsegment();
310+
}
311+
catch (Exception ex)
312+
{
313+
Assert.Fail($"EndSubsegment with annotation sanitization should not throw: {ex.Message}");
314+
}
315+
}
316+
317+
[Fact]
318+
public void SanitizeEntityHttpInformation_WithHttpSanitizationError_HandlesGracefully()
319+
{
320+
// Arrange
321+
var mockAwsXRayRecorder = Substitute.For<IAWSXRayRecorder>();
322+
var mockConfigurations = Substitute.For<IPowertoolsConfigurations>();
323+
mockConfigurations.IsLambdaEnvironment.Returns(true);
324+
325+
// Create a subsegment (HTTP info is handled internally by X-Ray SDK)
326+
var subsegment = new Subsegment("TestSegment");
327+
328+
var mockTraceContext = Substitute.For<Amazon.XRay.Recorder.Core.Internal.Context.ITraceContext>();
329+
mockTraceContext.GetEntity().Returns(subsegment);
330+
mockAwsXRayRecorder.TraceContext.Returns(mockTraceContext);
331+
332+
var recorder = new XRayRecorder(mockAwsXRayRecorder, mockConfigurations);
333+
334+
// Act & Assert - Should not throw even if HTTP sanitization encounters issues
335+
try
336+
{
337+
recorder.EndSubsegment();
338+
339+
// Verify that EndSubsegment was called
340+
mockAwsXRayRecorder.Received(1).EndSubsegment();
341+
}
342+
catch (Exception ex)
343+
{
344+
Assert.Fail($"EndSubsegment with HTTP sanitization should not throw: {ex.Message}");
345+
}
346+
}
347+
348+
[Fact]
349+
public void SanitizeEntityMetadata_WithMetadataSanitizationError_HandlesGracefully()
350+
{
351+
// Arrange
352+
var mockAwsXRayRecorder = Substitute.For<IAWSXRayRecorder>();
353+
var mockConfigurations = Substitute.For<IPowertoolsConfigurations>();
354+
mockConfigurations.IsLambdaEnvironment.Returns(true);
355+
356+
// Create a subsegment with metadata that needs sanitization
357+
var subsegment = new Subsegment("TestSegment");
358+
subsegment.AddMetadata("test_namespace", "problematic_key", 42ul); // ulong needs sanitization
359+
subsegment.AddMetadata("test_namespace", "guid_key", Guid.NewGuid()); // Guid needs sanitization
360+
361+
var mockTraceContext = Substitute.For<Amazon.XRay.Recorder.Core.Internal.Context.ITraceContext>();
362+
mockTraceContext.GetEntity().Returns(subsegment);
363+
mockAwsXRayRecorder.TraceContext.Returns(mockTraceContext);
364+
365+
var recorder = new XRayRecorder(mockAwsXRayRecorder, mockConfigurations);
366+
367+
// Act & Assert - Should not throw even if metadata sanitization encounters issues
368+
try
369+
{
370+
recorder.EndSubsegment();
371+
372+
// Verify that EndSubsegment was called
373+
mockAwsXRayRecorder.Received(1).EndSubsegment();
374+
}
375+
catch (Exception ex)
376+
{
377+
Assert.Fail($"EndSubsegment with metadata sanitization should not throw: {ex.Message}");
378+
}
379+
}
284380
}

libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderSanitizationAdvancedTests.cs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,105 @@ public void AddMetadata_WithMaxDepthReached_ReturnsMaxDepthMessage()
376376
_mockAwsXRayRecorder.Received(1).AddMetadata("test", "very_deep", Arg.Any<object>());
377377
}
378378

379+
[Fact]
380+
public void SanitizeValueForMetadata_WithObjectThatThrowsInToString_ReturnsSanitizationFailedMessage()
381+
{
382+
// Arrange - Create an object that throws during ToString and during sanitization
383+
var problematicObject = new ObjectThatThrowsEverywhere();
384+
385+
// Act & Assert - Should not throw, should handle gracefully
386+
_xrayRecorder.AddMetadata("test", "throws_everywhere", problematicObject);
387+
388+
// Verify the call was made with sanitized data
389+
_mockAwsXRayRecorder.Received(1).AddMetadata("test", "throws_everywhere", Arg.Any<object>());
390+
}
391+
392+
[Fact]
393+
public void SanitizeValueForMetadata_WithObjectThatThrowsInSanitization_CatchesException()
394+
{
395+
// Arrange - Create an object that will cause an exception during the sanitization process itself
396+
var objectThatCausesRecursionError = new ObjectWithCircularToStringReference();
397+
398+
// Act & Assert - Should not throw, should return sanitization failed message
399+
_xrayRecorder.AddMetadata("test", "recursion_error", objectThatCausesRecursionError);
400+
401+
// Verify the call was made (the sanitization error should be caught and handled)
402+
_mockAwsXRayRecorder.Received(1).AddMetadata("test", "recursion_error", Arg.Any<object>());
403+
}
404+
405+
[Fact]
406+
public void AddMetadata_WithUnsafeArrayElements_TriggersArraySanitization()
407+
{
408+
// Arrange - Create array with mixed safe and unsafe elements to trigger IsArrayElementsSafe check
409+
var mixedArray = new object[]
410+
{
411+
"safe_string",
412+
42,
413+
42ul, // This will trigger NeedsTypeSanitization = true
414+
new IntPtr(123), // This will also trigger sanitization
415+
true
416+
};
417+
418+
// Act
419+
_xrayRecorder.AddMetadata("test", "mixed_array", mixedArray);
420+
421+
// Assert - Should call with sanitized array
422+
_mockAwsXRayRecorder.Received(1).AddMetadata("test", "mixed_array", Arg.Any<object>());
423+
}
424+
425+
[Fact]
426+
public void AddMetadata_WithSpecificUnsafeArrayType_TriggersIsArrayElementsSafeCheck()
427+
{
428+
// Arrange - Create a typed array that is NOT in the known safe list but has unsafe elements
429+
// This will force the code to call IsArrayElementsSafe and return false
430+
var unsafeTypedArray = new uint[] { 1u, 2u, 3u }; // uint[] is not in IsKnownSafeArrayType
431+
432+
// Act
433+
_xrayRecorder.AddMetadata("test", "unsafe_typed_array", unsafeTypedArray);
434+
435+
// Assert - Should call with sanitized array
436+
_mockAwsXRayRecorder.Received(1).AddMetadata("test", "unsafe_typed_array", Arg.Any<object>());
437+
}
438+
439+
[Fact]
440+
public void AddMetadata_WithEntityContainingAnnotations_SanitizesAnnotations()
441+
{
442+
// This test will be handled in EntityLevelSanitizationTests since it requires entity manipulation
443+
// But we can test the annotation sanitization indirectly through EndSubsegment
444+
445+
// Arrange - Create a subsegment with annotations that need sanitization
446+
var subsegment = new Subsegment("TestSegment");
447+
subsegment.AddAnnotation("safe_annotation", "safe_value");
448+
subsegment.AddAnnotation("numeric_annotation", 42);
449+
450+
var mockTraceContext = Substitute.For<Amazon.XRay.Recorder.Core.Internal.Context.ITraceContext>();
451+
mockTraceContext.GetEntity().Returns(subsegment);
452+
_mockAwsXRayRecorder.TraceContext.Returns(mockTraceContext);
453+
454+
// Act - This will trigger entity sanitization including annotations
455+
_xrayRecorder.EndSubsegment();
456+
457+
// Assert
458+
_mockAwsXRayRecorder.Received(1).EndSubsegment();
459+
}
460+
461+
[Fact]
462+
public void AddMetadata_WithEntityContainingHttpInfo_SanitizesHttpInfo()
463+
{
464+
// Arrange - Create a subsegment (HTTP info will be tested in EntityLevelSanitizationTests)
465+
var subsegment = new Subsegment("TestSegment");
466+
467+
var mockTraceContext = Substitute.For<Amazon.XRay.Recorder.Core.Internal.Context.ITraceContext>();
468+
mockTraceContext.GetEntity().Returns(subsegment);
469+
_mockAwsXRayRecorder.TraceContext.Returns(mockTraceContext);
470+
471+
// Act - This will trigger entity sanitization including HTTP info
472+
_xrayRecorder.EndSubsegment();
473+
474+
// Assert
475+
_mockAwsXRayRecorder.Received(1).EndSubsegment();
476+
}
477+
379478
public enum TestEnum
380479
{
381480
Value1,
@@ -398,6 +497,54 @@ public override string ToString()
398497
}
399498
}
400499

500+
public class ObjectThatThrowsEverywhere
501+
{
502+
public string ProblematicProperty
503+
{
504+
get => throw new Exception("Property access failed");
505+
}
506+
507+
public override string ToString()
508+
{
509+
throw new Exception("ToString failed");
510+
}
511+
512+
public override int GetHashCode()
513+
{
514+
throw new Exception("GetHashCode failed");
515+
}
516+
}
517+
518+
public class ObjectWithCircularToStringReference
519+
{
520+
private static int _toStringCallCount = 0;
521+
522+
public ObjectWithCircularToStringReference Self { get; set; }
523+
524+
public ObjectWithCircularToStringReference()
525+
{
526+
Self = this; // Create circular reference
527+
}
528+
529+
public override string ToString()
530+
{
531+
// Prevent infinite recursion by limiting calls
532+
if (++_toStringCallCount > 5)
533+
{
534+
throw new StackOverflowException("Simulated stack overflow during ToString");
535+
}
536+
537+
try
538+
{
539+
return $"Object with self: {Self}";
540+
}
541+
finally
542+
{
543+
_toStringCallCount--;
544+
}
545+
}
546+
}
547+
401548
public class TestObjectWithReference
402549
{
403550
public string Name { get; set; }

0 commit comments

Comments
 (0)