Harden Surreal migration with retry/coverage fixes and XML docs cleanup
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m17s
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m17s
This commit is contained in:
78
tests/ZB.MOM.WW.CBDDC.Core.Tests/RetryPolicyTests.cs
Normal file
78
tests/ZB.MOM.WW.CBDDC.Core.Tests/RetryPolicyTests.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using ZB.MOM.WW.CBDDC.Core.Exceptions;
|
||||
using ZB.MOM.WW.CBDDC.Core.Network;
|
||||
using ZB.MOM.WW.CBDDC.Core.Resilience;
|
||||
|
||||
namespace ZB.MOM.WW.CBDDC.Core.Tests;
|
||||
|
||||
public class RetryPolicyTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies transient failures are retried until a successful result is returned.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WhenTransientFailureEventuallySucceeds_RetriesAndReturnsResult()
|
||||
{
|
||||
var policy = new RetryPolicy(CreateConfigProvider(retryAttempts: 3, retryDelayMs: 1));
|
||||
var attempts = 0;
|
||||
|
||||
int result = await policy.ExecuteAsync(async () =>
|
||||
{
|
||||
attempts++;
|
||||
if (attempts < 3) throw new NetworkException("transient");
|
||||
await Task.CompletedTask;
|
||||
return 42;
|
||||
}, "test-op");
|
||||
|
||||
result.ShouldBe(42);
|
||||
attempts.ShouldBe(3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies transient failures throw retry exhausted when all retries are consumed.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WhenTransientFailureExhausted_ThrowsRetryExhaustedException()
|
||||
{
|
||||
var policy = new RetryPolicy(CreateConfigProvider(retryAttempts: 2, retryDelayMs: 1));
|
||||
var attempts = 0;
|
||||
|
||||
var ex = await Should.ThrowAsync<CBDDCException>(() => policy.ExecuteAsync<int>(() =>
|
||||
{
|
||||
attempts++;
|
||||
throw new NetworkException("still transient");
|
||||
}, "test-op"));
|
||||
|
||||
ex.ErrorCode.ShouldBe("RETRY_EXHAUSTED");
|
||||
ex.InnerException.ShouldBeOfType<NetworkException>();
|
||||
attempts.ShouldBe(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies non-transient failures are not retried.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WhenFailureIsNonTransient_DoesNotRetry()
|
||||
{
|
||||
var policy = new RetryPolicy(CreateConfigProvider(retryAttempts: 3, retryDelayMs: 1));
|
||||
var attempts = 0;
|
||||
|
||||
await Should.ThrowAsync<InvalidOperationException>(() => policy.ExecuteAsync<int>(() =>
|
||||
{
|
||||
attempts++;
|
||||
throw new InvalidOperationException("non-transient");
|
||||
}, "test-op"));
|
||||
|
||||
attempts.ShouldBe(1);
|
||||
}
|
||||
|
||||
private static IPeerNodeConfigurationProvider CreateConfigProvider(int retryAttempts, int retryDelayMs)
|
||||
{
|
||||
var configProvider = Substitute.For<IPeerNodeConfigurationProvider>();
|
||||
configProvider.GetConfiguration().Returns(new PeerNodeConfiguration
|
||||
{
|
||||
RetryAttempts = retryAttempts,
|
||||
RetryDelayMs = retryDelayMs
|
||||
});
|
||||
return configProvider;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user