2757869176
Add contract validation, SMTP delivery results, terminal failure context, neutral development seeding, and local Docker setup. Ref: IT-1033
108 lines
4.3 KiB
C#
108 lines
4.3 KiB
C#
namespace HrynCo.NotificationService.Services.Tests.EmailProcessing;
|
|
|
|
using HrynCo.NotificationService.Contracts.Messages;
|
|
using HrynCo.NotificationService.Worker.Services.EmailProcessing;
|
|
using Hrynco.RabbitMq;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using NSubstitute;
|
|
|
|
public sealed class NotificationResultPublisherTests
|
|
{
|
|
[Fact]
|
|
public async Task PublishAsync_TerminalFailure_PublishesNeutralFailureResultToReplyQueue()
|
|
{
|
|
IRabbitMqPublisher rabbitMqPublisher = Substitute.For<IRabbitMqPublisher>();
|
|
var publisher = new NotificationResultPublisher(
|
|
rabbitMqPublisher,
|
|
NullLogger<NotificationResultPublisher>.Instance);
|
|
SendEmailMessage message = CreateMessage();
|
|
NotificationResultMessage? publishedResult = null;
|
|
rabbitMqPublisher
|
|
.When(x => x.PublishAsync(
|
|
"item-tracker.notifications.result",
|
|
Arg.Any<NotificationResultMessage>(),
|
|
Arg.Any<CancellationToken>()))
|
|
.Do(call => publishedResult = call.ArgAt<NotificationResultMessage>(1));
|
|
|
|
await publisher.PublishAsync(
|
|
message,
|
|
"Email provider could not deliver the notification.",
|
|
CancellationToken.None);
|
|
|
|
await rabbitMqPublisher.Received(1).PublishAsync(
|
|
"item-tracker.notifications.result",
|
|
Arg.Any<NotificationResultMessage>(),
|
|
CancellationToken.None);
|
|
Assert.NotNull(publishedResult);
|
|
Assert.Equal(message.CorrelationContext.CorrelationId, publishedResult.CorrelationContext.CorrelationId);
|
|
Assert.Null(publishedResult.CorrelationContext.ReplyTo);
|
|
Assert.Equal(message.Data.ServiceName, publishedResult.Data.ServiceName);
|
|
Assert.Equal(message.Data.TemplateKey, publishedResult.Data.TemplateKey);
|
|
Assert.Equal(message.Data.RecipientEmail, publishedResult.Data.RecipientEmail);
|
|
Assert.Equal("Email provider could not deliver the notification.", publishedResult.Data.ErrorMessage);
|
|
Assert.False(publishedResult.Data.IsSuccess);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PublishAsync_NoReplyQueue_DoesNotPublish()
|
|
{
|
|
IRabbitMqPublisher rabbitMqPublisher = Substitute.For<IRabbitMqPublisher>();
|
|
var publisher = new NotificationResultPublisher(
|
|
rabbitMqPublisher,
|
|
NullLogger<NotificationResultPublisher>.Instance);
|
|
SendEmailMessage message = CreateMessage();
|
|
message.CorrelationContext = message.CorrelationContext with { ReplyTo = null };
|
|
|
|
await publisher.PublishAsync(message, "delivery failed", CancellationToken.None);
|
|
|
|
await rabbitMqPublisher.DidNotReceive()
|
|
.PublishAsync<NotificationResultData>(
|
|
Arg.Any<string>(),
|
|
Arg.Any<NotificationResultMessage>(),
|
|
Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PublishAsync_ResultBrokerFailure_IsBestEffort()
|
|
{
|
|
IRabbitMqPublisher rabbitMqPublisher = Substitute.For<IRabbitMqPublisher>();
|
|
rabbitMqPublisher
|
|
.PublishAsync(
|
|
Arg.Any<string>(),
|
|
Arg.Any<NotificationResultMessage>(),
|
|
Arg.Any<CancellationToken>())
|
|
.Returns<Task>(_ => throw new InvalidOperationException("reply broker unavailable"));
|
|
var publisher = new NotificationResultPublisher(
|
|
rabbitMqPublisher,
|
|
NullLogger<NotificationResultPublisher>.Instance);
|
|
|
|
Exception? exception = await Record.ExceptionAsync(() => publisher.PublishAsync(
|
|
CreateMessage(),
|
|
"delivery failed",
|
|
CancellationToken.None));
|
|
|
|
Assert.Null(exception);
|
|
}
|
|
|
|
private static SendEmailMessage CreateMessage()
|
|
{
|
|
return new SendEmailMessage
|
|
{
|
|
CorrelationContext = new CorrelationContext
|
|
{
|
|
CorrelationId = "correlation-id",
|
|
ReplyTo = "item-tracker.notifications.result"
|
|
},
|
|
Data = new SendEmailMessageData
|
|
{
|
|
ServiceName = "TestService",
|
|
TemplateKey = "TestEmail",
|
|
RecipientEmail = "test.user@itemtracker.local",
|
|
RecipientName = "Test User",
|
|
LanguageCode = "en",
|
|
Variables = new Dictionary<string, string>()
|
|
}
|
|
};
|
|
}
|
|
}
|