mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 02:33:12 +00:00
fix(auth): trace a reset email the provider rejects as an error
A send that the mail provider did not accept finished its background transaction as ok, so rejected reset emails looked delivered in tracing. It now finishes as an error with a fixed message that names no recipient.
This commit is contained in:
parent
c985e9423d
commit
74d5aa17eb
2 changed files with 66 additions and 5 deletions
|
|
@ -0,0 +1,55 @@
|
|||
using Api.SeaHavenIndustries.HostedServices;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using Sentry;
|
||||
using SeaHaven.Services.Interfaces;
|
||||
using Xunit;
|
||||
|
||||
namespace Api.SeaHavenIndustries.Tests;
|
||||
|
||||
public class PasswordResetEmailSenderTracingTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task Each_send_finishes_its_transaction_as_ok_only_when_the_provider_accepts_it(bool accepted)
|
||||
{
|
||||
var transaction = new Mock<ITransactionTracer>();
|
||||
var hub = new Mock<IHub>();
|
||||
hub.Setup(h => h.PushScope()).Returns(Mock.Of<IDisposable>());
|
||||
hub.Setup(h => h.StartTransaction(It.IsAny<ITransactionContext>(), It.IsAny<IReadOnlyDictionary<string, object?>>()))
|
||||
.Returns(transaction.Object);
|
||||
|
||||
var sender = new Mock<IEmailSender>();
|
||||
sender.Setup(s => s.SendEmailAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(accepted);
|
||||
var services = new ServiceCollection().AddSingleton(sender.Object).BuildServiceProvider();
|
||||
var channel = new PasswordResetEmailChannel(NullLogger<PasswordResetEmailChannel>.Instance);
|
||||
var worker = new PasswordResetEmailSenderHostedService(
|
||||
channel,
|
||||
services.GetRequiredService<IServiceScopeFactory>(),
|
||||
NullLogger<PasswordResetEmailSenderHostedService>.Instance,
|
||||
hub.Object);
|
||||
|
||||
await worker.StartAsync(CancellationToken.None);
|
||||
Assert.True(channel.TryEnqueue("user@example.com", "subject", "Your code is 123456"));
|
||||
var deadline = DateTime.UtcNow.AddSeconds(10);
|
||||
while (channel.Pending > 0 && DateTime.UtcNow < deadline)
|
||||
await Task.Delay(10);
|
||||
await worker.StopAsync(CancellationToken.None);
|
||||
|
||||
Assert.Equal(0, channel.Pending);
|
||||
if (accepted)
|
||||
{
|
||||
transaction.Verify(t => t.Finish(SpanStatus.Ok), Times.Once);
|
||||
transaction.Verify(t => t.Finish(It.IsAny<Exception>(), It.IsAny<SpanStatus>()), Times.Never);
|
||||
}
|
||||
else
|
||||
{
|
||||
transaction.Verify(t => t.Finish(SpanStatus.Ok), Times.Never);
|
||||
transaction.Verify(t => t.Finish(
|
||||
It.Is<Exception>(ex => !ex.Message.Contains("user@example.com") && !ex.Message.Contains("123456")),
|
||||
SpanStatus.InternalError), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +91,10 @@ namespace Api.SeaHavenIndustries.HostedServices
|
|||
$"{nameof(PasswordResetEmailSenderHostedService)}.{nameof(SendAsync)}");
|
||||
try
|
||||
{
|
||||
await SendAsync(email);
|
||||
transaction.FinishOk();
|
||||
if (await SendAsync(email))
|
||||
transaction.FinishOk();
|
||||
else
|
||||
transaction.FinishError(new InvalidOperationException("The mail provider did not accept the password reset email."));
|
||||
}
|
||||
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
|
|
@ -112,12 +114,16 @@ namespace Api.SeaHavenIndustries.HostedServices
|
|||
}
|
||||
}
|
||||
|
||||
private async Task SendAsync(PasswordResetEmail email)
|
||||
/// <summary>True when the mail provider accepted the email.</summary>
|
||||
private async Task<bool> SendAsync(PasswordResetEmail email)
|
||||
{
|
||||
await using var scope = _scopeFactory.CreateAsyncScope();
|
||||
var sender = scope.ServiceProvider.GetRequiredService<IEmailSender>();
|
||||
if (!await sender.SendEmailAsync(email.EmailTo, email.Subject, email.Body))
|
||||
_logger.LogWarning("Password reset email was not accepted by the mail provider.");
|
||||
if (await sender.SendEmailAsync(email.EmailTo, email.Subject, email.Body))
|
||||
return true;
|
||||
|
||||
_logger.LogWarning("Password reset email was not accepted by the mail provider.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue