79 lines
2.5 KiB
C#
79 lines
2.5 KiB
C#
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;
|
|
}
|
|
}
|