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 = "
{{AppName}}
",
TextBody = "{{AppName}}",
Variables = [new EmailTemplateVariable { Name = "AppName", Required = true }]
};
IEmailChannelRepository channels = Substitute.For();
channels.GetByServiceAsync("StoreMate-Prod", Arg.Any())
.Returns([channel]);
IEmailChannelUsageRepository usage = Substitute.For();
IEmailTemplateService templates = Substitute.For();
templates.GetAsync("StoreMate-Prod", "EmailVerification", "uk", Arg.Any())
.Returns(template);
var renderer = new EmailTemplateRenderingService();
var smtp = new RecordingSmtpEmailSender();
INotificationResultPublisher resultPublisher = Substitute.For();
var service = new SendEmailService(
channels,
usage,
templates,
renderer,
smtp,
resultPublisher,
NullLogger.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 { ["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(),
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;
}
}
}