aba4173827
Share template keys across email and push with independent editors and revisions. Render localized actions and preserve version-one delivery. Ref: IT-1627
97 lines
5.2 KiB
C#
97 lines
5.2 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text.Json;
|
|
using HrynCo.NotificationService.DAL.Abstract.Push;
|
|
using HrynCo.NotificationService.DAL.Abstract.PushChannels;
|
|
using HrynCo.NotificationService.Worker.Services.Push;
|
|
using NSubstitute;
|
|
|
|
namespace HrynCo.NotificationService.Services.Tests.Push;
|
|
|
|
public sealed class PushChannelTestServiceTests
|
|
{
|
|
[Theory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public async Task UsesSavedCredentialsWithoutSavingTokenAndSeparatesAuthorizationFromSend(bool send)
|
|
{
|
|
var channels = Substitute.For<IPushChannelRepository>();
|
|
var firebase = Client();
|
|
var id = Guid.NewGuid();
|
|
channels.GetByIdAsync(id, Arg.Any<CancellationToken>()).Returns(new PushChannel
|
|
{ Id = id, ServiceId = Guid.NewGuid(), FirebaseProjectId = "test-project", IsActive = false });
|
|
channels.GetCredentialsAsync(id, Arg.Any<CancellationToken>()).Returns(Credentials());
|
|
var outcome = await new PushChannelTestService(channels, firebase).TestAsync(new PushChannelTestSettings
|
|
{ ChannelId = id, FirebaseProjectId = "test-project", RecipientToken = send ? "test-token" : null }, send, default);
|
|
Assert.Null(outcome.Error);
|
|
await firebase.Received(send ? 1 : 0).SendTestAsync(Arg.Is<PushChannelTestMessage>(m => m.Token == "test-token" && m.Version == 1), Arg.Any<FirebaseServiceAccountCredentials>(), Arg.Any<CancellationToken>());
|
|
await firebase.Received(send ? 0 : 1).CheckAuthorizationAsync(Arg.Any<FirebaseServiceAccountCredentials>(), Arg.Any<CancellationToken>());
|
|
await channels.DidNotReceiveWithAnyArgs().SaveAsync(default!, default!, default, default);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UnsavedCredentialsOverrideSavedConfiguration()
|
|
{
|
|
var channels = Substitute.For<IPushChannelRepository>();
|
|
var firebase = Client();
|
|
var outcome = await new PushChannelTestService(channels, firebase).TestAsync(new PushChannelTestSettings
|
|
{ ChannelId = Guid.NewGuid(), FirebaseProjectId = "test-project", CredentialsJson = Credentials() }, false, default);
|
|
Assert.Null(outcome.Error);
|
|
await channels.DidNotReceiveWithAnyArgs().GetCredentialsAsync(default, default);
|
|
await firebase.Received(1).CheckAuthorizationAsync(Arg.Any<FirebaseServiceAccountCredentials>(), Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("changed-project")]
|
|
[InlineData("invalid-json")]
|
|
[InlineData("missing-token")]
|
|
[InlineData("unknown-channel")]
|
|
public async Task InvalidInputNeverContactsFirebase(string scenario)
|
|
{
|
|
var channels = Substitute.For<IPushChannelRepository>();
|
|
var firebase = Client();
|
|
var id = Guid.NewGuid();
|
|
if (scenario != "unknown-channel") channels.GetByIdAsync(id, Arg.Any<CancellationToken>()).Returns(new PushChannel
|
|
{ Id = id, ServiceId = Guid.NewGuid(), FirebaseProjectId = "test-project" });
|
|
channels.GetCredentialsAsync(id, Arg.Any<CancellationToken>()).Returns(Credentials());
|
|
var settings = new PushChannelTestSettings
|
|
{
|
|
ChannelId = id, FirebaseProjectId = scenario == "changed-project" ? "other-project" : "test-project",
|
|
CredentialsJson = scenario == "invalid-json" ? "private-secret-do-not-echo" : null
|
|
};
|
|
var outcome = await new PushChannelTestService(channels, firebase).TestAsync(settings, scenario == "missing-token", default);
|
|
Assert.NotNull(outcome.Error);
|
|
Assert.DoesNotContain("private-secret-do-not-echo", outcome.Error);
|
|
await firebase.DidNotReceiveWithAnyArgs().CheckAuthorizationAsync(default!, default);
|
|
await firebase.DidNotReceiveWithAnyArgs().SendTestAsync(default!, default!, default);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RetryableProviderFailureReturnsSafeUnconfirmedResult()
|
|
{
|
|
var channels = Substitute.For<IPushChannelRepository>();
|
|
var firebase = Client();
|
|
firebase.SendTestAsync(Arg.Any<PushChannelTestMessage>(), Arg.Any<FirebaseServiceAccountCredentials>(), Arg.Any<CancellationToken>())
|
|
.Returns(Task.FromException<PushDeliveryOutcome>(new PushRetryException(TimeSpan.FromSeconds(30))));
|
|
var outcome = await new PushChannelTestService(channels, firebase).TestAsync(new PushChannelTestSettings
|
|
{ FirebaseProjectId = "test-project", CredentialsJson = Credentials(), RecipientToken = "test-token" }, true, default);
|
|
Assert.Contains("acceptance was not confirmed", outcome.Error);
|
|
}
|
|
|
|
private static IFirebasePushClient Client()
|
|
{
|
|
var firebase = Substitute.For<IFirebasePushClient>();
|
|
firebase.CheckAuthorizationAsync(Arg.Any<FirebaseServiceAccountCredentials>(), Arg.Any<CancellationToken>())
|
|
.Returns(new PushDeliveryOutcome(null));
|
|
firebase.SendTestAsync(Arg.Any<PushChannelTestMessage>(), Arg.Any<FirebaseServiceAccountCredentials>(), Arg.Any<CancellationToken>())
|
|
.Returns(new PushDeliveryOutcome(null));
|
|
return firebase;
|
|
}
|
|
|
|
private static string Credentials()
|
|
{
|
|
using var rsa = RSA.Create(2048);
|
|
return JsonSerializer.Serialize(new
|
|
{ type = "service_account", project_id = "test-project", client_email = "test@example.invalid", private_key = rsa.ExportPkcs8PrivateKeyPem() });
|
|
}
|
|
}
|