This sample demonstrates how to test custom recoverability policies. The sample uses the policy as explained in the custom recoverability policy documentation.
Creating the policy
The syntax of a custom recoverability policy is following:
RecoverabilityAction MyCustomRetryPolicy(RecoverabilityConfig config, ErrorContext context)
This means that an instance of RecoverabilityConfig
is necessary in order to test the custom policy. This class contains information about immediate and delayed retries and about what happens when all retries have been exhausted. Normally this information is configured with an EndpointConfiguration
and provided by NServiceBus to the recoverability policy. In the test context it needs to be build based on the test parameters. This can be done using the following helper method:
static Func<ErrorContext, RecoverabilityAction> CreatePolicy(int maxImmediateRetries = 2, int maxDelayedRetries = 2, TimeSpan? delayedRetryDelay = null, HashSet<Type> unrecoverableExceptions = null)
{
var failedConfig = new FailedConfig("errorQueue", unrecoverableExceptions ?? new HashSet<Type>());
var config = new RecoverabilityConfig(new ImmediateConfig(maxImmediateRetries), new DelayedConfig(maxDelayedRetries, delayedRetryDelay.GetValueOrDefault(TimeSpan.FromSeconds(2))), failedConfig);
return context => CustomizedRecoverabilityPolicy.MyCustomRetryPolicy(config, context);
}
Executing the policy requires an error context, which provides information about the error that occurred and how many retries have already been executed. This sample also includes a helper method that creates the error context.
static ErrorContext CreateErrorContext(int numberOfDeliveryAttempts = 1, int? retryNumber = null, Dictionary<string, string> headers = null, Exception exception = null) =>
new ErrorContext(
exception ?? new Exception(),
retryNumber.HasValue
? new Dictionary<string, string> { { Headers.DelayedRetries, retryNumber.ToString() } }
: headers ?? new Dictionary<string, string>(),
"message-id",
new ReadOnlyMemory<byte>(new byte[0]),
new TransportTransaction(),
numberOfDeliveryAttempts,
"receive-address",
new ContextBag());
Creating a test
Multiple tests can then be created using the helper methods. According to the custom recoverability policy, messages that cause a certain custom exception should be discarded and not moved to the error queue.
[Test]
public void ShouldDiscardBecauseOfCustomException()
{
var policy = CreatePolicy();
var errorContext = CreateErrorContext(numberOfDeliveryAttempts: 1, exception: new MyBusinessTimedOutException());
var recoverabilityAction = policy(errorContext);
Assert.That(recoverabilityAction, Is.InstanceOf<Discard>(), "Message should be discarded");
}
There are additional tests in the sample that show how it is possible to verify which error queue a message was sent to.