2757869176
Add contract validation, SMTP delivery results, terminal failure context, neutral development seeding, and local Docker setup. Ref: IT-1033
124 lines
4.5 KiB
C#
124 lines
4.5 KiB
C#
namespace HrynCo.NotificationService.Services.Tests.EmailProcessing;
|
|
|
|
using HrynCo.NotificationService.Contracts.Messages;
|
|
using HrynCo.NotificationService.DAL.Abstract.Providers;
|
|
using HrynCo.NotificationService.DAL.Abstract.Repositories;
|
|
using HrynCo.NotificationService.DAL.Abstract.Templates;
|
|
using HrynCo.NotificationService.Worker.Services.EmailProcessing;
|
|
using Hrynco.RabbitMq;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using NSubstitute;
|
|
|
|
public sealed class SendEmailServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task ProcessAsync_ValidItemTrackerMessage_SendsOnceAndUpdatesUsage()
|
|
{
|
|
Guid channelId = Guid.NewGuid();
|
|
var settings = new SmtpChannelSettings
|
|
{
|
|
Host = "smtp.example.invalid",
|
|
Port = 587,
|
|
Username = "smtp-user",
|
|
Password = "not-a-real-secret",
|
|
UseSsl = true,
|
|
FromEmail = "notifications@example.com",
|
|
FromName = "StoreMate"
|
|
};
|
|
var channel = new EmailChannel
|
|
{
|
|
Id = channelId,
|
|
ServiceName = "StoreMate-Prod",
|
|
Priority = 1,
|
|
EmailChannelType = EmailChannelType.Smtp,
|
|
Settings = settings,
|
|
IsActive = true
|
|
};
|
|
var template = new EmailTemplate
|
|
{
|
|
ServiceName = "StoreMate-Prod",
|
|
Key = "EmailVerification",
|
|
LanguageCode = "uk",
|
|
Subject = "Verify {{AppName}}",
|
|
HtmlBody = "<p>{{AppName}}</p>",
|
|
TextBody = "{{AppName}}",
|
|
Variables = [new EmailTemplateVariable { Name = "AppName", Required = true }]
|
|
};
|
|
|
|
IEmailChannelRepository channels = Substitute.For<IEmailChannelRepository>();
|
|
channels.GetByServiceAsync("StoreMate-Prod", Arg.Any<CancellationToken>())
|
|
.Returns([channel]);
|
|
IEmailChannelUsageRepository usage = Substitute.For<IEmailChannelUsageRepository>();
|
|
IEmailTemplateService templates = Substitute.For<IEmailTemplateService>();
|
|
templates.GetAsync("StoreMate-Prod", "EmailVerification", "uk", Arg.Any<CancellationToken>())
|
|
.Returns(template);
|
|
var renderer = new EmailTemplateRenderingService();
|
|
var smtp = new RecordingSmtpEmailSender();
|
|
INotificationResultPublisher resultPublisher = Substitute.For<INotificationResultPublisher>();
|
|
var service = new SendEmailService(
|
|
channels,
|
|
usage,
|
|
templates,
|
|
renderer,
|
|
smtp,
|
|
resultPublisher,
|
|
NullLogger<SendEmailService>.Instance);
|
|
var message = new SendEmailMessage
|
|
{
|
|
CorrelationContext = new CorrelationContext
|
|
{
|
|
CorrelationId = Guid.NewGuid().ToString("D")
|
|
},
|
|
Data = new SendEmailMessageData
|
|
{
|
|
ServiceName = "StoreMate-Prod",
|
|
TemplateKey = "EmailVerification",
|
|
RecipientEmail = "owner@example.com",
|
|
RecipientName = "Owner",
|
|
LanguageCode = "uk",
|
|
Variables = new Dictionary<string, string> { ["AppName"] = "StoreMate" }
|
|
}
|
|
};
|
|
|
|
await service.ProcessAsync(message, CancellationToken.None);
|
|
|
|
Assert.Equal(1, smtp.SendCount);
|
|
Assert.Same(settings, smtp.Settings);
|
|
Assert.Equal("Verify StoreMate", smtp.Email?.Subject);
|
|
Assert.Equal("owner@example.com", smtp.RecipientEmail);
|
|
Assert.Equal("Owner", smtp.RecipientName);
|
|
await usage.Received(1).IncrementUsageAsync(
|
|
channelId,
|
|
Arg.Any<DateOnly>(),
|
|
CancellationToken.None);
|
|
await resultPublisher.Received(1).PublishAsync(
|
|
message,
|
|
null,
|
|
CancellationToken.None);
|
|
}
|
|
|
|
private sealed class RecordingSmtpEmailSender : ISmtpEmailSender
|
|
{
|
|
public int SendCount { get; private set; }
|
|
public SmtpChannelSettings? Settings { get; private set; }
|
|
public RenderedEmail? Email { get; private set; }
|
|
public string? RecipientEmail { get; private set; }
|
|
public string? RecipientName { get; private set; }
|
|
|
|
public Task SendAsync(
|
|
SmtpChannelSettings settings,
|
|
RenderedEmail email,
|
|
string recipientEmail,
|
|
string recipientName,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
SendCount++;
|
|
Settings = settings;
|
|
Email = email;
|
|
RecipientEmail = recipientEmail;
|
|
RecipientName = recipientName;
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
}
|