using HrynCo.NotificationService.Contracts.Messages; using HrynCo.NotificationService.DAL.Abstract.Repositories; using HrynCo.NotificationService.DAL.Abstract.Templates; using HrynCo.NotificationService.DAL.EF; using HrynCo.NotificationService.Worker.Services; using HrynCo.NotificationService.Worker.Services.EmailProcessing; using Microsoft.Extensions.DependencyInjection; namespace HrynCo.NotificationService.Web.IntegrationTests; public sealed class WorkerTemplateIntegrationTests(TemplateDatabaseFixture fixture) : IClassFixture { [Fact] public async Task Worker_UsesExactLanguageContentAndCurrentSharedContract() { var connection = await fixture.CreateDatabaseAsync(); using var provider = new ServiceCollection().AddNotificationDataAccess(connection).AddNotificationWorkerServices().BuildServiceProvider(); var codes = new[] { "de", "en", "ru", "uk", "ru-RU" }; foreach (var code in codes) await AddVersionAsync(provider, code); foreach (var code in codes) { using var readScope = provider.CreateScope(); var template = await readScope.ServiceProvider.GetRequiredService().GetAsync("TestService", "Delivery", code, default); var rendered = readScope.ServiceProvider.GetRequiredService().Render(template, Message(code)); Assert.Equal(code + " A < B", rendered.Subject); Assert.Equal("

A < B

", rendered.HtmlBody); Assert.Equal("A < B", rendered.TextBody); } using (var updateScope = provider.CreateScope()) { var definitions = updateScope.ServiceProvider.GetRequiredService(); var definition = (await definitions.GetDefinitionAsync("TestService", "Delivery"))!; definition.Variables = [new EmailTemplateVariable { Name = "Extra", Required = true }]; await definitions.SaveDefinitionAsync(definition, false); } using var finalScope = provider.CreateScope(); var loader = finalScope.ServiceProvider.GetRequiredService(); var updated = await loader.GetAsync("TestService", "Delivery", "ru-RU", default); var error = Assert.Throws(() => finalScope.ServiceProvider.GetRequiredService().Render(updated, Message("ru-RU"))); Assert.Contains("Extra", error.Message); await Assert.ThrowsAsync(() => loader.GetAsync("TestService", "Delivery", "RU-ru", default)); await Assert.ThrowsAsync(() => loader.GetAsync("TestService", "Missing", "en", default)); } [Fact] public async Task Worker_CompatibilityRetryPreservesExactVersionPriorityAndRepositoryCodes() { var connection = await fixture.CreateDatabaseAsync(); using var provider = new ServiceCollection().AddNotificationDataAccess(connection).AddNotificationWorkerServices().BuildServiceProvider(); await AddVersionAsync(provider, "ru"); await AddVersionAsync(provider, "ru-RU"); using (var legacyScope = provider.CreateScope()) { var loader = legacyScope.ServiceProvider.GetRequiredService(); Assert.Equal("ru", (await loader.GetAsync("TestService", "Delivery", "RU", default)).LanguageCode); Assert.Equal("ru", (await loader.GetAsync("TestService", "Delivery", " ru ", default)).LanguageCode); Assert.Null(await legacyScope.ServiceProvider.GetRequiredService().GetAsync("TestService", "Delivery", "RU")); } using (var catalogScope = provider.CreateScope()) { var services = catalogScope.ServiceProvider.GetRequiredService(); var service = (await services.GetAllAsync()).Single(s => s.Name == "TestService"); service.Languages = [..service.Languages, new ServiceLanguageInfo { Code = "RU" }]; await services.SaveAsync(service, false); } await AddVersionAsync(provider, "RU"); using var exactScope = provider.CreateScope(); var exactLoader = exactScope.ServiceProvider.GetRequiredService(); Assert.Equal("RU", (await exactLoader.GetAsync("TestService", "Delivery", "RU", default)).LanguageCode); Assert.Equal("ru-RU", (await exactLoader.GetAsync("TestService", "Delivery", "ru-RU", default)).LanguageCode); Assert.Equal("ru", (await exactLoader.GetAsync("TestService", "Delivery", "ru", default)).LanguageCode); await Assert.ThrowsAsync(() => exactLoader.GetAsync("TestService", "Delivery", "RU-ru", default)); await Assert.ThrowsAsync(() => exactLoader.GetAsync("TestService", "Delivery", "zz", default)); } private static async Task AddVersionAsync(ServiceProvider provider, string code) { using var scope = provider.CreateScope(); await scope.ServiceProvider.GetRequiredService().AddAsync(new EmailTemplate { ServiceName = "TestService", Key = "Delivery", LanguageCode = code, Subject = code + " {{Name}}", HtmlBody = "

{{Name}}

", TextBody = "{{Name}}", Variables = [new EmailTemplateVariable { Name = "Name", Required = true }] }); } private static SendEmailMessageData Message(string code) => new() { ServiceName = "TestService", TemplateKey = "Delivery", LanguageCode = code, RecipientEmail = "test@example.invalid", RecipientName = "Test", Variables = new Dictionary { ["Name"] = "A < B" } }; }