From d0d27c058297e1e3ac73ef5b5b2344d5413ccbb4 Mon Sep 17 00:00:00 2001 From: Martin Othamar Date: Tue, 16 Apr 2024 07:49:03 +0200 Subject: [PATCH 1/4] Remove keyed services for --- src/Altinn.App.Core/Altinn.App.Core.csproj | 1 + .../Extensions/ServiceCollectionExtensions.cs | 4 ++-- .../ProcessTask/EndTaskEventHandler.cs | 10 +++++----- .../ServiceTasks/EformidlingServiceTask.cs | 4 +++- .../Process/ServiceTasks/PdfServiceTask.cs | 4 +++- .../ProcessTask/EndTaskEventHandlerTests.cs | 19 +++++++++++-------- 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/Altinn.App.Core/Altinn.App.Core.csproj b/src/Altinn.App.Core/Altinn.App.Core.csproj index ab28be50e6..78fda5f20b 100644 --- a/src/Altinn.App.Core/Altinn.App.Core.csproj +++ b/src/Altinn.App.Core/Altinn.App.Core.csproj @@ -27,5 +27,6 @@ + diff --git a/src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs b/src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs index bd175cd64d..50fbb536f6 100644 --- a/src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs +++ b/src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs @@ -298,8 +298,8 @@ private static void AddProcessServices(IServiceCollection services) services.AddTransient(); //SERVICE TASKS - services.AddKeyedTransient("pdfService"); - services.AddKeyedTransient("eFormidlingService"); + services.AddTransient(); + services.AddTransient(); } private static void AddActionServices(IServiceCollection services) diff --git a/src/Altinn.App.Core/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandler.cs b/src/Altinn.App.Core/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandler.cs index 42afeb67dd..f42c750544 100644 --- a/src/Altinn.App.Core/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandler.cs +++ b/src/Altinn.App.Core/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandler.cs @@ -2,7 +2,6 @@ using Altinn.App.Core.Internal.Process.ProcessTasks; using Altinn.App.Core.Internal.Process.ServiceTasks; using Altinn.Platform.Storage.Interface.Models; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Altinn.App.Core.Internal.Process.EventHandlers.ProcessTask @@ -25,16 +24,17 @@ public class EndTaskEventHandler : IEndTaskEventHandler public EndTaskEventHandler( IProcessTaskDataLocker processTaskDataLocker, IProcessTaskFinalizer processTaskFinisher, - [FromKeyedServices("pdfService")] IServiceTask pdfServiceTask, - [FromKeyedServices("eFormidlingService")] IServiceTask eformidlingServiceTask, + IEnumerable serviceTasks, IEnumerable processTaskEnds, ILogger logger ) { _processTaskDataLocker = processTaskDataLocker; _processTaskFinisher = processTaskFinisher; - _pdfServiceTask = pdfServiceTask; - _eformidlingServiceTask = eformidlingServiceTask; + _pdfServiceTask = serviceTasks.FirstOrDefault(x => x is IPdfServiceTask) + ?? throw new InvalidOperationException("PdfServiceTask not found in serviceTasks"); + _eformidlingServiceTask = serviceTasks.FirstOrDefault(x => x is IEformidlingServiceTask) + ?? throw new InvalidOperationException("EformidlingServiceTask not found in serviceTasks"); _processTaskEnds = processTaskEnds; _logger = logger; } diff --git a/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs b/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs index acc304e0c3..785fd03921 100644 --- a/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs +++ b/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs @@ -9,10 +9,12 @@ namespace Altinn.App.Core.Internal.Process.ServiceTasks; +internal interface IEformidlingServiceTask : IServiceTask {} + /// /// Service task that sends eFormidling shipment, if EFormidling is enabled in config and EFormidling.SendAfterTaskId matches the current task. /// -public class EformidlingServiceTask : IServiceTask +public class EformidlingServiceTask : IEformidlingServiceTask { private readonly ILogger _logger; private readonly IAppMetadata _appMetadata; diff --git a/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs b/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs index 6065aa5cd2..35cab04c08 100644 --- a/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs +++ b/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs @@ -5,10 +5,12 @@ namespace Altinn.App.Core.Internal.Process.ServiceTasks; +internal interface IPdfServiceTask : IServiceTask {} + /// /// Service task that generates PDFs for all connected datatypes that have the EnablePdfCreation flag set to true. /// -public class PdfServiceTask : IServiceTask +public class PdfServiceTask : IPdfServiceTask { private readonly IAppMetadata _appMetadata; private readonly IPdfService _pdfService; diff --git a/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs b/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs index dd0f698d26..1ce89e9c44 100644 --- a/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs +++ b/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs @@ -14,8 +14,14 @@ public class EndTaskEventHandlerTests { private readonly Mock _processTaskDataLocker = new(); private readonly Mock _processTaskFinisher = new(); - private readonly Mock _pdfServiceTask = new(); - private readonly Mock _eformidlingServiceTask = new(); + private readonly Mock _pdfServiceTask = new(); + private readonly Mock _eformidlingServiceTask = new(); + + private IServiceTask[] ServiceTasks => [ + _pdfServiceTask.Object, + _eformidlingServiceTask.Object + ]; + private IEnumerable _processTaskEnds = new List(); private readonly ILogger _logger = new NullLogger(); @@ -25,8 +31,7 @@ public async Task Execute_handles_no_IProcessTaskAbandon_injected() EndTaskEventHandler eteh = new EndTaskEventHandler( _processTaskDataLocker.Object, _processTaskFinisher.Object, - _pdfServiceTask.Object, - _eformidlingServiceTask.Object, + ServiceTasks, _processTaskEnds, _logger); var instance = new Instance() @@ -58,8 +63,7 @@ public async Task Execute_calls_all_added_implementations_of_IProcessTaskEnd() EndTaskEventHandler eteh = new( _processTaskDataLocker.Object, _processTaskFinisher.Object, - _pdfServiceTask.Object, - _eformidlingServiceTask.Object, + ServiceTasks, _processTaskEnds, _logger); var instance = new Instance() @@ -92,8 +96,7 @@ public async Task Calls_unlock_if_pdf_fails() EndTaskEventHandler eteh = new( _processTaskDataLocker.Object, _processTaskFinisher.Object, - _pdfServiceTask.Object, - _eformidlingServiceTask.Object, + ServiceTasks, _processTaskEnds, _logger); From 610eee843340c39759dd88be6efa7f6c34bd7824 Mon Sep 17 00:00:00 2001 From: Martin Othamar Date: Tue, 16 Apr 2024 08:34:27 +0200 Subject: [PATCH 2/4] Ensure app insights are registered properly in test --- src/Altinn.App.Api/Altinn.App.Api.csproj | 5 + .../Extensions/ServiceCollectionExtensions.cs | 8 +- test/Altinn.App.Api.Tests/DITests.cs | 94 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 test/Altinn.App.Api.Tests/DITests.cs diff --git a/src/Altinn.App.Api/Altinn.App.Api.csproj b/src/Altinn.App.Api/Altinn.App.Api.csproj index 3fcd862fa9..a66f13d85b 100644 --- a/src/Altinn.App.Api/Altinn.App.Api.csproj +++ b/src/Altinn.App.Api/Altinn.App.Api.csproj @@ -48,4 +48,9 @@ true $(NoWarn);1591 + + + + + diff --git a/src/Altinn.App.Api/Extensions/ServiceCollectionExtensions.cs b/src/Altinn.App.Api/Extensions/ServiceCollectionExtensions.cs index 31c160dc7c..d85e9fb97d 100644 --- a/src/Altinn.App.Api/Extensions/ServiceCollectionExtensions.cs +++ b/src/Altinn.App.Api/Extensions/ServiceCollectionExtensions.cs @@ -73,7 +73,13 @@ public static void AddAltinnAppServices(this IServiceCollection services, IConfi services.AddMetricsServer(config); } - private static void AddApplicationInsights(IServiceCollection services, IConfiguration config, IWebHostEnvironment env) + /// + /// Adds Application Insights to the service collection. + /// + /// Services + /// Config + /// Environment + internal static void AddApplicationInsights(IServiceCollection services, IConfiguration config, IWebHostEnvironment env) { string? applicationInsightsKey = env.IsDevelopment() ? config["ApplicationInsights:InstrumentationKey"] diff --git a/test/Altinn.App.Api.Tests/DITests.cs b/test/Altinn.App.Api.Tests/DITests.cs new file mode 100644 index 0000000000..ce9ca85733 --- /dev/null +++ b/test/Altinn.App.Api.Tests/DITests.cs @@ -0,0 +1,94 @@ + +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Configuration; +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.ApplicationInsights; +using System.Diagnostics.Tracing; + +namespace Altinn.App.Api.Tests; + +public class DITests +{ + private sealed record FakeWebHostEnvironment : IWebHostEnvironment, IHostingEnvironment + { + private string _env = ""; + + public string WebRootPath { get => new DirectoryInfo("./").FullName; set => throw new NotImplementedException(); } + public IFileProvider WebRootFileProvider { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ApplicationName { get => "test"; set => throw new NotImplementedException(); } + public IFileProvider ContentRootFileProvider { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ContentRootPath { get => new DirectoryInfo("./").FullName; set => throw new NotImplementedException(); } + public string EnvironmentName { get => _env; set => _env = value; } + } + + private sealed class AppInsightsListener : EventListener + { + private readonly List _eventSources = []; + public readonly List Events = []; + + protected override void OnEventSourceCreated(EventSource eventSource) + { + + if (eventSource.Name == "Microsoft-ApplicationInsights-AspNetCore") + { + _eventSources.Add(eventSource); + EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All); + } + + base.OnEventSourceCreated(eventSource); + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + if (eventData.EventSource.Name != "Microsoft-ApplicationInsights-AspNetCore") + { + return; + } + + Events.Add(eventData); + base.OnEventWritten(eventData); + } + + public override void Dispose() + { + foreach (var eventSource in _eventSources) + { + DisableEvents(eventSource); + } + base.Dispose(); + } + } + + [Fact] + public void AppInsights_Registers_Correctly() + { + using var listener = new AppInsightsListener(); + + var services = new ServiceCollection(); + var env = new FakeWebHostEnvironment { EnvironmentName = "Development" }; + + services.AddSingleton(env); + services.AddSingleton(env); + + var config = new ConfigurationBuilder() + .AddInMemoryCollection([ + new KeyValuePair("ApplicationInsights:InstrumentationKey", "test") + ]).Build(); + + Extensions.ServiceCollectionExtensions.AddAltinnAppServices(services, config, env); + + using var sp = services.BuildServiceProvider(); + + var telemetryConfig = sp.GetRequiredService(); + Assert.NotNull(telemetryConfig); + + var client = sp.GetRequiredService(); + Assert.NotNull(client); + + EventLevel[] errorLevels = [EventLevel.Error, EventLevel.Critical]; + Assert.Empty(listener.Events.Where(e => errorLevels.Contains(e.Level))); + } +} \ No newline at end of file From 567bca06f5f7d7dcb7f9b8c356d2f277f2f06757 Mon Sep 17 00:00:00 2001 From: Martin Othamar Date: Tue, 16 Apr 2024 08:39:34 +0200 Subject: [PATCH 3/4] Add test for services registration EndTaskEventHandler --- .../ProcessTask/EndTaskEventHandlerTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs b/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs index 1ce89e9c44..70726f9f8d 100644 --- a/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs +++ b/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs @@ -127,4 +127,38 @@ public async Task Calls_unlock_if_pdf_fails() // Make sure eFormidling service task is not called if PDF failed. _eformidlingServiceTask.Verify(p => p.Execute(taskId, instance), Times.Never); } + + [Fact] + public void Throws_If_Missing_Pdf_ServiceTask() + { + IServiceTask[] serviceTasks = [ + _eformidlingServiceTask.Object + ]; + + var ex = Assert.Throws(() => + new EndTaskEventHandler( + _processTaskDataLocker.Object, + _processTaskFinisher.Object, + serviceTasks, + _processTaskEnds, + _logger)); + Assert.Equal("PdfServiceTask not found in serviceTasks", ex.Message); + } + + [Fact] + public void Throws_If_Missing_Eformidling_ServiceTask() + { + IServiceTask[] serviceTasks = [ + _pdfServiceTask.Object + ]; + + var ex = Assert.Throws(() => + new EndTaskEventHandler( + _processTaskDataLocker.Object, + _processTaskFinisher.Object, + serviceTasks, + _processTaskEnds, + _logger)); + Assert.Equal("EformidlingServiceTask not found in serviceTasks", ex.Message); + } } \ No newline at end of file From da1d6d1fe4b09344ae9330555436b00757d30510 Mon Sep 17 00:00:00 2001 From: Martin Othamar Date: Tue, 16 Apr 2024 08:40:39 +0200 Subject: [PATCH 4/4] dotnet format ... --- .../Process/ServiceTasks/EformidlingServiceTask.cs | 2 +- .../Internal/Process/ServiceTasks/PdfServiceTask.cs | 2 +- test/Altinn.App.Api.Tests/DITests.cs | 8 ++++---- .../EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs b/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs index 785fd03921..764adeaff5 100644 --- a/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs +++ b/src/Altinn.App.Core/Internal/Process/ServiceTasks/EformidlingServiceTask.cs @@ -9,7 +9,7 @@ namespace Altinn.App.Core.Internal.Process.ServiceTasks; -internal interface IEformidlingServiceTask : IServiceTask {} +internal interface IEformidlingServiceTask : IServiceTask { } /// /// Service task that sends eFormidling shipment, if EFormidling is enabled in config and EFormidling.SendAfterTaskId matches the current task. diff --git a/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs b/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs index 35cab04c08..d79b257221 100644 --- a/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs +++ b/src/Altinn.App.Core/Internal/Process/ServiceTasks/PdfServiceTask.cs @@ -5,7 +5,7 @@ namespace Altinn.App.Core.Internal.Process.ServiceTasks; -internal interface IPdfServiceTask : IServiceTask {} +internal interface IPdfServiceTask : IServiceTask { } /// /// Service task that generates PDFs for all connected datatypes that have the EnablePdfCreation flag set to true. diff --git a/test/Altinn.App.Api.Tests/DITests.cs b/test/Altinn.App.Api.Tests/DITests.cs index ce9ca85733..2eb0fc4659 100644 --- a/test/Altinn.App.Api.Tests/DITests.cs +++ b/test/Altinn.App.Api.Tests/DITests.cs @@ -21,7 +21,7 @@ private sealed record FakeWebHostEnvironment : IWebHostEnvironment, IHostingEnvi public string ApplicationName { get => "test"; set => throw new NotImplementedException(); } public IFileProvider ContentRootFileProvider { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public string ContentRootPath { get => new DirectoryInfo("./").FullName; set => throw new NotImplementedException(); } - public string EnvironmentName { get => _env; set => _env = value; } + public string EnvironmentName { get => _env; set => _env = value; } } private sealed class AppInsightsListener : EventListener @@ -31,7 +31,7 @@ private sealed class AppInsightsListener : EventListener protected override void OnEventSourceCreated(EventSource eventSource) { - + if (eventSource.Name == "Microsoft-ApplicationInsights-AspNetCore") { _eventSources.Add(eventSource); @@ -60,7 +60,7 @@ public override void Dispose() } base.Dispose(); } - } + } [Fact] public void AppInsights_Registers_Correctly() @@ -84,7 +84,7 @@ public void AppInsights_Registers_Correctly() var telemetryConfig = sp.GetRequiredService(); Assert.NotNull(telemetryConfig); - + var client = sp.GetRequiredService(); Assert.NotNull(client); diff --git a/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs b/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs index 70726f9f8d..642b24c593 100644 --- a/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs +++ b/test/Altinn.App.Core.Tests/Internal/Process/EventHandlers/ProcessTask/EndTaskEventHandlerTests.cs @@ -135,7 +135,7 @@ public void Throws_If_Missing_Pdf_ServiceTask() _eformidlingServiceTask.Object ]; - var ex = Assert.Throws(() => + var ex = Assert.Throws(() => new EndTaskEventHandler( _processTaskDataLocker.Object, _processTaskFinisher.Object, @@ -152,7 +152,7 @@ public void Throws_If_Missing_Eformidling_ServiceTask() _pdfServiceTask.Object ]; - var ex = Assert.Throws(() => + var ex = Assert.Throws(() => new EndTaskEventHandler( _processTaskDataLocker.Object, _processTaskFinisher.Object,