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,112 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using HrynCo.NotificationService.DAL.Abstract.Providers;
|
||||
using HrynCo.NotificationService.DAL.Abstract.Repositories;
|
||||
using HrynCo.NotificationService.DAL.Abstract.Templates;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace HrynCo.NotificationService.Web.IntegrationTests;
|
||||
|
||||
public sealed class EmailChannelServiceLinkTests(TemplateDatabaseFixture fixture) : IClassFixture<TemplateDatabaseFixture>
|
||||
{
|
||||
[Fact]
|
||||
public async Task RenameUpdatesAllReadPathsAndResolvesChannelsByCurrentName()
|
||||
{
|
||||
await using var context = await DefinitionApiTestContext.CreateAsync(fixture);
|
||||
var channel = await SeedAsync(context);
|
||||
using (var scope = context.App.Services.CreateScope())
|
||||
{
|
||||
var services = scope.ServiceProvider.GetRequiredService<INotificationServiceRepository>();
|
||||
var service = (await services.GetAsync(context.ServiceId))!;
|
||||
service.Name = "Invemory-Renamed";
|
||||
await services.SaveAsync(service, false);
|
||||
}
|
||||
var read = (await context.Client.GetFromJsonAsync<JsonElement>($"/api/v1/email-channels/{channel.Id}")).GetProperty("data");
|
||||
Assert.Equal(context.ServiceId, read.GetProperty("serviceId").GetGuid());
|
||||
Assert.Equal("Invemory-Renamed", read.GetProperty("serviceName").GetString());
|
||||
var current = await context.Client.GetFromJsonAsync<JsonElement>("/api/v1/email-channels?serviceName=Invemory-Renamed");
|
||||
Assert.Single(current.GetProperty("data").EnumerateArray());
|
||||
var previous = await context.Client.GetFromJsonAsync<JsonElement>("/api/v1/email-channels?serviceName=TestService");
|
||||
Assert.Empty(previous.GetProperty("data").EnumerateArray());
|
||||
Assert.Contains("Invemory-Renamed", await context.Client.GetStringAsync("/admin/channels"));
|
||||
Assert.Contains("Invemory-Renamed", await context.Client.GetStringAsync($"/admin/channels/{channel.Id}"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EditorAllowsReassignmentWithoutReplacingPasswordOrUsage()
|
||||
{
|
||||
await using var context = await DefinitionApiTestContext.CreateAsync(fixture);
|
||||
var channel = await SeedAsync(context);
|
||||
using var scope = context.App.Services.CreateScope();
|
||||
var destination = new NotificationServiceInfo { Name = "Invemory-Other" };
|
||||
await scope.ServiceProvider.GetRequiredService<INotificationServiceRepository>().SaveAsync(destination, true);
|
||||
using var client = context.App.CreateClient(new() { AllowAutoRedirect = false });
|
||||
var html = await client.GetStringAsync($"/admin/channels/{channel.Id}");
|
||||
Assert.Contains("<select", html);
|
||||
Assert.Contains("name=\"ServiceId\"", html);
|
||||
Assert.Contains("Invemory-Other", html);
|
||||
Assert.DoesNotContain("name=\"ServiceName\"", html);
|
||||
var fields = TemplateEditorTestFields.Read(html);
|
||||
fields["ServiceId"] = destination.Id.ToString();
|
||||
fields["Password"] = "";
|
||||
fields["UseSsl"] = "true";
|
||||
fields["IsActive"] = "true";
|
||||
var response = await client.PostAsync("/admin/channels/save", new FormUrlEncodedContent(fields));
|
||||
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||
using var readScope = context.App.Services.CreateScope();
|
||||
var channels = readScope.ServiceProvider.GetRequiredService<IEmailChannelRepository>();
|
||||
var saved = (await channels.GetByIdAsync(channel.Id))!;
|
||||
Assert.Equal(destination.Id, saved.ServiceId);
|
||||
Assert.Equal("Invemory-Other", saved.ServiceName);
|
||||
Assert.Equal("test-only-password", Assert.IsType<SmtpChannelSettings>(saved.Settings).Password);
|
||||
Assert.Equal(25, saved.DailyLimit);
|
||||
Assert.Equal(250, saved.MonthlyLimit);
|
||||
Assert.Equal(2, saved.Priority);
|
||||
var summary = Assert.Single(await channels.GetAllWithUsageSummaryAsync(DateOnly.FromDateTime(DateTime.UtcNow)));
|
||||
Assert.Equal(1, summary.DailySent);
|
||||
Assert.Empty(await channels.GetByServiceAsync(context.ServiceId));
|
||||
Assert.Single(await channels.GetByServiceAsync(destination.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task UpdateRejectsMissingServiceWithoutChangingChannel(bool empty)
|
||||
{
|
||||
await using var context = await DefinitionApiTestContext.CreateAsync(fixture);
|
||||
var channel = await SeedAsync(context);
|
||||
var response = await context.Client.PutAsJsonAsync($"/api/v1/email-channels/{channel.Id}", new
|
||||
{
|
||||
serviceId = empty ? Guid.Empty : Guid.NewGuid(), priority = 9,
|
||||
settings = (SmtpChannelSettings)channel.Settings, dailyLimit = 1, monthlyLimit = 2, warnThresholdPercent = 80, isActive = false
|
||||
});
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal("Select an existing service.", result.GetProperty("error").GetProperty("message").GetString());
|
||||
using var scope = context.App.Services.CreateScope();
|
||||
var saved = (await scope.ServiceProvider.GetRequiredService<IEmailChannelRepository>().GetByIdAsync(channel.Id))!;
|
||||
Assert.Equal(context.ServiceId, saved.ServiceId);
|
||||
Assert.Equal(2, saved.Priority);
|
||||
Assert.Equal(25, saved.DailyLimit);
|
||||
}
|
||||
|
||||
private static async Task<EmailChannel> SeedAsync(DefinitionApiTestContext context)
|
||||
{
|
||||
using var scope = context.App.Services.CreateScope();
|
||||
var channel = new EmailChannel
|
||||
{
|
||||
ServiceId = context.ServiceId, Priority = 2, EmailChannelType = EmailChannelType.Smtp,
|
||||
DailyLimit = 25, MonthlyLimit = 250, IsActive = true,
|
||||
Settings = new SmtpChannelSettings
|
||||
{
|
||||
Host = "smtp.invalid", Port = 587, Username = "test-user", Password = "test-only-password",
|
||||
UseSsl = true, FromEmail = "sender@example.invalid", FromName = "Invemory Test"
|
||||
}
|
||||
};
|
||||
await scope.ServiceProvider.GetRequiredService<IEmailChannelRepository>().AddAsync(channel);
|
||||
await scope.ServiceProvider.GetRequiredService<IEmailChannelUsageRepository>()
|
||||
.IncrementUsageAsync(channel.Id, DateOnly.FromDateTime(DateTime.UtcNow));
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user