feat(push): add service-owned firebase channels and delivery
Add push contracts, provider delivery and channel diagnostics. Link email channels to services and document migration and validation. Ref: IT-1074
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
namespace HrynCo.NotificationService.Services.Tests.Push;
|
||||
|
||||
using FirebaseAdmin.Messaging;
|
||||
using HrynCo.NotificationService.Contracts.Messages;
|
||||
using HrynCo.NotificationService.DAL.Abstract.Push;
|
||||
using HrynCo.NotificationService.Worker.Services.Push;
|
||||
using Hrynco.RabbitMq;
|
||||
using NSubstitute;
|
||||
|
||||
public sealed class PushDeliveryTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(MessagingErrorCode.Unregistered, true)]
|
||||
[InlineData(MessagingErrorCode.SenderIdMismatch, false)]
|
||||
[InlineData(MessagingErrorCode.InvalidArgument, false)]
|
||||
public void OnlyUnregisteredInvalidatesTheInstallation(MessagingErrorCode code, bool invalid)
|
||||
{
|
||||
var result = FirebasePushClient.Classify(code);
|
||||
Assert.Equal(invalid, result.InvalidRegistration);
|
||||
Assert.NotNull(result.Error);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(MessagingErrorCode.Internal)]
|
||||
[InlineData(MessagingErrorCode.Unavailable)]
|
||||
[InlineData(MessagingErrorCode.QuotaExceeded)]
|
||||
public void TransientFailuresPreserveRetryAfter(MessagingErrorCode code)
|
||||
{
|
||||
var exception = Assert.Throws<PushRetryException>(() => FirebasePushClient.Classify(code, TimeSpan.FromMinutes(3)));
|
||||
Assert.Equal(TimeSpan.FromMinutes(3), exception.RetryAfter);
|
||||
Assert.True(PushDeliveryService.RetryDelay(0, exception.RetryAfter) >= TimeSpan.FromMinutes(3));
|
||||
Assert.True(PushDeliveryService.RetryDelay(1, TimeSpan.Zero) >= TimeSpan.FromMinutes(2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExhaustedReplyRetriesReplaySavedSuccessWithoutSendingAgain()
|
||||
{
|
||||
var repository = Substitute.For<IPushDeliveryRepository>();
|
||||
var sender = Substitute.For<IPushSender>();
|
||||
var publisher = Substitute.For<IRabbitMqPublisher>();
|
||||
repository.DeliverOnceAsync(Arg.Any<Guid>(), Arg.Any<string>(),
|
||||
Arg.Any<Func<CancellationToken, Task<PushDeliveryOutcome>>>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new PushDeliveryOutcome(null));
|
||||
var service = new PushDeliveryService(repository, sender, publisher);
|
||||
var id = Guid.NewGuid();
|
||||
var message = new SendPushMessage
|
||||
{
|
||||
CorrelationContext = new CorrelationContext { CorrelationId = id.ToString(), ReplyTo = "results" },
|
||||
Data = new SendPushMessageData
|
||||
{
|
||||
RegistrationId = Guid.NewGuid(), BindingId = Guid.NewGuid(), UserId = Guid.NewGuid(),
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddMinutes(10), ServiceName = "Invemory", Title = "Invemory", Body = "Test", TokenHash = new string('a', 64)
|
||||
}
|
||||
};
|
||||
await service.CompleteFailureAsync(id, message, default);
|
||||
await publisher.Received(1).PublishAsync("results",
|
||||
Arg.Is<NotificationResultMessage>(x => x.Data.IsSuccess && x.Data.PushBindingId == message.Data.BindingId), default);
|
||||
await sender.DidNotReceive().SendAsync(Arg.Any<Guid>(), Arg.Any<SendPushMessageData>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user