diff --git a/test/Cuemon.Diagnostics.Tests/TimeMeasureTest.cs b/test/Cuemon.Diagnostics.Tests/TimeMeasureTest.cs index c6ba1678..0ab17e83 100644 --- a/test/Cuemon.Diagnostics.Tests/TimeMeasureTest.cs +++ b/test/Cuemon.Diagnostics.Tests/TimeMeasureTest.cs @@ -11,19 +11,25 @@ namespace Cuemon.Diagnostics public class TimeMeasureTest : Test { private static readonly TimeSpan ExpectedExecutionTime = TimeSpan.FromSeconds(1); - private static readonly TimeSpan Jitter = TimeSpan.FromMilliseconds(250); + private static readonly TimeSpan LowerJitter = TimeSpan.FromMilliseconds(250); + private static readonly TimeSpan UpperJitter = TimeSpan.FromMilliseconds(500); public TimeMeasureTest(ITestOutputHelper output) : base(output) { } + private static void AssertElapsedAround(TimeSpan actual, TimeSpan expected) + { + Assert.InRange(actual, expected.Subtract(LowerJitter), expected.Add(UpperJitter)); + } + [Fact] public void WithAction_Use_0_Arguments_ShouldTakeAroundOneSecond() { var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction(() => Thread.Sleep(expected)); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.False(profiler.Member.HasParameters()); Assert.Empty(profiler.Data); @@ -37,7 +43,7 @@ public void WithAction_Use_1_Argument_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction(a1 => Thread.Sleep(expected), 1); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Contains(profiler.Data.Values, o => o is int i && i == 1); @@ -52,7 +58,7 @@ public void WithAction_Use_2_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2) => Thread.Sleep(expected), 1, 2); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, i => Assert.Equal(1, i), i => Assert.Equal(2, i)); @@ -67,7 +73,7 @@ public void WithAction_Use_3_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3) => Thread.Sleep(expected), 1, 2, 3); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -85,7 +91,7 @@ public void WithAction_Use_4_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4) => Thread.Sleep(expected), 1, 2, 3, 4); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -104,7 +110,7 @@ public void WithAction_Use_5_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4, a5) => Thread.Sleep(expected), 1, 2, 3, 4, 5); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -124,7 +130,7 @@ public void WithAction_Use_6_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4, a5, a6) => Thread.Sleep(expected), 1, 2, 3, 4, 5, 6); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -145,7 +151,7 @@ public void WithAction_Use_7_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4, a5, a6, a7) => Thread.Sleep(expected), 1, 2, 3, 4, 5, 6, 7); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -167,7 +173,7 @@ public void WithAction_Use_8_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4, a5, a6, a7, a8) => Thread.Sleep(expected), 1, 2, 3, 4, 5, 6, 7, 8); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -190,7 +196,7 @@ public void WithAction_Use_9_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4, a5, a6, a7, a8, a9) => Thread.Sleep(expected), 1, 2, 3, 4, 5, 6, 7, 8, 9); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -214,7 +220,7 @@ public void WithAction_Use_10_Arguments_ShouldTakeAroundOneSecond() var expected = ExpectedExecutionTime; var profiler = TimeMeasure.WithAction((a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) => Thread.Sleep(expected), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -245,7 +251,7 @@ public void WithFunc_Use_0_Arguments_ShouldTakeAroundOneSecond() }); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.False(profiler.Member.HasParameters()); Assert.Empty(profiler.Data); @@ -265,7 +271,7 @@ public void WithFunc_Use_1_Argument_ShouldTakeAroundOneSecond() }, 1); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -287,7 +293,7 @@ public void WithFunc_Use_2_Arguments_ShouldTakeAroundOneSecond() }, 1, 2); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -310,7 +316,7 @@ public void WithFunc_Use_3_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -334,7 +340,7 @@ public void WithFunc_Use_4_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -359,7 +365,7 @@ public void WithFunc_Use_5_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4, 5); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -385,7 +391,7 @@ public void WithFunc_Use_6_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4, 5, 6); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -412,7 +418,7 @@ public void WithFunc_Use_7_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4, 5, 6, 7); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -440,7 +446,7 @@ public void WithFunc_Use_8_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4, 5, 6, 7, 8); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -469,7 +475,7 @@ public void WithFunc_Use_9_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4, 5, 6, 7, 8, 9); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -498,7 +504,7 @@ public void WithFunc_Use_10_Arguments_ShouldTakeAroundOneSecond() }, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.NotEmpty(profiler.Data); Assert.Collection(profiler.Data.Values, @@ -530,7 +536,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync(token => Task.Delay(expected, token), o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.Empty(profiler.Data); @@ -552,7 +558,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a, token) => Task.Delay(expected, token), 1, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -576,7 +582,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, token) => Task.Delay(expected, token), 1, 2, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -601,7 +607,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, token) => Task.Delay(expected, token), 1, 2, 3, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -627,7 +633,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, token) => Task.Delay(expected, token), 1, 2, 3, 4, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -654,7 +660,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, a5, token) => Task.Delay(expected, token), 1, 2, 3, 4, 5, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -682,7 +688,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, a5, a6, token) => Task.Delay(expected, token), 1, 2, 3, 4, 5, 6, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -711,7 +717,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, a5, a6, a7, token) => Task.Delay(expected, token), 1, 2, 3, 4, 5, 6, 7, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -741,7 +747,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, a5, a6, a7, a8, token) => Task.Delay(expected, token), 1, 2, 3, 4, 5, 6, 7, 8, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -772,7 +778,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, a5, a6, a7, a8, a9, token) => Task.Delay(expected, token), 1, 2, 3, 4, 5, 6, 7, 8, 9, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -804,7 +810,7 @@ await Assert.ThrowsAnyAsync(async () => }); var profiler = await TimeMeasure.WithActionAsync((a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, token) => Task.Delay(expected, token), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, o => o.CancellationToken = ctsShouldPass.Token); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -847,7 +853,7 @@ await TimeMeasure.WithFuncAsync(async token => }, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.Empty(profiler.Data); @@ -879,7 +885,7 @@ await TimeMeasure.WithFuncAsync(async (a, token) => }, 1, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -913,7 +919,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, token) => }, 1, 2, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -948,7 +954,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, token) => }, 1, 2, 3, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -984,7 +990,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, token) => }, 1, 2, 3, 4, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -1021,7 +1027,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, a5, token) => }, 1, 2, 3, 4, 5, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -1059,7 +1065,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, a5, a6, token) => }, 1, 2, 3, 4, 5, 6, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -1098,7 +1104,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, a5, a6, a7, token) => }, 1, 2, 3, 4, 5, 6, 7, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -1138,7 +1144,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, a5, a6, a7, a8, token) => }, 1, 2, 3, 4, 5, 6, 7, 8, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -1179,7 +1185,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, a5, a6, a7, a8, a9, token }, 1, 2, 3, 4, 5, 6, 7, 8, 9, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); @@ -1221,7 +1227,7 @@ await TimeMeasure.WithFuncAsync(async (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, }, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, o => o.CancellationToken = ctsShouldPass.Token); Assert.Equal(42, profiler.Result); - Assert.InRange(profiler.Elapsed, expected.Subtract(Jitter), expected.Add(Jitter)); + AssertElapsedAround(profiler.Elapsed, expected); Assert.True(profiler.Member.HasParameters()); Assert.Contains(profiler.Member.Parameters, item => item.ParameterName == "token" && item.ParameterType == typeof(CancellationToken)); Assert.NotEmpty(profiler.Data); diff --git a/test/Cuemon.Extensions.Net.Tests/Http/UriExtensionsTest.cs b/test/Cuemon.Extensions.Net.Tests/Http/UriExtensionsTest.cs index f47b1a94..5bf1ab47 100644 --- a/test/Cuemon.Extensions.Net.Tests/Http/UriExtensionsTest.cs +++ b/test/Cuemon.Extensions.Net.Tests/Http/UriExtensionsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net; using System.Net.Http; using System.Threading; @@ -13,18 +13,14 @@ public class UriExtensionsTest : Test { public UriExtensionsTest(ITestOutputHelper output) : base(output) { - UriExtensions.DefaultHttpClientFactory = new SlimHttpClientFactory(() => new HttpClientHandler() - { - AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, - MaxAutomaticRedirections = 10 - }, o => o.HandlerLifetime = TimeSpan.MinValue); } [Fact] public async Task HttpGetAsync_ShouldGetResponseFromUri() { - // Test SlimHttpClientFactory robustness under parallel load using a reliable external server - var uri = new Uri("https://httpbin.org/status/200"); + var factory = new StatusCodeHttpClientFactory(HttpStatusCode.OK); + UriExtensions.DefaultHttpClientFactory = factory; + var uri = new Uri("https://example.com/200"); var expected = 125; var atomicCount = 0; @@ -38,13 +34,15 @@ await ParallelFactory.ForAsync(0, expected, async (i, ct) => }); Assert.Equal(expected, atomicCount); + Assert.Equal(expected, factory.RequestCount); } [Fact] public async Task HttpGetAsync_ShouldHandleHttpStatusCodes() { - // Test that the extension method properly returns non-OK status codes under parallel load - var uri = new Uri("https://httpbin.org/status/404"); + var factory = new StatusCodeHttpClientFactory(HttpStatusCode.NotFound); + UriExtensions.DefaultHttpClientFactory = factory; + var uri = new Uri("https://example.com/404"); var expected = 50; var atomicCount = 0; @@ -58,6 +56,52 @@ await ParallelFactory.ForAsync(0, expected, async (i, ct) => }); Assert.Equal(expected, atomicCount); + Assert.Equal(expected, factory.RequestCount); + } + + private sealed class StatusCodeHttpClientFactory : IHttpClientFactory + { + private int _requestCount; + private readonly HttpStatusCode _statusCode; + + public StatusCodeHttpClientFactory(HttpStatusCode statusCode) + { + _statusCode = statusCode; + } + + public int RequestCount => _requestCount; + + public HttpClient CreateClient(string name) + { + return new HttpClient(new StatusCodeHttpMessageHandler(this, _statusCode)); + } + + private void IncrementRequestCount() + { + Interlocked.Increment(ref _requestCount); + } + + private sealed class StatusCodeHttpMessageHandler : HttpMessageHandler + { + private readonly StatusCodeHttpClientFactory _factory; + private readonly HttpStatusCode _statusCode; + + public StatusCodeHttpMessageHandler(StatusCodeHttpClientFactory factory, HttpStatusCode statusCode) + { + _factory = factory; + _statusCode = statusCode; + } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + _factory.IncrementRequestCount(); + return Task.FromResult(new HttpResponseMessage(_statusCode) + { + Content = new ByteArrayContent(Array.Empty()), + RequestMessage = request + }); + } + } } } -} \ No newline at end of file +} diff --git a/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs b/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs index a55e5a91..af586734 100644 --- a/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs +++ b/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs @@ -25,6 +25,7 @@ public class SlimMemoryCacheTest : HostTest private const string Dependency60Namespace = "Dependency60"; private const int NumberOfItemsToCache = 1000; + private static readonly TimeSpan CleanupTimeout = TimeSpan.FromSeconds(15); public SlimMemoryCacheTest(ManagedHostFixture hostFixture, ITestOutputHelper output = null) : base(hostFixture, output) { @@ -230,19 +231,17 @@ public void Add_VerifyBothLogicalAndActualCacheRemovalUponExpirationForThirtySec { Thread.Sleep(TimeSpan.FromSeconds(30)); - Assert.Equal(0, _cache.Count(Dependency30Namespace)); - Assert.Equal(0, _cache.Count(Sliding30Namespace)); - Assert.Equal(0, _cache.Count(Absolute30Namespace)); + AssertNamespaceIsLogicallyExpired(Dependency30Namespace); + AssertNamespaceIsLogicallyExpired(Sliding30Namespace); + AssertNamespaceIsLogicallyExpired(Absolute30Namespace); - Assert.Equal(NumberOfItemsToCache, _cache.Where(pair => pair.Value.Namespace == Dependency30Namespace).ToList().Count); - Assert.Equal(NumberOfItemsToCache, _cache.Where(pair => pair.Value.Namespace == Sliding30Namespace).ToList().Count); - Assert.Equal(NumberOfItemsToCache, _cache.Where(pair => pair.Value.Namespace == Absolute30Namespace).ToList().Count); + AssertNamespaceIsPhysicallyPresent(Dependency30Namespace); + AssertNamespaceIsPhysicallyPresent(Sliding30Namespace); + AssertNamespaceIsPhysicallyPresent(Absolute30Namespace); - Thread.Sleep(TimeSpan.FromSeconds(10)); - - Assert.Equal(0, _cache.Where(pair => pair.Value.Namespace == Dependency30Namespace).ToList().Count); - Assert.Equal(0, _cache.Where(pair => pair.Value.Namespace == Sliding30Namespace).ToList().Count); - Assert.Equal(0, _cache.Where(pair => pair.Value.Namespace == Absolute30Namespace).ToList().Count); + AssertNamespaceIsPhysicallyRemoved(Dependency30Namespace); + AssertNamespaceIsPhysicallyRemoved(Sliding30Namespace); + AssertNamespaceIsPhysicallyRemoved(Absolute30Namespace); } [Fact, Priority(9)] @@ -250,19 +249,17 @@ public void Add_VerifyBothLogicalAndActualCacheRemovalUponExpirationForSixtySeco { Thread.Sleep(TimeSpan.FromSeconds(20)); - Assert.Equal(0, _cache.Count(Dependency60Namespace)); - Assert.Equal(0, _cache.Count(Sliding60Namespace)); - Assert.Equal(0, _cache.Count(Absolute60Namespace)); - - Assert.Equal(NumberOfItemsToCache, _cache.Where(pair => pair.Value.Namespace == Dependency60Namespace).ToList().Count); - Assert.Equal(NumberOfItemsToCache, _cache.Where(pair => pair.Value.Namespace == Sliding60Namespace).ToList().Count); - Assert.Equal(NumberOfItemsToCache, _cache.Where(pair => pair.Value.Namespace == Absolute60Namespace).ToList().Count); + AssertNamespaceIsLogicallyExpired(Dependency60Namespace); + AssertNamespaceIsLogicallyExpired(Sliding60Namespace); + AssertNamespaceIsLogicallyExpired(Absolute60Namespace); - Thread.Sleep(TimeSpan.FromSeconds(10)); + AssertNamespaceIsPhysicallyPresent(Dependency60Namespace); + AssertNamespaceIsPhysicallyPresent(Sliding60Namespace); + AssertNamespaceIsPhysicallyPresent(Absolute60Namespace); - Assert.Equal(0, _cache.Where(pair => pair.Value.Namespace == Dependency60Namespace).ToList().Count); - Assert.Equal(0, _cache.Where(pair => pair.Value.Namespace == Sliding60Namespace).ToList().Count); - Assert.Equal(0, _cache.Where(pair => pair.Value.Namespace == Absolute60Namespace).ToList().Count); + AssertNamespaceIsPhysicallyRemoved(Dependency60Namespace); + AssertNamespaceIsPhysicallyRemoved(Sliding60Namespace); + AssertNamespaceIsPhysicallyRemoved(Absolute60Namespace); } [Fact] @@ -329,5 +326,25 @@ public override void ConfigureServices(IServiceCollection services) }); services.AddSingleton(); } + + private void AssertNamespaceIsPhysicallyRemoved(string ns) + { + Assert.True(SpinWait.SpinUntil(() => !_cache.Any(pair => pair.Value.Namespace == ns), CleanupTimeout), + $"Cache entries in namespace '{ns}' were not physically removed within {CleanupTimeout}."); + } + + private void AssertNamespaceIsPhysicallyPresent(string ns) + { + var physicalCount = _cache.Where(pair => pair.Value.Namespace == ns).Count(); + + Assert.True(physicalCount == NumberOfItemsToCache, + $"Cache entries in namespace '{ns}' should remain physically present until cleanup. Expected {NumberOfItemsToCache}, actual {physicalCount}."); + } + + private void AssertNamespaceIsLogicallyExpired(string ns) + { + Assert.True(SpinWait.SpinUntil(() => _cache.Count(ns) == 0, CleanupTimeout), + $"Cache entries in namespace '{ns}' did not logically expire within {CleanupTimeout}."); + } } -} \ No newline at end of file +}