From 7bd2c2e3e9dee1e4b964f0936610c2d7715ebded Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Tue, 10 Dec 2024 08:42:34 +0000 Subject: [PATCH 01/12] Fixed almost all outstanding ReSharper warnings --- .../Helpers/MultiSeriesDatasetAssertions.cs | 1 - .../Helpers/SingleSeriesDatasetAssertions.cs | 2 - .../Helpers/TestContextHelper.cs | 2 +- .../Helpers/TestDataGeneratorHelpers.cs | 20 +- .../ImportNotificationsByCommoditiesTests.cs | 2 +- .../ImportNotificationsByCreatedDateTests.cs | 4 +- .../MovementsByCreatedDateTests.cs | 4 +- Btms.Analytics.Tests/MovementsByItemsTests.cs | 2 +- ...MovementsByUniqueDocumentReferenceTests.cs | 2 +- ...ementsDocumentReferencesByMovementTests.cs | 1 - .../Extensions/AnalyticsExtensions.cs | 21 +- Btms.Analytics/Extensions/AnalyticsHelpers.cs | 9 +- Btms.Analytics/ImportNotificationMetrics.cs | 15 +- .../ImportNotificationsAggregationService.cs | 19 +- Btms.Analytics/MovementsAggregationService.cs | 30 +-- Btms.Azure/AzureService.cs | 7 +- ...dentialClientApplicationTokenCredential.cs | 4 +- Btms.Azure/Extensions/IServiceExtensions.cs | 4 +- Btms.Azure/IAzureConfig.cs | 13 +- .../GenerateModels/CSharpFileBuilder.cs | 219 ++++++++-------- .../GenerateModels/ClassMaps/Bootstrap.cs | 5 +- .../ClassMaps/GeneratorClassMap.cs | 166 ++++++------ .../ClassMaps/GeneratorEnumMap.cs | 14 +- .../GenerateModels/ClassMaps/PropertyMap.cs | 8 +- .../DescriptorModel/ClassDescriptor.cs | 2 +- .../DescriptorModel/EnumDescriptor.cs | 6 +- .../DescriptorModel/PropertyDescriptor.cs | 218 ++++++++-------- .../Commands/GenerateAlvsModelCommand.cs | 139 +++++----- .../Commands/XmlSchemaExtensions.cs | 2 +- .../DescriptorBuilderSchemaVisitor.cs | 4 +- .../Commands/GenerateIpaffsModelCommand.cs | 47 ++-- .../GenerateVehicleMovementModelCommand.cs | 179 +++++++------ .../Templates/ClassTemplate.cshtml | 1 - .../Templates/EnumMapperTemplate.cshtml | 2 - .../Templates/EnumTemplate.cshtml | 1 - .../Templates/InternalClassTemplate.cshtml | 1 - .../Templates/InternalEnumTemplate.cshtml | 1 - .../Templates/MapperTemplate.cshtml | 6 +- Btms.Backend.Cli/Program.cs | 4 +- .../Extensions/ServiceCollectionExtensions.cs | 45 ++-- .../Healthcheck/MongoDbHealthCheck.cs | 91 ++++--- .../MongoDbHealthCheckBuilderExtensions.cs | 5 +- Btms.Backend.Data/IMongoCollectionSet.cs | 2 +- Btms.Backend.Data/IMongoDbTransaction.cs | 2 +- .../InMemory/MemoryCollectionSet.cs | 8 +- Btms.Backend.Data/Mongo/MongoCollectionSet.cs | 112 ++++---- Btms.Backend.Data/Mongo/MongoDbTransaction.cs | 4 +- Btms.Backend.Data/Mongo/MongoIndexService.cs | 2 +- Btms.Backend.IntegrationTests/BaseApiTests.cs | 135 +++++----- Btms.Backend.IntegrationTests/GmrTests.cs | 17 +- .../JsonApiClient/JsonApiClient.cs | 32 +-- .../JsonApiClient/JsonApiClientExtensions.cs | 18 +- .../JsonApiClient/JsonApiDocument.cs | 2 +- .../JsonApiClient/ManyItemsJsonApiDocument.cs | 4 +- .../SingleItemJsonApiDocument.cs | 4 +- Btms.Backend.IntegrationTests/LinkingTests.cs | 165 ++++++------ .../SensitiveDataTests.cs | 10 +- Btms.Backend.IntegrationTests/SmokeTests.cs | 245 +++++++++--------- .../SyncJobResponse.cs | 31 ++- Btms.Backend.Test/Auditing/AuditingTests.cs | 8 +- Btms.Backend.Test/Config/ApiOptionsTest.cs | 2 +- Btms.Backend.Test/Utils/Http/ProxyTest.cs | 3 +- .../ClientCredentialsManager.cs | 17 +- .../IClientCredentialsManager.cs | 9 +- .../BackgroundTaskQueue.cs | 62 +++-- .../BackgroundTaskQueue/QueueHostedService.cs | 13 +- Btms.Backend/Config/ApiOptions.cs | 4 +- Btms.Backend/Endpoints/AnalyticsEndpoints.cs | 1 - Btms.Backend/Endpoints/ManagementEndpoints.cs | 14 +- Btms.Backend/Endpoints/SyncEndpoints.cs | 11 +- .../JsonApi/BtmsResponseModelAdapter.cs | 13 +- Btms.Backend/Mediatr/BtmsMediator.cs | 85 +++--- Btms.Backend/Program.cs | 4 +- Btms.Backend/Utils/Http/Proxy.cs | 3 +- Btms.Backend/Utils/Logging/LogLevelMapper.cs | 2 +- Btms.Backend/Utils/TrustStore.cs | 2 +- Btms.BlobService/BlobService.cs | 17 +- Btms.BlobService/BlobServiceClientFactory.cs | 2 +- Btms.BlobService/BlobServiceOptions.cs | 1 - Btms.BlobService/BtmsBlobItem.cs | 2 - Btms.BlobService/CachingBlobService.cs | 15 +- .../Extensions/ServiceCollectionExtensions.cs | 40 ++- Btms.BlobService/IBlobItem.cs | 2 - Btms.BlobService/Status.cs | 13 +- .../SyncClearanceRequestsCommandTests.cs | 75 +++--- .../Commands/SyncDecisionsCommandTests.cs | 72 +++-- .../Commands/SyncNotificationsCommandTests.cs | 81 +++--- Btms.Business.Tests/Commands/TestBlobItem.cs | 4 +- Btms.Business.Tests/DummyMeterFactory.cs | 2 +- .../Matching/MatchPreProcessTests.cs | 2 +- .../MovementPreProcessingTests.cs | 6 +- .../NotificationsPreProcessingTests.cs | 99 ++++--- .../Services/LinkingServiceTests.cs | 46 ++-- Btms.Business/BusinessOptions.cs | 1 - .../Commands/DownloadNotificationsCommand.cs | 22 +- .../Commands/SyncClearanceRequestsCommand.cs | 2 +- .../Commands/SyncDecisionsCommand.cs | 2 +- Btms.Business/Commands/SyncGmrsCommand.cs | 2 +- Btms.Business/Commands/SyncHandler.cs | 16 +- .../Commands/SyncNotificationsCommand.cs | 88 +++---- .../Extensions/ServiceCollectionExtensions.cs | 77 +++--- .../ImportNotificationPreProcessor.cs | 5 +- .../PreProcessing/MovementPreProcessor.cs | 19 +- Btms.Business/Services/LinkingService.cs | 6 +- Btms.Common/Extensions/GeneralExtensions.cs | 2 +- Btms.Common/Extensions/OptionsExtensions.cs | 12 - .../ClearanceRequestConsumerTests.cs | 131 +++++----- Btms.Consumers.Tests/DummyMeterFactory.cs | 2 +- .../NotificationsConsumerTests.cs | 132 +++++----- .../AlvsClearanceRequestConsumer.cs | 51 ++-- Btms.Consumers/ConsumerLogging.cs | 1 - Btms.Consumers/DecisionsConsumer.cs | 31 ++- .../Extensions/ServiceCollectionExtensions.cs | 105 ++++---- Btms.Consumers/GmrConsumer.cs | 60 +++-- .../InMemoryConsumerErrorHandler.cs | 7 +- .../Interceptors/MetricsInterceptor.cs | 12 +- .../MemoryQueue/MemoryQueueStatsMonitor.cs | 4 +- Btms.Consumers/NotificationConsumer.cs | 53 ++-- Btms.Emf/EmfExporter.cs | 128 +++++---- Btms.Metrics/ConsumerMetrics.cs | 13 +- .../Extensions/ServiceCollectionExtensions.cs | 19 +- Btms.Metrics/InMemoryQueueMetrics.cs | 8 +- Btms.Metrics/LinkingMetrics.cs | 6 +- Btms.Metrics/MetricNames.cs | 23 +- Btms.Metrics/ObservabilityUtils.cs | 51 ++-- Btms.Metrics/SyncMetrics.cs | 9 +- Btms.Model/Alvs/AlvsClearanceRequest.g.cs | 6 +- Btms.Model/Alvs/AlvsClearanceRequestPost.g.cs | 10 +- Btms.Model/Alvs/Check.cs | 4 +- Btms.Model/Alvs/Check.g.cs | 4 +- Btms.Model/Alvs/Document.g.cs | 10 +- Btms.Model/Alvs/Header.g.cs | 26 +- Btms.Model/Alvs/Items.cs | 4 +- Btms.Model/Alvs/Items.g.cs | 24 +- Btms.Model/Alvs/ServiceHeader.g.cs | 8 +- Btms.Model/Auditing/AuditEntry.cs | 20 +- Btms.Model/ChangeLog/ChangeSet.cs | 6 +- .../ChangeLog/ChangeSetTypeInfoResolver.cs | 4 +- Btms.Model/Data/IDataEntity.cs | 1 + .../ImportNotificationTypeEnumExtensions.cs | 1 - Btms.Model/Extensions/JsonExtensions.cs | 21 +- Btms.Model/Extensions/LinksBuilder.cs | 16 +- Btms.Model/Gvms/Gmr.cs | 5 +- Btms.Model/Ipaffs/ImportNotification.cs | 33 ++- Btms.Model/MatchIdentifier.cs | 4 +- Btms.Model/Movement.cs | 25 +- .../Relationships/RelationshipDataItem.cs | 40 +-- Btms.Model/Relationships/RelationshipLinks.cs | 4 +- .../Relationships/TdmRelationshipObject.cs | 4 +- .../SensitiveDataSerializerTests.cs | 30 +-- Btms.SensitiveData.Tests/SimpleClass.cs | 15 +- Btms.SensitiveData/SensitiveDataOptions.cs | 8 +- Btms.SensitiveData/SensitiveDataSerializer.cs | 8 +- .../SensitiveDataTypeInfoResolver.cs | 2 +- Btms.SensitiveData/SensitiveFieldsProvider.cs | 20 +- ...ringArraySensitiveDataRedactedConverter.cs | 2 +- .../Extensions/ServiceCollectionExtensions.cs | 13 +- Btms.SyncJob/SyncJobStore.cs | 43 ++- .../CheckMapperTests.cs | 2 - .../DocumentMapperTests.cs | 2 - .../HeaderMapperTests.cs | 45 ++-- .../ItemsMapperTests.cs | 2 - .../ServiceHeaderMapperTests.cs | 2 - Btms.Types.Alvs.V1/AlvsClearanceRequest.g.cs | 6 +- .../AlvsClearanceRequestPost.g.cs | 10 +- .../AlvsClearanceRequestPostResult.g.cs | 8 +- Btms.Types.Alvs.V1/Check.cs | 4 +- Btms.Types.Alvs.V1/Check.g.cs | 4 +- .../ClearanceRequestExtensions.cs | 8 +- Btms.Types.Alvs.V1/Document.g.cs | 10 +- Btms.Types.Alvs.V1/Header.g.cs | 26 +- Btms.Types.Alvs.V1/Items.g.cs | 24 +- Btms.Types.Alvs.V1/ServiceHeader.g.cs | 8 +- .../GrmWithTransformMapper.cs | 14 +- .../DictionaryMapper.cs | 27 +- .../ImportNotificationWithTransformMapper.cs | 32 +-- .../ImportNotificationTypeEnumExtensions.cs | 2 - ...rsToDictionaryStringObjectJsonConverter.cs | 3 +- TestDataGenerator/ClearanceRequestBuilder.cs | 6 +- TestDataGenerator/Generator.cs | 8 +- .../Helpers/BuilderExtensions.cs | 1 - .../ImportNotificationBuilder.cs | 3 +- TestDataGenerator/Program.cs | 9 +- .../ChedAManyCommoditiesScenarioGenerator.cs | 2 +- .../ChedANoMatchScenarioGenerator.cs | 2 +- .../ChedASimpleMatchScenarioGenerator.cs | 2 +- .../Scenarios/ScenarioFactory.cs | 5 - 187 files changed, 2210 insertions(+), 2441 deletions(-) diff --git a/Btms.Analytics.Tests/Helpers/MultiSeriesDatasetAssertions.cs b/Btms.Analytics.Tests/Helpers/MultiSeriesDatasetAssertions.cs index d2c8140..85350c7 100644 --- a/Btms.Analytics.Tests/Helpers/MultiSeriesDatasetAssertions.cs +++ b/Btms.Analytics.Tests/Helpers/MultiSeriesDatasetAssertions.cs @@ -1,4 +1,3 @@ -using Btms.Common.Extensions; using FluentAssertions; using FluentAssertions.Collections; diff --git a/Btms.Analytics.Tests/Helpers/SingleSeriesDatasetAssertions.cs b/Btms.Analytics.Tests/Helpers/SingleSeriesDatasetAssertions.cs index 19cb006..e8ff273 100644 --- a/Btms.Analytics.Tests/Helpers/SingleSeriesDatasetAssertions.cs +++ b/Btms.Analytics.Tests/Helpers/SingleSeriesDatasetAssertions.cs @@ -1,6 +1,4 @@ -using Btms.Common.Extensions; using FluentAssertions; -using FluentAssertions.Collections; namespace Btms.Analytics.Tests.Helpers; diff --git a/Btms.Analytics.Tests/Helpers/TestContextHelper.cs b/Btms.Analytics.Tests/Helpers/TestContextHelper.cs index a9bd538..0f03e74 100644 --- a/Btms.Analytics.Tests/Helpers/TestContextHelper.cs +++ b/Btms.Analytics.Tests/Helpers/TestContextHelper.cs @@ -17,7 +17,7 @@ namespace Btms.Analytics.Tests.Helpers; public static class TestContextHelper { - public static IHostBuilder CreateBuilder(ITestOutputHelper testOutputHelper = null!) + public static IHostBuilder CreateBuilder(ITestOutputHelper? testOutputHelper = null) { var builder = Host.CreateDefaultBuilder(); diff --git a/Btms.Analytics.Tests/Helpers/TestDataGeneratorHelpers.cs b/Btms.Analytics.Tests/Helpers/TestDataGeneratorHelpers.cs index 168dff9..d7343f2 100644 --- a/Btms.Analytics.Tests/Helpers/TestDataGeneratorHelpers.cs +++ b/Btms.Analytics.Tests/Helpers/TestDataGeneratorHelpers.cs @@ -1,6 +1,4 @@ -using System.Collections; using Btms.Consumers; -using Btms.Model.Extensions; using Btms.Types.Alvs; using Btms.Types.Ipaffs; using Microsoft.Extensions.DependencyInjection; @@ -15,14 +13,14 @@ namespace Btms.Analytics.Tests.Helpers; public static class TestDataGeneratorHelpers { - private static int scenarioIndex = 0; + private static int _scenarioIndex; public static async Task PushToConsumers(this IHost app, ScenarioConfig scenario) { var generatorResults = app.Generate(scenario); - scenarioIndex++; + _scenarioIndex++; - var logger = app.Services.GetRequiredService>(); + app.Services.GetRequiredService>(); foreach (var generatorResult in generatorResults) { @@ -31,9 +29,9 @@ public static async Task PushToConsumers(this IHost app, ScenarioConfig s var scope = app.Services.CreateScope(); var consumer = (AlvsClearanceRequestConsumer)scope.ServiceProvider.GetRequiredService>(); - consumer.Context = new ConsumerContext() + consumer.Context = new ConsumerContext { - Headers = new Dictionary() { { "messageId", cr!.Header!.EntryReference! } } + Headers = new Dictionary { { "messageId", cr.Header!.EntryReference! } } }; await consumer.OnHandle(cr); @@ -44,9 +42,9 @@ public static async Task PushToConsumers(this IHost app, ScenarioConfig s var scope = app.Services.CreateScope(); var consumer = (NotificationConsumer)scope.ServiceProvider.GetRequiredService>(); - consumer.Context = new ConsumerContext() + consumer.Context = new ConsumerContext { - Headers = new Dictionary() { { "messageId", n!.ReferenceNumber! } } + Headers = new Dictionary { { "messageId", n.ReferenceNumber! } } }; await consumer.OnHandle(n); @@ -63,7 +61,7 @@ private static ScenarioGenerator.GeneratorResult[] Generate(this IHost app, Scen var count = scenario.Count; var generator = scenario.Generator; - logger.LogInformation("Generating {Count}x{Days} {Generator}.", count, days, generator); + logger.LogInformation("Generating {Count}x{Days} {@Generator}", count, days, generator); var results = new List(); for (var d = -days + 1; d <= 0; d++) @@ -75,7 +73,7 @@ private static ScenarioGenerator.GeneratorResult[] Generate(this IHost app, Scen { logger.LogInformation("Generating item {I}", i); - results.Add(generator.Generate(scenarioIndex, i, entryDate, scenario)); + results.Add(generator.Generate(_scenarioIndex, i, entryDate, scenario)); } } diff --git a/Btms.Analytics.Tests/ImportNotificationsByCommoditiesTests.cs b/Btms.Analytics.Tests/ImportNotificationsByCommoditiesTests.cs index c371553..c132682 100644 --- a/Btms.Analytics.Tests/ImportNotificationsByCommoditiesTests.cs +++ b/Btms.Analytics.Tests/ImportNotificationsByCommoditiesTests.cs @@ -20,7 +20,7 @@ public async Task WhenCalledLastWeek_ReturnExpectedAggregation() testOutputHelper.WriteLine("Querying for aggregated data"); var result = (await multiItemDataTestFixture.ImportNotificationsAggregationService .ByCommodityCount(DateTime.Today.WeekAgo(), DateTime.Today.Tomorrow())) - .ToList();; + .ToList(); testOutputHelper.WriteLine("{0} aggregated items found", result.Count); diff --git a/Btms.Analytics.Tests/ImportNotificationsByCreatedDateTests.cs b/Btms.Analytics.Tests/ImportNotificationsByCreatedDateTests.cs index d750853..8426b5f 100644 --- a/Btms.Analytics.Tests/ImportNotificationsByCreatedDateTests.cs +++ b/Btms.Analytics.Tests/ImportNotificationsByCreatedDateTests.cs @@ -58,8 +58,8 @@ public async Task WhenCalledLastMonth_ReturnExpectedAggregation() [Fact] public async Task WhenCalledWithTimePeriodYieldingNoResults_ReturnEmptyAggregation() { - DateTime from = DateTime.MaxValue.AddDays(-1); - DateTime to = DateTime.MaxValue; + var from = DateTime.MaxValue.AddDays(-1); + var to = DateTime.MaxValue; var result = (await basicSampleDataTestFixture.ImportNotificationsAggregationService .ByCreated(from, to, AggregationPeriod.Hour)) diff --git a/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs b/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs index e57094b..a762775 100644 --- a/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs +++ b/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs @@ -33,8 +33,8 @@ public async Task WhenCalledLast48Hours_ReturnExpectedAggregation() [Fact] public async Task WhenCalledWithTimePeriodYieldingNoResults_ReturnEmptyAggregation() { - DateTime from = DateTime.MaxValue.AddDays(-1); - DateTime to = DateTime.MaxValue; + var from = DateTime.MaxValue.AddDays(-1); + var to = DateTime.MaxValue; var result = (await basicSampleDataTestFixture.MovementsAggregationService .ByCreated(from, to, AggregationPeriod.Hour)) diff --git a/Btms.Analytics.Tests/MovementsByItemsTests.cs b/Btms.Analytics.Tests/MovementsByItemsTests.cs index 4575d59..0f12701 100644 --- a/Btms.Analytics.Tests/MovementsByItemsTests.cs +++ b/Btms.Analytics.Tests/MovementsByItemsTests.cs @@ -20,7 +20,7 @@ public async Task WhenCalledLastWeek_ReturnExpectedAggregation() testOutputHelper.WriteLine("Querying for aggregated data"); var result = (await multiItemDataTestFixture.MovementsAggregationService .ByItemCount(DateTime.Today.WeekAgo(), DateTime.Today.Tomorrow())) - .ToList();; + .ToList(); testOutputHelper.WriteLine("{0} aggregated items found", result.Count); diff --git a/Btms.Analytics.Tests/MovementsByUniqueDocumentReferenceTests.cs b/Btms.Analytics.Tests/MovementsByUniqueDocumentReferenceTests.cs index 1a4f6ca..b0b80be 100644 --- a/Btms.Analytics.Tests/MovementsByUniqueDocumentReferenceTests.cs +++ b/Btms.Analytics.Tests/MovementsByUniqueDocumentReferenceTests.cs @@ -20,7 +20,7 @@ public async Task WhenCalledLastWeek_ReturnExpectedAggregation() testOutputHelper.WriteLine("Querying for aggregated data"); var result = (await multiItemDataTestFixture.MovementsAggregationService .ByUniqueDocumentReferenceCount(DateTime.Today.WeekAgo(), DateTime.Today.Tomorrow())) - .ToList();; + .ToList(); testOutputHelper.WriteLine("{0} aggregated items found", result.Count); diff --git a/Btms.Analytics.Tests/MovementsDocumentReferencesByMovementTests.cs b/Btms.Analytics.Tests/MovementsDocumentReferencesByMovementTests.cs index c17239b..6a2ed05 100644 --- a/Btms.Analytics.Tests/MovementsDocumentReferencesByMovementTests.cs +++ b/Btms.Analytics.Tests/MovementsDocumentReferencesByMovementTests.cs @@ -1,5 +1,4 @@ using Btms.Common.Extensions; -using FluentAssertions; using Xunit; using Xunit.Abstractions; diff --git a/Btms.Analytics/Extensions/AnalyticsExtensions.cs b/Btms.Analytics/Extensions/AnalyticsExtensions.cs index 70b2e1c..de14f73 100644 --- a/Btms.Analytics/Extensions/AnalyticsExtensions.cs +++ b/Btms.Analytics/Extensions/AnalyticsExtensions.cs @@ -1,10 +1,5 @@ -using System.Collections; -using System.Linq.Expressions; using Btms.Backend.Data; using Btms.Model.Data; -using Btms.Model.Extensions; -using Btms.Model.Ipaffs; -using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -17,7 +12,7 @@ namespace Btms.Analytics.Extensions; public static class AnalyticsExtensions { - private static readonly bool enableMetrics = true; + private static readonly bool EnableMetrics = true; public static IServiceCollection AddAnalyticsServices(this IServiceCollection services, IConfiguration configuration) { @@ -25,7 +20,7 @@ public static IServiceCollection AddAnalyticsServices(this IServiceCollection se services.AddScoped(); // To revisit in future - if (enableMetrics) + if (EnableMetrics) { services.TryAddScoped(); } @@ -76,11 +71,11 @@ public static MultiSeriesDatetimeDataset AsDataset(this Dictionary - new ByDateTimeResult() + new ByDateTimeResult { Period = resultDate, Value = dates.GetValueOrDefault(resultDate, 0) }) - .Order(AnalyticsHelpers.byDateTimeResultComparer) + .Order(AnalyticsHelpers.ByDateTimeResultComparer) .ToList() }; } @@ -102,7 +97,7 @@ internal static IEnumerable> Execute(thi } catch(Exception ex) { - logger.LogError(ex, "Error querying Mongo : {message}", ex.Message); + logger.LogError(ex, "Error querying Mongo : {Message}", ex.Message); throw new AnalyticsException("Error querying Mongo", ex); } finally @@ -122,7 +117,7 @@ internal static IEnumerable Execute( } catch(Exception ex) { - logger.LogError(ex, "Error querying Mongo : {message}", ex.Message); + logger.LogError(ex, "Error querying Mongo : {Message}", ex.Message); throw new AnalyticsException("Error querying Mongo", ex); } finally @@ -141,8 +136,6 @@ private static void LogExecutedMongoString(this ILogger logger, IQueryable sourc { var stages = ((IMongoQueryProvider)source.Provider).LoggedStages; - var query = "[" + String.Join(",", stages.Select(s => s.ToString()).ToArray()) +"]"; - - logger.LogInformation(query); + logger.LogInformation("[{Query}]", string.Join(",", stages.Select(s => s.ToString()).ToArray())); } } \ No newline at end of file diff --git a/Btms.Analytics/Extensions/AnalyticsHelpers.cs b/Btms.Analytics/Extensions/AnalyticsHelpers.cs index 62ab413..3b830f7 100644 --- a/Btms.Analytics/Extensions/AnalyticsHelpers.cs +++ b/Btms.Analytics/Extensions/AnalyticsHelpers.cs @@ -1,6 +1,3 @@ -using Btms.Common.Extensions; -using Btms.Model.Extensions; -using System.Collections.Generic; using Btms.Model; using MongoDB.Bson; namespace Btms.Analytics.Extensions; @@ -40,17 +37,17 @@ internal static DateTime[] CreateDateRange(DateTime from, DateTime to, Aggregati .Select(offset => from.Increment(offset, aggregateBy)) // from.AddDays(offset)) .ToArray(); - internal static readonly Comparer? byDateTimeResultComparer = Comparer.Create((d1, d2) => d1.Period.CompareTo(d2.Period)); + internal static readonly Comparer? ByDateTimeResultComparer = Comparer.Create((d1, d2) => d1.Period.CompareTo(d2.Period)); public static string[] GetImportNotificationSegments() { return ModelHelpers.GetChedTypes() - .SelectMany(chedType => new string[] { $"{chedType} Linked", $"{chedType} Not Linked" }) + .SelectMany(chedType => new[] { $"{chedType} Linked", $"{chedType} Not Linked" }) .ToArray(); } public static string[] GetMovementSegments() { - return new string[] { "Linked", "Not Linked" }; + return ["Linked", "Not Linked"]; } } \ No newline at end of file diff --git a/Btms.Analytics/ImportNotificationMetrics.cs b/Btms.Analytics/ImportNotificationMetrics.cs index 63b274a..cf83903 100644 --- a/Btms.Analytics/ImportNotificationMetrics.cs +++ b/Btms.Analytics/ImportNotificationMetrics.cs @@ -1,16 +1,7 @@ - - -using System.Diagnostics; using System.Diagnostics.Metrics; -using System.Runtime.InteropServices.JavaScript; -using System.Text; -using Btms.Common; -using Btms.Metrics; using Btms.Analytics.Extensions; using Btms.Common.Extensions; using Btms.Model; -using Btms.Model.Extensions; -using Btms.Model.Ipaffs; using Microsoft.Extensions.Logging; namespace Btms.Analytics; @@ -22,7 +13,7 @@ namespace Btms.Analytics; public class ImportNotificationMetrics { private readonly IImportNotificationsAggregationService _importService; - private readonly Dictionary _metrics = new Dictionary(); + private readonly Dictionary _metrics = new(); private readonly ILogger _logger; private void Add(Instrument i) @@ -59,12 +50,12 @@ public async Task RecordCurrentState() } else { - _logger.LogWarning("Unexpected type of instrument {type} for metric {name}", instrument.GetType(), key); + _logger.LogWarning("Unexpected type of instrument {Type} for metric {Name}", instrument.GetType(), key); } } else { - _logger.LogWarning("No instrument present for metric {name}", key); + _logger.LogWarning("No instrument present for metric {Name}", key); } } } diff --git a/Btms.Analytics/ImportNotificationsAggregationService.cs b/Btms.Analytics/ImportNotificationsAggregationService.cs index 67345d9..f2af39a 100644 --- a/Btms.Analytics/ImportNotificationsAggregationService.cs +++ b/Btms.Analytics/ImportNotificationsAggregationService.cs @@ -1,17 +1,12 @@ -using System.Collections; using Microsoft.Extensions.Logging; using System.Linq.Expressions; using Btms.Backend.Data; -using Btms.Common.Extensions; using Btms.Model.Extensions; using Btms.Model.Ipaffs; -using Btms.Model; -using Microsoft.AspNetCore.Http; using MongoDB.Bson; using MongoDB.Driver; using Btms.Analytics.Extensions; -using MongoDB.Driver.Linq; namespace Btms.Analytics; @@ -25,7 +20,7 @@ public Task ByCreated(DateTime from, DateTime to, n.CreatedSource >= from && n.CreatedSource < to; string CreateDatasetName(BsonDocument b) => - AnalyticsHelpers.GetLinkedName(b["_id"]["linked"].ToBoolean(), b["_id"]["importNotificationType"].ToString()!.FromImportNotificationTypeEnumString()!); + AnalyticsHelpers.GetLinkedName(b["_id"]["linked"].ToBoolean(), b["_id"]["importNotificationType"].ToString()!.FromImportNotificationTypeEnumString()); return Aggregate(dateRange, CreateDatasetName, matchFilter, "$createdSource", aggregateBy); } @@ -38,7 +33,7 @@ public Task ByArrival(DateTime from, DateTime to, n.PartOne!.ArrivesAt >= from && n.PartOne!.ArrivesAt < to; string CreateDatasetName(BsonDocument b) => - AnalyticsHelpers.GetLinkedName(b["_id"]["linked"].ToBoolean(), b["_id"]["importNotificationType"].ToString()!.FromImportNotificationTypeEnumString()!); + AnalyticsHelpers.GetLinkedName(b["_id"]["linked"].ToBoolean(), b["_id"]["importNotificationType"].ToString()!.FromImportNotificationTypeEnumString()); return Aggregate(dateRange, CreateDatasetName, matchFilter, "$partOne.arrivesAt", aggregateBy); } @@ -50,10 +45,10 @@ public Task ByStatus(DateTime from, DateTime to) .Where(n => n.CreatedSource >= from && n.CreatedSource < to) .GroupBy(n => new { n.ImportNotificationType, Linked = n.Relationships.Movements.Data.Count > 0 }) .Select(g => new { g.Key.Linked, g.Key.ImportNotificationType, Count = g.Count() }) - .ToDictionary(g => AnalyticsHelpers.GetLinkedName(g.Linked, g.ImportNotificationType.AsString()!), + .ToDictionary(g => AnalyticsHelpers.GetLinkedName(g.Linked, g.ImportNotificationType.AsString()), g => g.Count); - return Task.FromResult(new SingeSeriesDataset() + return Task.FromResult(new SingeSeriesDataset { Values = AnalyticsHelpers.GetImportNotificationSegments().ToDictionary(title => title, title => data.GetValueOrDefault(title, 0)) }); @@ -83,7 +78,7 @@ public Task ByCommodityCount(DateTime from, DateTime to) .SelectMany(g => g.Select(r => new { - Title = AnalyticsHelpers.GetLinkedName(g.Key.Linked, g.Key.ImportNotificationType.AsString()!), + Title = AnalyticsHelpers.GetLinkedName(g.Key.Linked, g.Key.ImportNotificationType.AsString()), r.Key.CommodityCount, NotificationCount = r.Count }) @@ -102,7 +97,7 @@ public Task ByCommodityCount(DateTime from, DateTime to) { // Results = asDictionary.AsResultList(title, maxCommodities) Results = Enumerable.Range(0, maxCommodities) - .Select(i => new ByNumericDimensionResult() + .Select(i => new ByNumericDimensionResult { Dimension = i, Value = asDictionary.GetValueOrDefault(new { Title=title, CommodityCount = i }) @@ -133,7 +128,7 @@ private Task Aggregate(DateTime[] dateRange, Func< .Select(title => mongoResult.AsDataset(dateRange, title)) .AsOrderedArray(d => d.Name); - logger.LogDebug("Aggregated Data {result}", output.ToList().ToJsonString()); + logger.LogDebug("Aggregated Data {Result}", output.ToList().ToJsonString()); return Task.FromResult(output); } diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 672fb26..4d91fa6 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -1,14 +1,8 @@ -using System.Collections; -using System.Data.Common; using Microsoft.Extensions.Logging; using System.Linq.Expressions; -using System.Text.RegularExpressions; using Btms.Backend.Data; -using Btms.Common.Extensions; using Btms.Model.Extensions; -using Btms.Model.Ipaffs; using Btms.Model; -using Microsoft.AspNetCore.Http; using MongoDB.Bson; using MongoDB.Driver; @@ -47,7 +41,7 @@ public Task ByStatus(DateTime from, DateTime to) .Select(g => new { g.Key, Count = g.Count() }) .ToDictionary(g => AnalyticsHelpers.GetLinkedName(g.Key), g => g.Count); - return Task.FromResult(new SingeSeriesDataset() + return Task.FromResult(new SingeSeriesDataset { Values = AnalyticsHelpers.GetMovementSegments().ToDictionary(title => title, title => data.GetValueOrDefault(title, 0)) }); @@ -72,7 +66,7 @@ public Task ByItemCount(DateTime from, DateTime to) .ToList(); var dictionary = mongoResult - .ToDictionary(g => new { Title = AnalyticsHelpers.GetLinkedName(g.Linked), ItemCount = g.ItemCount }, g => g.Count); + .ToDictionary(g => new { Title = AnalyticsHelpers.GetLinkedName(g.Linked), g.ItemCount }, g => g.Count); var maxCount = mongoResult .Max(r => r.Count); @@ -80,10 +74,10 @@ public Task ByItemCount(DateTime from, DateTime to) return Task.FromResult(AnalyticsHelpers.GetMovementSegments() .Select(title => new MultiSeriesDataset(title, "Item Count") { Results = Enumerable.Range(0, maxCount + 1) - .Select(i => new ByNumericDimensionResult() + .Select(i => new ByNumericDimensionResult { Dimension = i, - Value = dictionary!.GetValueOrDefault(new { Title=title, ItemCount = i }, 0) + Value = dictionary.GetValueOrDefault(new { Title=title, ItemCount = i }, 0) }).ToList() }) .ToArray() @@ -110,25 +104,25 @@ public Task ByUniqueDocumentReferenceCount(DateTime from, .SelectMany(g => g.Select(l => new { Linked = g.Key, - DocumentReferenceCount = l.Key.DocumentReferenceCount, + l.Key.DocumentReferenceCount, MovementCount = l.Count() })) .ToList(); var dictionary = mongoResult .ToDictionary( - g => new { Title = AnalyticsHelpers.GetLinkedName(g.Linked), DocumentReferenceCount = g.DocumentReferenceCount }, - g => g.MovementCount)!; + g => new { Title = AnalyticsHelpers.GetLinkedName(g.Linked), g.DocumentReferenceCount }, + g => g.MovementCount); var maxReferences = mongoResult.Max(r => r.DocumentReferenceCount); return Task.FromResult(AnalyticsHelpers.GetMovementSegments() .Select(title => new MultiSeriesDataset(title, "Document Reference Count") { Results = Enumerable.Range(0, maxReferences + 1) - .Select(i => new ByNumericDimensionResult() + .Select(i => new ByNumericDimensionResult { Dimension = i, - Value = dictionary!.GetValueOrDefault(new { Title=title, DocumentReferenceCount = i }, 0) + Value = dictionary.GetValueOrDefault(new { Title=title, DocumentReferenceCount = i }, 0) }).ToList() }) .ToArray() @@ -142,7 +136,7 @@ public Task UniqueDocumentReferenceByMovementCount(DateTime .Where(m => m.CreatedSource >= from && m.CreatedSource < to) .SelectMany(m => m.Items.Select(i => new { Item = i, MovementId = m.Id })) .SelectMany(i => i.Item.Documents!.Select(d => - new { MovementId = i.MovementId, DocumentReference = d.DocumentReference })) + new { i.MovementId, d.DocumentReference })) .Distinct() .GroupBy(d => d.DocumentReference) .Select(d => new { DocumentReference = d.Key, MovementCount = d.Count() }) @@ -155,7 +149,7 @@ public Task UniqueDocumentReferenceByMovementCount(DateTime r =>r.MovementCount.ToString(), r=> r.DocumentReferenceCount); - var result = new SingeSeriesDataset() { Values = mongoResult }; + var result = new SingeSeriesDataset { Values = mongoResult }; return Task.FromResult(result); } @@ -180,7 +174,7 @@ private Task Aggregate(DateTime[] dateRange, Func< .Select(title => mongoResult.AsDataset(dateRange, title)) .AsOrderedArray(m => m.Name); - logger.LogDebug("Aggregated Data {result}", output.ToList().ToJsonString()); + logger.LogDebug("Aggregated Data {Result}", output.ToList().ToJsonString()); return Task.FromResult(output); } diff --git a/Btms.Azure/AzureService.cs b/Btms.Azure/AzureService.cs index 036ec6f..296dc6f 100644 --- a/Btms.Azure/AzureService.cs +++ b/Btms.Azure/AzureService.cs @@ -3,10 +3,7 @@ using Azure.Core.Diagnostics; using Azure.Core.Pipeline; using Azure.Identity; -using Btms.Azure.Extensions; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Identity.Client; namespace Btms.Azure; @@ -20,7 +17,7 @@ public abstract class AzureService protected AzureService(IServiceProvider serviceProvider, ILogger logger, IAzureConfig config, IHttpClientFactory? clientFactory = null) { Logger = logger; - using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger(EventLevel.Verbose); + using var listener = AzureEventSourceListener.CreateConsoleLogger(EventLevel.Verbose); if (config.AzureClientId != null) { @@ -35,7 +32,7 @@ protected AzureService(IServiceProvider serviceProvider, ILogger logger, IAzureC else { logger.LogDebug( - "Creating azure credentials using default creds because AZURE_CLIENT_ID env var not found."); + "Creating azure credentials using default creds because AZURE_CLIENT_ID env var not found"); Credentials = new DefaultAzureCredential(); logger.LogDebug("Created azure default credentials"); } diff --git a/Btms.Azure/ConfidentialClientApplicationTokenCredential.cs b/Btms.Azure/ConfidentialClientApplicationTokenCredential.cs index db8df43..e11b46d 100644 --- a/Btms.Azure/ConfidentialClientApplicationTokenCredential.cs +++ b/Btms.Azure/ConfidentialClientApplicationTokenCredential.cs @@ -14,11 +14,9 @@ namespace Btms.Azure; /// - The ClientSecretCredential has an internal constructor accepting MsalConfidentialClient but nothing seems to use it /// - MsalConfidentialClient is itself internal /// -/// -/// public class ConfidentialClientApplicationTokenCredential : TokenCredential { - private readonly string[] _scopes = { "https://storage.azure.com/.default" }; + private readonly string[] _scopes = ["https://storage.azure.com/.default"]; private readonly IConfidentialClientApplication _app; public ConfidentialClientApplicationTokenCredential(IServiceProvider serviceProvider, IAzureConfig config) diff --git a/Btms.Azure/Extensions/IServiceExtensions.cs b/Btms.Azure/Extensions/IServiceExtensions.cs index 9853502..0c9256b 100644 --- a/Btms.Azure/Extensions/IServiceExtensions.cs +++ b/Btms.Azure/Extensions/IServiceExtensions.cs @@ -1,8 +1,6 @@ using System.Net.Http.Headers; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Microsoft.Identity.Client; namespace Btms.Azure.Extensions; @@ -22,7 +20,7 @@ public HttpClient GetHttpClient() } } -public static class IServiceExtensions +public static class ServiceExtensions { public static void AddMsalHttpProxyClient(this IServiceCollection services, Func configurePrimaryHttpMessageHandler) { diff --git a/Btms.Azure/IAzureConfig.cs b/Btms.Azure/IAzureConfig.cs index 755be56..9e50f2b 100644 --- a/Btms.Azure/IAzureConfig.cs +++ b/Btms.Azure/IAzureConfig.cs @@ -1,9 +1,8 @@ -namespace Btms.Azure +namespace Btms.Azure; + +public interface IAzureConfig { - public interface IAzureConfig - { - public string? AzureClientId { get; } - public string? AzureTenantId { get; } - public string? AzureClientSecret { get; } - } + public string? AzureClientId { get; } + public string? AzureTenantId { get; } + public string? AzureClientSecret { get; } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/CSharpFileBuilder.cs b/Btms.Backend.Cli/Features/GenerateModels/CSharpFileBuilder.cs index cb8af43..4de5cee 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/CSharpFileBuilder.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/CSharpFileBuilder.cs @@ -2,155 +2,154 @@ using Btms.Backend.Cli.Features.GenerateModels.DescriptorModel; using RazorLight; -namespace Btms.Backend.Cli.Features.GenerateModels +namespace Btms.Backend.Cli.Features.GenerateModels; + +internal class CSharpFileBuilder { - class CSharpFileBuilder + public static async Task Build(CSharpDescriptor descriptor, string sourceOutputPath, string internalOutputPath, + string mappingOutputPath, CancellationToken cancellationToken = default) { - public static async Task Build(CSharpDescriptor descriptor, string sourceOutputPath, string internalOutputPath, - string mappingOutputPath, CancellationToken cancellationToken = default) + var engine = new RazorLightEngineBuilder() + .UseEmbeddedResourcesProject(typeof(Program).Assembly, + "Btms.Backend.Cli.Features.GenerateModels.Templates") + .UseMemoryCachingProvider() + .Build(); + + foreach (var @class in descriptor.Classes.OrderBy(x => x.Name)) { - var engine = new RazorLightEngineBuilder() - .UseEmbeddedResourcesProject(typeof(Program).Assembly, - "Btms.Backend.Cli.Features.GenerateModels.Templates") - .UseMemoryCachingProvider() - .Build(); + ApplySourceClassMapOverrides(@class); - foreach (var @class in descriptor.Classes.OrderBy(x => x.Name)) - { - ApplySourceClassMapOverrides(@class); + //create source - //create source + var contents = await engine.CompileRenderAsync("ClassTemplate", @class); + await File.WriteAllTextAsync(Path.Combine(sourceOutputPath, $"{@class.GetClassName()}.g.cs"), contents, + cancellationToken); + Console.WriteLine($"Created file: {@class.GetClassName()}.cs"); - var contents = await engine.CompileRenderAsync("ClassTemplate", @class); - await File.WriteAllTextAsync(Path.Combine(sourceOutputPath, $"{@class.GetClassName()}.g.cs"), contents, - cancellationToken); - Console.WriteLine($"Created file: {@class.GetClassName()}.cs"); + //create internal - //create internal - - if (!@class.IgnoreInternalClass) - { - contents = await engine.CompileRenderAsync("InternalClassTemplate", @class); - await File.WriteAllTextAsync(Path.Combine(internalOutputPath, $"{@class.GetClassName()}.g.cs"), - contents, cancellationToken); - Console.WriteLine($"Created file: {@class.GetClassName()}.cs"); - - contents = await engine.CompileRenderAsync("MapperTemplate", @class); - await File.WriteAllTextAsync(Path.Combine(mappingOutputPath, $"{@class.GetClassName()}Mapper.g.cs"), - contents, cancellationToken); - Console.WriteLine($"Created file: {@class.GetClassName()}.cs"); - } - } - - foreach (var @enum in descriptor.Enums.OrderBy(x => x.Name)) + if (!@class.IgnoreInternalClass) { - ApplyEnumMapOverrides(@enum); - - var contents = await engine.CompileRenderAsync("EnumTemplate", @enum); - await File.WriteAllTextAsync(Path.Combine(sourceOutputPath, $"{@enum.GetEnumName()}.g.cs"), contents, - cancellationToken); - // File.WriteAllText($"../../../Model/{@enum.GetEnumName()}.cs", contents); - Console.WriteLine($"Created file: {@enum.GetEnumName()}.cs"); - - contents = await engine.CompileRenderAsync("InternalEnumTemplate", @enum); - await File.WriteAllTextAsync(Path.Combine(internalOutputPath, $"{@enum.GetEnumName()}.g.cs"), contents, - cancellationToken); - // File.WriteAllText($"../../../Model/{@enum.GetEnumName()}.cs", contents); - Console.WriteLine($"Created file: {@enum.GetEnumName()}.cs"); - - contents = await engine.CompileRenderAsync("EnumMapperTemplate", @enum); - await File.WriteAllTextAsync(Path.Combine(mappingOutputPath, $"{@enum.GetEnumName()}Mapper.g.cs"), + contents = await engine.CompileRenderAsync("InternalClassTemplate", @class); + await File.WriteAllTextAsync(Path.Combine(internalOutputPath, $"{@class.GetClassName()}.g.cs"), + contents, cancellationToken); + Console.WriteLine($"Created file: {@class.GetClassName()}.cs"); + + contents = await engine.CompileRenderAsync("MapperTemplate", @class); + await File.WriteAllTextAsync(Path.Combine(mappingOutputPath, $"{@class.GetClassName()}Mapper.g.cs"), contents, cancellationToken); - // File.WriteAllText($"../../../Model/{@enum.GetEnumName()}.cs", contents); - Console.WriteLine($"Created file: {@enum.GetEnumName()}.cs"); + Console.WriteLine($"Created file: {@class.GetClassName()}.cs"); } } - private static void ApplySourceClassMapOverrides(ClassDescriptor @class) + foreach (var @enum in descriptor.Enums.OrderBy(x => x.Name)) { - var classMap = GeneratorClassMap.LookupClassMap(@class.Name); + ApplyEnumMapOverrides(@enum); + + var contents = await engine.CompileRenderAsync("EnumTemplate", @enum); + await File.WriteAllTextAsync(Path.Combine(sourceOutputPath, $"{@enum.GetEnumName()}.g.cs"), contents, + cancellationToken); + // File.WriteAllText($"../../../Model/{@enum.GetEnumName()}.cs", contents); + Console.WriteLine($"Created file: {@enum.GetEnumName()}.cs"); + + contents = await engine.CompileRenderAsync("InternalEnumTemplate", @enum); + await File.WriteAllTextAsync(Path.Combine(internalOutputPath, $"{@enum.GetEnumName()}.g.cs"), contents, + cancellationToken); + // File.WriteAllText($"../../../Model/{@enum.GetEnumName()}.cs", contents); + Console.WriteLine($"Created file: {@enum.GetEnumName()}.cs"); + + contents = await engine.CompileRenderAsync("EnumMapperTemplate", @enum); + await File.WriteAllTextAsync(Path.Combine(mappingOutputPath, $"{@enum.GetEnumName()}Mapper.g.cs"), + contents, cancellationToken); + // File.WriteAllText($"../../../Model/{@enum.GetEnumName()}.cs", contents); + Console.WriteLine($"Created file: {@enum.GetEnumName()}.cs"); + } + } + + private static void ApplySourceClassMapOverrides(ClassDescriptor @class) + { + var classMap = GeneratorClassMap.LookupClassMap(@class.Name); + + if (classMap is not null) + { + @class.Name = classMap.SourceClassName; + @class.IgnoreInternalClass = classMap.IgnoreInternalClass; - if (classMap is not null) + foreach (var propertyMap in classMap.Properties) { - @class.Name = classMap.SourceClassName; - @class.IgnoreInternalClass = classMap.IgnoreInternalClass; + var propertyDescriptor = @class.Properties.FirstOrDefault(x => + x.SourceName.Equals(propertyMap.Name, StringComparison.InvariantCultureIgnoreCase)); - foreach (var propertyMap in classMap.Properties) + if (propertyDescriptor is not null) { - var propertyDescriptor = @class.Properties.FirstOrDefault(x => - x.SourceName.Equals(propertyMap.Name, StringComparison.InvariantCultureIgnoreCase)); + if (propertyMap.TypeOverwritten) + { + propertyDescriptor.OverrideType(propertyMap.Type); + } - if (propertyDescriptor is not null) + if (propertyMap.SourceNameOverwritten) { - if (propertyMap.TypeOverwritten) - { - propertyDescriptor.OverrideType(propertyMap.Type); - } + propertyDescriptor.SourceName = propertyMap.OverriddenSourceName; + } - if (propertyMap.SourceNameOverwritten) - { - propertyDescriptor.SourceName = propertyMap.OverriddenSourceName; - } + if (propertyMap.InternalNameOverwritten) + { + propertyDescriptor.InternalName = propertyMap.OverriddenInternalName; + } - if (propertyMap.InternalNameOverwritten) + if (propertyMap.AttributesOverwritten) + { + if (propertyMap.NoAttributes) { - propertyDescriptor.InternalName = propertyMap.OverriddenInternalName; + propertyDescriptor.SourceAttributes.Clear(); + propertyDescriptor.InternalAttributes.Clear(); } - - if (propertyMap.AttributesOverwritten) + else { - if (propertyMap.NoAttributes) - { - propertyDescriptor.SourceAttributes.Clear(); - propertyDescriptor.InternalAttributes.Clear(); - } - else - { - propertyDescriptor.SourceAttributes.AddRange(propertyMap.SourceAttributes); - propertyDescriptor.InternalAttributes.AddRange(propertyMap.InternalAttributes); - } + propertyDescriptor.SourceAttributes.AddRange(propertyMap.SourceAttributes); + propertyDescriptor.InternalAttributes.AddRange(propertyMap.InternalAttributes); } + } - propertyDescriptor.ExcludedFromSource = propertyMap.ExcludedFromSource; - propertyDescriptor.ExcludedFromInternal = propertyMap.ExcludedFromInternal; + propertyDescriptor.ExcludedFromSource = propertyMap.ExcludedFromSource; + propertyDescriptor.ExcludedFromInternal = propertyMap.ExcludedFromInternal; - if (propertyMap.Mapper is not null) - { - propertyDescriptor.Mapper = propertyMap.Mapper.Name; - propertyDescriptor.MappingInline = propertyMap.Mapper.Inline; - } + if (propertyMap.Mapper is not null) + { + propertyDescriptor.Mapper = propertyMap.Mapper.Name; + propertyDescriptor.MappingInline = propertyMap.Mapper.Inline; } } + } - foreach (var propertyMap in classMap.NewProperties) - { - @class.AddPropertyDescriptor(propertyMap); - } + foreach (var propertyMap in classMap.NewProperties) + { + @class.AddPropertyDescriptor(propertyMap); } } + } - private static void ApplyEnumMapOverrides(EnumDescriptor @enum) - { - var classMap = GeneratorEnumMap.LookupEnumMap(@enum.FullName); + private static void ApplyEnumMapOverrides(EnumDescriptor @enum) + { + var classMap = GeneratorEnumMap.LookupEnumMap(@enum.FullName); - if (classMap is not null) + if (classMap is not null) + { + foreach (var v in classMap.EnumValuesToRemove) { - foreach (var v in classMap.EnumValuesToRemove) - { - @enum.Values.RemoveAll(x => x.Value == v); - } + @enum.Values.RemoveAll(x => x.Value == v); + } - foreach (var v in classMap.EnumValuesToRename) + foreach (var v in classMap.EnumValuesToRename) + { + var item = @enum.Values.SingleOrDefault(x => x.Value == v.OldValue); + if (item is not null) { - var item = @enum.Values.SingleOrDefault(x => x.Value == v.OldValue); - if (item is not null) - { - item.OverriddenValue = v.NewValue; - } + item.OverriddenValue = v.NewValue; } - - @enum.Values.AddRange(classMap.EnumValues); } + + @enum.Values.AddRange(classMap.EnumValues); } } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/Bootstrap.cs b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/Bootstrap.cs index a96ec8e..b754eba 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/Bootstrap.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/Bootstrap.cs @@ -1,12 +1,9 @@ -using SharpYaml.Serialization; -using System.Text.Json; using Btms.Backend.Cli.Features.GenerateModels.DescriptorModel; using Btms.Backend.Cli.Features.GenerateModels.GenerateIpaffsModel.Builders; -using Newtonsoft.Json.Serialization; namespace Btms.Backend.Cli.Features.GenerateModels.ClassMaps; -static class Bootstrap +internal static class Bootstrap { public static void GeneratorClassMaps() { diff --git a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorClassMap.cs b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorClassMap.cs index 0a1c37e..2c56bcb 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorClassMap.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorClassMap.cs @@ -1,115 +1,113 @@ using Btms.Backend.Cli.Features.GenerateModels.DescriptorModel; -namespace Btms.Backend.Cli.Features.GenerateModels.ClassMaps +namespace Btms.Backend.Cli.Features.GenerateModels.ClassMaps; + +internal class GeneratorClassMap { - internal class GeneratorClassMap + private static readonly Dictionary ClassMaps = new(); + + public GeneratorClassMap(string className, Action classMapInitializer) { - private static readonly Dictionary classMaps = - new Dictionary(); + Name = className; + SourceClassName = className; + InternalClassName = className; + classMapInitializer(this); + } - public GeneratorClassMap(string className, Action classMapInitializer) - { - Name = className; - SourceClassName = className; - InternalClassName = className; - classMapInitializer(this); - } + public string Name { get; set; } - public string Name { get; set; } + public string SourceClassName { get; private set; } - public string SourceClassName { get; private set; } + public string InternalClassName { get; private set; } - public string InternalClassName { get; private set; } + public bool IgnoreInternalClass { get; private set; } - public bool IgnoreInternalClass { get; private set; } + public List Properties { get; private set; } = new(); - public List Properties { get; private set; } = new List(); + public List NewProperties { get; private set; } = new(); - public List NewProperties { get; private set; } = new List(); + public GeneratorClassMap SetClassName(string className) + { + SetSourceClassName(className); + SetInternalClassName(className); + return this; + } - public GeneratorClassMap SetClassName(string className) - { - SetSourceClassName(className); - SetInternalClassName(className); - return this; - } + public GeneratorClassMap NoInternalClass() + { + IgnoreInternalClass = true; + return this; + } - public GeneratorClassMap NoInternalClass() + public GeneratorClassMap SetSourceClassName(string className) + { + if (string.IsNullOrEmpty(className)) { - IgnoreInternalClass = true; - return this; + throw new ArgumentNullException("className"); } - public GeneratorClassMap SetSourceClassName(string className) - { - if (string.IsNullOrEmpty(className)) - { - throw new ArgumentNullException("className"); - } - - SourceClassName = className; - return this; - } + SourceClassName = className; + return this; + } - public GeneratorClassMap SetInternalClassName(string className) + public GeneratorClassMap SetInternalClassName(string className) + { + if (string.IsNullOrEmpty(className)) { - if (string.IsNullOrEmpty(className)) - { - throw new ArgumentNullException("className"); - } - - InternalClassName = className; - return this; + throw new ArgumentNullException("className"); } - public void AddProperty(PropertyDescriptor property) - { - if (property == null) - { - throw new ArgumentNullException("property"); - } - - NewProperties.Add(property); - } + InternalClassName = className; + return this; + } - public void MapDateOnlyAndTimeOnlyToDateTimeProperty(string dateOnlyProperty, string timeOnlyProperty, - string dateTimeProperty) + public void AddProperty(PropertyDescriptor property) + { + if (property == null) { - MapProperty(timeOnlyProperty).IsTime().ExcludeFromInternal(); - MapProperty(dateOnlyProperty).IsDate().ExcludeFromInternal(); - AddProperty(new PropertyDescriptor(dateTimeProperty, "DateTime", - "DateTime", false, false, "") - { - ExcludedFromSource = true, - Mapper = - $"DateTimeMapper.Map(from?.{PascalCaseNamingPolicy.ConvertName(dateOnlyProperty)}, from?.{PascalCaseNamingPolicy.ConvertName(timeOnlyProperty)});", - MappingInline = true, - }); + throw new ArgumentNullException("property"); } - public PropertyMap MapProperty(string propertyName) - { - if (propertyName == null) - { - throw new ArgumentNullException("propertyName"); - } - - var propertyMap = new PropertyMap(propertyName); - Properties.Add(propertyMap); - return propertyMap; - } + NewProperties.Add(property); + } - public static GeneratorClassMap RegisterClassMap(string name, Action classMapInitializer) + public void MapDateOnlyAndTimeOnlyToDateTimeProperty(string dateOnlyProperty, string timeOnlyProperty, + string dateTimeProperty) + { + MapProperty(timeOnlyProperty).IsTime().ExcludeFromInternal(); + MapProperty(dateOnlyProperty).IsDate().ExcludeFromInternal(); + AddProperty(new PropertyDescriptor(dateTimeProperty, "DateTime", + "DateTime", false, false, "") { - var classMap = new GeneratorClassMap(name, classMapInitializer); - classMaps.Add(classMap.Name.ToLower(), classMap); - return classMap; - } + ExcludedFromSource = true, + Mapper = + $"DateTimeMapper.Map(from?.{PascalCaseNamingPolicy.ConvertName(dateOnlyProperty)}, from?.{PascalCaseNamingPolicy.ConvertName(timeOnlyProperty)});", + MappingInline = true, + }); + } - public static GeneratorClassMap LookupClassMap(string name) + public PropertyMap MapProperty(string propertyName) + { + if (propertyName == null) { - classMaps.TryGetValue(name.ToLower(), out var classMap); - return classMap!; + throw new ArgumentNullException("propertyName"); } + + var propertyMap = new PropertyMap(propertyName); + Properties.Add(propertyMap); + return propertyMap; + } + + public static GeneratorClassMap RegisterClassMap(string name, Action classMapInitializer) + { + var classMap = new GeneratorClassMap(name, classMapInitializer); + ClassMaps.Add(classMap.Name.ToLower(), classMap); + return classMap; + } + + public static GeneratorClassMap? LookupClassMap(string name) + { + ClassMaps.TryGetValue(name.ToLower(), out var classMap); + return classMap; } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorEnumMap.cs b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorEnumMap.cs index acb7e58..5dd58b4 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorEnumMap.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/GeneratorEnumMap.cs @@ -4,7 +4,7 @@ namespace Btms.Backend.Cli.Features.GenerateModels.ClassMaps; internal class GeneratorEnumMap { - private static readonly Dictionary classMaps = new Dictionary(); + private static readonly Dictionary ClassMaps = new(); public GeneratorEnumMap(string className, Action classMapInitializer) @@ -15,8 +15,8 @@ public GeneratorEnumMap(string className, Action classMapIniti public string Name { get; set; } - public List EnumValues = new List(); - public List EnumValuesToRemove = new List(); + public List EnumValues = new(); + public List EnumValuesToRemove = new(); public List<(string OldValue, string NewValue)> EnumValuesToRename = new (); public GeneratorEnumMap AddEnumValue(string value) @@ -40,13 +40,13 @@ public GeneratorEnumMap RenameEnumValue(string oldValue, string newValue) public static GeneratorEnumMap RegisterEnumMap(string name, Action classMapInitializer) { var classMap = new GeneratorEnumMap(name, classMapInitializer); - classMaps.Add(classMap.Name, classMap); + ClassMaps.Add(classMap.Name, classMap); return classMap; } - public static GeneratorEnumMap LookupEnumMap(string name) + public static GeneratorEnumMap? LookupEnumMap(string name) { - classMaps.TryGetValue(name, out var classMap); - return classMap!; + ClassMaps.TryGetValue(name, out var classMap); + return classMap; } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/PropertyMap.cs b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/PropertyMap.cs index e1bb7d8..b53005c 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/PropertyMap.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/ClassMaps/PropertyMap.cs @@ -35,11 +35,11 @@ internal class PropertyMap(string name) public bool NoAttributes { get; set; } - public bool ExcludedFromInternal { get; set; } = false; + public bool ExcludedFromInternal { get; set; } - public bool ExcludedFromSource { get; set; } = false; + public bool ExcludedFromSource { get; set; } - public MapperMap Mapper { get; set; } = null!; + public MapperMap? Mapper { get; set; } public class MapperMap { @@ -129,7 +129,7 @@ public PropertyMap ExcludeFromSource() public PropertyMap SetMapper(string mapperName, bool inline = false) { - Mapper = new MapperMap() { Inline = inline, Name = mapperName }; + Mapper = new MapperMap { Inline = inline, Name = mapperName }; return this; } diff --git a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/ClassDescriptor.cs b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/ClassDescriptor.cs index 21047ac..42e10c1 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/ClassDescriptor.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/ClassDescriptor.cs @@ -42,7 +42,7 @@ public string GetInternalFullClassName() return $"{InternalNamespace}.{BuildClassName(Name, classNamePrefix, IsResource)}"; } - public static string BuildClassName(string name, string classNamePrefix, bool isResource = false) + public static string BuildClassName(string name, string? classNamePrefix, bool isResource = false) { if (classNamePrefix != null && name.StartsWith(classNamePrefix)) { diff --git a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/EnumDescriptor.cs b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/EnumDescriptor.cs index d8c1be0..bb2e716 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/EnumDescriptor.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/EnumDescriptor.cs @@ -6,7 +6,7 @@ namespace Btms.Backend.Cli.Features.GenerateModels.DescriptorModel; [DebuggerDisplay("{Name}")] public class EnumDescriptor(string name, string parentName, string sourceNamespace, string internalNamespace, string classNamePrefix) { - private const string suffix = "Enum"; + private const string Suffix = "Enum"; public string Name { get; set; } = name; @@ -86,9 +86,9 @@ public static string BuildEnumName(string name, string parentName, string classN { if (string.IsNullOrEmpty(parentName)) { - return $"{classNamePrefix}{name.Dehumanize()}{suffix}"; + return $"{classNamePrefix}{name.Dehumanize()}{Suffix}"; } - return $"{classNamePrefix}{parentName}{name.Dehumanize()}{suffix}"; + return $"{classNamePrefix}{parentName}{name.Dehumanize()}{Suffix}"; } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs index a5fb955..7faa78b 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs @@ -1,165 +1,161 @@ using System.Diagnostics; using Humanizer; -namespace Btms.Backend.Cli.Features.GenerateModels.DescriptorModel +namespace Btms.Backend.Cli.Features.GenerateModels.DescriptorModel; + +[DebuggerDisplay("{SourceName}")] +public class PropertyDescriptor { - [DebuggerDisplay("{SourceName}")] - public class PropertyDescriptor - { - private readonly bool _isReferenceType; + private readonly bool _isReferenceType; - private readonly bool _isArray; + private readonly bool _isArray; - private readonly string _classNamePrefix; - private bool _typeOverridden; + private readonly string _classNamePrefix; + private bool _typeOverridden; - public PropertyDescriptor(string sourceName, string type, string description, bool isReferenceType, - bool isArray, string classNamePrefix) - : this(sourceName, sourceName, type, description, isReferenceType, isArray, classNamePrefix) - { - } + public PropertyDescriptor(string sourceName, string type, string description, bool isReferenceType, + bool isArray, string classNamePrefix) + : this(sourceName, sourceName, type, description, isReferenceType, isArray, classNamePrefix) + { + } - public PropertyDescriptor(string sourceName, string internalName, string type, string description, - bool isReferenceType, bool isArray, string classNamePrefix) + public PropertyDescriptor(string sourceName, string internalName, string type, string description, + bool isReferenceType, bool isArray, string classNamePrefix) + { + SourceName = sourceName; + InternalName = internalName; + + _isReferenceType = isReferenceType; + _isArray = isArray; + _classNamePrefix = classNamePrefix; + Type = type; + Description = description; + IsReferenceType = isReferenceType; + IsArray = isArray; + SourceAttributes = [$"[JsonPropertyName(\"{sourceName}\")]"]; + InternalAttributes = ["[Attr]", $"[System.ComponentModel.Description(\"{Description}\")]"]; + + if (type.EndsWith("Enum")) { - SourceName = sourceName; - InternalName = internalName; - - _isReferenceType = isReferenceType; - _isArray = isArray; - _classNamePrefix = classNamePrefix; - Type = type; - Description = description; - IsReferenceType = isReferenceType; - IsArray = isArray; - SourceAttributes = new List() { $"[JsonPropertyName(\"{sourceName}\")]" }; - InternalAttributes = new List() - { - "[Attr]", $"[System.ComponentModel.Description(\"{Description}\")]" - }; - - if (type.EndsWith("Enum")) - { - InternalAttributes.Add( - "[MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]"); - } + InternalAttributes.Add( + "[MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)]"); } - public string SourceName { get; set; } + } + public string SourceName { get; set; } - public string InternalName { get; set; } + public string InternalName { get; set; } - public string Type { get; set; } + public string Type { get; set; } - public string Description { get; set; } + public string Description { get; set; } - public List SourceAttributes { get; set; } = new(); + public List SourceAttributes { get; set; } - public List InternalAttributes { get; set; } = new(); + public List InternalAttributes { get; set; } - public bool IsReferenceType { get; set; } + public bool IsReferenceType { get; set; } - public bool IsNullable { get; set; } + public bool IsNullable { get; set; } - public bool IsArray { get; set; } + public bool IsArray { get; set; } - public string Mapper { get; set; } = null!; + public string Mapper { get; set; } = null!; - public bool MappingInline { get; set; } + public bool MappingInline { get; set; } - public bool ExcludedFromInternal { get; set; } = false; + public bool ExcludedFromInternal { get; set; } = false; - public bool ExcludedFromSource { get; set; } = false; + public bool ExcludedFromSource { get; set; } = false; - public void OverrideType(string type) - { - Type = type; - _typeOverridden = true; - } + public void OverrideType(string type) + { + Type = type; + _typeOverridden = true; + } - public string GetSourcePropertyName() + public string GetSourcePropertyName() + { + var n = SourceName.Dehumanize(); + if (SourceName.Equals("type", StringComparison.InvariantCultureIgnoreCase) || + SourceName.Equals("id", StringComparison.InvariantCultureIgnoreCase)) { - var n = SourceName.Dehumanize(); - if (SourceName.Equals("type", StringComparison.InvariantCultureIgnoreCase) || - SourceName.Equals("id", StringComparison.InvariantCultureIgnoreCase)) + if (SourceName.StartsWith(_classNamePrefix)) { - if (SourceName.StartsWith(_classNamePrefix)) - { - return $"{SourceName.Dehumanize()}"; - } - - return $"{_classNamePrefix}{SourceName.Dehumanize()}"; + return $"{SourceName.Dehumanize()}"; } + return $"{_classNamePrefix}{SourceName.Dehumanize()}"; + } - if (_isArray) - { - n = n.Pluralize(); - } - - if (n.Contains("ID", StringComparison.CurrentCulture)) - { - n = n.Replace("ID", "Id"); - } - return n; + if (_isArray) + { + n = n.Pluralize(); } - public string GetInternalPropertyName() + if (n.Contains("ID", StringComparison.CurrentCulture)) { - var n = InternalName.Dehumanize(); - if (InternalName.Equals("type", StringComparison.InvariantCultureIgnoreCase) || - InternalName.Equals("id", StringComparison.InvariantCultureIgnoreCase)) - { - if (InternalName.StartsWith(_classNamePrefix)) - { - return $"{InternalName.Dehumanize()}"; - } - - return $"{_classNamePrefix}{InternalName.Dehumanize()}"; - } + n = n.Replace("ID", "Id"); + } + return n; + } - if (_isArray) + public string GetInternalPropertyName() + { + var n = InternalName.Dehumanize(); + if (InternalName.Equals("type", StringComparison.InvariantCultureIgnoreCase) || + InternalName.Equals("id", StringComparison.InvariantCultureIgnoreCase)) + { + if (InternalName.StartsWith(_classNamePrefix)) { - n = n.Pluralize(); + return $"{InternalName.Dehumanize()}"; } - if (n.Contains("ID", StringComparison.CurrentCulture)) - { - n = n.Replace("ID", "Id"); - } + return $"{_classNamePrefix}{InternalName.Dehumanize()}"; + } - return n; + + if (_isArray) + { + n = n.Pluralize(); } - public string GetPropertyType() + if (n.Contains("ID", StringComparison.CurrentCulture)) { - var t = Type; + n = n.Replace("ID", "Id"); + } - if (_typeOverridden) - { - return t; - } + return n; + } + public string GetPropertyType() + { + var t = Type; - if (_isReferenceType && !Type.Equals("Result") && !Type.Equals("Unit") && !Type.Equals("string") && - !Type.Equals("InspectionRequired")) - { - t = ClassDescriptor.BuildClassName(Type, _classNamePrefix); - } + if (_typeOverridden) + { + return t; + } - if (IsArray && !t.Contains("[]")) - { - t = $"{t}[]"; - } - return t; + if (_isReferenceType && !Type.Equals("Result") && !Type.Equals("Unit") && !Type.Equals("string") && + !Type.Equals("InspectionRequired")) + { + t = ClassDescriptor.BuildClassName(Type, _classNamePrefix); } - public string GetPropertyTypeName() + if (IsArray && !t.Contains("[]")) { - return GetPropertyType().Replace("[]", ""); + t = $"{t}[]"; } + + return t; + } + + public string GetPropertyTypeName() + { + return GetPropertyType().Replace("[]", ""); } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs index 33a32e1..576f8af 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs @@ -4,102 +4,101 @@ using CommandLine; using MediatR; -namespace Btms.Backend.Cli.Features.GenerateModels.GenerateAlvsModel.Commands +namespace Btms.Backend.Cli.Features.GenerateModels.GenerateAlvsModel.Commands; + +[Verb("generate-alvs-model", isDefault: false, HelpText = "Generates Csharp ALVS classes from XSD Schema.")] +internal class GenerateAlvsModelCommand : IRequest { - [Verb("generate-alvs-model", isDefault: false, HelpText = "Generates Csharp ALVS classes from XSD Schema.")] - class GenerateAlvsModelCommand : IRequest - { - public const string SourceNamespace = "Btms.Types.Alvs"; - public const string InternalNamespace = "Btms.Model.Alvs"; - public const string ClassNamePrefix = ""; + public const string SourceNamespace = "Btms.Types.Alvs"; + public const string InternalNamespace = "Btms.Model.Alvs"; + public const string ClassNamePrefix = ""; - //[Option('o', "sourceOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] - public string SourceOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Alvs.V1\\"; + //[Option('o', "sourceOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] + public string SourceOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Alvs.V1\\"; - // [Option('i', "internalOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] - public string InternalOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Model\\Alvs\\"; + // [Option('i', "internalOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] + public string InternalOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Model\\Alvs\\"; - public string MappingOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Alvs.Mapping.V1\\"; + public string MappingOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Alvs.Mapping.V1\\"; - public class Handler : AsyncRequestHandler - { + public class Handler : AsyncRequestHandler + { - protected override async Task Handle(GenerateAlvsModelCommand request, CancellationToken cancellationToken) - { + protected override async Task Handle(GenerateAlvsModelCommand request, CancellationToken cancellationToken) + { #pragma warning disable S1075 - XmlTextReader reader = new XmlTextReader("D:\\repos\\esynergy\\Btms-Backend\\Btms.Backend.Cli\\Features\\GenerateModels\\GenerateAlvsModel\\sendALVSClearanceRequest.xsd"); + var reader = new XmlTextReader("D:\\repos\\esynergy\\Btms-Backend\\Btms.Backend.Cli\\Features\\GenerateModels\\GenerateAlvsModel\\sendALVSClearanceRequest.xsd"); #pragma warning restore S1075 - XmlSchema schema = XmlSchema.Read(reader, ValidationCallback!)!; + var schema = XmlSchema.Read(reader, ValidationCallback!)!; - var csharpDescriptor = new CSharpDescriptor(); + var csharpDescriptor = new CSharpDescriptor(); - foreach (var schemaItem in schema?.Items!) + foreach (var schemaItem in schema.Items) + { + if (schemaItem is XmlSchemaComplexType complexType) { - if (schemaItem is XmlSchemaComplexType complexType) - { - BuildClass(csharpDescriptor, complexType); - } + BuildClass(csharpDescriptor, complexType); } - - await CSharpFileBuilder.Build(csharpDescriptor, request.SourceOutputPath, request.InternalOutputPath, request.MappingOutputPath, cancellationToken); } - private void BuildClass(CSharpDescriptor cSharpDescriptor, XmlSchemaComplexType complexType) - { - var name = complexType.Name; + await CSharpFileBuilder.Build(csharpDescriptor, request.SourceOutputPath, request.InternalOutputPath, request.MappingOutputPath, cancellationToken); + } - if (string.IsNullOrEmpty(name)) - { - name = ((XmlSchemaElement)complexType.Parent!)?.Name; - } + private void BuildClass(CSharpDescriptor cSharpDescriptor, XmlSchemaComplexType complexType) + { + var name = complexType.Name; - Console.WriteLine($"Class Name: {name}"); - var classDescriptor = new ClassDescriptor(name!, SourceNamespace, InternalNamespace, ClassNamePrefix); + if (string.IsNullOrEmpty(name)) + { + name = ((XmlSchemaElement)complexType.Parent!).Name; + } - classDescriptor.Description = complexType.GetDescription(); - cSharpDescriptor.AddClassDescriptor(classDescriptor); + Console.WriteLine($"Class Name: {name}"); + var classDescriptor = new ClassDescriptor(name!, SourceNamespace, InternalNamespace, ClassNamePrefix); - if (complexType.Particle is XmlSchemaSequence sequence) + classDescriptor.Description = complexType.GetDescription(); + cSharpDescriptor.AddClassDescriptor(classDescriptor); + + if (complexType.Particle is XmlSchemaSequence sequence) + { + foreach (var sequenceItem in sequence.Items) { - foreach (var sequenceItem in sequence.Items) + if (sequenceItem is XmlSchemaElement schemaSequence && schemaSequence.SchemaType is XmlSchemaComplexType ct) { - if (sequenceItem is XmlSchemaElement schemaSequence && schemaSequence.SchemaType is XmlSchemaComplexType ct) - { - BuildClass(cSharpDescriptor, ct); - } - - var schemaElement = sequenceItem as XmlSchemaElement; - Console.WriteLine($"Property Name: {schemaElement?.Name} - Type: {schemaElement?.GetSchemaType()}"); - var propertyName = System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(schemaElement?.Name!); - var propertyDescriptor = new PropertyDescriptor( - sourceName: propertyName, - type: schemaElement?.GetSchemaType()!, - description: "", - isReferenceType: IsReferenceType(schemaElement!.GetSchemaType()), - isArray: schemaElement?.MaxOccursString == "unbounded", - classNamePrefix: ClassNamePrefix); - classDescriptor.Properties.Add(propertyDescriptor); + BuildClass(cSharpDescriptor, ct); } - + var schemaElement = sequenceItem as XmlSchemaElement; + Console.WriteLine($"Property Name: {schemaElement?.Name} - Type: {schemaElement?.GetSchemaType()}"); + var propertyName = System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(schemaElement?.Name!); + var propertyDescriptor = new PropertyDescriptor( + sourceName: propertyName, + type: schemaElement?.GetSchemaType()!, + description: "", + isReferenceType: IsReferenceType(schemaElement!.GetSchemaType()), + isArray: schemaElement?.MaxOccursString == "unbounded", + classNamePrefix: ClassNamePrefix); + classDescriptor.Properties.Add(propertyDescriptor); } - } - static bool IsReferenceType(string type) - { - var nonReferenceTypes = new string[] { "string", "DateTime", "int", "decimal" }; - return !nonReferenceTypes.Contains(type); + } + } - static void ValidationCallback(object sender, ValidationEventArgs args) - { - if (args.Severity == XmlSeverityType.Warning) - Console.Write("WARNING: "); - else if (args.Severity == XmlSeverityType.Error) - Console.Write("ERROR: "); + private static bool IsReferenceType(string type) + { + var nonReferenceTypes = new[] { "string", "DateTime", "int", "decimal" }; + return !nonReferenceTypes.Contains(type); + } - Console.WriteLine(args.Message); - } + private static void ValidationCallback(object sender, ValidationEventArgs args) + { + if (args.Severity == XmlSeverityType.Warning) + Console.Write("WARNING: "); + else if (args.Severity == XmlSeverityType.Error) + Console.Write("ERROR: "); + + Console.WriteLine(args.Message); } } -} +} \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs index 5b554c4..d265e06 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs @@ -53,7 +53,7 @@ public static string GetSchemaType(this XmlSchemaElement schemaElement) } //schemaElement.SchemaTypeName - foreach (var item in ((XmlSchema)schema!)?.Items!) + foreach (var item in ((XmlSchema)schema!).Items) { if (item is XmlSchemaType schemaType && schemaType.Name == schemaElement.SchemaTypeName.Name) { diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Builders/DescriptorBuilderSchemaVisitor.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Builders/DescriptorBuilderSchemaVisitor.cs index a63310e..08d253b 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Builders/DescriptorBuilderSchemaVisitor.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Builders/DescriptorBuilderSchemaVisitor.cs @@ -74,7 +74,7 @@ public void OnProperty(PropertyVisitorContext context) else { var t = typeKeyword.Type.ToCSharpType(context.Key); - bool referenceType = false; + var referenceType = false; if (context.JsonSchema.IsEnum()) { t = EnumDescriptor.BuildEnumName(context.Key, context.ClassDescriptor.Name, IpaffsDescriptorBuilder.ClassNamePrefix); @@ -185,7 +185,7 @@ private void OnEnum(CSharpDescriptor cSharpDescriptor, JsonSchema schema, ClassD { var values = enumKeyword.Values.Select(x => new EnumDescriptor.EnumValueDescriptor(x!.ToString())) .ToList(); - cSharpDescriptor.AddEnumDescriptor(new EnumDescriptor(name, classDescriptor?.Name!, IpaffsDescriptorBuilder.SourceNamespace, IpaffsDescriptorBuilder.InternalNamespace, IpaffsDescriptorBuilder.ClassNamePrefix) { Values = values }); + cSharpDescriptor.AddEnumDescriptor(new EnumDescriptor(name, classDescriptor.Name, IpaffsDescriptorBuilder.SourceNamespace, IpaffsDescriptorBuilder.InternalNamespace, IpaffsDescriptorBuilder.ClassNamePrefix) { Values = values }); } } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Commands/GenerateIpaffsModelCommand.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Commands/GenerateIpaffsModelCommand.cs index 0cdf65c..c7b6b53 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Commands/GenerateIpaffsModelCommand.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateIpaffsModel/Commands/GenerateIpaffsModelCommand.cs @@ -2,38 +2,37 @@ using CommandLine; using MediatR; -namespace Btms.Backend.Cli.Features.GenerateModels.GenerateIpaffsModel.Commands +namespace Btms.Backend.Cli.Features.GenerateModels.GenerateIpaffsModel.Commands; + +[Verb("generate-ipaffs-model", isDefault: false, HelpText = "Generates Csharp Ipaffs classes from Json Schema.")] +internal class GenerateIpaffsModelCommand : IRequest { - [Verb("generate-ipaffs-model", isDefault: false, HelpText = "Generates Csharp Ipaffs classes from Json Schema.")] - class GenerateIpaffsModelCommand : IRequest - { - [Option('s', "schema", Required = true, - HelpText = "The Json schema file, which to use to generate the csharp classes.")] - public string SchemaFile { get; set; } = null!; + [Option('s', "schema", Required = true, + HelpText = "The Json schema file, which to use to generate the csharp classes.")] + public string SchemaFile { get; set; } = null!; - // [Option('o', "sourceOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] - public string SourceOutputPath { get; set; } = "D:\\repos\\esynergy\\btms-backend\\Btms.Types.Ipaffs.V1\\"; + // [Option('o', "sourceOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] + public string SourceOutputPath { get; set; } = "D:\\repos\\esynergy\\btms-backend\\Btms.Types.Ipaffs.V1\\"; - // [Option('i', "internalOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] - public string InteralOutputPath { get; set; } = "D:\\repos\\esynergy\\btms-backend\\Btms.Model\\Ipaffs\\"; + // [Option('i', "internalOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] + public string InteralOutputPath { get; set; } = "D:\\repos\\esynergy\\btms-backend\\Btms.Model\\Ipaffs\\"; - // [Option('i', "internalOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] - public string MappingOutputPath { get; set; } = - "D:\\repos\\esynergy\\btms-backend\\Btms.Types.Ipaffs.Mapping.V1\\"; + // [Option('i', "internalOutputPath", Required = true, HelpText = "The path to save the generated csharp classes.")] + public string MappingOutputPath { get; set; } = + "D:\\repos\\esynergy\\btms-backend\\Btms.Types.Ipaffs.Mapping.V1\\"; - public class Handler : AsyncRequestHandler + public class Handler : AsyncRequestHandler + { + protected override async Task Handle(GenerateIpaffsModelCommand request, + CancellationToken cancellationToken) { - protected override async Task Handle(GenerateIpaffsModelCommand request, - CancellationToken cancellationToken) - { - var builder = - new IpaffsDescriptorBuilder(new List() { new DescriptorBuilderSchemaVisitor() }); + var builder = + new IpaffsDescriptorBuilder([new DescriptorBuilderSchemaVisitor()]); - var model = builder.Build(await File.ReadAllTextAsync(request.SchemaFile, cancellationToken)); + var model = builder.Build(await File.ReadAllTextAsync(request.SchemaFile, cancellationToken)); - await CSharpFileBuilder.Build(model, request.SourceOutputPath, request.InteralOutputPath, - request.MappingOutputPath); - } + await CSharpFileBuilder.Build(model, request.SourceOutputPath, request.InteralOutputPath, + request.MappingOutputPath); } } } \ No newline at end of file diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateVehicleMovementModel/Commands/GenerateVehicleMovementModelCommand.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateVehicleMovementModel/Commands/GenerateVehicleMovementModelCommand.cs index e33fadb..11ce3c9 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateVehicleMovementModel/Commands/GenerateVehicleMovementModelCommand.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateVehicleMovementModel/Commands/GenerateVehicleMovementModelCommand.cs @@ -5,126 +5,125 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers; -namespace Btms.Backend.Cli.Features.GenerateModels.GenerateVehicleMovementModel.Commands +namespace Btms.Backend.Cli.Features.GenerateModels.GenerateVehicleMovementModel.Commands; + +[Verb("generate-vehicle-movement-model", isDefault: false, + HelpText = "Generates Csharp Ipaffs classes from Json Schema.")] +internal class GenerateVehicleMovementModelCommand : IRequest { - [Verb("generate-vehicle-movement-model", isDefault: false, - HelpText = "Generates Csharp Ipaffs classes from Json Schema.")] - class GenerateVehicleMovementModelCommand : IRequest - { - public const string SourceNamespace = "Btms.Types.Gvms"; - public const string InternalNamespace = "Btms.Model.Gvms"; - public const string ClassNamePrefix = ""; + public const string SourceNamespace = "Btms.Types.Gvms"; + public const string InternalNamespace = "Btms.Model.Gvms"; + public const string ClassNamePrefix = ""; - public string SourceOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Gvms.V1\\"; + public string SourceOutputPath { get; set; } = "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Gvms.V1\\"; - public string InternalOutputPath { get; set; } = - "D:\\repos\\esynergy\\Btms-Backend\\Btms.Model\\Gvms\\"; + public string InternalOutputPath { get; set; } = + "D:\\repos\\esynergy\\Btms-Backend\\Btms.Model\\Gvms\\"; - public string MappingOutputPath { get; set; } = - "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Gvms.Mapping.V1\\"; + public string MappingOutputPath { get; set; } = + "D:\\repos\\esynergy\\Btms-Backend\\Btms.Types.Gvms.Mapping.V1\\"; - public class Handler : AsyncRequestHandler + public class Handler : AsyncRequestHandler + { + protected override async Task Handle(GenerateVehicleMovementModelCommand request, + CancellationToken cancellationToken) { - protected override async Task Handle(GenerateVehicleMovementModelCommand request, - CancellationToken cancellationToken) - { - using var streamReader = - new StreamReader( + using var streamReader = + new StreamReader( #pragma warning disable S1075 - "D:\\repos\\esynergy\\btms-backend\\Btms.Backend.Cli\\Features\\GenerateModels\\GenerateVehicleMovementModel\\Goods-Vehicle-Movement-Search-1.0-Open-API-Spec.yaml"); + "D:\\repos\\esynergy\\btms-backend\\Btms.Backend.Cli\\Features\\GenerateModels\\GenerateVehicleMovementModel\\Goods-Vehicle-Movement-Search-1.0-Open-API-Spec.yaml"); #pragma warning restore S1075 - var reader = new OpenApiStreamReader(); - var document = reader.Read(streamReader.BaseStream, out var diagnostic); + var reader = new OpenApiStreamReader(); + var document = reader.Read(streamReader.BaseStream, out _); - var csharpDescriptor = new CSharpDescriptor(); - - foreach (var schemas in document.Components.Schemas) - { - if (schemas.Key.EndsWith("request", StringComparison.InvariantCultureIgnoreCase) || - schemas.Key.EndsWith("response", StringComparison.InvariantCultureIgnoreCase)) + var csharpDescriptor = new CSharpDescriptor(); + foreach (var schemas in document.Components.Schemas) + { + if (schemas.Key.EndsWith("request", StringComparison.InvariantCultureIgnoreCase) || + schemas.Key.EndsWith("response", StringComparison.InvariantCultureIgnoreCase)) - BuildClass(csharpDescriptor, schemas.Key, schemas.Value); - } - await CSharpFileBuilder.Build(csharpDescriptor, request.SourceOutputPath, request.InternalOutputPath, - request.MappingOutputPath); + BuildClass(csharpDescriptor, schemas.Key, schemas.Value); } - private void BuildClass(CSharpDescriptor cSharpDescriptor, string name, OpenApiSchema schema) - { - var classDescriptor = new ClassDescriptor(name, SourceNamespace, InternalNamespace, ClassNamePrefix); + await CSharpFileBuilder.Build(csharpDescriptor, request.SourceOutputPath, request.InternalOutputPath, + request.MappingOutputPath); + } + + private void BuildClass(CSharpDescriptor cSharpDescriptor, string name, OpenApiSchema schema) + { + var classDescriptor = new ClassDescriptor(name, SourceNamespace, InternalNamespace, ClassNamePrefix); - classDescriptor.Description = schema.Description; - cSharpDescriptor.AddClassDescriptor(classDescriptor); + classDescriptor.Description = schema.Description; + cSharpDescriptor.AddClassDescriptor(classDescriptor); - foreach (var property in schema.Properties) + foreach (var property in schema.Properties) + { + if (property.Value.IsArray()) { - if (property.Value.IsArray()) - { - var arrayType = property.Value.GetArrayType(); - - if (arrayType == "object") - { - var propertyDescriptor = new PropertyDescriptor( - sourceName: property.Key, - type: ClassDescriptor.BuildClassName(property.Key, null!), - description: property.Value.Description, - isReferenceType: true, - isArray: true, - classNamePrefix: ClassNamePrefix); - classDescriptor.Properties.Add(propertyDescriptor); - - //build class - BuildClass(cSharpDescriptor, property.Key, property.Value.Items); - } - } - else if (property.Value.IsObject()) + var arrayType = property.Value.GetArrayType(); + + if (arrayType == "object") { var propertyDescriptor = new PropertyDescriptor( sourceName: property.Key, type: ClassDescriptor.BuildClassName(property.Key, null!), description: property.Value.Description, isReferenceType: true, - isArray: false, + isArray: true, classNamePrefix: ClassNamePrefix); classDescriptor.Properties.Add(propertyDescriptor); - BuildClass(cSharpDescriptor, property.Key, property.Value); + //build class + BuildClass(cSharpDescriptor, property.Key, property.Value.Items); } - else if (property.Value.OneOf.Any()) + } + else if (property.Value.IsObject()) + { + var propertyDescriptor = new PropertyDescriptor( + sourceName: property.Key, + type: ClassDescriptor.BuildClassName(property.Key, null!), + description: property.Value.Description, + isReferenceType: true, + isArray: false, + classNamePrefix: ClassNamePrefix); + classDescriptor.Properties.Add(propertyDescriptor); + + BuildClass(cSharpDescriptor, property.Key, property.Value); + } + else if (property.Value.OneOf.Any()) + { + var enumDescriptor = new EnumDescriptor(property.Key, null!, SourceNamespace, InternalNamespace, + ClassNamePrefix); + cSharpDescriptor.AddEnumDescriptor(enumDescriptor); + foreach (var oneOfSchema in property.Value.OneOf) { - var enumDescriptor = new EnumDescriptor(property.Key, null!, SourceNamespace, InternalNamespace, - ClassNamePrefix); - cSharpDescriptor.AddEnumDescriptor(enumDescriptor); - foreach (var oneOfSchema in property.Value.OneOf) - { - var values = oneOfSchema.Enum.Select(x => ((OpenApiString)x).Value).ToList(); - enumDescriptor.AddValues(values.Select(x => new EnumDescriptor.EnumValueDescriptor(x)) - .ToList()); - } - - var propertyDescriptor = new PropertyDescriptor( - sourceName: property.Key, - type: EnumDescriptor.BuildEnumName(property.Key, null!, null!), - description: property.Value.Description, - isReferenceType: true, - isArray: false, - classNamePrefix: ClassNamePrefix); - classDescriptor.Properties.Add(propertyDescriptor); + var values = oneOfSchema.Enum.Select(x => ((OpenApiString)x).Value).ToList(); + enumDescriptor.AddValues(values.Select(x => new EnumDescriptor.EnumValueDescriptor(x)) + .ToList()); } - else - { - var propertyDescriptor = new PropertyDescriptor( - sourceName: property.Key, - type: property.ToCSharpType(), - description: property.Value.Description, - isReferenceType: false, - isArray: property.Value.IsArray(), - classNamePrefix: ClassNamePrefix); - classDescriptor.Properties.Add(propertyDescriptor); - } + var propertyDescriptor = new PropertyDescriptor( + sourceName: property.Key, + type: EnumDescriptor.BuildEnumName(property.Key, null!, null!), + description: property.Value.Description, + isReferenceType: true, + isArray: false, + classNamePrefix: ClassNamePrefix); + classDescriptor.Properties.Add(propertyDescriptor); + } + else + { + var propertyDescriptor = new PropertyDescriptor( + sourceName: property.Key, + type: property.ToCSharpType(), + description: property.Value.Description, + isReferenceType: false, + isArray: property.Value.IsArray(), + classNamePrefix: ClassNamePrefix); + + classDescriptor.Properties.Add(propertyDescriptor); } } } diff --git a/Btms.Backend.Cli/Features/GenerateModels/Templates/ClassTemplate.cshtml b/Btms.Backend.Cli/Features/GenerateModels/Templates/ClassTemplate.cshtml index 1ae24a1..c634075 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/Templates/ClassTemplate.cshtml +++ b/Btms.Backend.Cli/Features/GenerateModels/Templates/ClassTemplate.cshtml @@ -1,4 +1,3 @@ -@using RazorLight @using Microsoft.AspNetCore.Html; @model Btms.Backend.Cli.Features.GenerateModels.DescriptorModel.ClassDescriptor @inherits RazorLight.TemplatePage diff --git a/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumMapperTemplate.cshtml b/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumMapperTemplate.cshtml index 740f7a5..8abe9fc 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumMapperTemplate.cshtml +++ b/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumMapperTemplate.cshtml @@ -1,5 +1,3 @@ -@using RazorLight -@using Microsoft.AspNetCore.Html; @model Btms.Backend.Cli.Features.GenerateModels.DescriptorModel.EnumDescriptor @inherits RazorLight.TemplatePage @{ diff --git a/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumTemplate.cshtml b/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumTemplate.cshtml index 7d41750..4dd555c 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumTemplate.cshtml +++ b/Btms.Backend.Cli/Features/GenerateModels/Templates/EnumTemplate.cshtml @@ -1,4 +1,3 @@ -@using RazorLight @model Btms.Backend.Cli.Features.GenerateModels.DescriptorModel.EnumDescriptor @inherits RazorLight.TemplatePage diff --git a/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalClassTemplate.cshtml b/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalClassTemplate.cshtml index 352db5e..1a8b2bd 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalClassTemplate.cshtml +++ b/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalClassTemplate.cshtml @@ -1,4 +1,3 @@ -@using RazorLight @using Microsoft.AspNetCore.Html; @model Btms.Backend.Cli.Features.GenerateModels.DescriptorModel.ClassDescriptor @inherits RazorLight.TemplatePage diff --git a/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalEnumTemplate.cshtml b/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalEnumTemplate.cshtml index af40bde..2029e3d 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalEnumTemplate.cshtml +++ b/Btms.Backend.Cli/Features/GenerateModels/Templates/InternalEnumTemplate.cshtml @@ -1,4 +1,3 @@ -@using RazorLight @model Btms.Backend.Cli.Features.GenerateModels.DescriptorModel.EnumDescriptor @inherits RazorLight.TemplatePage diff --git a/Btms.Backend.Cli/Features/GenerateModels/Templates/MapperTemplate.cshtml b/Btms.Backend.Cli/Features/GenerateModels/Templates/MapperTemplate.cshtml index 2f5c578..53ac8df 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/Templates/MapperTemplate.cshtml +++ b/Btms.Backend.Cli/Features/GenerateModels/Templates/MapperTemplate.cshtml @@ -1,5 +1,3 @@ -@using RazorLight -@using Microsoft.AspNetCore.Html; @model Btms.Backend.Cli.Features.GenerateModels.DescriptorModel.ClassDescriptor @inherits RazorLight.TemplatePage @{ @@ -43,7 +41,7 @@ public static class @Model.GetClassName()Mapper } else { - var line = $"to.{property.GetInternalPropertyName()} = {property.Mapper}.Map(from?.{@property?.GetSourcePropertyName()});"; + var line = $"to.{property.GetInternalPropertyName()} = {property.Mapper}.Map(from?.{@property.GetSourcePropertyName()});"; @line } @@ -63,7 +61,7 @@ public static class @Model.GetClassName()Mapper } else { - to.@property.GetInternalPropertyName() = @property.GetPropertyTypeName()Mapper.Map(from?.@property?.GetSourcePropertyName()); + to.@property.GetInternalPropertyName() = @property.GetPropertyTypeName()Mapper.Map(from?.@property.GetSourcePropertyName()); } diff --git a/Btms.Backend.Cli/Program.cs b/Btms.Backend.Cli/Program.cs index 4a519e8..fec2f45 100644 --- a/Btms.Backend.Cli/Program.cs +++ b/Btms.Backend.Cli/Program.cs @@ -11,7 +11,7 @@ Bootstrap.GeneratorClassMaps(); var builder = Host.CreateDefaultBuilder(args) - .ConfigureServices((hostContext, services) => + .ConfigureServices((_, services) => { services.AddLogging(configure => configure.AddConsole().SetMinimumLevel(LogLevel.Warning)); services.AddTransient(); @@ -37,7 +37,7 @@ namespace Btms.Backend.Cli { - class App(IMediator mediator) + internal class App(IMediator mediator) { public Task Run(string[] args) { diff --git a/Btms.Backend.Data/Extensions/ServiceCollectionExtensions.cs b/Btms.Backend.Data/Extensions/ServiceCollectionExtensions.cs index 8fa8530..3e9c3f8 100644 --- a/Btms.Backend.Data/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Backend.Data/Extensions/ServiceCollectionExtensions.cs @@ -6,35 +6,34 @@ using MongoDB.Driver; using MongoDB.Driver.Core.Extensions.DiagnosticSources; -namespace Btms.Backend.Data.Extensions +namespace Btms.Backend.Data.Extensions; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddMongoDbContext(this IServiceCollection services, + IConfiguration configuration) { - public static IServiceCollection AddMongoDbContext(this IServiceCollection services, - IConfiguration configuration) - { - services.AddOptions() - .Bind(configuration.GetSection(MongoDbOptions.SectionName)) - .ValidateDataAnnotations(); + services.AddOptions() + .Bind(configuration.GetSection(MongoDbOptions.SectionName)) + .ValidateDataAnnotations(); - services.AddHostedService(); + services.AddHostedService(); - services.AddScoped(); - services.AddSingleton(sp => - { - var options = sp.GetService>(); - var settings = MongoClientSettings.FromConnectionString(options?.Value.DatabaseUri); - settings.ClusterConfigurator = cb => cb.Subscribe(new DiagnosticsActivityEventSubscriber(new InstrumentationOptions { CaptureCommandText = true })); - var client = new MongoClient(settings); + services.AddScoped(); + services.AddSingleton(sp => + { + var options = sp.GetService>(); + var settings = MongoClientSettings.FromConnectionString(options?.Value.DatabaseUri); + settings.ClusterConfigurator = cb => cb.Subscribe(new DiagnosticsActivityEventSubscriber(new InstrumentationOptions { CaptureCommandText = true })); + var client = new MongoClient(settings); - var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; - // convention must be registered before initialising collection - ConventionRegistry.Register("CamelCase", camelCaseConvention, _ => true); + var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; + // convention must be registered before initialising collection + ConventionRegistry.Register("CamelCase", camelCaseConvention, _ => true); - return client.GetDatabase(options?.Value.DatabaseName); - }); + return client.GetDatabase(options?.Value.DatabaseName); + }); - return services; - } + return services; } } \ No newline at end of file diff --git a/Btms.Backend.Data/Healthcheck/MongoDbHealthCheck.cs b/Btms.Backend.Data/Healthcheck/MongoDbHealthCheck.cs index b28d015..afd4c34 100644 --- a/Btms.Backend.Data/Healthcheck/MongoDbHealthCheck.cs +++ b/Btms.Backend.Data/Healthcheck/MongoDbHealthCheck.cs @@ -3,64 +3,63 @@ using MongoDB.Driver; using System.Collections.Concurrent; -namespace Btms.Backend.Data.Healthcheck +namespace Btms.Backend.Data.Healthcheck; + +public class MongoDbHealthCheck(MongoClientSettings clientSettings, string? databaseName = default) + : IHealthCheck { - public class MongoDbHealthCheck(MongoClientSettings clientSettings, string? databaseName = default) - : IHealthCheck - { - private static readonly BsonDocumentCommand _command = new(BsonDocument.Parse("{ping:1}")); - private static readonly ConcurrentDictionary _mongoClient = new(); - private readonly MongoClientSettings _mongoClientSettings = clientSettings; - private readonly string? _specifiedDatabase = databaseName; + private static readonly BsonDocumentCommand Command = new(BsonDocument.Parse("{ping:1}")); + private static readonly ConcurrentDictionary MongoClient = new(); + private readonly MongoClientSettings _mongoClientSettings = clientSettings; + private readonly string? _specifiedDatabase = databaseName; - public MongoDbHealthCheck(string connectionString, string? databaseName = default) - : this(MongoClientSettings.FromUrl(MongoUrl.Create(connectionString)), databaseName) + public MongoDbHealthCheck(string connectionString, string? databaseName = default) + : this(MongoClientSettings.FromUrl(MongoUrl.Create(connectionString)), databaseName) + { + if (databaseName == default) { - if (databaseName == default) - { - _specifiedDatabase = MongoUrl.Create(connectionString)?.DatabaseName; - } + _specifiedDatabase = MongoUrl.Create(connectionString)?.DatabaseName; } + } - public MongoDbHealthCheck(IMongoClient client, string? databaseName = default) - : this(client.Settings, databaseName) - { - _mongoClient[_mongoClientSettings.ToString()] = client; - } + public MongoDbHealthCheck(IMongoClient client, string? databaseName = default) + : this(client.Settings, databaseName) + { + MongoClient[_mongoClientSettings.ToString()] = client; + } - /// - public async Task CheckHealthAsync(HealthCheckContext context, - CancellationToken cancellationToken = default) + /// + public async Task CheckHealthAsync(HealthCheckContext context, + CancellationToken cancellationToken = default) + { + try { - try - { - var mongoClient = _mongoClient.GetOrAdd(_mongoClientSettings.ToString(), - _ => new MongoClient(_mongoClientSettings)); - - if (!string.IsNullOrEmpty(_specifiedDatabase)) - { - // some users can't list all databases depending on database privileges, with - // this you can check a specified database. - // Related with issue #43 and #617 + var mongoClient = MongoClient.GetOrAdd(_mongoClientSettings.ToString(), + _ => new MongoClient(_mongoClientSettings)); - await mongoClient - .GetDatabase(_specifiedDatabase) - .RunCommandAsync(_command, cancellationToken: cancellationToken) - .ConfigureAwait(false); - } - else - { - using var cursor = - await mongoClient.ListDatabaseNamesAsync(cancellationToken).ConfigureAwait(false); - await cursor.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); - } + if (!string.IsNullOrEmpty(_specifiedDatabase)) + { + // some users can't list all databases depending on database privileges, with + // this you can check a specified database. + // Related with issue #43 and #617 - return HealthCheckResult.Healthy(); + await mongoClient + .GetDatabase(_specifiedDatabase) + .RunCommandAsync(Command, cancellationToken: cancellationToken) + .ConfigureAwait(false); } - catch (Exception ex) + else { - return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); + using var cursor = + await mongoClient.ListDatabaseNamesAsync(cancellationToken).ConfigureAwait(false); + await cursor.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); } + + return HealthCheckResult.Healthy(); + } + catch (Exception ex) + { + return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); } } } \ No newline at end of file diff --git a/Btms.Backend.Data/Healthcheck/MongoDbHealthCheckBuilderExtensions.cs b/Btms.Backend.Data/Healthcheck/MongoDbHealthCheckBuilderExtensions.cs index 2a9bde2..1db4bff 100644 --- a/Btms.Backend.Data/Healthcheck/MongoDbHealthCheckBuilderExtensions.cs +++ b/Btms.Backend.Data/Healthcheck/MongoDbHealthCheckBuilderExtensions.cs @@ -1,4 +1,3 @@ -using Btms.Backend.Data.Extensions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Options; @@ -10,7 +9,7 @@ namespace Btms.Backend.Data.Healthcheck; /// public static class MongoDbHealthCheckBuilderExtensions { - private const string NAME = "mongodb"; + private const string Name = "mongodb"; public static IHealthChecksBuilder AddMongoDb( this IHealthChecksBuilder builder, @@ -20,7 +19,7 @@ public static IHealthChecksBuilder AddMongoDb( TimeSpan? timeout = default) { return builder.Add(new HealthCheckRegistration( - name ?? NAME, + name ?? Name, sp => { var options = sp.GetService>(); diff --git a/Btms.Backend.Data/IMongoCollectionSet.cs b/Btms.Backend.Data/IMongoCollectionSet.cs index 14720ab..29a8967 100644 --- a/Btms.Backend.Data/IMongoCollectionSet.cs +++ b/Btms.Backend.Data/IMongoCollectionSet.cs @@ -5,7 +5,7 @@ namespace Btms.Backend.Data; public interface IMongoCollectionSet : IQueryable where T : IDataEntity { - Task Find(string id); + Task Find(string id); Task Insert(T item, IMongoDbTransaction transaction = default!, CancellationToken cancellationToken = default); Task Update(T item, string etag, IMongoDbTransaction transaction = default!, diff --git a/Btms.Backend.Data/IMongoDbTransaction.cs b/Btms.Backend.Data/IMongoDbTransaction.cs index d5fb3c5..8a40190 100644 --- a/Btms.Backend.Data/IMongoDbTransaction.cs +++ b/Btms.Backend.Data/IMongoDbTransaction.cs @@ -4,7 +4,7 @@ namespace Btms.Backend.Data; public interface IMongoDbTransaction : IDisposable { - IClientSessionHandle Session { get; } + IClientSessionHandle? Session { get; } Task CommitTransaction(CancellationToken cancellationToken = default); Task RollbackTransaction(CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/Btms.Backend.Data/InMemory/MemoryCollectionSet.cs b/Btms.Backend.Data/InMemory/MemoryCollectionSet.cs index 58d1746..913c804 100644 --- a/Btms.Backend.Data/InMemory/MemoryCollectionSet.cs +++ b/Btms.Backend.Data/InMemory/MemoryCollectionSet.cs @@ -26,9 +26,9 @@ IEnumerator IEnumerable.GetEnumerator() public Type ElementType => EntityQueryable.ElementType; public Expression Expression => EntityQueryable.Expression; public IQueryProvider Provider => EntityQueryable.Provider; - public Task Find(string id) + public Task Find(string id) { - return Task.FromResult(data.Find(x => x.Id == id))!; + return Task.FromResult(data.Find(x => x.Id == id)); } public Task Insert(T item, IMongoDbTransaction transaction = default!, CancellationToken cancellationToken = default) @@ -46,13 +46,13 @@ public Task Update(T item, string etag, IMongoDbTransaction transaction = defaul var existingItem = data.Find(x => x.Id == item.Id); if (existingItem == null) return Task.CompletedTask; - if ((existingItem._Etag ?? "") != etag) + if ((existingItem._Etag) != etag) { throw new ConcurrencyException(item.Id!, etag); } item._Etag = BsonObjectIdGenerator.Instance.GenerateId(null, null).ToString()!; - data[data.IndexOf(existingItem!)] = item; + data[data.IndexOf(existingItem)] = item; return Task.CompletedTask; } diff --git a/Btms.Backend.Data/Mongo/MongoCollectionSet.cs b/Btms.Backend.Data/Mongo/MongoCollectionSet.cs index bfbe271..6490ec2 100644 --- a/Btms.Backend.Data/Mongo/MongoCollectionSet.cs +++ b/Btms.Backend.Data/Mongo/MongoCollectionSet.cs @@ -5,75 +5,71 @@ using System.Collections; using System.Linq.Expressions; -namespace Btms.Backend.Data.Mongo +namespace Btms.Backend.Data.Mongo; + +public class MongoCollectionSet(MongoDbContext dbContext, string collectionName = null!) + : IMongoCollectionSet where T : IDataEntity { - public class MongoCollectionSet(MongoDbContext dbContext, string collectionName = null!) - : IMongoCollectionSet where T : IDataEntity - { - private readonly IMongoCollection collection = string.IsNullOrEmpty(collectionName) - ? dbContext.Database.GetCollection(typeof(T).Name) - : dbContext.Database.GetCollection(collectionName); + private readonly IMongoCollection collection = string.IsNullOrEmpty(collectionName) + ? dbContext.Database.GetCollection(typeof(T).Name) + : dbContext.Database.GetCollection(collectionName); - private IMongoQueryable EntityQueryable => collection.AsQueryable(); + private IMongoQueryable EntityQueryable => collection.AsQueryable(); - public IEnumerator GetEnumerator() - { - return EntityQueryable.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return EntityQueryable.GetEnumerator(); - } + public IEnumerator GetEnumerator() + { + return EntityQueryable.GetEnumerator(); + } - public Type ElementType => EntityQueryable.ElementType; - public Expression Expression => EntityQueryable.Expression; - public IQueryProvider Provider => EntityQueryable.Provider; + IEnumerator IEnumerable.GetEnumerator() + { + return EntityQueryable.GetEnumerator(); + } - public Task Find(string id) - { - return EntityQueryable.SingleOrDefaultAsync(x => x.Id == id); - } + public Type ElementType => EntityQueryable.ElementType; + public Expression Expression => EntityQueryable.Expression; + public IQueryProvider Provider => EntityQueryable.Provider; - public Task Insert(T item, IMongoDbTransaction transaction = null!, CancellationToken cancellationToken = default) - { - item._Etag = BsonObjectIdGenerator.Instance.GenerateId(null, null).ToString()!; - item.Created = DateTime.UtcNow; - item.Updated = DateTime.UtcNow; - var session = - transaction is null ? dbContext.ActiveTransaction?.Session : transaction.Session; - return session is not null - ? collection.InsertOneAsync(session, item, cancellationToken: cancellationToken) - : collection.InsertOneAsync(item, cancellationToken: cancellationToken); - } + public async Task Find(string id) + { + return await EntityQueryable.SingleOrDefaultAsync(x => x.Id == id); + } - public async Task Update(T item, string etag, IMongoDbTransaction transaction = null!, - CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(etag); - var builder = Builders.Filter; + public Task Insert(T item, IMongoDbTransaction? transaction, CancellationToken cancellationToken = default) + { + item._Etag = BsonObjectIdGenerator.Instance.GenerateId(null, null).ToString()!; + item.Created = DateTime.UtcNow; + item.Updated = DateTime.UtcNow; + var session = transaction is null ? dbContext.ActiveTransaction?.Session : transaction.Session; + return session is not null + ? collection.InsertOneAsync(session, item, cancellationToken: cancellationToken) + : collection.InsertOneAsync(item, cancellationToken: cancellationToken); + } - var filter = builder.Eq(x => x.Id, item.Id) & builder.Eq(x => x._Etag, etag); + public async Task Update(T item, string etag, IMongoDbTransaction? transaction = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(etag); + var builder = Builders.Filter; - item._Etag = BsonObjectIdGenerator.Instance.GenerateId(null, null).ToString()!; - item.Updated = DateTime.UtcNow; - var session = - transaction is null ? dbContext.ActiveTransaction?.Session : transaction.Session; - var updateResult = session is not null - ? await collection.ReplaceOneAsync(session, filter, item, - cancellationToken: cancellationToken) - : await collection.ReplaceOneAsync(filter, item, - cancellationToken: cancellationToken); + var filter = builder.Eq(x => x.Id, item.Id) & builder.Eq(x => x._Etag, etag); - if (updateResult.ModifiedCount == 0) - { - throw new ConcurrencyException(item.Id!, etag); - } - } + item._Etag = BsonObjectIdGenerator.Instance.GenerateId(null, null).ToString()!; + item.Updated = DateTime.UtcNow; + var session = transaction is null ? dbContext.ActiveTransaction?.Session : transaction.Session; + var updateResult = session is not null + ? await collection.ReplaceOneAsync(session, filter, item, + cancellationToken: cancellationToken) + : await collection.ReplaceOneAsync(filter, item, + cancellationToken: cancellationToken); - public IAggregateFluent Aggregate() + if (updateResult.ModifiedCount == 0) { - return collection.Aggregate(); + throw new ConcurrencyException(item.Id!, etag); } } -} + + public IAggregateFluent Aggregate() + { + return collection.Aggregate(); + } +} \ No newline at end of file diff --git a/Btms.Backend.Data/Mongo/MongoDbTransaction.cs b/Btms.Backend.Data/Mongo/MongoDbTransaction.cs index 1857738..5066c50 100644 --- a/Btms.Backend.Data/Mongo/MongoDbTransaction.cs +++ b/Btms.Backend.Data/Mongo/MongoDbTransaction.cs @@ -4,16 +4,18 @@ namespace Btms.Backend.Data.Mongo; public class MongoDbTransaction(IClientSessionHandle session) : IMongoDbTransaction { - public IClientSessionHandle Session { get; private set; } = session; + public IClientSessionHandle? Session { get; private set; } = session; public async Task CommitTransaction(CancellationToken cancellationToken = default) { + ArgumentNullException.ThrowIfNull(Session); await Session.CommitTransactionAsync(cancellationToken: cancellationToken); Session = null!; } public async Task RollbackTransaction(CancellationToken cancellationToken = default) { + ArgumentNullException.ThrowIfNull(Session); await Session.AbortTransactionAsync(cancellationToken); Session = null!; } diff --git a/Btms.Backend.Data/Mongo/MongoIndexService.cs b/Btms.Backend.Data/Mongo/MongoIndexService.cs index 1362026..88de933 100644 --- a/Btms.Backend.Data/Mongo/MongoIndexService.cs +++ b/Btms.Backend.Data/Mongo/MongoIndexService.cs @@ -29,7 +29,7 @@ private async Task CreateIndex(string name, IndexKeysDefinition keys, Canc try { var indexModel = new CreateIndexModel(keys, - new CreateIndexOptions() + new CreateIndexOptions { Name = name, Background = true, diff --git a/Btms.Backend.IntegrationTests/BaseApiTests.cs b/Btms.Backend.IntegrationTests/BaseApiTests.cs index a92811b..3d547e4 100644 --- a/Btms.Backend.IntegrationTests/BaseApiTests.cs +++ b/Btms.Backend.IntegrationTests/BaseApiTests.cs @@ -14,94 +14,93 @@ using Xunit.Abstractions; [assembly: CollectionBehavior(DisableTestParallelization = true)] -namespace Btms.Backend.IntegrationTests +namespace Btms.Backend.IntegrationTests; + +public abstract class BaseApiTests { - public abstract class BaseApiTests + protected readonly HttpClient Client; + protected readonly IntegrationTestsApplicationFactory Factory; + + protected BaseApiTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) { - protected readonly HttpClient Client; - protected readonly IntegrationTestsApplicationFactory Factory; + Factory = factory; + Factory.TestOutputHelper = testOutputHelper; + Factory.DatabaseName = "SmokeTests"; + Client = + Factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); + var credentials = "IntTest:Password"; + var credentialsAsBytes = Encoding.UTF8.GetBytes(credentials.ToCharArray()); + var encodedCredentials = Convert.ToBase64String(credentialsAsBytes); + Client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue(BasicAuthenticationDefaults.AuthenticationScheme, encodedCredentials); + } - protected BaseApiTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) - { - this.Factory = factory; - this.Factory.TestOutputHelper = testOutputHelper; - this.Factory.DatabaseName = "SmokeTests"; - Client = - this.Factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); - string credentials = "IntTest:Password"; - byte[] credentialsAsBytes = Encoding.UTF8.GetBytes(credentials.ToCharArray()); - var encodedCredentials = Convert.ToBase64String(credentialsAsBytes); - Client.DefaultRequestHeaders.Authorization = - new AuthenticationHeaderValue(BasicAuthenticationDefaults.AuthenticationScheme, encodedCredentials); - } + private async Task WaitOnJobCompleting(Uri jobUri) + { + var jsonOptions = new JsonSerializerOptions(); + jsonOptions.Converters.Add(new JsonStringEnumConverter()); + jsonOptions.PropertyNameCaseInsensitive = true; - private async Task WaitOnJobCompleting(Uri jobUri) + var jobStatusTask = Task.Run(async () => { - var jsonOptions = new JsonSerializerOptions(); - jsonOptions.Converters.Add(new JsonStringEnumConverter()); - jsonOptions.PropertyNameCaseInsensitive = true; + var status = SyncJobStatus.Pending; - var jobStatusTask = Task.Run(async () => - { - SyncJobStatus status = SyncJobStatus.Pending; - - while (status != SyncJobStatus.Completed) - { - await Task.Delay(200); - var jobResponse = await Client.GetAsync(jobUri); - var syncJob = await jobResponse.Content.ReadFromJsonAsync(jsonOptions); - if (syncJob != null) status = syncJob.Status; - } - }); - - var winningTask = await Task.WhenAny( - jobStatusTask, - Task.Delay(TimeSpan.FromMinutes(5))); - - if (winningTask != jobStatusTask) + while (status != SyncJobStatus.Completed) { - Assert.Fail("Waiting for job to complete timed out!"); + await Task.Delay(200); + var jobResponse = await Client.GetAsync(jobUri); + var syncJob = await jobResponse.Content.ReadFromJsonAsync(jsonOptions); + if (syncJob != null) status = syncJob.Status; } + }); - } + var winningTask = await Task.WhenAny( + jobStatusTask, + Task.Delay(TimeSpan.FromMinutes(5))); - protected Task MakeSyncDecisionsRequest(SyncDecisionsCommand command) + if (winningTask != jobStatusTask) { - return PostCommand(command, "/sync/decisions"); + Assert.Fail("Waiting for job to complete timed out!"); } - protected Task MakeSyncNotificationsRequest(SyncNotificationsCommand command) - { - return PostCommand(command, "/sync/import-notifications"); - } + } - protected Task MakeSyncClearanceRequest(SyncClearanceRequestsCommand command) - { - return PostCommand(command, "/sync/clearance-requests"); - } + protected Task MakeSyncDecisionsRequest(SyncDecisionsCommand command) + { + return PostCommand(command, "/sync/decisions"); + } - protected Task MakeSyncGmrsRequest(SyncGmrsCommand command) - { - return PostCommand(command, "/sync/gmrs"); + protected Task MakeSyncNotificationsRequest(SyncNotificationsCommand command) + { + return PostCommand(command, "/sync/import-notifications"); + } - } + protected Task MakeSyncClearanceRequest(SyncClearanceRequestsCommand command) + { + return PostCommand(command, "/sync/clearance-requests"); + } - private async Task PostCommand(T command, string uri) - { - var jsonData = JsonSerializer.Serialize(command); - HttpContent content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + protected Task MakeSyncGmrsRequest(SyncGmrsCommand command) + { + return PostCommand(command, "/sync/gmrs"); - //Act - var response = await Client.PostAsync(uri, content); + } - // Assert - response.StatusCode.Should().Be(HttpStatusCode.Accepted); + private async Task PostCommand(T command, string uri) + { + var jsonData = JsonSerializer.Serialize(command); + HttpContent content = new StringContent(jsonData, Encoding.UTF8, "application/json"); - //get job id and wait for job to be completed - var jobUri = response.Headers.Location; - if (jobUri != null) await WaitOnJobCompleting(jobUri); + //Act + var response = await Client.PostAsync(uri, content); - return response; - } + // Assert + response.StatusCode.Should().Be(HttpStatusCode.Accepted); + + //get job id and wait for job to be completed + var jobUri = response.Headers.Location; + if (jobUri != null) await WaitOnJobCompleting(jobUri); + + return response; } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/GmrTests.cs b/Btms.Backend.IntegrationTests/GmrTests.cs index 2f7f27d..5fb2cf0 100644 --- a/Btms.Backend.IntegrationTests/GmrTests.cs +++ b/Btms.Backend.IntegrationTests/GmrTests.cs @@ -17,17 +17,14 @@ public class GmrTests : IClassFixture, IAsyncLifetime { private readonly HttpClient client; - private readonly IntegrationTestsApplicationFactory factory; public GmrTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) { - this.factory = factory; - this.factory.TestOutputHelper = testOutputHelper; - this.factory.DatabaseName = "GmrTests"; - client = - this.factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); - string credentials = "IntTest:Password"; - byte[] credentialsAsBytes = Encoding.UTF8.GetBytes(credentials.ToCharArray()); + factory.TestOutputHelper = testOutputHelper; + factory.DatabaseName = "GmrTests"; + client = factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); + var credentials = "IntTest:Password"; + var credentialsAsBytes = Encoding.UTF8.GetBytes(credentials.ToCharArray()); var encodedCredentials = Convert.ToBase64String(credentialsAsBytes); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(BasicAuthenticationDefaults.AuthenticationScheme, encodedCredentials); @@ -37,7 +34,7 @@ public async Task InitializeAsync() { await IntegrationTestsApplicationFactory.ClearDb(client); - await MakeSyncGmrsRequest(new SyncGmrsCommand() + await MakeSyncGmrsRequest(new SyncGmrsCommand { SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" @@ -58,7 +55,7 @@ public void FetchSingleGmrTest() jsonClientResponse.Data.Relationships?["customs"]?.Links?.Self.Should().Be("/api/gmr/:id/relationships/import-notifications"); jsonClientResponse.Data.Relationships?["customs"]?.Links?.Related.Should().Be("/api/import-notifications/:id"); - jsonClientResponse.Data.Relationships?["customs"]?.Data.ManyValue?[0]?.Id.Should().Be("56GB123456789AB043"); + jsonClientResponse.Data.Relationships?["customs"]?.Data.ManyValue?[0].Id.Should().Be("56GB123456789AB043"); jsonClientResponse.Data.Relationships?["customs"]?.Data.ManyValue?[0].Type.Should().Be("import-notifications"); } diff --git a/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClient.cs b/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClient.cs index 3c72618..b7b7ad0 100644 --- a/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClient.cs +++ b/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClient.cs @@ -10,18 +10,18 @@ namespace Btms.Backend.IntegrationTests.JsonApiClient; public class JsonApiClient(HttpClient client) { - static string strContentType = "application/vnd.api+json"; + private static readonly string StringContentType = "application/vnd.api+json"; - static MediaTypeWithQualityHeaderValue contentType = new MediaTypeWithQualityHeaderValue(strContentType); + private static readonly MediaTypeWithQualityHeaderValue ContentType = new(StringContentType); public ManyItemsJsonApiDocument Get( string path, - Dictionary query = null!, - Dictionary headers = null!, - IList relations = null!) + Dictionary? query = null, + Dictionary? headers = null, + IList? relations = null) { - client.DefaultRequestHeaders.Accept.Add(contentType); + client.DefaultRequestHeaders.Accept.Add(ContentType); if (headers != null) { @@ -34,7 +34,7 @@ public ManyItemsJsonApiDocument Get( } } - string uri = $"/{path}"; + var uri = $"/{path}"; if (relations != null) { @@ -46,7 +46,7 @@ public ManyItemsJsonApiDocument Get( uri = QueryHelpers.AddQueryString(uri, query!); } - HttpResponseMessage responseMessage = client.GetAsync(uri).Result; + var responseMessage = client.GetAsync(uri).Result; responseMessage.StatusCode.Should().Be(HttpStatusCode.OK, $"Status code was {responseMessage.StatusCode}"); @@ -54,7 +54,7 @@ public ManyItemsJsonApiDocument Get( var s = responseMessage.Content.ReadAsStringAsync().Result; return JsonSerializer.Deserialize(s, - new JsonSerializerOptions() + new JsonSerializerOptions { Converters = { new SingleOrManyDataConverterFactory() }, PropertyNameCaseInsensitive = true @@ -63,11 +63,11 @@ public ManyItemsJsonApiDocument Get( public SingleItemJsonApiDocument GetById(string id, string path, - Dictionary query = null!, - Dictionary headers = null!, - IList relations = null!) + Dictionary? query = null, + Dictionary? headers = null, + IList? relations = null) { - client.DefaultRequestHeaders.Accept.Add(contentType); + client.DefaultRequestHeaders.Accept.Add(ContentType); if (headers != null) { @@ -80,7 +80,7 @@ public SingleItemJsonApiDocument GetById(string id, } } - string uri = $"/{path}/{id}"; + var uri = $"/{path}/{id}"; if (relations != null) { @@ -92,14 +92,14 @@ public SingleItemJsonApiDocument GetById(string id, uri = QueryHelpers.AddQueryString(uri, query!); } - HttpResponseMessage responseMessage = client.GetAsync(uri).Result; + var responseMessage = client.GetAsync(uri).Result; responseMessage.StatusCode.Should().Be(HttpStatusCode.OK, $"Status code was {responseMessage.StatusCode}"); var s = responseMessage.Content.ReadAsStringAsync().Result; return JsonSerializer.Deserialize(s, - new JsonSerializerOptions() + new JsonSerializerOptions { Converters = { new SingleOrManyDataConverterFactory() }, PropertyNameCaseInsensitive = true diff --git a/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClientExtensions.cs b/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClientExtensions.cs index 24e0bf2..f580df4 100644 --- a/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClientExtensions.cs +++ b/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiClientExtensions.cs @@ -1,19 +1,9 @@ -using Newtonsoft.Json.Serialization; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http.Json; -using System.Text; -using System.Threading.Tasks; -using Azure; +namespace Btms.Backend.IntegrationTests.JsonApiClient; -namespace Btms.Backend.IntegrationTests.JsonApiClient +public static class JsonApiClientExtensions { - public static class JsonApiClientExtensions + public static JsonApiClient AsJsonApiClient(this HttpClient client) { - public static JsonApiClient AsJsonApiClient(this HttpClient client) - { - return new JsonApiClient(client); - } + return new JsonApiClient(client); } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiDocument.cs b/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiDocument.cs index 88f8970..70fce18 100644 --- a/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiDocument.cs +++ b/Btms.Backend.IntegrationTests/JsonApiClient/JsonApiDocument.cs @@ -7,7 +7,7 @@ namespace Btms.Backend.IntegrationTests.JsonApiClient; public abstract class JsonApiDocument { - protected JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions() + protected JsonSerializerOptions JsonSerializerOptions = new() { Converters = { new SingleOrManyDataConverterFactory() }, PropertyNameCaseInsensitive = true, diff --git a/Btms.Backend.IntegrationTests/JsonApiClient/ManyItemsJsonApiDocument.cs b/Btms.Backend.IntegrationTests/JsonApiClient/ManyItemsJsonApiDocument.cs index 336f054..ae0b101 100644 --- a/Btms.Backend.IntegrationTests/JsonApiClient/ManyItemsJsonApiDocument.cs +++ b/Btms.Backend.IntegrationTests/JsonApiClient/ManyItemsJsonApiDocument.cs @@ -8,7 +8,7 @@ public class ManyItemsJsonApiDocument : JsonApiDocument> public List GetResourceObjects() { return Data.Select(x => - JsonSerializer.Deserialize(JsonSerializer.Serialize(x.Attributes, jsonSerializerOptions), - jsonSerializerOptions)).ToList()!; + JsonSerializer.Deserialize(JsonSerializer.Serialize(x.Attributes, JsonSerializerOptions), + JsonSerializerOptions)).ToList()!; } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/JsonApiClient/SingleItemJsonApiDocument.cs b/Btms.Backend.IntegrationTests/JsonApiClient/SingleItemJsonApiDocument.cs index d4923c1..5be7c47 100644 --- a/Btms.Backend.IntegrationTests/JsonApiClient/SingleItemJsonApiDocument.cs +++ b/Btms.Backend.IntegrationTests/JsonApiClient/SingleItemJsonApiDocument.cs @@ -7,7 +7,7 @@ public class SingleItemJsonApiDocument : JsonApiDocument { public T GetResourceObject() { - return JsonSerializer.Deserialize(JsonSerializer.Serialize(this.Data.Attributes, jsonSerializerOptions), - jsonSerializerOptions)!; + return JsonSerializer.Deserialize(JsonSerializer.Serialize(Data.Attributes, JsonSerializerOptions), + JsonSerializerOptions)!; } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/LinkingTests.cs b/Btms.Backend.IntegrationTests/LinkingTests.cs index ea7f85a..a2ef463 100644 --- a/Btms.Backend.IntegrationTests/LinkingTests.cs +++ b/Btms.Backend.IntegrationTests/LinkingTests.cs @@ -5,102 +5,101 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Backend.IntegrationTests +namespace Btms.Backend.IntegrationTests; + +[Trait("Category", "Integration")] +public class LinkingTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) + : BaseApiTests(factory, testOutputHelper), IClassFixture { - [Trait("Category", "Integration")] - public class LinkingTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) - : BaseApiTests(factory, testOutputHelper), IClassFixture + [Fact] + public async Task SyncClearanceRequests_WithNoReferencedNotifications_ShouldNotLink() { - [Fact] - public async Task SyncClearanceRequests_WithNoReferencedNotifications_ShouldNotLink() + // Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); + + // Act + await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand { - // Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); + SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" + }); - // Act - await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand() - { - SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" - }); + // Assert + var jsonClientResponse = Client.AsJsonApiClient().Get("api/movements"); + jsonClientResponse.Data + .Where(x => x.Relationships is not null) + .SelectMany(x => x.Relationships!) + .Any(x => x.Value is { Links: not null }) + .Should().Be(false); + } - // Assert - var jsonClientResponse = Client.AsJsonApiClient().Get("api/movements"); - jsonClientResponse.Data - .Where(x => x.Relationships is not null) - .SelectMany(x => x.Relationships!) - .Any(x => x.Value is { Links: not null }) - .Should().Be(false); - } + [Fact] + public async Task SyncClearanceRequests_WithReferencedNotifications_ShouldLink() + { + // Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); - [Fact] - public async Task SyncClearanceRequests_WithReferencedNotifications_ShouldLink() + // Act + await MakeSyncNotificationsRequest(new SyncNotificationsCommand { - // Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); - - // Act - await MakeSyncNotificationsRequest(new SyncNotificationsCommand() - { - SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" - }); - await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand() - { - SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" - }); + SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" + }); + await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand + { + SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" + }); - // Assert - var jsonClientResponse = Client.AsJsonApiClient().Get("api/movements"); - jsonClientResponse.Data - .Where(x => x.Relationships is not null) - .SelectMany(x => x.Relationships!) - .Any(x => x.Value is { Links: not null }) - .Should().Be(true); - } + // Assert + var jsonClientResponse = Client.AsJsonApiClient().Get("api/movements"); + jsonClientResponse.Data + .Where(x => x.Relationships is not null) + .SelectMany(x => x.Relationships!) + .Any(x => x.Value is { Links: not null }) + .Should().Be(true); + } - [Fact] - public async Task SyncNotifications_WithNoReferencedMovements_ShouldNotLink() - { - // Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); + [Fact] + public async Task SyncNotifications_WithNoReferencedMovements_ShouldNotLink() + { + // Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); - // Act - await MakeSyncNotificationsRequest(new SyncNotificationsCommand() - { - SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" - }); + // Act + await MakeSyncNotificationsRequest(new SyncNotificationsCommand + { + SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" + }); - // Assert - var jsonClientResponse = Client.AsJsonApiClient().Get("api/import-notifications"); - jsonClientResponse.Data - .Where(x => x.Relationships is not null) - .SelectMany(x => x.Relationships!) - .Any(x => x.Value is { Links: not null }) - .Should().Be(false); - } + // Assert + var jsonClientResponse = Client.AsJsonApiClient().Get("api/import-notifications"); + jsonClientResponse.Data + .Where(x => x.Relationships is not null) + .SelectMany(x => x.Relationships!) + .Any(x => x.Value is { Links: not null }) + .Should().Be(false); + } - [Fact] - public async Task SyncNotifications_WithReferencedMovements_ShouldLink() - { - // Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); + [Fact] + public async Task SyncNotifications_WithReferencedMovements_ShouldLink() + { + // Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); - // Act - await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand() - { - SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" - }); - await MakeSyncNotificationsRequest(new SyncNotificationsCommand() - { - SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" - }); + // Act + await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand + { + SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" + }); + await MakeSyncNotificationsRequest(new SyncNotificationsCommand + { + SyncPeriod = SyncPeriod.All, RootFolder = "SmokeTest" + }); - // Assert - var jsonClientResponse = Client.AsJsonApiClient().Get("api/import-notifications"); - jsonClientResponse.Data - .Where(x => x.Relationships is not null) - .SelectMany(x => x.Relationships!) - .Any(x => x.Value is { Links: not null }) - .Should().Be(true); - } + // Assert + var jsonClientResponse = Client.AsJsonApiClient().Get("api/import-notifications"); + jsonClientResponse.Data + .Where(x => x.Relationships is not null) + .SelectMany(x => x.Relationships!) + .Any(x => x.Value is { Links: not null }) + .Should().Be(true); } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/SensitiveDataTests.cs b/Btms.Backend.IntegrationTests/SensitiveDataTests.cs index 149fee0..77ca196 100644 --- a/Btms.Backend.IntegrationTests/SensitiveDataTests.cs +++ b/Btms.Backend.IntegrationTests/SensitiveDataTests.cs @@ -1,6 +1,4 @@ using System.Text.Json.Nodes; -using Btms.Backend.IntegrationTests.Helpers; -using Btms.BlobService; using Btms.SensitiveData; using Btms.Types.Ipaffs; using FluentAssertions; @@ -17,10 +15,10 @@ public class SensitiveDataTests public void WhenIncludeSensitiveData_RedactedShouldBeSameAsJson() { var filePath = "../../../Fixtures/SmokeTest/IPAFFS/CHEDA/CHEDA_GB_2024_1041389-ee0e6fcf-52a4-45ea-8830-d4553ee70361.json"; - string json = + var json = File.ReadAllText(filePath); - SensitiveDataOptions options = new SensitiveDataOptions { Getter = s => "TestRedacted", Include = true }; + var options = new SensitiveDataOptions { Getter = _ => "TestRedacted", Include = true }; var serializer = new SensitiveDataSerializer(Options.Create(options), NullLogger.Instance); var result = serializer.RedactRawJson(json, typeof(ImportNotification)); @@ -33,10 +31,10 @@ public void WhenIncludeSensitiveData_RedactedShouldBeSameAsJson() public void WhenIncludeSensitiveData_RedactedShouldBeDifferentJson() { var filePath = "../../../Fixtures/SmokeTest/IPAFFS/CHEDA/CHEDA_GB_2024_1041389-ee0e6fcf-52a4-45ea-8830-d4553ee70361.json"; - string json = + var json = File.ReadAllText(filePath); - SensitiveDataOptions options = new SensitiveDataOptions { Getter = s => "TestRedacted", Include = false }; + var options = new SensitiveDataOptions { Getter = _ => "TestRedacted", Include = false }; var serializer = new SensitiveDataSerializer(Options.Create(options), NullLogger.Instance); var result = serializer.RedactRawJson(json, typeof(ImportNotification)); diff --git a/Btms.Backend.IntegrationTests/SmokeTests.cs b/Btms.Backend.IntegrationTests/SmokeTests.cs index 9815b70..f80669e 100644 --- a/Btms.Backend.IntegrationTests/SmokeTests.cs +++ b/Btms.Backend.IntegrationTests/SmokeTests.cs @@ -12,150 +12,149 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Backend.IntegrationTests +namespace Btms.Backend.IntegrationTests; + +[Trait("Category", "Integration")] +public class SmokeTests : BaseApiTests, IClassFixture { - [Trait("Category", "Integration")] - public class SmokeTests : BaseApiTests, IClassFixture - { - private readonly JsonSerializerOptions jsonOptions; + private readonly JsonSerializerOptions jsonOptions; - public SmokeTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) :base(factory, testOutputHelper) - { - jsonOptions = new JsonSerializerOptions(); - jsonOptions.Converters.Add(new JsonStringEnumConverter()); - jsonOptions.PropertyNameCaseInsensitive = true; - } + public SmokeTests(IntegrationTestsApplicationFactory factory, ITestOutputHelper testOutputHelper) :base(factory, testOutputHelper) + { + jsonOptions = new JsonSerializerOptions(); + jsonOptions.Converters.Add(new JsonStringEnumConverter()); + jsonOptions.PropertyNameCaseInsensitive = true; + } - [Fact] - public async Task CancelSyncJob() + [Fact] + public async Task CancelSyncJob() + { + //Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); + var jobId = await StartJob(new SyncNotificationsCommand { - //Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); - var jobId = await StartJob(new SyncNotificationsCommand() - { - SyncPeriod = SyncPeriod.All, - RootFolder = "SmokeTest" - }, "/sync/import-notifications"); + SyncPeriod = SyncPeriod.All, + RootFolder = "SmokeTest" + }, "/sync/import-notifications"); - //Act - var cancelJobResponse = await Client.GetAsync($"/sync/jobs/{jobId}/cancel"); + //Act + var cancelJobResponse = await Client.GetAsync($"/sync/jobs/{jobId}/cancel"); - // Assert - cancelJobResponse.IsSuccessStatusCode.Should().BeTrue(cancelJobResponse.StatusCode.ToString()); + // Assert + cancelJobResponse.IsSuccessStatusCode.Should().BeTrue(cancelJobResponse.StatusCode.ToString()); - // Check Api - var jobResponse = await Client.GetAsync($"/sync/jobs/{jobId}"); - var syncJob = await jobResponse.Content.ReadFromJsonAsync(jsonOptions); - syncJob?.Status.Should().Be(SyncJobStatus.Cancelled); - } + // Check Api + var jobResponse = await Client.GetAsync($"/sync/jobs/{jobId}"); + var syncJob = await jobResponse.Content.ReadFromJsonAsync(jsonOptions); + syncJob?.Status.Should().Be(SyncJobStatus.Cancelled); + } - [Fact] - public async Task SyncNotifications() - { - //Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); - await MakeSyncNotificationsRequest(new SyncNotificationsCommand() - { - SyncPeriod = SyncPeriod.All, - RootFolder = "SmokeTest" - }); - - // Assert - // Check Db - Factory.GetDbContext().Notifications.Count().Should().Be(5); - - // Check Api - var jsonClientResponse = Client.AsJsonApiClient().Get("api/import-notifications"); - jsonClientResponse.Data.Count.Should().Be(5); - } - - [Fact] - public async Task SyncDecisions() + [Fact] + public async Task SyncNotifications() + { + //Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); + await MakeSyncNotificationsRequest(new SyncNotificationsCommand { - //Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); - await SyncClearanceRequests(); - await MakeSyncDecisionsRequest(new SyncDecisionsCommand() - { - SyncPeriod = SyncPeriod.All, - RootFolder = "SmokeTest" - }); - - // Assert - var existingMovement = await Factory.GetDbContext().Movements.Find("CHEDPGB20241039875A5"); - - existingMovement.Should().NotBeNull(); - existingMovement.Items[0].Checks.Should().NotBeNull(); - existingMovement.Items[0].Checks?.Length.Should().Be(1); - existingMovement.Items[0].Checks?[0].CheckCode.Should().Be("H234"); - existingMovement.Items[0].Checks?[0].DepartmentCode.Should().Be("PHA"); - - // Check Api - var jsonClientResponse = - Client.AsJsonApiClient().GetById("CHEDPGB20241039875A5", "api/movements"); - var movement = jsonClientResponse.GetResourceObject(); - movement.Items[0].Checks?.Length.Should().Be(1); - movement.Items[0].Checks?[0].CheckCode.Should().Be("H234"); - movement.Items[0].Checks?[0].DepartmentCode.Should().Be("PHA"); - } - - [Fact] - public async Task SyncClearanceRequests() + SyncPeriod = SyncPeriod.All, + RootFolder = "SmokeTest" + }); + + // Assert + // Check Db + Factory.GetDbContext().Notifications.Count().Should().Be(5); + + // Check Api + var jsonClientResponse = Client.AsJsonApiClient().Get("api/import-notifications"); + jsonClientResponse.Data.Count.Should().Be(5); + } + + [Fact] + public async Task SyncDecisions() + { + //Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); + await SyncClearanceRequests(); + await MakeSyncDecisionsRequest(new SyncDecisionsCommand { - //Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); - - //Act - await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand() - { - SyncPeriod = SyncPeriod.All, - RootFolder = "SmokeTest" - }); - - // Assert - Factory.GetDbContext().Movements.Count().Should().Be(5); - - // Check Api - var jsonClientResponse = Client.AsJsonApiClient().Get("api/movements"); - jsonClientResponse.Data.Count.Should().Be(5); - } - - [Fact] - public async Task SyncGmrs() + SyncPeriod = SyncPeriod.All, + RootFolder = "SmokeTest" + }); + + // Assert + var existingMovement = await Factory.GetDbContext().Movements.Find("CHEDPGB20241039875A5"); + + existingMovement.Should().NotBeNull(); + existingMovement?.Items[0].Checks.Should().NotBeNull(); + existingMovement?.Items[0].Checks?.Length.Should().Be(1); + existingMovement?.Items[0].Checks?[0].CheckCode.Should().Be("H234"); + existingMovement?.Items[0].Checks?[0].DepartmentCode.Should().Be("PHA"); + + // Check Api + var jsonClientResponse = + Client.AsJsonApiClient().GetById("CHEDPGB20241039875A5", "api/movements"); + var movement = jsonClientResponse.GetResourceObject(); + movement.Items[0].Checks?.Length.Should().Be(1); + movement.Items[0].Checks?[0].CheckCode.Should().Be("H234"); + movement.Items[0].Checks?[0].DepartmentCode.Should().Be("PHA"); + } + + [Fact] + public async Task SyncClearanceRequests() + { + //Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); + + //Act + await MakeSyncClearanceRequest(new SyncClearanceRequestsCommand { - //Arrange - await IntegrationTestsApplicationFactory.ClearDb(Client); + SyncPeriod = SyncPeriod.All, + RootFolder = "SmokeTest" + }); - //Act - await MakeSyncGmrsRequest(new SyncGmrsCommand() - { - SyncPeriod = SyncPeriod.All, - RootFolder = "SmokeTest" - }); + // Assert + Factory.GetDbContext().Movements.Count().Should().Be(5); - // Assert - Factory.GetDbContext().Gmrs.Count().Should().Be(3); + // Check Api + var jsonClientResponse = Client.AsJsonApiClient().Get("api/movements"); + jsonClientResponse.Data.Count.Should().Be(5); + } - // Check Api - var jsonClientResponse = Client.AsJsonApiClient().Get("api/gmrs"); - jsonClientResponse.Data.Count.Should().Be(3); - } + [Fact] + public async Task SyncGmrs() + { + //Arrange + await IntegrationTestsApplicationFactory.ClearDb(Client); - private async Task StartJob(T command, string uri) + //Act + await MakeSyncGmrsRequest(new SyncGmrsCommand { - var jsonData = JsonSerializer.Serialize(command); - HttpContent content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + SyncPeriod = SyncPeriod.All, + RootFolder = "SmokeTest" + }); + + // Assert + Factory.GetDbContext().Gmrs.Count().Should().Be(3); + + // Check Api + var jsonClientResponse = Client.AsJsonApiClient().Get("api/gmrs"); + jsonClientResponse.Data.Count.Should().Be(3); + } + + private async Task StartJob(T command, string uri) + { + var jsonData = JsonSerializer.Serialize(command); + HttpContent content = new StringContent(jsonData, Encoding.UTF8, "application/json"); - //Act - var response = await Client.PostAsync(uri, content); + //Act + var response = await Client.PostAsync(uri, content); - // Assert - response.StatusCode.Should().Be(HttpStatusCode.Accepted); + // Assert + response.StatusCode.Should().Be(HttpStatusCode.Accepted); - return Path.GetFileName(response.Headers.Location?.ToString()); - } + return Path.GetFileName(response.Headers.Location?.ToString()); } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/SyncJobResponse.cs b/Btms.Backend.IntegrationTests/SyncJobResponse.cs index ff8d78d..bcd1756 100644 --- a/Btms.Backend.IntegrationTests/SyncJobResponse.cs +++ b/Btms.Backend.IntegrationTests/SyncJobResponse.cs @@ -1,31 +1,30 @@ using Btms.SyncJob; -namespace Btms.Backend.IntegrationTests +namespace Btms.Backend.IntegrationTests; + +public class SyncJobResponse { - public class SyncJobResponse - { - public Guid JobId { get; set; } + public Guid JobId { get; set; } - public string Description { get; set; } = null!; + public string Description { get; set; } = null!; - public int BlobsRead { get; set; } + public int BlobsRead { get; set; } - public int BlobsPublished { get; set; } + public int BlobsPublished { get; set; } - public int BlobsFailed { get; set; } + public int BlobsFailed { get; set; } - public int MessagesProcessed { get; set; } + public int MessagesProcessed { get; set; } - public int MessagesFailed { get; set; } + public int MessagesFailed { get; set; } - public DateTime QueuedOn { get; set; } - public DateTime StartedOn { get; set; } + public DateTime QueuedOn { get; set; } + public DateTime StartedOn { get; set; } - public DateTime? CompletedOn { get; set; } + public DateTime? CompletedOn { get; set; } - public TimeSpan RunTime { get; set; } + public TimeSpan RunTime { get; set; } - public SyncJobStatus Status { get; set; } - } + public SyncJobStatus Status { get; set; } } \ No newline at end of file diff --git a/Btms.Backend.Test/Auditing/AuditingTests.cs b/Btms.Backend.Test/Auditing/AuditingTests.cs index 224ecad..42bc5c3 100644 --- a/Btms.Backend.Test/Auditing/AuditingTests.cs +++ b/Btms.Backend.Test/Auditing/AuditingTests.cs @@ -13,8 +13,8 @@ public class TestClassOne [Fact] public void CreateAuditWhenDifferentIsDouble() { - var previous = new TestClassOne() { NumberValue = 1.2 }; - var current = new TestClassOne() { NumberValue = 2.2 }; + var previous = new TestClassOne { NumberValue = 1.2 }; + var current = new TestClassOne { NumberValue = 2.2 }; var auditEntry = AuditEntry.CreateUpdated(previous, current, "testid", 1, DateTime.UtcNow); auditEntry.Should().NotBeNull(); @@ -29,8 +29,8 @@ public void CreateAuditWhenDifferentIsDouble() [Fact] public void CreateAuditWhenDifferentIsInt() { - var previous = new TestClassOne() { NumberValue = 1 }; - var current = new TestClassOne() { NumberValue = 2 }; + var previous = new TestClassOne { NumberValue = 1 }; + var current = new TestClassOne { NumberValue = 2 }; var auditEntry = AuditEntry.CreateUpdated(previous, current, "testid", 1, DateTime.UtcNow); auditEntry.Should().NotBeNull(); diff --git a/Btms.Backend.Test/Config/ApiOptionsTest.cs b/Btms.Backend.Test/Config/ApiOptionsTest.cs index 0fd2971..fc732d8 100644 --- a/Btms.Backend.Test/Config/ApiOptionsTest.cs +++ b/Btms.Backend.Test/Config/ApiOptionsTest.cs @@ -19,7 +19,7 @@ public void ShouldSucceedIfNoCdsProxy() [Fact] public void ShouldFailIfCdsProxyDoesntHaveProtocol() { - var c = new ApiOptions() { CdpHttpsProxy = "aaa" }; + var c = new ApiOptions { CdpHttpsProxy = "aaa" }; validator.Validate("", c).Failed.Should().BeTrue(); } diff --git a/Btms.Backend.Test/Utils/Http/ProxyTest.cs b/Btms.Backend.Test/Utils/Http/ProxyTest.cs index 5edf01f..36173d4 100644 --- a/Btms.Backend.Test/Utils/Http/ProxyTest.cs +++ b/Btms.Backend.Test/Utils/Http/ProxyTest.cs @@ -1,4 +1,3 @@ -using Amazon.Runtime.Internal.Util; using Btms.Backend.Utils.Http; using Microsoft.Extensions.Logging.Abstractions; using FluentAssertions; @@ -22,7 +21,7 @@ public void ExtractProxyCredentials() Proxy.ConfigureProxy(proxy, proxyUri, NullLogger.Instance); - var credentials = proxy.Credentials?.GetCredential(new System.Uri(proxyUri), "Basic"); + var credentials = proxy.Credentials?.GetCredential(new Uri(proxyUri), "Basic"); credentials?.UserName.Should().Be("user"); credentials?.Password.Should().Be("password"); diff --git a/Btms.Backend/Authentication/ClientCredentialsManager.cs b/Btms.Backend/Authentication/ClientCredentialsManager.cs index edce3f1..25da64b 100644 --- a/Btms.Backend/Authentication/ClientCredentialsManager.cs +++ b/Btms.Backend/Authentication/ClientCredentialsManager.cs @@ -1,18 +1,17 @@ using Btms.Backend.Config; using Microsoft.Extensions.Options; -namespace Btms.Backend.Authentication +namespace Btms.Backend.Authentication; + +public class ClientCredentialsManager(IOptions options) : IClientCredentialsManager { - public class ClientCredentialsManager(IOptions options) : IClientCredentialsManager + public Task IsValid(string clientId, string clientSecret) { - public Task IsValid(string clientId, string clientSecret) + if (options.Value.Credentials.TryGetValue(clientId, out var secret)) { - if (options.Value.Credentials.TryGetValue(clientId, out string? secret)) - { - return Task.FromResult(!string.IsNullOrEmpty(secret) && clientSecret.Equals(secret)); - } - - return Task.FromResult(false); + return Task.FromResult(!string.IsNullOrEmpty(secret) && clientSecret.Equals(secret)); } + + return Task.FromResult(false); } } \ No newline at end of file diff --git a/Btms.Backend/Authentication/IClientCredentialsManager.cs b/Btms.Backend/Authentication/IClientCredentialsManager.cs index b4e9da9..a5b8e17 100644 --- a/Btms.Backend/Authentication/IClientCredentialsManager.cs +++ b/Btms.Backend/Authentication/IClientCredentialsManager.cs @@ -1,7 +1,6 @@ -namespace Btms.Backend.Authentication +namespace Btms.Backend.Authentication; + +public interface IClientCredentialsManager { - public interface IClientCredentialsManager - { - Task IsValid(string clientId, string clientSecret); - } + Task IsValid(string clientId, string clientSecret); } \ No newline at end of file diff --git a/Btms.Backend/BackgroundTaskQueue/BackgroundTaskQueue.cs b/Btms.Backend/BackgroundTaskQueue/BackgroundTaskQueue.cs index 53d1199..e38ed1e 100644 --- a/Btms.Backend/BackgroundTaskQueue/BackgroundTaskQueue.cs +++ b/Btms.Backend/BackgroundTaskQueue/BackgroundTaskQueue.cs @@ -1,46 +1,44 @@ using System.Threading.Channels; -namespace Btms.Backend.BackgroundTaskQueue +namespace Btms.Backend.BackgroundTaskQueue; + +internal class BackgroundTaskQueue : IBackgroundTaskQueue { - internal class BackgroundTaskQueue : IBackgroundTaskQueue - { - private readonly Channel> _queue; - private readonly ILogger _logger; + private readonly Channel> _queue; + private readonly ILogger _logger; - public BackgroundTaskQueue(ILogger logger) + public BackgroundTaskQueue(ILogger logger) + { + var queueCapacity = 10; //refer to docs on setting the capacity + var options = new BoundedChannelOptions(queueCapacity) { - var queueCapacity = 10; //refer to docs on setting the capacity - var options = new BoundedChannelOptions(queueCapacity) - { - FullMode = BoundedChannelFullMode.Wait - }; - _queue = Channel.CreateBounded>(options); - - _logger = logger; - } + FullMode = BoundedChannelFullMode.Wait + }; + _queue = Channel.CreateBounded>(options); - public async ValueTask> DequeueAsync(CancellationToken cancellationToken) - { - var workItem = await _queue.Reader.ReadAsync(cancellationToken); + _logger = logger; + } - _logger.LogInformation("Item {workItemName} has been read and will be dequeued from background queue.", nameof(workItem)); + public async ValueTask> DequeueAsync(CancellationToken cancellationToken) + { + var workItem = await _queue.Reader.ReadAsync(cancellationToken); - return workItem; - } + _logger.LogInformation("Item {WorkItemName} has been read and will be dequeued from background queue", nameof(workItem)); + + return workItem; + } - public async ValueTask QueueBackgroundWorkItemAsync(Func workItem) + public async ValueTask QueueBackgroundWorkItemAsync(Func workItem) + { + if (workItem == null) { - if (workItem == null) - { - throw new ArgumentNullException(nameof(workItem)); - } + throw new ArgumentNullException(nameof(workItem)); + } - _logger.LogInformation("Preparing to write item {workItemName} to background queue.", nameof(workItem)); + _logger.LogInformation("Preparing to write item {WorkItemName} to background queue", nameof(workItem)); - await _queue.Writer.WriteAsync(workItem); + await _queue.Writer.WriteAsync(workItem); - _logger.LogInformation("Item {workItemName} has been written to background queue and will be executed.", - nameof(workItem)); - } + _logger.LogInformation("Item {WorkItemName} has been written to background queue and will be executed", nameof(workItem)); } -} +} \ No newline at end of file diff --git a/Btms.Backend/BackgroundTaskQueue/QueueHostedService.cs b/Btms.Backend/BackgroundTaskQueue/QueueHostedService.cs index bff744f..ea23809 100644 --- a/Btms.Backend/BackgroundTaskQueue/QueueHostedService.cs +++ b/Btms.Backend/BackgroundTaskQueue/QueueHostedService.cs @@ -1,10 +1,9 @@ -using Btms.Common; using Btms.Metrics; using System.Diagnostics; namespace Btms.Backend.BackgroundTaskQueue; -internal class QueueHostedService : Microsoft.Extensions.Hosting.BackgroundService +internal class QueueHostedService : BackgroundService { public const string ActivityName = "Btms.Job.Run"; private readonly ILogger _logger; @@ -30,21 +29,21 @@ private async Task BackgroundProcessing(CancellationToken stoppingToken) { var workItem = await TaskQueue.DequeueAsync(stoppingToken); - ThreadPool.QueueUserWorkItem(state => + ThreadPool.QueueUserWorkItem(_ => { try { - _logger.LogInformation("Starting execution of {workItem}...", nameof(workItem)); - using (var activity = BtmsDiagnostics.ActivitySource.StartActivity(ActivityName, ActivityKind.Client)) + _logger.LogInformation("Starting execution of {WorkItem}...", nameof(workItem)); + using (BtmsDiagnostics.ActivitySource.StartActivity(ActivityName, ActivityKind.Client)) { workItem(stoppingToken).GetAwaiter().GetResult(); } - _logger.LogInformation("Execution of {workItem} completed!!!", nameof(workItem)); + _logger.LogInformation("Execution of {WorkItem} completed!!!", nameof(workItem)); } catch (Exception ex) { - _logger.LogError(ex, "Error occured executing {workItem}", nameof(workItem)); + _logger.LogError(ex, "Error occured executing {WorkItem}", nameof(workItem)); } }); diff --git a/Btms.Backend/Config/ApiOptions.cs b/Btms.Backend/Config/ApiOptions.cs index fe9a1c2..d247965 100644 --- a/Btms.Backend/Config/ApiOptions.cs +++ b/Btms.Backend/Config/ApiOptions.cs @@ -8,7 +8,7 @@ public class ApiOptions public static readonly string SectionName = nameof(ApiOptions); public bool EnableManagement { get; set; } = default!; - public bool EnableSync { get; set; } = true!; + public bool EnableSync { get; set; } = true; [ConfigurationKeyName("CDP_HTTPS_PROXY")] public string? CdpHttpsProxy { get; set; } @@ -21,7 +21,7 @@ public class ApiOptions public Dictionary Credentials { get; set; } = []; - public class Validator() : IValidateOptions + public class Validator : IValidateOptions { /// /// Validates that CDP_HTTPS_PROXY is shaped correctly if present diff --git a/Btms.Backend/Endpoints/AnalyticsEndpoints.cs b/Btms.Backend/Endpoints/AnalyticsEndpoints.cs index bf67833..cd3cb95 100644 --- a/Btms.Backend/Endpoints/AnalyticsEndpoints.cs +++ b/Btms.Backend/Endpoints/AnalyticsEndpoints.cs @@ -1,5 +1,4 @@ using Btms.Analytics; -using Btms.Analytics.Extensions; using Btms.Common.Extensions; using Microsoft.AspNetCore.Mvc; diff --git a/Btms.Backend/Endpoints/ManagementEndpoints.cs b/Btms.Backend/Endpoints/ManagementEndpoints.cs index bec4465..7a88e3b 100644 --- a/Btms.Backend/Endpoints/ManagementEndpoints.cs +++ b/Btms.Backend/Endpoints/ManagementEndpoints.cs @@ -6,8 +6,6 @@ using System.Collections; using Btms.Backend.Config; using Btms.Business.Commands; -using Btms.SyncJob; -using Btms.Backend.Mediatr; using Microsoft.AspNetCore.Mvc; namespace Btms.Backend.Endpoints; @@ -28,7 +26,7 @@ public static void UseManagementEndpoints(this IEndpointRouteBuilder app, IOptio } } - private static string[] KeysToRedact = [ + private static string[] _keysToRedact = [ "Mongo__DatabaseUri", "MONGO_URI" ]; @@ -38,7 +36,7 @@ private static bool RedactKeys(string key) return key.StartsWith("AZURE") || key.StartsWith("BlobServiceOptions__Azure") || key.Contains("password", StringComparison.OrdinalIgnoreCase) || - KeysToRedact.Contains(key); + _keysToRedact.Contains(key); } private const string Redacted = "--redacted--"; @@ -46,7 +44,7 @@ private static bool RedactKeys(string key) private static DictionaryEntry Redact(DictionaryEntry d) { - object? value = d.Value; + var value = d.Value; try { @@ -65,8 +63,6 @@ private static DictionaryEntry Redact(DictionaryEntry d) case string s when RedactKeys(s): value = Redacted; break; - default: - break; } } catch (Exception) @@ -74,7 +70,7 @@ private static DictionaryEntry Redact(DictionaryEntry d) value = Redacted; } - return new DictionaryEntry() { Key = d.Key, Value = value }; + return new DictionaryEntry { Key = d.Key, Value = value }; } private static async Task Initialise( @@ -116,7 +112,7 @@ private static async Task GetCollectionsAsync(IMongoDatabase db) indexes = GetIndexes(db, c["name"].ToString()!) }); - return Results.Ok(new { collections = collections }); + return Results.Ok(new { collections }); } private static async Task DropCollectionsAsync(IMongoDbContext context) diff --git a/Btms.Backend/Endpoints/SyncEndpoints.cs b/Btms.Backend/Endpoints/SyncEndpoints.cs index 4c017ba..bee3d22 100644 --- a/Btms.Backend/Endpoints/SyncEndpoints.cs +++ b/Btms.Backend/Endpoints/SyncEndpoints.cs @@ -1,17 +1,10 @@ -using System.IO.Compression; -using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Models; using Btms.Backend.Config; using Btms.Backend.Mediatr; using Btms.Business.Commands; using Btms.Consumers.MemoryQueue; using Btms.SyncJob; -using Btms.Types.Alvs; -using Btms.Types.Ipaffs; -using MediatR; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using static Btms.Business.Commands.DownloadCommand; namespace Btms.Backend.Endpoints; @@ -58,13 +51,13 @@ internal static async Task InitialiseEnvironment(IHost app, SyncPeriod private static IResult DownloadNotifications([FromServices] IWebHostEnvironment env, string id) { - var stream = File.OpenRead($"{System.IO.Path.Combine(env.ContentRootPath, id)}.zip"); + var stream = File.OpenRead($"{Path.Combine(env.ContentRootPath, id)}.zip"); return Results.File(stream, "application/zip", $"{id}.zip"); } private static async Task GenerateDownload([FromServices] IBtmsMediator mediator, [FromQuery] SyncPeriod period) { - var command = new DownloadCommand() { SyncPeriod = period }; + var command = new DownloadCommand { SyncPeriod = period }; await mediator.SendJob(command); return Results.Ok(command.JobId); } diff --git a/Btms.Backend/JsonApi/BtmsResponseModelAdapter.cs b/Btms.Backend/JsonApi/BtmsResponseModelAdapter.cs index 5b4b166..26fad6c 100644 --- a/Btms.Backend/JsonApi/BtmsResponseModelAdapter.cs +++ b/Btms.Backend/JsonApi/BtmsResponseModelAdapter.cs @@ -63,7 +63,7 @@ private static void ProcessRelationships(object? value, ResourceObject resourceO { #pragma warning disable CS8602 // Dereference of a possibly null reference. List list = relationship.Item2.Data.Select(item => - new ResourceIdentifierObject() + new ResourceIdentifierObject { Type = item.Type, Id = item.Id, Meta = item.ToDictionary(), }) @@ -73,19 +73,16 @@ private static void ProcessRelationships(object? value, ResourceObject resourceO var meta = new Dictionary(); - if (relationship.Item2.Matched.HasValue) - { - meta.Add("matched", relationship.Item2.Matched); - } + meta.Add("matched", relationship.Item2.Matched); resourceObject.Relationships.Add(relationship.Item1, - new RelationshipObject() + new RelationshipObject { Meta = meta, - Links = new RelationshipLinks() + Links = new RelationshipLinks { Self = relationship.Item2.Links?.Self, - Related = relationship.Item2?.Links?.Related + Related = relationship.Item2.Links?.Related }, Data = new SingleOrManyData(list) }); diff --git a/Btms.Backend/Mediatr/BtmsMediator.cs b/Btms.Backend/Mediatr/BtmsMediator.cs index 9b21c51..1206263 100644 --- a/Btms.Backend/Mediatr/BtmsMediator.cs +++ b/Btms.Backend/Mediatr/BtmsMediator.cs @@ -3,55 +3,54 @@ using System.Diagnostics; using Btms.Backend.BackgroundTaskQueue; -namespace Btms.Backend.Mediatr +namespace Btms.Backend.Mediatr; + +internal class BtmsMediator( + IBackgroundTaskQueue backgroundTaskQueue, + IServiceScopeFactory serviceScopeFactory, + IMediator mediator, + ISyncJobStore syncJobStore) + : IBtmsMediator { - internal class BtmsMediator( - IBackgroundTaskQueue backgroundTaskQueue, - IServiceScopeFactory serviceScopeFactory, - IMediator mediator, - ISyncJobStore syncJobStore) - : IBtmsMediator - { - internal static readonly string ActivitySourceName = "Btms"; - internal static readonly ActivitySource ActivitySource = new(ActivitySourceName, "1.0"); - public const string ActivityName = "BtmsMediator.Queue.Background"; + internal static readonly string ActivitySourceName = "Btms"; + internal static readonly ActivitySource ActivitySource = new(ActivitySourceName, "1.0"); + public const string ActivityName = "BtmsMediator.Queue.Background"; - public async Task SendSyncJob(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest, ISyncJob - { - var job = syncJobStore.CreateJob(request.JobId, request.Timespan, request.Resource); + public async Task SendSyncJob(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest, ISyncJob + { + var job = syncJobStore.CreateJob(request.JobId, request.Timespan, request.Resource); - await backgroundTaskQueue.QueueBackgroundWorkItemAsync(async (ct) => - { - using var scope = serviceScopeFactory.CreateScope(); - using var activity = ActivitySource.StartActivity(ActivityName, ActivityKind.Client); - var m = scope.ServiceProvider.GetRequiredService(); - await m.Send(request, job.CancellationToken); - }); - } - - public async Task SendJob(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest, ISyncJob + await backgroundTaskQueue.QueueBackgroundWorkItemAsync(async (_) => { - var job = syncJobStore.CreateJob(request.JobId, request.Timespan, request.Resource); + using var scope = serviceScopeFactory.CreateScope(); + using var activity = ActivitySource.StartActivity(ActivityName, ActivityKind.Client); + var m = scope.ServiceProvider.GetRequiredService(); + await m.Send(request, job.CancellationToken); + }); + } - await backgroundTaskQueue.QueueBackgroundWorkItemAsync(async (ct) => - { - job.Start(); - using var scope = serviceScopeFactory.CreateScope(); - using var activity = ActivitySource.StartActivity(ActivityName, ActivityKind.Client); - var m = scope.ServiceProvider.GetRequiredService(); - await m.Send(request, job.CancellationToken); - job.Complete(); - }); - } + public async Task SendJob(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest, ISyncJob + { + var job = syncJobStore.CreateJob(request.JobId, request.Timespan, request.Resource); - Task IBtmsMediator.Send(IRequest request, CancellationToken cancellationToken) + await backgroundTaskQueue.QueueBackgroundWorkItemAsync(async (_) => { - return mediator.Send(request, cancellationToken); - } + job.Start(); + using var scope = serviceScopeFactory.CreateScope(); + using var activity = ActivitySource.StartActivity(ActivityName, ActivityKind.Client); + var m = scope.ServiceProvider.GetRequiredService(); + await m.Send(request, job.CancellationToken); + job.Complete(); + }); + } - public Task Send(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest - { - return mediator.Send(request, cancellationToken); - } + Task IBtmsMediator.Send(IRequest request, CancellationToken cancellationToken) + { + return mediator.Send(request, cancellationToken); + } + + public Task Send(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest + { + return mediator.Send(request, cancellationToken); } -} +} \ No newline at end of file diff --git a/Btms.Backend/Program.cs b/Btms.Backend/Program.cs index 28f6fa9..68b2c57 100644 --- a/Btms.Backend/Program.cs +++ b/Btms.Backend/Program.cs @@ -38,8 +38,6 @@ using Btms.Azure.Extensions; using Environment = System.Environment; -using OpenTelemetry.Extensions.Hosting; - //-------- Configure the WebApplication builder------------------// var app = CreateWebApplication(args); @@ -235,7 +233,7 @@ static WebApplication BuildWebApplication(WebApplicationBuilder builder) var dotnetHealthEndpoint = "/health-dotnet"; app.MapGet("/health", GetStatus).AllowAnonymous(); app.MapHealthChecks(dotnetHealthEndpoint, - new HealthCheckOptions() + new HealthCheckOptions { Predicate = _ => true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse diff --git a/Btms.Backend/Utils/Http/Proxy.cs b/Btms.Backend/Utils/Http/Proxy.cs index 25aca22..8879318 100644 --- a/Btms.Backend/Utils/Http/Proxy.cs +++ b/Btms.Backend/Utils/Http/Proxy.cs @@ -1,5 +1,4 @@ using System.Net; -using Serilog.Core; using System.Diagnostics.CodeAnalysis; using Btms.Backend.Config; using Microsoft.Extensions.Options; @@ -46,7 +45,7 @@ public static HttpClientHandler ConfigurePrimaryHttpMessageHandler(IServiceProvi return CreateHttpClientHandler(proxy, options.Value.CdpHttpsProxy!); } - public static HttpClientHandler CreateHttpClientHandler(IWebProxy proxy, string proxyUri) + public static HttpClientHandler CreateHttpClientHandler(IWebProxy proxy, string? proxyUri) { return new HttpClientHandler { Proxy = proxy, UseProxy = proxyUri != null }; } diff --git a/Btms.Backend/Utils/Logging/LogLevelMapper.cs b/Btms.Backend/Utils/Logging/LogLevelMapper.cs index 4327eab..74d4907 100644 --- a/Btms.Backend/Utils/Logging/LogLevelMapper.cs +++ b/Btms.Backend/Utils/Logging/LogLevelMapper.cs @@ -4,10 +4,10 @@ namespace Btms.Backend.Utils.Logging; -[ExcludeFromCodeCoverage] /** * Maps log levels from the C# default 'Information' etc to the node style 'info'. */ +[ExcludeFromCodeCoverage] public class LogLevelMapper : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) diff --git a/Btms.Backend/Utils/TrustStore.cs b/Btms.Backend/Utils/TrustStore.cs index be111c8..7f40c60 100644 --- a/Btms.Backend/Utils/TrustStore.cs +++ b/Btms.Backend/Utils/TrustStore.cs @@ -23,7 +23,7 @@ private static List GetCertificates(Logger logger) .Select(entry => { var data = Convert.FromBase64String(entry.Value!.ToString() ?? ""); - logger.Information($"{entry.Key} certificate decoded"); + logger.Information("{EntryKey} certificate decoded", entry.Key); return Encoding.UTF8.GetString(data); }).ToList(); } diff --git a/Btms.BlobService/BlobService.cs b/Btms.BlobService/BlobService.cs index d746639..0355fe3 100644 --- a/Btms.BlobService/BlobService.cs +++ b/Btms.BlobService/BlobService.cs @@ -1,10 +1,7 @@ -using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using Azure.Storage.Blobs; -using Azure.Storage.Blobs.Models; using Btms.Azure; using Microsoft.Extensions.Logging; -using System.IO; using System.Runtime.CompilerServices; using Microsoft.Extensions.Options; @@ -33,7 +30,7 @@ public async Task CheckBlobAsync(int timeout = default, int retries = de public async Task CheckBlobAsync(string uri, int timeout = default, int retries = default) { - Logger.LogInformation("Connecting to blob storage {Uri} : {BlobContainer}. timeout={Timeout}, retries={Retries}.", + Logger.LogInformation("Connecting to blob storage {Uri} : {BlobContainer}. timeout={Timeout}, retries={Retries}", uri, options.Value.DmpBlobContainer, timeout, retries); try @@ -44,13 +41,13 @@ public async Task CheckBlobAsync(string uri, int timeout = default, int var folders = containerClient.GetBlobsByHierarchyAsync(prefix: "RAW/", delimiter: "/"); var itemCount = 0; - await foreach (BlobHierarchyItem blobItem in folders) + await foreach (var blobItem in folders) { Logger.LogInformation("\t{Prefix}", blobItem.Prefix); itemCount++; } - return new Status() + return new Status { Success = true, Description = $"Connected. {itemCount} blob folders found in RAW" }; @@ -58,7 +55,7 @@ public async Task CheckBlobAsync(string uri, int timeout = default, int catch (Exception ex) { Logger.LogError(ex, "Error loading files"); - return new Status() { Success = false, Description = ex.Message }; + return new Status { Success = false, Description = ex.Message }; } } @@ -78,17 +75,17 @@ public async IAsyncEnumerable GetResourcesAsync(string prefix, [Enume var files = containerClient.GetBlobsAsync(prefix: prefix, cancellationToken: cancellationToken); - await foreach (BlobItem item in files) + await foreach (var item in files) { if (item.Properties.ContentLength is not 0) { yield return - new BtmsBlobItem() { Name = item.Name }; + new BtmsBlobItem { Name = item.Name }; itemCount++; } } - Logger.LogDebug("GetResourcesAsync {ItemCount} blobs found.", itemCount); + Logger.LogDebug("GetResourcesAsync {ItemCount} blobs found", itemCount); } public async Task GetResource(IBlobItem item, CancellationToken cancellationToken) diff --git a/Btms.BlobService/BlobServiceClientFactory.cs b/Btms.BlobService/BlobServiceClientFactory.cs index 7ce84d4..daca2f1 100644 --- a/Btms.BlobService/BlobServiceClientFactory.cs +++ b/Btms.BlobService/BlobServiceClientFactory.cs @@ -18,7 +18,7 @@ public BlobServiceClient CreateBlobServiceClient(int timeout = default, int retr timeout = timeout > 0 ? timeout : options.Value.Timeout; retries = retries > 0 ? retries : options.Value.Retries; - logger.LogInformation("CreateBlobServiceClient timeout={Timeout}, retries={Retries}.", timeout, retries); + logger.LogInformation("CreateBlobServiceClient timeout={Timeout}, retries={Retries}", timeout, retries); var bcOptions = new BlobClientOptions { diff --git a/Btms.BlobService/BlobServiceOptions.cs b/Btms.BlobService/BlobServiceOptions.cs index a7373f0..fd44351 100644 --- a/Btms.BlobService/BlobServiceOptions.cs +++ b/Btms.BlobService/BlobServiceOptions.cs @@ -1,6 +1,5 @@ using System.ComponentModel.DataAnnotations; using Btms.Azure; -using Btms.Common.Extensions; namespace Btms.BlobService; diff --git a/Btms.BlobService/BtmsBlobItem.cs b/Btms.BlobService/BtmsBlobItem.cs index cd0c66b..dff504c 100644 --- a/Btms.BlobService/BtmsBlobItem.cs +++ b/Btms.BlobService/BtmsBlobItem.cs @@ -1,5 +1,3 @@ -using Azure.Storage.Blobs; - namespace Btms.BlobService; public class BtmsBlobItem : IBlobItem diff --git a/Btms.BlobService/CachingBlobService.cs b/Btms.BlobService/CachingBlobService.cs index 5cd8add..9019aa6 100644 --- a/Btms.BlobService/CachingBlobService.cs +++ b/Btms.BlobService/CachingBlobService.cs @@ -1,5 +1,4 @@ using System.Runtime.CompilerServices; -using Azure.Storage.Blobs.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -29,16 +28,16 @@ public async IAsyncEnumerable GetResourcesAsync(string prefix, [Enume if (Directory.Exists(path)) { - logger.LogInformation("Folder {Path} exists, looking for files.", path); - foreach (string f in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + logger.LogInformation("Folder {Path} exists, looking for files", path); + foreach (var f in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) { var relativePath = Path.GetRelativePath($"{Directory.GetCurrentDirectory()}/{options.Value.CachePath}", f); logger.LogInformation("Found file {RelativePath}", relativePath); - yield return await Task.FromResult(new BtmsBlobItem() { Name = relativePath }); + yield return await Task.FromResult(new BtmsBlobItem { Name = relativePath }); } } else{ - logger.LogWarning("Cannot scan folder {Path} as it doesn't exist.", path); + logger.LogWarning("Cannot scan folder {Path} as it doesn't exist", path); } } @@ -56,7 +55,7 @@ public async Task CreateBlobsAsync(IBlobItem[] items) return true; } - private async Task CreateBlobAsync(IBlobItem item) + private async Task CreateBlobAsync(IBlobItem item) { var fullPath = Path.GetFullPath($"{options.Value.CachePath}/{item.Name}"); @@ -65,14 +64,12 @@ private async Task CreateBlobAsync(IBlobItem item) logger.LogInformation("Create file {FullPath}", fullPath); await File.WriteAllTextAsync(fullPath, item.Content); - - return true; } public Task CleanAsync(string prefix) { var fullPath = Path.GetFullPath($"{options.Value.CachePath}/{prefix}"); - logger.LogInformation("Clearing local storage {path}", fullPath); + logger.LogInformation("Clearing local storage {Path}", fullPath); try { diff --git a/Btms.BlobService/Extensions/ServiceCollectionExtensions.cs b/Btms.BlobService/Extensions/ServiceCollectionExtensions.cs index 915dc5b..328c8ae 100644 --- a/Btms.BlobService/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.BlobService/Extensions/ServiceCollectionExtensions.cs @@ -1,34 +1,32 @@ using Btms.Common.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -namespace Btms.BlobService.Extensions +namespace Btms.BlobService.Extensions; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddBlobStorage(this IServiceCollection services, + IConfiguration configuration) { - public static IServiceCollection AddBlobStorage(this IServiceCollection services, - IConfiguration configuration) - { - var config = configuration.GetSection(BlobServiceOptions.SectionName); + var config = configuration.GetSection(BlobServiceOptions.SectionName); - services.BtmsAddOptions(configuration, BlobServiceOptions.SectionName); + services.BtmsAddOptions(configuration, BlobServiceOptions.SectionName); - var blobOptions = config.Get()!; + var blobOptions = config.Get()!; - if (blobOptions.CacheReadEnabled || blobOptions.CacheWriteEnabled) - { - services.AddKeyedSingleton("base"); - services.AddSingleton(); - } - else - { - services.AddSingleton(); - } + if (blobOptions.CacheReadEnabled || blobOptions.CacheWriteEnabled) + { + services.AddKeyedSingleton("base"); + services.AddSingleton(); + } + else + { + services.AddSingleton(); + } - services.AddSingleton(); + services.AddSingleton(); - return services; - } + return services; } } \ No newline at end of file diff --git a/Btms.BlobService/IBlobItem.cs b/Btms.BlobService/IBlobItem.cs index 58d0e62..7ca10c3 100644 --- a/Btms.BlobService/IBlobItem.cs +++ b/Btms.BlobService/IBlobItem.cs @@ -1,5 +1,3 @@ -using Azure.Storage.Blobs; - namespace Btms.BlobService; public interface IBlobItem diff --git a/Btms.BlobService/Status.cs b/Btms.BlobService/Status.cs index 3985a65..9378079 100644 --- a/Btms.BlobService/Status.cs +++ b/Btms.BlobService/Status.cs @@ -1,13 +1,8 @@ -using System.IO; -using System.Net; -using Microsoft.Extensions.Logging; +namespace Btms.BlobService; -namespace Btms.BlobService +public class Status { - public class Status - { - public string Description { get; set; } = default!; + public string Description { get; set; } = default!; - public bool Success { get; set; } - } + public bool Success { get; set; } } \ No newline at end of file diff --git a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs index 85c2621..4c79019 100644 --- a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs @@ -5,8 +5,6 @@ using Btms.SensitiveData; using Btms.SyncJob; using Btms.Types.Alvs; -using Btms.Types.Ipaffs; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using NSubstitute; @@ -15,44 +13,43 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Business.Tests.Commands +namespace Btms.Business.Tests.Commands; + +public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) { - public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) + [Fact] + public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() { - [Fact] - public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() - { - var clearanceRequest = ClearanceRequestBuilder.Default().Build(); - var command = new SyncClearanceRequestsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); - - - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(clearanceRequest!.Header!.EntryReference!, clearanceRequest.ToJsonString()) - .ToAsyncEnumerator()); - - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(clearanceRequest.ToJsonString()); - - - var handler = new SyncClearanceRequestsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); - - await handler.Handle(command, CancellationToken.None); - - // ASSERT - await bus.Received(1).Publish(Arg.Any(), "ALVS", - Arg.Any>(), Arg.Any()); - } + var clearanceRequest = ClearanceRequestBuilder.Default().Build(); + var command = new SyncClearanceRequestsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); + + + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns( + new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()) + .ToAsyncEnumerator()); + + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(clearanceRequest.ToJsonString()); + + + var handler = new SyncClearanceRequestsCommand.Handler( + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); + + await handler.Handle(command, CancellationToken.None); + + // ASSERT + await bus.Received(1).Publish(Arg.Any(), "ALVS", + Arg.Any>(), Arg.Any()); } } \ No newline at end of file diff --git a/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs b/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs index 9fd9cc4..dcc7f0c 100644 --- a/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs @@ -5,7 +5,6 @@ using Btms.SensitiveData; using Btms.SyncJob; using Btms.Types.Alvs; -using Btms.Types.Ipaffs; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using NSubstitute; @@ -14,43 +13,42 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Business.Tests.Commands +namespace Btms.Business.Tests.Commands; + +public class SyncDecisionsCommandTests(ITestOutputHelper outputHelper) { - public class SyncDecisionsCommandTests(ITestOutputHelper outputHelper) + [Fact] + public async Task WhenDecisionBlobsExist_ThenTheyShouldBePlacedOnInternalBus() { - [Fact] - public async Task WhenDecisionBlobsExist_ThenTheyShouldBePlacedOnInternalBus() - { - var clearanceRequest = ClearanceRequestBuilder.Default().Build(); - var command = new SyncDecisionsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "Test Job"); - - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(clearanceRequest!.Header!.EntryReference!, clearanceRequest.ToJsonString()) - .ToAsyncEnumerator()); - - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(clearanceRequest.ToJsonString()); - - - var handler = new SyncDecisionsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); - - await handler.Handle(command, CancellationToken.None); - - // ASSERT - await bus.Received(1).Publish(Arg.Any(), "DECISIONS", - Arg.Any>(), Arg.Any()); - } + var clearanceRequest = ClearanceRequestBuilder.Default().Build(); + var command = new SyncDecisionsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "Test Job"); + + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns( + new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()) + .ToAsyncEnumerator()); + + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(clearanceRequest.ToJsonString()); + + + var handler = new SyncDecisionsCommand.Handler( + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); + + await handler.Handle(command, CancellationToken.None); + + // ASSERT + await bus.Received(1).Publish(Arg.Any(), "DECISIONS", + Arg.Any>(), Arg.Any()); } } \ No newline at end of file diff --git a/Btms.Business.Tests/Commands/SyncNotificationsCommandTests.cs b/Btms.Business.Tests/Commands/SyncNotificationsCommandTests.cs index 8d9ee7e..4289332 100644 --- a/Btms.Business.Tests/Commands/SyncNotificationsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncNotificationsCommandTests.cs @@ -13,57 +13,56 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Business.Tests.Commands +namespace Btms.Business.Tests.Commands; + +public class SyncNotificationsCommandTests(ITestOutputHelper outputHelper) { - public class SyncNotificationsCommandTests(ITestOutputHelper outputHelper) + [Fact] + public async Task WhenNotificationBlobsExist_ThenTheyShouldBePlacedOnInternalBus() { - [Fact] - public async Task WhenNotificationBlobsExist_ThenTheyShouldBePlacedOnInternalBus() - { - // ARRANGE - var notification = CreateImportNotification(); - var command = new SyncNotificationsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "Test Job"); + // ARRANGE + var notification = CreateImportNotification(); + var command = new SyncNotificationsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "Test Job"); - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(notification!.ReferenceNumber!, notification.ToJsonString()).ToAsyncEnumerator()); + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns( + new TestBlobItem(notification.ReferenceNumber!, notification.ToJsonString()).ToAsyncEnumerator()); - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(notification.ToJsonString()); + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(notification.ToJsonString()); - var handler = new SyncNotificationsCommand.Handler( + var handler = new SyncNotificationsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); - // ACT - await handler.Handle(command, CancellationToken.None); + // ACT + await handler.Handle(command, CancellationToken.None); - // ASSERT - await bus.Received(4).Publish(Arg.Any(), "NOTIFICATIONS", - Arg.Any>(), Arg.Any()); - } + // ASSERT + await bus.Received(4).Publish(Arg.Any(), "NOTIFICATIONS", + Arg.Any>(), Arg.Any()); + } - private static ImportNotification CreateImportNotification() - { - return ImportNotificationBuilder.Default() - .Do(x => + private static ImportNotification CreateImportNotification() + { + return ImportNotificationBuilder.Default() + .Do(x => + { + foreach (var parameterSet in x.PartOne!.Commodities!.ComplementParameterSets!) { - foreach (var parameterSet in x!.PartOne!.Commodities!.ComplementParameterSets!) - { - parameterSet.KeyDataPairs = null; - } - }).Build(); - } + parameterSet.KeyDataPairs = null; + } + }).Build(); } } \ No newline at end of file diff --git a/Btms.Business.Tests/Commands/TestBlobItem.cs b/Btms.Business.Tests/Commands/TestBlobItem.cs index 47c51b6..9fcffa9 100644 --- a/Btms.Business.Tests/Commands/TestBlobItem.cs +++ b/Btms.Business.Tests/Commands/TestBlobItem.cs @@ -4,7 +4,7 @@ namespace Btms.Business.Tests.Commands; public class TestBlobItem(string name, string content) : IBlobItem { - public string Name { get; set; } = name!; + public string Name { get; set; } = name; - public string Content { get; set; } = content!; + public string Content { get; set; } = content; } \ No newline at end of file diff --git a/Btms.Business.Tests/DummyMeterFactory.cs b/Btms.Business.Tests/DummyMeterFactory.cs index dbf2608..3219fa2 100644 --- a/Btms.Business.Tests/DummyMeterFactory.cs +++ b/Btms.Business.Tests/DummyMeterFactory.cs @@ -4,7 +4,7 @@ namespace Btms.Business.Tests; internal sealed class DummyMeterFactory : IMeterFactory { - public Meter Create(MeterOptions options) => new Meter(options); + public Meter Create(MeterOptions options) => new(options); public void Dispose() { diff --git a/Btms.Business.Tests/Pipelines/Matching/MatchPreProcessTests.cs b/Btms.Business.Tests/Pipelines/Matching/MatchPreProcessTests.cs index bcccc3c..5393cc6 100644 --- a/Btms.Business.Tests/Pipelines/Matching/MatchPreProcessTests.cs +++ b/Btms.Business.Tests/Pipelines/Matching/MatchPreProcessTests.cs @@ -11,7 +11,7 @@ public async Task Process_ValidRequest_RecordsPreProcessing() { // Arrange var sut = new MatchPreProcess(); - var request = new MatchRequest(new MatchContext() + var request = new MatchRequest(new MatchContext { MatchReference = "ABC123" }); diff --git a/Btms.Business.Tests/PreProcessing/MovementPreProcessingTests.cs b/Btms.Business.Tests/PreProcessing/MovementPreProcessingTests.cs index 0913e43..b4c3966 100644 --- a/Btms.Business.Tests/PreProcessing/MovementPreProcessingTests.cs +++ b/Btms.Business.Tests/PreProcessing/MovementPreProcessingTests.cs @@ -25,10 +25,10 @@ public async Task WhenNotificationNotExists_ThenShouldBeCreated() // ASSERT preProcessingResult.Outcome.Should().Be(PreProcessingOutcome.New); - var savedMovement = await dbContext.Movements.Find(clearanceRequest!.Header!.EntryReference!); + var savedMovement = await dbContext.Movements.Find(clearanceRequest.Header!.EntryReference!); savedMovement.Should().NotBeNull(); - savedMovement.AuditEntries.Count.Should().Be(1); - savedMovement.AuditEntries[0].Status.Should().Be("Created"); + savedMovement?.AuditEntries.Count.Should().Be(1); + savedMovement?.AuditEntries[0].Status.Should().Be("Created"); } private static AlvsClearanceRequest CreateAlvsClearanceRequest() diff --git a/Btms.Business.Tests/PreProcessing/NotificationsPreProcessingTests.cs b/Btms.Business.Tests/PreProcessing/NotificationsPreProcessingTests.cs index f20f265..a5d26f7 100644 --- a/Btms.Business.Tests/PreProcessing/NotificationsPreProcessingTests.cs +++ b/Btms.Business.Tests/PreProcessing/NotificationsPreProcessingTests.cs @@ -7,65 +7,64 @@ using TestDataGenerator; using Xunit; -namespace Btms.Business.Tests.PreProcessing +namespace Btms.Business.Tests.PreProcessing; + +public class NotificationsPreProcessingTests { - public class NotificationsPreProcessingTests + [Fact] + public async Task WhenNotificationNotExists_ThenShouldBeCreated() { - [Fact] - public async Task WhenNotificationNotExists_ThenShouldBeCreated() - { - // ARRANGE - var notification = CreateImportNotification(); - var dbContext = new MemoryMongoDbContext(); - var preProcessor = new ImportNotificationPreProcessor(dbContext, NullLogger.Instance); + // ARRANGE + var notification = CreateImportNotification(); + var dbContext = new MemoryMongoDbContext(); + var preProcessor = new ImportNotificationPreProcessor(dbContext, NullLogger.Instance); - // ACT - var preProcessingResult = await preProcessor.Process( - new PreProcessingContext(notification, "TestMessageId")); + // ACT + var preProcessingResult = await preProcessor.Process( + new PreProcessingContext(notification, "TestMessageId")); - // ASSERT - preProcessingResult.Outcome.Should().Be(PreProcessingOutcome.New); - var savedNotification = await dbContext.Notifications.Find(notification!.ReferenceNumber!); - savedNotification.Should().NotBeNull(); - savedNotification.AuditEntries.Count.Should().Be(1); - savedNotification.AuditEntries[0].Status.Should().Be("Created"); - } + // ASSERT + preProcessingResult.Outcome.Should().Be(PreProcessingOutcome.New); + var savedNotification = await dbContext.Notifications.Find(notification.ReferenceNumber!); + savedNotification.Should().NotBeNull(); + savedNotification?.AuditEntries.Count.Should().Be(1); + savedNotification?.AuditEntries[0].Status.Should().Be("Created"); + } - [Fact] - public async Task WhenNotificationExists_AndLastUpdatedIsNewer_ThenShouldBeUpdated() - { - // ARRANGE - var notification = CreateImportNotification(); - var dbContext = new MemoryMongoDbContext(); - await dbContext.Notifications.Insert(notification.MapWithTransform()); - notification.LastUpdated = notification.LastUpdated?.AddHours(1); - var preProcessor = new ImportNotificationPreProcessor(dbContext, NullLogger.Instance); + [Fact] + public async Task WhenNotificationExists_AndLastUpdatedIsNewer_ThenShouldBeUpdated() + { + // ARRANGE + var notification = CreateImportNotification(); + var dbContext = new MemoryMongoDbContext(); + await dbContext.Notifications.Insert(notification.MapWithTransform()); + notification.LastUpdated = notification.LastUpdated?.AddHours(1); + var preProcessor = new ImportNotificationPreProcessor(dbContext, NullLogger.Instance); - // ACT - var preProcessingResult = await preProcessor.Process( - new PreProcessingContext(notification, "TestMessageId")); + // ACT + var preProcessingResult = await preProcessor.Process( + new PreProcessingContext(notification, "TestMessageId")); - // ASSERT - preProcessingResult.Outcome.Should().Be(PreProcessingOutcome.Changed); - var savedNotification = await dbContext.Notifications.Find(notification!.ReferenceNumber!); - savedNotification.Should().NotBeNull(); - savedNotification.AuditEntries.Count.Should().Be(1); - savedNotification.AuditEntries[0].Status.Should().Be("Updated"); - } + // ASSERT + preProcessingResult.Outcome.Should().Be(PreProcessingOutcome.Changed); + var savedNotification = await dbContext.Notifications.Find(notification.ReferenceNumber!); + savedNotification.Should().NotBeNull(); + savedNotification?.AuditEntries.Count.Should().Be(1); + savedNotification?.AuditEntries[0].Status.Should().Be("Updated"); + } - private static ImportNotification CreateImportNotification() - { - return ImportNotificationBuilder.Default() - .WithReferenceNumber(ImportNotificationTypeEnum.Chedpp, 1, DateTime.UtcNow, 1) - .WithRandomCommodities(1, 2) - .Do(x => + private static ImportNotification CreateImportNotification() + { + return ImportNotificationBuilder.Default() + .WithReferenceNumber(ImportNotificationTypeEnum.Chedpp, 1, DateTime.UtcNow, 1) + .WithRandomCommodities(1, 2) + .Do(x => + { + foreach (var parameterSet in x.PartOne?.Commodities?.ComplementParameterSets!) { - foreach (var parameterSet in x.PartOne?.Commodities?.ComplementParameterSets!) - { - parameterSet.KeyDataPairs = null; - } - }).Build(); - } + parameterSet.KeyDataPairs = null; + } + }).Build(); } } \ No newline at end of file diff --git a/Btms.Business.Tests/Services/LinkingServiceTests.cs b/Btms.Business.Tests/Services/LinkingServiceTests.cs index ace93c7..ccd934d 100644 --- a/Btms.Business.Tests/Services/LinkingServiceTests.cs +++ b/Btms.Business.Tests/Services/LinkingServiceTests.cs @@ -16,7 +16,7 @@ namespace Btms.Business.Tests.Services; public class LinkingServiceTests { - private static readonly Random random = new (); + private static readonly Random Random = new (); private readonly IMongoDbContext dbContext = new MemoryMongoDbContext(); private readonly LinkingMetrics linkingMetrics = new(new DummyMeterFactory()); private static string GenerateDocumentReference(int id) => $"GBCVD2024.{id}"; @@ -287,28 +287,30 @@ private MovementLinkContext CreateMovementContext(Movement? movement, List x != null ? x._MatchReference : $"{GenerateRandomReference()}") .Select(y => int.Parse(y)).ToList(); - var mov = new Movement() + var mov = new Movement { Id = entryReference, EntryReference = entryReference, _Etag = etag, - Items = chedReferences.Select(x => new Items() + Items = chedReferences.Select(x => new Items { Documents = [ new Document { DocumentReference = GenerateDocumentReference(x) } ] - }).ToList() + }).ToList(), + ClearanceRequests = [] }; var existingMovement = createExistingMovement ? - new Movement() + new Movement { Id = entryReference, EntryReference = entryReference, - Items = chedReferences.Select(x => new Items() + Items = chedReferences.Select(x => new Items { Documents = fieldsOfInterest ? [] : [ new Document { DocumentReference = GenerateDocumentReference(x) } ] - }).ToList() + }).ToList(), + ClearanceRequests = [] } : null; var changeSet = mov.GenerateChangeSet(existingMovement); @@ -320,7 +322,7 @@ private MovementLinkContext CreateMovementContext(Movement? movement, List GenerateRandomReference()).ToList(); - for (int i = 0; i < chedCount; i++) + for (var i = 0; i < chedCount; i++) { var matchingRef = GenerateRandomReference(); - var ched = new ImportNotification() + var ched = new ImportNotification { Updated = DateTime.UtcNow.AddHours(-1), ReferenceNumber = GenerateNotificationReference(matchingRef), @@ -381,10 +383,10 @@ private ImportNotificationLinkContext CreateNotificationContext(int chedReferenc await dbContext.Notifications.Insert(ched); } - for (int i = 0; i < movementCount; i++) + for (var i = 0; i < movementCount; i++) { var entryRef = $"TESTREF{GenerateRandomReference()}"; - var mov = new Movement() + var mov = new Movement { Id = entryRef, EntryReference = entryRef, @@ -400,17 +402,17 @@ private ImportNotificationLinkContext CreateNotificationContext(int chedReferenc movements.Add(mov); - for (int j = 0; j < matchedChedsPerMovement; j++) + for (var j = 0; j < matchedChedsPerMovement; j++) { var matchRef = cheds[j]._MatchReference; var refNo = int.Parse(matchRef); mov.Items.Add( - new Items() + new Items { Documents = [ - new Document() { DocumentReference = GenerateDocumentReference(refNo) } + new Document { DocumentReference = GenerateDocumentReference(refNo) } ] }); } @@ -418,11 +420,11 @@ private ImportNotificationLinkContext CreateNotificationContext(int chedReferenc foreach (var refNo in unmatchedChedRefs) { mov.Items.Add( - new Items() + new Items { Documents = [ - new Document() { DocumentReference = GenerateDocumentReference(refNo) } + new Document { DocumentReference = GenerateDocumentReference(refNo) } ] }); } @@ -435,11 +437,11 @@ private ImportNotificationLinkContext CreateNotificationContext(int chedReferenc private static int GenerateRandomReference() { - string intString = "1"; + var intString = "1"; - for (int i = 0; i < 6; i++) + for (var i = 0; i < 6; i++) { - intString += random.Next(9).ToString(); + intString += Random.Next(9).ToString(); } return int.Parse(intString); diff --git a/Btms.Business/BusinessOptions.cs b/Btms.Business/BusinessOptions.cs index a62a3bd..5f57e62 100644 --- a/Btms.Business/BusinessOptions.cs +++ b/Btms.Business/BusinessOptions.cs @@ -1,5 +1,4 @@ using System.ComponentModel.DataAnnotations; -using Btms.Azure; namespace Btms.Business; diff --git a/Btms.Business/Commands/DownloadNotificationsCommand.cs b/Btms.Business/Commands/DownloadNotificationsCommand.cs index 78f14e3..be1ac52 100644 --- a/Btms.Business/Commands/DownloadNotificationsCommand.cs +++ b/Btms.Business/Commands/DownloadNotificationsCommand.cs @@ -1,17 +1,9 @@ -using System.Dynamic; -using System.IO; using System.IO.Compression; using System.Text.Json.Serialization; -using Bogus; using Btms.BlobService; -using System.Threading; using MediatR; -using Newtonsoft.Json; -using JsonSerializer = System.Text.Json.JsonSerializer; -using SharpCompress.Writers; using Btms.SensitiveData; using Btms.Types.Ipaffs; -using Microsoft.AspNetCore.Hosting; using Btms.SyncJob; using Btms.Types.Alvs; using Btms.Types.Gvms; @@ -21,7 +13,7 @@ namespace Btms.Business.Commands; public class DownloadCommand : IRequest, ISyncJob { - [System.Text.Json.Serialization.JsonConverter(typeof(JsonStringEnumConverter))] + [JsonConverter(typeof(JsonStringEnumConverter))] public SyncPeriod SyncPeriod { get; set; } public Guid JobId { get; } = Guid.NewGuid(); @@ -33,8 +25,8 @@ internal class Handler(IBlobService blobService, ISensitiveDataSerializer sensit public async Task Handle(DownloadCommand request, CancellationToken cancellationToken) { - string subFolder = $"temp\\{request.JobId}"; - string rootFolder = Path.Combine(env.ContentRootPath, subFolder); + var subFolder = $"temp\\{request.JobId}"; + var rootFolder = Path.Combine(env.ContentRootPath, subFolder); Directory.CreateDirectory(rootFolder); await Download(request, rootFolder, "RAW/IPAFFS/CHEDA", typeof(ImportNotification), cancellationToken); @@ -60,12 +52,12 @@ private async Task Download(DownloadCommand request, string rootFolder, string f var result = blobService.GetResourcesAsync($"{folder}{request.SyncPeriod.GetPeriodPath()}", cancellationToken); //Write local files - await Parallel.ForEachAsync(result, options, async (item, token) => + await Parallel.ForEachAsync(result, options, async (item, _) => { var blobContent = await blobService.GetResource(item, cancellationToken); - string redactedContent = sensitiveDataSerializer.RedactRawJson(blobContent, type); - var filename = System.IO.Path.Combine(rootFolder, item.Name.Replace('/', System.IO.Path.DirectorySeparatorChar)); - Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filename)!); + var redactedContent = sensitiveDataSerializer.RedactRawJson(blobContent, type); + var filename = Path.Combine(rootFolder, item.Name.Replace('/', Path.DirectorySeparatorChar)); + Directory.CreateDirectory(Path.GetDirectoryName(filename)!); await File.WriteAllTextAsync(filename, redactedContent, cancellationToken); }); } diff --git a/Btms.Business/Commands/SyncClearanceRequestsCommand.cs b/Btms.Business/Commands/SyncClearanceRequestsCommand.cs index f84431c..0d59a93 100644 --- a/Btms.Business/Commands/SyncClearanceRequestsCommand.cs +++ b/Btms.Business/Commands/SyncClearanceRequestsCommand.cs @@ -19,7 +19,7 @@ internal class Handler( IBlobService blobService, IOptions businessOptions, ISyncJobStore syncJobStore) - : SyncCommand.Handler(syncMetrics, bus, logger, sensitiveDataSerializer, + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) { public override async Task Handle(SyncClearanceRequestsCommand request, CancellationToken cancellationToken) diff --git a/Btms.Business/Commands/SyncDecisionsCommand.cs b/Btms.Business/Commands/SyncDecisionsCommand.cs index a549a9f..ace4dc0 100644 --- a/Btms.Business/Commands/SyncDecisionsCommand.cs +++ b/Btms.Business/Commands/SyncDecisionsCommand.cs @@ -19,7 +19,7 @@ internal class Handler( IBlobService blobService, IOptions businessOptions, ISyncJobStore syncJobStore) - : SyncCommand.Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) { public override async Task Handle(SyncDecisionsCommand request, CancellationToken cancellationToken) { diff --git a/Btms.Business/Commands/SyncGmrsCommand.cs b/Btms.Business/Commands/SyncGmrsCommand.cs index d2fc0e6..02c9fa3 100644 --- a/Btms.Business/Commands/SyncGmrsCommand.cs +++ b/Btms.Business/Commands/SyncGmrsCommand.cs @@ -19,7 +19,7 @@ internal class Handler( IBlobService blobService, IOptions businessOptions, ISyncJobStore syncJobStore) - : SyncCommand.Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) { public override async Task Handle(SyncGmrsCommand request, CancellationToken cancellationToken) { diff --git a/Btms.Business/Commands/SyncHandler.cs b/Btms.Business/Commands/SyncHandler.cs index b5260e8..e71d2e9 100644 --- a/Btms.Business/Commands/SyncHandler.cs +++ b/Btms.Business/Commands/SyncHandler.cs @@ -33,7 +33,7 @@ internal static partial class SyncHandlerLogging internal static partial void BlobFailed(this ILogger logger, Exception exception, string jobId, string blobPath); } -public abstract class SyncCommand() : IRequest, ISyncJob +public abstract class SyncCommand : IRequest, ISyncJob { [JsonConverter(typeof(JsonStringEnumConverter))] public SyncPeriod SyncPeriod { get; set; } @@ -43,7 +43,7 @@ public abstract class SyncCommand() : IRequest, ISyncJob public Guid JobId { get; set; } = Guid.NewGuid(); public string Timespan => SyncPeriod.ToString(); public abstract string Resource { get; } - public string Description => $"{GetType().Name} for {this.SyncPeriod}"; + public string Description => $"{GetType().Name} for {SyncPeriod}"; internal abstract class Handler( SyncMetrics syncMetrics, @@ -78,8 +78,8 @@ protected async Task SyncBlobPaths(SyncPeriod period, string topic, Gu try { await Parallel.ForEachAsync(paths, - new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism }, - async (path, token) => + new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, + async (path, _) => { using (logger.BeginScope(new List> { new("SyncPath", path), })) { @@ -105,7 +105,7 @@ protected async Task SyncBlobPath(string path, SyncPeriod period, stri { var result = blobService.GetResourcesAsync($"{path}{period.GetPeriodPath()}", cancellationToken); - await Parallel.ForEachAsync(result, new ParallelOptions() { CancellationToken = cancellationToken, MaxDegreeOfParallelism = maxDegreeOfParallelism }, async (item, token) => + await Parallel.ForEachAsync(result, new ParallelOptions { CancellationToken = cancellationToken, MaxDegreeOfParallelism = maxDegreeOfParallelism }, async (item, _) => { await SyncBlob(path, topic, item, job, cancellationToken); }); @@ -123,7 +123,7 @@ protected async Task SyncBlobs(SyncPeriod period, string topic, Guid j { if (job?.Status != SyncJobStatus.Cancelled) { - await SyncBlob(path, topic, new BtmsBlobItem() { Name = path }, job!, cancellationToken); + await SyncBlob(path, topic, new BtmsBlobItem { Name = path }, job!, cancellationToken); } } @@ -149,11 +149,11 @@ private async Task SyncBlob(string path, string topic, IBlobItem item, logger.BlobStarted(job.JobId.ToString(), item.Name); syncMetrics.SyncStarted(path, topic); using (var activity = BtmsDiagnostics.ActivitySource.StartActivity(name: ActivityName, - kind: ActivityKind.Client, tags: new TagList() { { "blob.name", item.Name } })) + kind: ActivityKind.Client, tags: new TagList { { "blob.name", item.Name } })) { var blobContent = await blobService.GetResource(item, cancellationToken); var message = sensitiveDataSerializer.Deserialize(blobContent, _ => { })!; - var headers = new Dictionary() + var headers = new Dictionary { { "messageId", item.Name.TrimStart(path.ToCharArray()) }, { "jobId", job.JobId } }; diff --git a/Btms.Business/Commands/SyncNotificationsCommand.cs b/Btms.Business/Commands/SyncNotificationsCommand.cs index 5f2ef1f..5c6c920 100644 --- a/Btms.Business/Commands/SyncNotificationsCommand.cs +++ b/Btms.Business/Commands/SyncNotificationsCommand.cs @@ -1,4 +1,3 @@ -using Azure.Core; using Btms.BlobService; using Btms.Metrics; using Btms.SensitiveData; @@ -8,61 +7,60 @@ using Microsoft.Extensions.Options; using SlimMessageBus; -namespace Btms.Business.Commands +namespace Btms.Business.Commands; + +public class SyncNotificationsCommand : SyncCommand { - public class SyncNotificationsCommand : SyncCommand - { - public string[] ChedTypes { get; set; } = []; - public override string Resource => "ImportNotification"; + public string[] ChedTypes { get; set; } = []; + public override string Resource => "ImportNotification"; - public string[] BlobFiles { get; set; } = []; + public string[] BlobFiles { get; set; } = []; - internal class Handler( - SyncMetrics syncMetrics, - IPublishBus bus, - ILogger logger, - ISensitiveDataSerializer sensitiveDataSerializer, - IBlobService blobService, - IOptions businessOptions, - ISyncJobStore syncJobStore) - : SyncCommand.Handler(syncMetrics, bus, logger, sensitiveDataSerializer, - blobService, syncJobStore) + internal class Handler( + SyncMetrics syncMetrics, + IPublishBus bus, + ILogger logger, + ISensitiveDataSerializer sensitiveDataSerializer, + IBlobService blobService, + IOptions businessOptions, + ISyncJobStore syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, + blobService, syncJobStore) + { + public override async Task Handle(SyncNotificationsCommand request, CancellationToken cancellationToken) { - public override async Task Handle(SyncNotificationsCommand request, CancellationToken cancellationToken) - { - var rootFolder = string.IsNullOrEmpty(request.RootFolder) - ? businessOptions.Value.DmpBlobRootFolder - : request.RootFolder; - - if (request.BlobFiles.Any()) - { - await SyncBlobs(request.SyncPeriod, "NOTIFICATIONS", - request.JobId, - cancellationToken, - request.BlobFiles.Select(x => $"{rootFolder}/IPAFFS/{x}").ToArray()); - return; - } - - var chedTypesToSync = new List(); - - AddIf(chedTypesToSync, request, rootFolder, "CHEDA"); - AddIf(chedTypesToSync, request, rootFolder, "CHEDD"); - AddIf(chedTypesToSync, request, rootFolder, "CHEDP"); - AddIf(chedTypesToSync, request, rootFolder, "CHEDPP"); + var rootFolder = string.IsNullOrEmpty(request.RootFolder) + ? businessOptions.Value.DmpBlobRootFolder + : request.RootFolder; - await SyncBlobPaths(request.SyncPeriod, "NOTIFICATIONS", + if (request.BlobFiles.Any()) + { + await SyncBlobs(request.SyncPeriod, "NOTIFICATIONS", request.JobId, cancellationToken, - chedTypesToSync.ToArray()); + request.BlobFiles.Select(x => $"{rootFolder}/IPAFFS/{x}").ToArray()); + return; } - private static void AddIf(List chedTypesToSync, SyncNotificationsCommand request, string rootFolder, string chedType) + var chedTypesToSync = new List(); + + AddIf(chedTypesToSync, request, rootFolder, "CHEDA"); + AddIf(chedTypesToSync, request, rootFolder, "CHEDD"); + AddIf(chedTypesToSync, request, rootFolder, "CHEDP"); + AddIf(chedTypesToSync, request, rootFolder, "CHEDPP"); + + await SyncBlobPaths(request.SyncPeriod, "NOTIFICATIONS", + request.JobId, + cancellationToken, + chedTypesToSync.ToArray()); + } + + private static void AddIf(List chedTypesToSync, SyncNotificationsCommand request, string rootFolder, string chedType) + { + if (!request.ChedTypes.Any() || request.ChedTypes.Contains(chedType)) { - if (!request.ChedTypes.Any() || request.ChedTypes.Contains(chedType)) - { - chedTypesToSync.Add($"{rootFolder}/IPAFFS/{chedType}"); - } + chedTypesToSync.Add($"{rootFolder}/IPAFFS/{chedType}"); } } } diff --git a/Btms.Business/Extensions/ServiceCollectionExtensions.cs b/Btms.Business/Extensions/ServiceCollectionExtensions.cs index f68acb7..33a3cd5 100644 --- a/Btms.Business/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Business/Extensions/ServiceCollectionExtensions.cs @@ -16,56 +16,55 @@ using Btms.Business.Pipelines.PreProcessing; using Btms.Types.Alvs; -namespace Btms.Business.Extensions +namespace Btms.Business.Extensions; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddBusinessServices(this IServiceCollection services, + IConfiguration configuration) { - public static IServiceCollection AddBusinessServices(this IServiceCollection services, - IConfiguration configuration) - { - services.AddBtmsMetrics(); - services.BtmsAddOptions(configuration, SensitiveDataOptions.SectionName); - services.BtmsAddOptions(configuration, BusinessOptions.SectionName); + services.AddBtmsMetrics(); + services.BtmsAddOptions(configuration, SensitiveDataOptions.SectionName); + services.BtmsAddOptions(configuration, BusinessOptions.SectionName); - services.AddMongoDbContext(configuration); - services.AddBlobStorage(configuration); - services.AddSingleton(); - services.AddSingleton(); + services.AddMongoDbContext(configuration); + services.AddBlobStorage(configuration); + services.AddSingleton(); + services.AddSingleton(); - services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); - // hard code list for now, get via config -> reflection later - List rules = new List - { - typeof(Level1Rule8), - typeof(Level1Rule4), - typeof(Level1Rule2), - typeof(Level1Rule1), - typeof(Level1RuleZ) - }; + // hard code list for now, get via config -> reflection later + List rules = + [ + typeof(Level1Rule8), + typeof(Level1Rule4), + typeof(Level1Rule2), + typeof(Level1Rule1), + typeof(Level1RuleZ) + ]; - // Add matching pipelines - services.AddMediatR(cfg => - { - cfg.RegisterServicesFromAssembly(typeof(PipelineResult).Assembly); - cfg.AddRequestPreProcessor(); - cfg.AddRequestPostProcessor(); + // Add matching pipelines + services.AddMediatR(cfg => + { + cfg.RegisterServicesFromAssembly(typeof(PipelineResult).Assembly); + cfg.AddRequestPreProcessor(); + cfg.AddRequestPostProcessor(); - foreach (var rule in rules) - { + foreach (var rule in rules) + { - cfg.AddBehavior(typeof(IPipelineBehavior), rule); - } + cfg.AddBehavior(typeof(IPipelineBehavior), rule); + } - cfg.AddBehavior, MatchTerminatePipeline>(); - }); + cfg.AddBehavior, MatchTerminatePipeline>(); + }); - services.AddScoped(); + services.AddScoped(); - services.AddScoped, ImportNotificationPreProcessor>(); - services.AddScoped, MovementPreProcessor>(); + services.AddScoped, ImportNotificationPreProcessor>(); + services.AddScoped, MovementPreProcessor>(); - return services; - } + return services; } } \ No newline at end of file diff --git a/Btms.Business/Pipelines/PreProcessing/ImportNotificationPreProcessor.cs b/Btms.Business/Pipelines/PreProcessing/ImportNotificationPreProcessor.cs index 54b1c5e..5d0270d 100644 --- a/Btms.Business/Pipelines/PreProcessing/ImportNotificationPreProcessor.cs +++ b/Btms.Business/Pipelines/PreProcessing/ImportNotificationPreProcessor.cs @@ -12,8 +12,7 @@ public class ImportNotificationPreProcessor(IMongoDbContext dbContext, ILogger> Process(PreProcessingContext preProcessingContext) { var internalNotification = preProcessingContext.Message.MapWithTransform(); - var existingNotification = - await dbContext.Notifications.Find(preProcessingContext.Message.ReferenceNumber!); + var existingNotification = await dbContext.Notifications.Find(preProcessingContext.Message.ReferenceNumber!); if (existingNotification is null) { @@ -43,7 +42,7 @@ public class ImportNotificationPreProcessor(IMongoDbContext dbContext, ILogger logger) : IPreProcessor +public class MovementPreProcessor(IMongoDbContext dbContext, ILogger logger) : IPreProcessor { - public async Task> Process(PreProcessingContext preProcessingContext) + public async Task> Process(PreProcessingContext preProcessingContext) { var internalClearanceRequest = AlvsClearanceRequestMapper.Map(preProcessingContext.Message); @@ -19,18 +19,19 @@ public class MovementPreProcessor(IMongoDbContext dbContext, ILogger - existingMovement.ClearanceRequests[0].Header?.EntryVersionNumber) + if (movement.ClearanceRequests[^1].Header?.EntryVersionNumber > existingMovement.ClearanceRequests[0].Header?.EntryVersionNumber) { var changeSet = movement.ClearanceRequests[^1].GenerateChangeSet(existingMovement.ClearanceRequests[0]); @@ -45,10 +46,6 @@ public class MovementPreProcessor(IMongoDbContext dbContext, ILogger Link(LinkContext linkContext, CancellationToken ca { foreach (var movement in result.Movements) { - notification.AddRelationship(new TdmRelationshipObject() + notification.AddRelationship(new TdmRelationshipObject { Links = RelationshipLinks.CreateForNotification(notification), Data = @@ -99,7 +97,7 @@ public async Task Link(LinkContext linkContext, CancellationToken ca ] }); - movement.AddRelationship(new TdmRelationshipObject() + movement.AddRelationship(new TdmRelationshipObject { Links = RelationshipLinks.CreateForMovement(movement), Data = diff --git a/Btms.Common/Extensions/GeneralExtensions.cs b/Btms.Common/Extensions/GeneralExtensions.cs index 07430ad..cb1d839 100644 --- a/Btms.Common/Extensions/GeneralExtensions.cs +++ b/Btms.Common/Extensions/GeneralExtensions.cs @@ -12,7 +12,7 @@ public static string ToJson(this object obj) public static bool HasValue(this T? val) { - return !object.Equals(val, default(T)); + return !Equals(val, default(T)); } public static void AssertHasValue(this T? val, string message = "Missing value") diff --git a/Btms.Common/Extensions/OptionsExtensions.cs b/Btms.Common/Extensions/OptionsExtensions.cs index 7904d40..944089a 100644 --- a/Btms.Common/Extensions/OptionsExtensions.cs +++ b/Btms.Common/Extensions/OptionsExtensions.cs @@ -1,6 +1,3 @@ - -using System.ComponentModel.DataAnnotations; -using System.Reflection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Microsoft.Extensions.DependencyInjection; @@ -14,15 +11,6 @@ public interface IValidatingOptions public static class OptionsExtensions { - - private static OptionsBuilder BtmsValidation(this OptionsBuilder options) where TOptions : class, IValidatingOptions - { - return options - .ValidateDataAnnotations() - .Validate(o => o.Validate()) - .ValidateOnStart(); - } - public static OptionsBuilder BtmsAddOptions(this IServiceCollection services, IConfiguration configuration, string section) where TOptions : class where TValidator : class, IValidateOptions diff --git a/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs b/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs index 6320736..3dcf1b5 100644 --- a/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs +++ b/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs @@ -12,92 +12,91 @@ using TestDataGenerator; using Xunit; -namespace Btms.Consumers.Tests +namespace Btms.Consumers.Tests; + +public class ClearanceRequestConsumerTests { - public class ClearanceRequestConsumerTests + [Theory] + [InlineData(PreProcessingOutcome.New)] + [InlineData(PreProcessingOutcome.Skipped)] + [InlineData(PreProcessingOutcome.Changed)] + [InlineData(PreProcessingOutcome.AlreadyProcessed)] + public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsLinked_ThenLinkShouldNotBeRun(PreProcessingOutcome outcome) { - [Theory] - [InlineData(PreProcessingOutcome.New)] - [InlineData(PreProcessingOutcome.Skipped)] - [InlineData(PreProcessingOutcome.Changed)] - [InlineData(PreProcessingOutcome.AlreadyProcessed)] - public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsLinked_ThenLinkShouldNotBeRun(PreProcessingOutcome outcome) - { - // ARRANGE - var clearanceRequest = CreateAlvsClearanceRequest(); - var movement = - MovementPreProcessor.BuildMovement(AlvsClearanceRequestMapper.Map(clearanceRequest)); + // ARRANGE + var clearanceRequest = CreateAlvsClearanceRequest(); + var movement = + MovementPreProcessor.BuildMovement(AlvsClearanceRequestMapper.Map(clearanceRequest)); - movement.Update(AuditEntry.CreateLinked("Test", 1, DateTime.Now)); + movement.Update(AuditEntry.CreateLinked("Test", 1, DateTime.Now)); - var mockLinkingService = Substitute.For(); - var preProcessor = Substitute.For>(); + var mockLinkingService = Substitute.For(); + var preProcessor = Substitute.For>(); - preProcessor.Process(Arg.Any>()) - .Returns(Task.FromResult(new PreProcessingResult(outcome, movement, null))); + preProcessor.Process(Arg.Any>()) + .Returns(Task.FromResult(new PreProcessingResult(outcome, movement, null))); - var consumer = - new AlvsClearanceRequestConsumer(preProcessor, mockLinkingService, NullLogger.Instance); - consumer.Context = new ConsumerContext() + var consumer = + new AlvsClearanceRequestConsumer(preProcessor, mockLinkingService, NullLogger.Instance); + consumer.Context = new ConsumerContext + { + Headers = new Dictionary { - Headers = new Dictionary() - { - { "messageId", clearanceRequest!.Header!.EntryReference! } - } - }; + { "messageId", clearanceRequest.Header!.EntryReference! } + } + }; - // ACT - await consumer.OnHandle(clearanceRequest); + // ACT + await consumer.OnHandle(clearanceRequest); - // ASSERT - consumer.Context.IsLinked().Should().BeFalse(); + // ASSERT + consumer.Context.IsLinked().Should().BeFalse(); - await mockLinkingService.DidNotReceive().Link(Arg.Any(), Arg.Any()); - } + await mockLinkingService.DidNotReceive().Link(Arg.Any(), Arg.Any()); + } - [Fact] - public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsCreated_ThenLinkShouldBeRun() - { - // ARRANGE - var clearanceRequest = CreateAlvsClearanceRequest(); - var movement = - MovementPreProcessor.BuildMovement(AlvsClearanceRequestMapper.Map(clearanceRequest)); + [Fact] + public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsCreated_ThenLinkShouldBeRun() + { + // ARRANGE + var clearanceRequest = CreateAlvsClearanceRequest(); + var movement = + MovementPreProcessor.BuildMovement(AlvsClearanceRequestMapper.Map(clearanceRequest)); - movement.Update(AuditEntry.CreateCreatedEntry(movement,"Test", 1, DateTime.Now)); + movement.Update(AuditEntry.CreateCreatedEntry(movement,"Test", 1, DateTime.Now)); - var mockLinkingService = Substitute.For(); - var preProcessor = Substitute.For>(); + var mockLinkingService = Substitute.For(); + var preProcessor = Substitute.For>(); - mockLinkingService.Link(Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(new LinkResult(LinkOutcome.Linked))); + mockLinkingService.Link(Arg.Any(), Arg.Any()) + .Returns(Task.FromResult(new LinkResult(LinkOutcome.Linked))); - preProcessor.Process(Arg.Any>()) - .Returns(Task.FromResult(new PreProcessingResult(PreProcessingOutcome.New, movement, null))); + preProcessor.Process(Arg.Any>()) + .Returns(Task.FromResult(new PreProcessingResult(PreProcessingOutcome.New, movement, null))); - var consumer = - new AlvsClearanceRequestConsumer(preProcessor, mockLinkingService, NullLogger.Instance); - consumer.Context = new ConsumerContext() + var consumer = + new AlvsClearanceRequestConsumer(preProcessor, mockLinkingService, NullLogger.Instance); + consumer.Context = new ConsumerContext + { + Headers = new Dictionary { - Headers = new Dictionary() - { - { "messageId", clearanceRequest!.Header!.EntryReference! } - } - }; + { "messageId", clearanceRequest.Header!.EntryReference! } + } + }; - // ACT - await consumer.OnHandle(clearanceRequest); + // ACT + await consumer.OnHandle(clearanceRequest); - // ASSERT - consumer.Context.IsPreProcessed().Should().BeTrue(); - consumer.Context.IsLinked().Should().BeTrue(); + // ASSERT + consumer.Context.IsPreProcessed().Should().BeTrue(); + consumer.Context.IsLinked().Should().BeTrue(); - await mockLinkingService.Received().Link(Arg.Any(), Arg.Any()); - } + await mockLinkingService.Received().Link(Arg.Any(), Arg.Any()); + } - private static AlvsClearanceRequest CreateAlvsClearanceRequest() - { - return ClearanceRequestBuilder.Default() - .WithValidDocumentReferenceNumbers().Build(); - } + private static AlvsClearanceRequest CreateAlvsClearanceRequest() + { + return ClearanceRequestBuilder.Default() + .WithValidDocumentReferenceNumbers().Build(); } } \ No newline at end of file diff --git a/Btms.Consumers.Tests/DummyMeterFactory.cs b/Btms.Consumers.Tests/DummyMeterFactory.cs index 8c6116c..f38984a 100644 --- a/Btms.Consumers.Tests/DummyMeterFactory.cs +++ b/Btms.Consumers.Tests/DummyMeterFactory.cs @@ -4,7 +4,7 @@ namespace Btms.Consumers.Tests; internal sealed class DummyMeterFactory : IMeterFactory { - public Meter Create(MeterOptions options) => new Meter(options); + public Meter Create(MeterOptions options) => new(options); public void Dispose() { diff --git a/Btms.Consumers.Tests/NotificationsConsumerTests.cs b/Btms.Consumers.Tests/NotificationsConsumerTests.cs index 2dd4419..a8921de 100644 --- a/Btms.Consumers.Tests/NotificationsConsumerTests.cs +++ b/Btms.Consumers.Tests/NotificationsConsumerTests.cs @@ -1,6 +1,5 @@ using Btms.Business.Pipelines.PreProcessing; using Btms.Business.Services; -using Btms.Consumers; using Btms.Consumers.Extensions; using Btms.Model.Auditing; using Btms.Types.Ipaffs; @@ -12,87 +11,86 @@ using TestDataGenerator; using Xunit; -namespace Btms.Consumers.Tests +namespace Btms.Consumers.Tests; + +public class NotificationsConsumerTests : ConsumerTests { - public class NotificationsConsumerTests : ConsumerTests + [Theory] + [InlineData(PreProcessingOutcome.New)] + [InlineData(PreProcessingOutcome.Skipped)] + [InlineData(PreProcessingOutcome.Changed)] + [InlineData(PreProcessingOutcome.AlreadyProcessed)] + public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsLinked_ThenLinkShouldNotBeRun(PreProcessingOutcome outcome) { - [Theory] - [InlineData(PreProcessingOutcome.New)] - [InlineData(PreProcessingOutcome.Skipped)] - [InlineData(PreProcessingOutcome.Changed)] - [InlineData(PreProcessingOutcome.AlreadyProcessed)] - public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsLinked_ThenLinkShouldNotBeRun(PreProcessingOutcome outcome) + // ARRANGE + var notification = CreateImportNotification(); + var modelNotification = notification.MapWithTransform(); + modelNotification.Changed(AuditEntry.CreateLinked("Test", 1, DateTime.Now)); + var mockLinkingService = Substitute.For(); + var preProcessor = Substitute.For>(); + + preProcessor.Process(Arg.Any>()) + .Returns(Task.FromResult(new PreProcessingResult(outcome, modelNotification, null))); + + var consumer = new NotificationConsumer(preProcessor, mockLinkingService, NullLogger.Instance); + consumer.Context = new ConsumerContext { - // ARRANGE - var notification = CreateImportNotification(); - var modelNotification = notification.MapWithTransform(); - modelNotification.Changed(AuditEntry.CreateLinked("Test", 1, DateTime.Now)); - var mockLinkingService = Substitute.For(); - var preProcessor = Substitute.For>(); - - preProcessor.Process(Arg.Any>()) - .Returns(Task.FromResult(new PreProcessingResult(outcome, modelNotification, null))); - - var consumer = new NotificationConsumer(preProcessor, mockLinkingService, NullLogger.Instance); - consumer.Context = new ConsumerContext() - { - Headers = new Dictionary() { { "messageId", notification!.ReferenceNumber! } } - }; + Headers = new Dictionary { { "messageId", notification.ReferenceNumber! } } + }; - // ACT - await consumer.OnHandle(notification); + // ACT + await consumer.OnHandle(notification); - // ASSERT - consumer.Context.IsLinked().Should().BeFalse(); + // ASSERT + consumer.Context.IsLinked().Should().BeFalse(); - await mockLinkingService.DidNotReceive().Link(Arg.Any(), Arg.Any()); - } + await mockLinkingService.DidNotReceive().Link(Arg.Any(), Arg.Any()); + } - [Fact] - public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsCreated_ThenLinkShouldBeRun() - { - // ARRANGE - var notification = CreateImportNotification(); - var modelNotification = notification.MapWithTransform(); - modelNotification.Changed(AuditEntry.CreateCreatedEntry(modelNotification, "Test", 1, DateTime.Now)); - var mockLinkingService = Substitute.For(); - var preProcessor = Substitute.For>(); + [Fact] + public async Task WhenPreProcessingSucceeds_AndLastAuditEntryIsCreated_ThenLinkShouldBeRun() + { + // ARRANGE + var notification = CreateImportNotification(); + var modelNotification = notification.MapWithTransform(); + modelNotification.Changed(AuditEntry.CreateCreatedEntry(modelNotification, "Test", 1, DateTime.Now)); + var mockLinkingService = Substitute.For(); + var preProcessor = Substitute.For>(); - mockLinkingService.Link(Arg.Any(), Arg.Any()) - .Returns(Task.FromResult(new LinkResult(LinkOutcome.Linked))); + mockLinkingService.Link(Arg.Any(), Arg.Any()) + .Returns(Task.FromResult(new LinkResult(LinkOutcome.Linked))); - preProcessor.Process(Arg.Any>()) - .Returns(Task.FromResult(new PreProcessingResult(PreProcessingOutcome.New, modelNotification, null))); + preProcessor.Process(Arg.Any>()) + .Returns(Task.FromResult(new PreProcessingResult(PreProcessingOutcome.New, modelNotification, null))); - var consumer = new NotificationConsumer(preProcessor, mockLinkingService, NullLogger.Instance); - consumer.Context = new ConsumerContext() - { - Headers = new Dictionary() { { "messageId", notification!.ReferenceNumber! } } - }; + var consumer = new NotificationConsumer(preProcessor, mockLinkingService, NullLogger.Instance); + consumer.Context = new ConsumerContext + { + Headers = new Dictionary { { "messageId", notification.ReferenceNumber! } } + }; - // ACT - await consumer.OnHandle(notification); + // ACT + await consumer.OnHandle(notification); - // ASSERT - consumer.Context.IsPreProcessed().Should().BeTrue(); - consumer.Context.IsLinked().Should().BeTrue(); + // ASSERT + consumer.Context.IsPreProcessed().Should().BeTrue(); + consumer.Context.IsLinked().Should().BeTrue(); - await mockLinkingService.Received().Link(Arg.Any(), Arg.Any()); - } + await mockLinkingService.Received().Link(Arg.Any(), Arg.Any()); + } - private static ImportNotification CreateImportNotification() - { - return ImportNotificationBuilder.Default() - .WithReferenceNumber(ImportNotificationTypeEnum.Chedpp, 1, DateTime.UtcNow, 1) - .WithRandomCommodities(1, 2) - .Do(x => + private static ImportNotification CreateImportNotification() + { + return ImportNotificationBuilder.Default() + .WithReferenceNumber(ImportNotificationTypeEnum.Chedpp, 1, DateTime.UtcNow, 1) + .WithRandomCommodities(1, 2) + .Do(x => + { + foreach (var parameterSet in x.PartOne?.Commodities?.ComplementParameterSets!) { - foreach (var parameterSet in x.PartOne?.Commodities?.ComplementParameterSets!) - { - parameterSet.KeyDataPairs = null; - } - }).Build(); - } + parameterSet.KeyDataPairs = null; + } + }).Build(); } } \ No newline at end of file diff --git a/Btms.Consumers/AlvsClearanceRequestConsumer.cs b/Btms.Consumers/AlvsClearanceRequestConsumer.cs index 8a7550e..dc7f38c 100644 --- a/Btms.Consumers/AlvsClearanceRequestConsumer.cs +++ b/Btms.Consumers/AlvsClearanceRequestConsumer.cs @@ -5,41 +5,40 @@ using Btms.Consumers.Extensions; using Btms.Business.Pipelines.PreProcessing; -namespace Btms.Consumers +namespace Btms.Consumers; + +internal class AlvsClearanceRequestConsumer(IPreProcessor preProcessor, ILinkingService linkingService, ILogger logger) + : IConsumer, IConsumerWithContext { - internal class AlvsClearanceRequestConsumer(IPreProcessor preProcessor, ILinkingService linkingService, ILogger logger) - : IConsumer, IConsumerWithContext + public async Task OnHandle(AlvsClearanceRequest message) { - public async Task OnHandle(AlvsClearanceRequest message) + var messageId = Context.GetMessageId(); + using (logger.BeginScope(Context.GetJobId()!, messageId, GetType().Name, message.Header?.EntryReference!)) { - var messageId = Context.GetMessageId(); - using (logger.BeginScope(Context.GetJobId()!, messageId, GetType().Name, message.Header?.EntryReference!)) + var preProcessingResult = await preProcessor.Process(new PreProcessingContext(message, messageId)); + + if (preProcessingResult.Outcome == PreProcessingOutcome.Skipped) + { + Context.Skipped(); + } + else { - var preProcessingResult = await preProcessor.Process(new PreProcessingContext(message, messageId)); + Context.PreProcessed(); + } - if (preProcessingResult.Outcome == PreProcessingOutcome.Skipped) - { - Context.Skipped(); - } - else - { - Context.PreProcessed(); - } + if (preProcessingResult.IsCreatedOrChanged()) + { + var linkContext = new MovementLinkContext(preProcessingResult.Record, + preProcessingResult.ChangeSet); + var linkResult = await linkingService.Link(linkContext, Context.CancellationToken); - if (preProcessingResult.IsCreatedOrChanged()) + if (linkResult.Outcome == LinkOutcome.Linked) { - var linkContext = new MovementLinkContext(preProcessingResult.Record!, - preProcessingResult.ChangeSet); - var linkResult = await linkingService.Link(linkContext, Context.CancellationToken); - - if (linkResult.Outcome == LinkOutcome.Linked) - { - Context.Linked(); - } + Context.Linked(); } } } - - public IConsumerContext Context { get; set; } = null!; } + + public IConsumerContext Context { get; set; } = null!; } \ No newline at end of file diff --git a/Btms.Consumers/ConsumerLogging.cs b/Btms.Consumers/ConsumerLogging.cs index 242d4e1..f960731 100644 --- a/Btms.Consumers/ConsumerLogging.cs +++ b/Btms.Consumers/ConsumerLogging.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Logging; -using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; namespace Btms.Consumers; diff --git a/Btms.Consumers/DecisionsConsumer.cs b/Btms.Consumers/DecisionsConsumer.cs index 35e08ca..b1fe7e0 100644 --- a/Btms.Consumers/DecisionsConsumer.cs +++ b/Btms.Consumers/DecisionsConsumer.cs @@ -3,27 +3,26 @@ using Btms.Types.Alvs.Mapping; using SlimMessageBus; -namespace Btms.Consumers +namespace Btms.Consumers; + +public class DecisionsConsumer(IMongoDbContext dbContext) + : IConsumer, IConsumerWithContext { - public class DecisionsConsumer(IMongoDbContext dbContext) - : IConsumer, IConsumerWithContext + public async Task OnHandle(AlvsClearanceRequest message) { - public async Task OnHandle(AlvsClearanceRequest message) - { - var internalClearanceRequest = AlvsClearanceRequestMapper.Map(message); - var existingMovement = await dbContext.Movements.Find(message.Header!.EntryReference!); + var internalClearanceRequest = AlvsClearanceRequestMapper.Map(message); + var existingMovement = await dbContext.Movements.Find(message.Header!.EntryReference!); - if (existingMovement != null) + if (existingMovement != null) + { + var auditId = Context.Headers["messageId"].ToString(); + var merged = existingMovement.MergeDecision(auditId!, internalClearanceRequest); + if (merged) { - var auditId = Context.Headers["messageId"].ToString(); - var merged = existingMovement.MergeDecision(auditId!, internalClearanceRequest); - if (merged) - { - await dbContext.Movements.Update(existingMovement, existingMovement._Etag); - } + await dbContext.Movements.Update(existingMovement, existingMovement._Etag); } } - - public IConsumerContext Context { get; set; } = null!; } + + public IConsumerContext Context { get; set; } = null!; } \ No newline at end of file diff --git a/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs b/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs index 04ce9a4..3cebb59 100644 --- a/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs @@ -10,62 +10,61 @@ using SlimMessageBus.Host.Memory; using AlvsClearanceRequest = Btms.Types.Alvs.AlvsClearanceRequest; -namespace Btms.Consumers.Extensions +namespace Btms.Consumers.Extensions; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddConsumers(this IServiceCollection services, + IConfiguration configuration) { - public static IServiceCollection AddConsumers(this IServiceCollection services, - IConfiguration configuration) - { - services.AddBtmsMetrics(); - services.AddSingleton(); - services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(MetricsInterceptor<>)); - services.AddSingleton(typeof(IPublishInterceptor<>), typeof(MetricsInterceptor<>)); - services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); - services.AddSingleton(typeof(IPublishInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); - services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(JobConsumerInterceptor<>)); - services.AddSingleton(typeof(IMemoryConsumerErrorHandler<>), typeof(InMemoryConsumerErrorHandler<>)); + services.AddBtmsMetrics(); + services.AddSingleton(); + services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(MetricsInterceptor<>)); + services.AddSingleton(typeof(IPublishInterceptor<>), typeof(MetricsInterceptor<>)); + services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); + services.AddSingleton(typeof(IPublishInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); + services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(JobConsumerInterceptor<>)); + services.AddSingleton(typeof(IMemoryConsumerErrorHandler<>), typeof(InMemoryConsumerErrorHandler<>)); - //Message Bus - services.AddSlimMessageBus(mbb => - { - mbb - .AddChildBus("InMemory", cbb => - { - cbb.WithProviderMemory(cfg => - { - cfg.EnableBlockingPublish = false; - cfg.EnableMessageHeaders = true; - }) - .AddServicesFromAssemblyContaining( - consumerLifetime: ServiceLifetime.Scoped) - .Produce(x => x.DefaultTopic("NOTIFICATIONS")) - .Consume(x => - { - x.Instances(2); - x.Topic("NOTIFICATIONS").WithConsumer(); - }) - .Produce(x => x.DefaultTopic("GMR")) - .Consume(x => - { - x.Instances(2); - x.Topic("GMR").WithConsumer(); - }) - .Produce(x => x.DefaultTopic(nameof(AlvsClearanceRequest))) - .Consume(x => - { - x.Instances(2); - x.Topic("ALVS").WithConsumer(); - }) - .Consume(x => - { - x.Instances(2); - x.Topic("DECISIONS").WithConsumer(); - }); - }); - }); + //Message Bus + services.AddSlimMessageBus(mbb => + { + mbb + .AddChildBus("InMemory", cbb => + { + cbb.WithProviderMemory(cfg => + { + cfg.EnableBlockingPublish = false; + cfg.EnableMessageHeaders = true; + }) + .AddServicesFromAssemblyContaining( + consumerLifetime: ServiceLifetime.Scoped) + .Produce(x => x.DefaultTopic("NOTIFICATIONS")) + .Consume(x => + { + x.Instances(2); + x.Topic("NOTIFICATIONS").WithConsumer(); + }) + .Produce(x => x.DefaultTopic("GMR")) + .Consume(x => + { + x.Instances(2); + x.Topic("GMR").WithConsumer(); + }) + .Produce(x => x.DefaultTopic(nameof(AlvsClearanceRequest))) + .Consume(x => + { + x.Instances(2); + x.Topic("ALVS").WithConsumer(); + }) + .Consume(x => + { + x.Instances(2); + x.Topic("DECISIONS").WithConsumer(); + }); + }); + }); - return services; - } + return services; } } \ No newline at end of file diff --git a/Btms.Consumers/GmrConsumer.cs b/Btms.Consumers/GmrConsumer.cs index c3295dc..76b464c 100644 --- a/Btms.Consumers/GmrConsumer.cs +++ b/Btms.Consumers/GmrConsumer.cs @@ -1,48 +1,46 @@ using Btms.Backend.Data; using Btms.Model.Auditing; -using Btms.Model.Gvms; using Btms.Types.Gvms.Mapping; using SlimMessageBus; using SearchGmrsForDeclarationIdsResponse = Btms.Types.Gvms.SearchGmrsForDeclarationIdsResponse; -namespace Btms.Consumers +namespace Btms.Consumers; + +internal class GmrConsumer(IMongoDbContext dbContext) + : IConsumer, IConsumerWithContext { - internal class GmrConsumer(IMongoDbContext dbContext) - : IConsumer, IConsumerWithContext + public async Task OnHandle(SearchGmrsForDeclarationIdsResponse message) { - public async Task OnHandle(SearchGmrsForDeclarationIdsResponse message) + foreach (var gmr in message.Gmrs!) { - foreach (var gmr in message.Gmrs!) + var internalGmr = GrmWithTransformMapper.MapWithTransform(gmr); + var existingGmr = await dbContext.Gmrs.Find(internalGmr.Id!); + var auditId = Context.Headers["messageId"].ToString(); + if (existingGmr is null) { - var internalGmr = GrmWithTransformMapper.MapWithTransform(gmr); - var existingGmr = await dbContext.Gmrs.Find(internalGmr.Id!); - var auditId = Context.Headers["messageId"].ToString(); - if (existingGmr is null) - { - var auditEntry = - AuditEntry.CreateCreatedEntry(internalGmr, auditId!, 1, gmr.UpdatedSource); - internalGmr.AuditEntries.Add(auditEntry); - await dbContext.Gmrs.Insert(internalGmr); - } - else + var auditEntry = + AuditEntry.CreateCreatedEntry(internalGmr, auditId!, 1, gmr.UpdatedSource); + internalGmr.AuditEntries.Add(auditEntry); + await dbContext.Gmrs.Insert(internalGmr); + } + else + { + if (gmr.UpdatedSource > existingGmr.UpdatedSource) { - if (gmr.UpdatedSource > existingGmr.UpdatedSource) - { - internalGmr.AuditEntries = existingGmr.AuditEntries; - var auditEntry = AuditEntry.CreateUpdated( - previous: existingGmr, - current: internalGmr, - id: auditId!, - version: internalGmr.AuditEntries.Count + 1, - lastUpdated: gmr.UpdatedSource); - internalGmr.AuditEntries.Add(auditEntry); - await dbContext.Gmrs.Update(internalGmr, existingGmr._Etag); - } + internalGmr.AuditEntries = existingGmr.AuditEntries; + var auditEntry = AuditEntry.CreateUpdated( + previous: existingGmr, + current: internalGmr, + id: auditId!, + version: internalGmr.AuditEntries.Count + 1, + lastUpdated: gmr.UpdatedSource); + internalGmr.AuditEntries.Add(auditEntry); + await dbContext.Gmrs.Update(internalGmr, existingGmr._Etag); } } } - - public IConsumerContext Context { get; set; } = null!; } + + public IConsumerContext Context { get; set; } = null!; } \ No newline at end of file diff --git a/Btms.Consumers/Interceptors/InMemoryConsumerErrorHandler.cs b/Btms.Consumers/Interceptors/InMemoryConsumerErrorHandler.cs index 4059748..ce43435 100644 --- a/Btms.Consumers/Interceptors/InMemoryConsumerErrorHandler.cs +++ b/Btms.Consumers/Interceptors/InMemoryConsumerErrorHandler.cs @@ -1,4 +1,3 @@ -using Btms.Common.Extensions; using Btms.Consumers.Extensions; using Microsoft.Extensions.Logging; using SlimMessageBus; @@ -10,7 +9,7 @@ namespace Btms.Consumers.Interceptors; public class InMemoryConsumerErrorHandler(ILogger> logger) : IMemoryConsumerErrorHandler { - private async Task AttemptRetry(T message, IConsumerContext consumerContext, + private async Task AttemptRetry(IConsumerContext consumerContext, Func> retry, Exception exception) { consumerContext.IncrementRetryAttempt(); @@ -30,7 +29,7 @@ private async Task AttemptRetry(T message, IConsumer } catch (Exception e) { - await AttemptRetry(message, consumerContext, retry, e); + await AttemptRetry(consumerContext, retry, e); } return ConsumerErrorHandlerResult.Success; @@ -44,6 +43,6 @@ public Task OnHandleError(T message, Func(InMemoryQueueMetrics queueMetrics, Con { public const string ActivityName = "Btms.Consumer"; public const string TimeInQueueActivityName = "Btms.TimeInQueue"; - private static readonly ConcurrentDictionary messageQueueTimes = new(); + private static readonly ConcurrentDictionary MessageQueueTimes = new(); public async Task OnHandle(TMessage message, Func> next, IConsumerContext context) { var timer = Stopwatch.StartNew(); @@ -30,7 +28,7 @@ public async Task OnHandle(TMessage message, Func> next, IC var activityContext = context.GetActivityContext(); - if (messageQueueTimes.TryGetValue(message, out var dateTime)) + if (MessageQueueTimes.TryGetValue(message, out var dateTime)) { int msInQueue; using (var activity = BtmsDiagnostics.ActivitySource.CreateActivity(TimeInQueueActivityName, @@ -42,13 +40,13 @@ public async Task OnHandle(TMessage message, Func> next, IC activity?.SetEndTime(deQueueTime); msInQueue = deQueueTime.Subtract(dateTime).Milliseconds; queueMetrics.TimeSpentInQueue(msInQueue, context.Path); - messageQueueTimes.Remove(message, out var _); + MessageQueueTimes.Remove(message, out var _); } } queueMetrics.Outgoing(queueName: context.Path); - using (var activity = BtmsDiagnostics.ActivitySource.StartActivity(ActivityName, parentContext: activityContext, kind: ActivityKind.Client)) + using (BtmsDiagnostics.ActivitySource.StartActivity(ActivityName, parentContext: activityContext, kind: ActivityKind.Client)) { var result = await next(); if (context.WasSkipped()) @@ -73,7 +71,7 @@ public async Task OnHandle(TMessage message, Func> next, IC public Task OnHandle(TMessage message, Func next, IProducerContext context) { queueMetrics.Incoming(context.Path); - messageQueueTimes.TryAdd(message, DateTime.UtcNow); + MessageQueueTimes.TryAdd(message, DateTime.UtcNow); return next(); } } \ No newline at end of file diff --git a/Btms.Consumers/MemoryQueue/MemoryQueueStatsMonitor.cs b/Btms.Consumers/MemoryQueue/MemoryQueueStatsMonitor.cs index ed0ea41..c2a0c77 100644 --- a/Btms.Consumers/MemoryQueue/MemoryQueueStatsMonitor.cs +++ b/Btms.Consumers/MemoryQueue/MemoryQueueStatsMonitor.cs @@ -14,7 +14,7 @@ public void Enqueue(string queue) value.Enqueue(); return value; - }, (s, stats) => + }, (_, stats) => { stats.Enqueue(); return stats; @@ -30,7 +30,7 @@ public void Dequeue(string queue) value.Dequeue(); return value; - }, (s, stats) => + }, (_, stats) => { stats.Dequeue(); return stats; diff --git a/Btms.Consumers/NotificationConsumer.cs b/Btms.Consumers/NotificationConsumer.cs index 66c08c2..249c4fb 100644 --- a/Btms.Consumers/NotificationConsumer.cs +++ b/Btms.Consumers/NotificationConsumer.cs @@ -5,42 +5,41 @@ using Microsoft.Extensions.Logging; using Btms.Business.Pipelines.PreProcessing; -namespace Btms.Consumers +namespace Btms.Consumers; + +internal class NotificationConsumer(IPreProcessor preProcessor, ILinkingService linkingService, ILogger logger) + : IConsumer, IConsumerWithContext { - internal class NotificationConsumer(IPreProcessor preProcessor, ILinkingService linkingService, ILogger logger) - : IConsumer, IConsumerWithContext + public async Task OnHandle(ImportNotification message) { - public async Task OnHandle(ImportNotification message) + var messageId = Context.GetMessageId(); + using (logger.BeginScope(Context.GetJobId()!, messageId, GetType().Name, message.ReferenceNumber!)) { - var messageId = Context.GetMessageId(); - using (logger.BeginScope(Context.GetJobId()!, messageId, GetType().Name, message.ReferenceNumber!)) + var preProcessingResult = await preProcessor.Process(new PreProcessingContext(message, messageId)); + + if (preProcessingResult.Outcome == PreProcessingOutcome.Skipped) + { + Context.Skipped(); + } + else { - var preProcessingResult = await preProcessor.Process(new PreProcessingContext(message, messageId)); + Context.PreProcessed(); + } - if (preProcessingResult.Outcome == PreProcessingOutcome.Skipped) - { - Context.Skipped(); - } - else - { - Context.PreProcessed(); - } + if (preProcessingResult.IsCreatedOrChanged()) + { + var linkContext = new ImportNotificationLinkContext(preProcessingResult.Record, + preProcessingResult.ChangeSet); + var linkResult = await linkingService.Link(linkContext, Context.CancellationToken); - if (preProcessingResult.IsCreatedOrChanged()) + if (linkResult.Outcome == LinkOutcome.Linked) { - var linkContext = new ImportNotificationLinkContext(preProcessingResult.Record!, - preProcessingResult.ChangeSet); - var linkResult = await linkingService.Link(linkContext, Context.CancellationToken); - - if (linkResult.Outcome == LinkOutcome.Linked) - { - Context.Linked(); - } + Context.Linked(); } - } - } - public IConsumerContext Context { get; set; } = null!; + } } + + public IConsumerContext Context { get; set; } = null!; } \ No newline at end of file diff --git a/Btms.Emf/EmfExporter.cs b/Btms.Emf/EmfExporter.cs index 3b3a9d9..de4f9d1 100644 --- a/Btms.Emf/EmfExporter.cs +++ b/Btms.Emf/EmfExporter.cs @@ -9,90 +9,88 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace Btms.Emf -{ +namespace Btms.Emf; - public static class EmfExportExtensions +public static class EmfExportExtensions +{ + public static IApplicationBuilder UseEmfExporter(this IApplicationBuilder builder) { - public static IApplicationBuilder UseEmfExporter(this IApplicationBuilder builder) - { - var config = builder.ApplicationServices.GetRequiredService(); + var config = builder.ApplicationServices.GetRequiredService(); - bool enabled = config.GetValue("AWS_EMF_ENABLED", true); + var enabled = config.GetValue("AWS_EMF_ENABLED", true); - if (enabled) - { - var ns = config.GetValue("AWS_EMF_NAMESPACE"); + if (enabled) + { + var ns = config.GetValue("AWS_EMF_NAMESPACE"); EmfExporter.Init(builder.ApplicationServices.GetRequiredService().CreateLogger(nameof(EmfExporter)), ns!); - } - return builder; } + return builder; } - public static class EmfExporter +} +public static class EmfExporter +{ + private static readonly MeterListener MeterListener = new(); + private static ILogger _log = null!; + private static string? _awsNamespace; + public static void Init(ILogger logger, string? awsNamespace) { - private static readonly MeterListener meterListener = new(); - private static ILogger log = null!; - private static string? awsNamespace; - public static void Init(ILogger logger, string? awsNamespace) + _log = logger; + EmfExporter._awsNamespace = awsNamespace; + MeterListener.InstrumentPublished = (instrument, listener) => { - log = logger; - EmfExporter.awsNamespace = awsNamespace; - meterListener.InstrumentPublished = (instrument, listener) => + if (instrument.Meter.Name is MetricNames.MeterName) { - if (instrument.Meter.Name is MetricNames.MeterName) - { - listener.EnableMeasurementEvents(instrument); - } - }; + listener.EnableMeasurementEvents(instrument); + } + }; - meterListener.SetMeasurementEventCallback(OnMeasurementRecorded); - meterListener.SetMeasurementEventCallback(OnMeasurementRecorded); - meterListener.SetMeasurementEventCallback(OnMeasurementRecorded); - meterListener.Start(); - } + MeterListener.SetMeasurementEventCallback(OnMeasurementRecorded); + MeterListener.SetMeasurementEventCallback(OnMeasurementRecorded); + MeterListener.SetMeasurementEventCallback(OnMeasurementRecorded); + MeterListener.Start(); + } - static void OnMeasurementRecorded( - Instrument instrument, - T measurement, - ReadOnlySpan> tags, - object? state) + private static void OnMeasurementRecorded( + Instrument instrument, + T measurement, + ReadOnlySpan> tags, + object? state) + { + try { - try + using (var metricsLogger = new MetricsLogger()) { - using (var metricsLogger = new MetricsLogger()) + metricsLogger.SetNamespace(_awsNamespace); + var dimensionSet = new DimensionSet(); + foreach (var tag in tags) { - metricsLogger.SetNamespace(awsNamespace); - var dimensionSet = new DimensionSet(); - foreach (var tag in tags) - { - dimensionSet.AddDimension(tag.Key, tag.Value?.ToString()); - } - - // If the request contains a w3c trace id, let's embed it in the logs - // Otherwise we'll include the TraceIdentifier which is the connectionId:requestCount - // identifier. - // https://www.w3.org/TR/trace-context/#traceparent-header - if (!string.IsNullOrEmpty(Activity.Current?.Id)) - { - metricsLogger.PutProperty("TraceId", Activity.Current.TraceStateString); - } + dimensionSet.AddDimension(tag.Key, tag.Value?.ToString()); + } - if (!string.IsNullOrEmpty(Activity.Current?.TraceStateString)) - { - metricsLogger.PutProperty("TraceState", Activity.Current.TraceStateString); - } - metricsLogger.SetDimensions(dimensionSet); - var name = instrument.Name.Dehumanize().Camelize(); - metricsLogger.PutMetric(name, Convert.ToDouble(measurement), instrument.Unit == "ea" ? Unit.COUNT : Unit.MILLISECONDS); - metricsLogger.Flush(); + // If the request contains a w3c trace id, let's embed it in the logs + // Otherwise we'll include the TraceIdentifier which is the connectionId:requestCount + // identifier. + // https://www.w3.org/TR/trace-context/#traceparent-header + if (!string.IsNullOrEmpty(Activity.Current?.Id)) + { + metricsLogger.PutProperty("TraceId", Activity.Current.TraceStateString); } - } - catch (Exception e) - { - log.LogError(e, "Failed to push EMF metric"); + if (!string.IsNullOrEmpty(Activity.Current?.TraceStateString)) + { + metricsLogger.PutProperty("TraceState", Activity.Current.TraceStateString); + } + metricsLogger.SetDimensions(dimensionSet); + var name = instrument.Name.Dehumanize().Camelize(); + metricsLogger.PutMetric(name, Convert.ToDouble(measurement), instrument.Unit == "ea" ? Unit.COUNT : Unit.MILLISECONDS); + metricsLogger.Flush(); } } + catch (Exception e) + { + _log.LogError(e, "Failed to push EMF metric"); + } + } -} +} \ No newline at end of file diff --git a/Btms.Metrics/ConsumerMetrics.cs b/Btms.Metrics/ConsumerMetrics.cs index 5fbde4d..96d9895 100644 --- a/Btms.Metrics/ConsumerMetrics.cs +++ b/Btms.Metrics/ConsumerMetrics.cs @@ -1,18 +1,17 @@ using System.Diagnostics; using System.Diagnostics.Metrics; using System.Text; -using Btms.Common; namespace Btms.Metrics; public class ConsumerMetrics { - readonly Histogram consumeDuration; - readonly Counter consumeTotal; - readonly Counter consumeFaultTotal; - readonly Counter consumerInProgress; - readonly Counter consumeRetryTotal; - readonly Counter skippedTotal; + private readonly Histogram consumeDuration; + private readonly Counter consumeTotal; + private readonly Counter consumeFaultTotal; + private readonly Counter consumerInProgress; + private readonly Counter consumeRetryTotal; + private readonly Counter skippedTotal; public ConsumerMetrics(IMeterFactory meterFactory) { diff --git a/Btms.Metrics/Extensions/ServiceCollectionExtensions.cs b/Btms.Metrics/Extensions/ServiceCollectionExtensions.cs index ff4890d..f56c4f6 100644 --- a/Btms.Metrics/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Metrics/Extensions/ServiceCollectionExtensions.cs @@ -1,18 +1,17 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -namespace Btms.Metrics.Extensions +namespace Btms.Metrics.Extensions; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddBtmsMetrics(this IServiceCollection services) { - public static IServiceCollection AddBtmsMetrics(this IServiceCollection services) - { - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); - return services; - } + return services; } } \ No newline at end of file diff --git a/Btms.Metrics/InMemoryQueueMetrics.cs b/Btms.Metrics/InMemoryQueueMetrics.cs index 5701223..8f7ea24 100644 --- a/Btms.Metrics/InMemoryQueueMetrics.cs +++ b/Btms.Metrics/InMemoryQueueMetrics.cs @@ -1,16 +1,14 @@ -using System; using System.Diagnostics; using System.Diagnostics.Metrics; -using System.IO; using SlimMessageBus.Host; namespace Btms.Metrics; public class InMemoryQueueMetrics { - readonly Histogram timeInQueue; - readonly Counter incomingCountMetric; - readonly Counter outgoingCountMetric; + private readonly Histogram timeInQueue; + private readonly Counter incomingCountMetric; + private readonly Counter outgoingCountMetric; private long queueCount; private readonly int noOfQueues; diff --git a/Btms.Metrics/LinkingMetrics.cs b/Btms.Metrics/LinkingMetrics.cs index 7919b68..8e79c57 100644 --- a/Btms.Metrics/LinkingMetrics.cs +++ b/Btms.Metrics/LinkingMetrics.cs @@ -5,9 +5,9 @@ namespace Btms.Metrics; public class LinkingMetrics { - readonly Histogram duration; - readonly Counter total; - readonly Counter faulted; + private readonly Histogram duration; + private readonly Counter total; + private readonly Counter faulted; public LinkingMetrics(IMeterFactory meterFactory) { diff --git a/Btms.Metrics/MetricNames.cs b/Btms.Metrics/MetricNames.cs index a1a3591..ac43583 100644 --- a/Btms.Metrics/MetricNames.cs +++ b/Btms.Metrics/MetricNames.cs @@ -1,15 +1,14 @@ -namespace Btms.Metrics +namespace Btms.Metrics; + +public static class MetricNames { - public static class MetricNames - { - public const string MeterName = "Btms.Backend"; + public const string MeterName = "Btms.Backend"; - public static class CommonTags - { - public const string Service = "btms.service"; - public const string ExceptionType = "btms.exception_type"; - public const string MessageType = "btms.message_type"; - public const string QueueName = "btms.memory.queue_name"; - } + public static class CommonTags + { + public const string Service = "btms.service"; + public const string ExceptionType = "btms.exception_type"; + public const string MessageType = "btms.message_type"; + public const string QueueName = "btms.memory.queue_name"; } -} +} \ No newline at end of file diff --git a/Btms.Metrics/ObservabilityUtils.cs b/Btms.Metrics/ObservabilityUtils.cs index e715fb1..e04dc44 100644 --- a/Btms.Metrics/ObservabilityUtils.cs +++ b/Btms.Metrics/ObservabilityUtils.cs @@ -1,38 +1,37 @@ using System.Text; -namespace Btms.Metrics +namespace Btms.Metrics; + +public static class ObservabilityUtils { - public static class ObservabilityUtils + public static string FormatTypeName(StringBuilder sb, Type type) { - public static string FormatTypeName(StringBuilder sb, Type type) - { - if (type.IsGenericParameter) - return ""; + if (type.IsGenericParameter) + return ""; - if (type.IsGenericType) - { - var name = type.GetGenericTypeDefinition().Name; + if (type.IsGenericType) + { + var name = type.GetGenericTypeDefinition().Name; - //remove `1 - var index = name.IndexOf('`'); - if (index > 0) - name = name.Remove(index); + //remove `1 + var index = name.IndexOf('`'); + if (index > 0) + name = name.Remove(index); - sb.Append(name); - sb.Append('_'); - Type[] arguments = type.GenericTypeArguments; - for (var i = 0; i < arguments.Length; i++) - { - if (i > 0) - sb.Append('_'); + sb.Append(name); + sb.Append('_'); + Type[] arguments = type.GenericTypeArguments; + for (var i = 0; i < arguments.Length; i++) + { + if (i > 0) + sb.Append('_'); - FormatTypeName(sb, arguments[i]); - } + FormatTypeName(sb, arguments[i]); } - else - sb.Append(type.Name); - - return sb.ToString(); } + else + sb.Append(type.Name); + + return sb.ToString(); } } \ No newline at end of file diff --git a/Btms.Metrics/SyncMetrics.cs b/Btms.Metrics/SyncMetrics.cs index 550a9af..5256a6c 100644 --- a/Btms.Metrics/SyncMetrics.cs +++ b/Btms.Metrics/SyncMetrics.cs @@ -1,16 +1,15 @@ using System.Diagnostics; using System.Diagnostics.Metrics; using System.Text; -using Btms.Common; namespace Btms.Metrics; public class SyncMetrics { - readonly Histogram syncDuration; - readonly Counter syncTotal; - readonly Counter syncFaultTotal; - readonly Counter syncInProgress; + private readonly Histogram syncDuration; + private readonly Counter syncTotal; + private readonly Counter syncFaultTotal; + private readonly Counter syncInProgress; public SyncMetrics(IMeterFactory meterFactory) { diff --git a/Btms.Model/Alvs/AlvsClearanceRequest.g.cs b/Btms.Model/Alvs/AlvsClearanceRequest.g.cs index 0fd8e1c..07e8337 100644 --- a/Btms.Model/Alvs/AlvsClearanceRequest.g.cs +++ b/Btms.Model/Alvs/AlvsClearanceRequest.g.cs @@ -24,7 +24,7 @@ public partial class AlvsClearanceRequest // /// /// - /// [Attr] [System.ComponentModel.Description("")] public ServiceHeader? ServiceHeader { get; set; } @@ -32,7 +32,7 @@ public partial class AlvsClearanceRequest // /// /// - /// [Attr] [System.ComponentModel.Description("")] public Header? Header { get; set; } @@ -40,7 +40,7 @@ public partial class AlvsClearanceRequest // /// /// - /// [Attr] [System.ComponentModel.Description("")] public Items[]? Items { get; set; } diff --git a/Btms.Model/Alvs/AlvsClearanceRequestPost.g.cs b/Btms.Model/Alvs/AlvsClearanceRequestPost.g.cs index ddce4cf..641ff95 100644 --- a/Btms.Model/Alvs/AlvsClearanceRequestPost.g.cs +++ b/Btms.Model/Alvs/AlvsClearanceRequestPost.g.cs @@ -24,7 +24,7 @@ public partial class AlvsClearanceRequestPost // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? XmlSchemaVersion { get; set; } @@ -32,7 +32,7 @@ public partial class AlvsClearanceRequestPost // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? UserIdentification { get; set; } @@ -40,7 +40,7 @@ public partial class AlvsClearanceRequestPost // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? UserPassword { get; set; } @@ -48,7 +48,7 @@ public partial class AlvsClearanceRequestPost // /// /// - /// [Attr] [System.ComponentModel.Description("")] public DateTime? SentOn { get; set; } @@ -56,7 +56,7 @@ public partial class AlvsClearanceRequestPost // /// /// - /// [Attr] [System.ComponentModel.Description("")] public AlvsClearanceRequest? AlvsClearanceRequest { get; set; } diff --git a/Btms.Model/Alvs/Check.cs b/Btms.Model/Alvs/Check.cs index c0b8933..93f97e2 100644 --- a/Btms.Model/Alvs/Check.cs +++ b/Btms.Model/Alvs/Check.cs @@ -23,7 +23,7 @@ public partial class Check // { /// /// - /// [Attr] [JsonPropertyName("decisionCode")] public string? DecisionCode { get; set; } @@ -31,7 +31,7 @@ public partial class Check // /// /// - /// [Attr] [JsonPropertyName("decisionsValidUntil")] public DateTime? DecisionsValidUntil { get; set; } diff --git a/Btms.Model/Alvs/Check.g.cs b/Btms.Model/Alvs/Check.g.cs index 3c89d1c..9d8ade7 100644 --- a/Btms.Model/Alvs/Check.g.cs +++ b/Btms.Model/Alvs/Check.g.cs @@ -24,7 +24,7 @@ public partial class Check // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? CheckCode { get; set; } @@ -32,7 +32,7 @@ public partial class Check // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DepartmentCode { get; set; } diff --git a/Btms.Model/Alvs/Document.g.cs b/Btms.Model/Alvs/Document.g.cs index 7e5a015..ccefa90 100644 --- a/Btms.Model/Alvs/Document.g.cs +++ b/Btms.Model/Alvs/Document.g.cs @@ -24,7 +24,7 @@ public partial class Document // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DocumentCode { get; set; } @@ -32,7 +32,7 @@ public partial class Document // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DocumentReference { get; set; } @@ -40,7 +40,7 @@ public partial class Document // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DocumentStatus { get; set; } @@ -48,7 +48,7 @@ public partial class Document // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DocumentControl { get; set; } @@ -56,7 +56,7 @@ public partial class Document // /// /// - /// [Attr] [System.ComponentModel.Description("")] public decimal? DocumentQuantity { get; set; } diff --git a/Btms.Model/Alvs/Header.g.cs b/Btms.Model/Alvs/Header.g.cs index 5581ac3..6ead11f 100644 --- a/Btms.Model/Alvs/Header.g.cs +++ b/Btms.Model/Alvs/Header.g.cs @@ -24,7 +24,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? EntryReference { get; set; } @@ -32,7 +32,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public int? EntryVersionNumber { get; set; } @@ -40,7 +40,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public int? PreviousVersionNumber { get; set; } @@ -48,7 +48,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DeclarationUcr { get; set; } @@ -56,7 +56,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DeclarationPartNumber { get; set; } @@ -64,7 +64,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DeclarationType { get; set; } @@ -72,7 +72,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public DateTime? ArrivesAt { get; set; } @@ -80,7 +80,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? SubmitterTurn { get; set; } @@ -88,7 +88,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DeclarantId { get; set; } @@ -96,7 +96,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DeclarantName { get; set; } @@ -104,7 +104,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DispatchCountryCode { get; set; } @@ -112,7 +112,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? GoodsLocationCode { get; set; } @@ -120,7 +120,7 @@ public partial class Header // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? MasterUcr { get; set; } diff --git a/Btms.Model/Alvs/Items.cs b/Btms.Model/Alvs/Items.cs index 5f2a865..1385c4e 100644 --- a/Btms.Model/Alvs/Items.cs +++ b/Btms.Model/Alvs/Items.cs @@ -22,7 +22,7 @@ public partial class Items // public void MergeChecks(Items decisionItems) { - var checks = this.Checks?.ToList(); + var checks = Checks?.ToList(); if (checks == null) { checks = new List(); @@ -44,7 +44,7 @@ public void MergeChecks(Items decisionItems) } } - this.Checks = checks.ToArray(); + Checks = checks.ToArray(); } } diff --git a/Btms.Model/Alvs/Items.g.cs b/Btms.Model/Alvs/Items.g.cs index 0f281e7..29e28fd 100644 --- a/Btms.Model/Alvs/Items.g.cs +++ b/Btms.Model/Alvs/Items.g.cs @@ -24,7 +24,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public int? ItemNumber { get; set; } @@ -32,7 +32,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? CustomsProcedureCode { get; set; } @@ -40,7 +40,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? TaricCommodityCode { get; set; } @@ -48,7 +48,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? GoodsDescription { get; set; } @@ -56,7 +56,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? ConsigneeId { get; set; } @@ -64,7 +64,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? ConsigneeName { get; set; } @@ -72,7 +72,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public decimal? ItemNetMass { get; set; } @@ -80,7 +80,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public decimal? ItemSupplementaryUnits { get; set; } @@ -88,7 +88,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public decimal? ItemThirdQuantity { get; set; } @@ -96,7 +96,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? ItemOriginCountryCode { get; set; } @@ -104,7 +104,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public Document[]? Documents { get; set; } @@ -112,7 +112,7 @@ public partial class Items // /// /// - /// [Attr] [System.ComponentModel.Description("")] public Check[]? Checks { get; set; } diff --git a/Btms.Model/Alvs/ServiceHeader.g.cs b/Btms.Model/Alvs/ServiceHeader.g.cs index 3249fba..5ec5368 100644 --- a/Btms.Model/Alvs/ServiceHeader.g.cs +++ b/Btms.Model/Alvs/ServiceHeader.g.cs @@ -24,7 +24,7 @@ public partial class ServiceHeader // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? SourceSystem { get; set; } @@ -32,7 +32,7 @@ public partial class ServiceHeader // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? DestinationSystem { get; set; } @@ -40,7 +40,7 @@ public partial class ServiceHeader // /// /// - /// [Attr] [System.ComponentModel.Description("")] public string? CorrelationId { get; set; } @@ -48,7 +48,7 @@ public partial class ServiceHeader // /// /// - /// [Attr] [System.ComponentModel.Description("")] public DateTime? ServiceCalled { get; set; } diff --git a/Btms.Model/Auditing/AuditEntry.cs b/Btms.Model/Auditing/AuditEntry.cs index fe729bc..8dcbe75 100644 --- a/Btms.Model/Auditing/AuditEntry.cs +++ b/Btms.Model/Auditing/AuditEntry.cs @@ -16,7 +16,7 @@ public class AuditEntry public DateTime? CreatedSource { get; set; } - public DateTime CreatedLocal { get; set; } = System.DateTime.UtcNow; + public DateTime CreatedLocal { get; set; } = DateTime.UtcNow; public string Status { get; set; } = default!; @@ -29,12 +29,12 @@ public bool IsCreatedOrUpdated() public bool IsCreated() { - return this.Status == "Created"; + return Status == "Created"; } public bool IsUpdated() { - return this.Status == "Created"; + return Status == "Created"; } @@ -54,7 +54,7 @@ public static AuditEntry CreateUpdated(T previous, T current, string id, int public static AuditEntry CreateUpdated(ChangeSet changeSet, string id, int version, DateTime? lastUpdated) { - var auditEntry = new AuditEntry() + var auditEntry = new AuditEntry { Id = id, Version = version, @@ -74,7 +74,7 @@ public static AuditEntry CreateUpdated(ChangeSet changeSet, string id, int versi public static AuditEntry CreateCreatedEntry(T current, string id, int version, DateTime? lastUpdated) { - return new AuditEntry() + return new AuditEntry { Id = id, Version = version, @@ -87,7 +87,7 @@ public static AuditEntry CreateCreatedEntry(T current, string id, int version public static AuditEntry CreateSkippedVersion(string id, int version, DateTime? lastUpdated) { - return new AuditEntry() + return new AuditEntry { Id = id, Version = version, @@ -100,7 +100,7 @@ public static AuditEntry CreateSkippedVersion(string id, int version, DateTime? public static AuditEntry CreateLinked(string id, int version, DateTime? lastUpdated) { - return new AuditEntry() + return new AuditEntry { Id = id, Version = version, @@ -113,7 +113,7 @@ public static AuditEntry CreateLinked(string id, int version, DateTime? lastUpda public static AuditEntry CreateMatch(string id, int version, DateTime? lastUpdated) { - return new AuditEntry() + return new AuditEntry { Id = id, Version = version, @@ -138,7 +138,7 @@ private static AuditEntry CreateInternal(JsonNode previous, JsonNode current, st { var diff = previous.CreatePatch(current); - var auditEntry = new AuditEntry() + var auditEntry = new AuditEntry { Id = id, Version = version, @@ -199,7 +199,7 @@ internal static AuditDiffEntry Internal(PatchOperation operation) } } - return new AuditEntry.AuditDiffEntry() + return new AuditDiffEntry { Path = operation.Path.ToString(), Op = operation.Op.ToString(), Value = value }; diff --git a/Btms.Model/ChangeLog/ChangeSet.cs b/Btms.Model/ChangeLog/ChangeSet.cs index 8fb0ffb..2f9d5f9 100644 --- a/Btms.Model/ChangeLog/ChangeSet.cs +++ b/Btms.Model/ChangeLog/ChangeSet.cs @@ -8,7 +8,7 @@ namespace Btms.Model.ChangeLog; public class ChangeSet(JsonPatch jsonPatch) { - private static JsonSerializerOptions jsonOptions = new JsonSerializerOptions() + private static JsonSerializerOptions _jsonOptions = new() { TypeInfoResolver = new ChangeSetTypeInfoResolver(), PropertyNameCaseInsensitive = true, @@ -19,8 +19,8 @@ public class ChangeSet(JsonPatch jsonPatch) public static ChangeSet CreateChangeSet(T current, T previous) { - var previousNode = JsonNode.Parse(previous.ToJsonString(jsonOptions)); - var currentNode = JsonNode.Parse(current.ToJsonString(jsonOptions)); + var previousNode = JsonNode.Parse(previous.ToJsonString(_jsonOptions)); + var currentNode = JsonNode.Parse(current.ToJsonString(_jsonOptions)); var diff = previousNode.CreatePatch(currentNode); //exclude fields from patch, like _ts, audit entries etc diff --git a/Btms.Model/ChangeLog/ChangeSetTypeInfoResolver.cs b/Btms.Model/ChangeLog/ChangeSetTypeInfoResolver.cs index 53d5b45..dbf5226 100644 --- a/Btms.Model/ChangeLog/ChangeSetTypeInfoResolver.cs +++ b/Btms.Model/ChangeLog/ChangeSetTypeInfoResolver.cs @@ -7,7 +7,7 @@ public class ChangeSetTypeInfoResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { - JsonTypeInfo typeInfo = base.GetTypeInfo(type, options); + var typeInfo = base.GetTypeInfo(type, options); if (typeInfo.Kind == JsonTypeInfoKind.Object) { @@ -15,7 +15,7 @@ public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions option { if (property.AttributeProvider!.GetCustomAttributes(typeof(ChangeSetIgnoreAttribute), false).Any()) { - property.ShouldSerialize = (o, o1) => false; + property.ShouldSerialize = (_, _) => false; } } } diff --git a/Btms.Model/Data/IDataEntity.cs b/Btms.Model/Data/IDataEntity.cs index c73f8ea..4bc525f 100644 --- a/Btms.Model/Data/IDataEntity.cs +++ b/Btms.Model/Data/IDataEntity.cs @@ -4,6 +4,7 @@ public interface IDataEntity { public string? Id { get; set; } + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _Etag { get; set; } public DateTime Created { get; set; } diff --git a/Btms.Model/Extensions/ImportNotificationTypeEnumExtensions.cs b/Btms.Model/Extensions/ImportNotificationTypeEnumExtensions.cs index 9113a79..68c3fe1 100644 --- a/Btms.Model/Extensions/ImportNotificationTypeEnumExtensions.cs +++ b/Btms.Model/Extensions/ImportNotificationTypeEnumExtensions.cs @@ -1,5 +1,4 @@ using Btms.Model.Ipaffs; -using Microsoft.AspNetCore.Components.Forms; namespace Btms.Model.Extensions; diff --git a/Btms.Model/Extensions/JsonExtensions.cs b/Btms.Model/Extensions/JsonExtensions.cs index e52f91b..6598dd2 100644 --- a/Btms.Model/Extensions/JsonExtensions.cs +++ b/Btms.Model/Extensions/JsonExtensions.cs @@ -1,20 +1,19 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Btms.Model.Extensions +namespace Btms.Model.Extensions; + +public static class JsonExtensions { - public static class JsonExtensions + private static readonly JsonSerializerOptions Default = new() { - private static readonly JsonSerializerOptions Default = new() - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }; + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; - public static string ToJsonString(this T value, JsonSerializerOptions? options = null) - { - if (value is string s) return s; + public static string ToJsonString(this T value, JsonSerializerOptions? options = null) + { + if (value is string s) return s; - return JsonSerializer.Serialize(value, options ?? Default); - } + return JsonSerializer.Serialize(value, options ?? Default); } } \ No newline at end of file diff --git a/Btms.Model/Extensions/LinksBuilder.cs b/Btms.Model/Extensions/LinksBuilder.cs index b5be66a..d1e13c2 100644 --- a/Btms.Model/Extensions/LinksBuilder.cs +++ b/Btms.Model/Extensions/LinksBuilder.cs @@ -7,12 +7,12 @@ public static class Notification public const string ResourceName = "import-notifications"; public static string BuildSelfNotificationLink(string id) { - return LinksBuilder.BuildSelfLink(ResourceName, id); + return BuildSelfLink(ResourceName, id); } public static string BuildRelatedMovementLink(string id) { - return LinksBuilder.BuildRelatedLink(ResourceName, id, "movements"); + return BuildRelatedLink(ResourceName, id, "movements"); } } @@ -21,12 +21,12 @@ public static class Movement public const string ResourceName = "movements"; public static string BuildSelfMovementLink(string id) { - return LinksBuilder.BuildSelfLink(ResourceName, id); + return BuildSelfLink(ResourceName, id); } public static string BuildRelatedMovementLink(string id) { - return LinksBuilder.BuildRelatedLink(ResourceName, id, Notification.ResourceName); + return BuildRelatedLink(ResourceName, id, Notification.ResourceName); } } @@ -35,22 +35,22 @@ public static class Gmr public const string ResourceName = "gmr"; public static string BuildSelfRelationshipCustomsLink(string id) { - return LinksBuilder.BuildSelfRelationshipLink(ResourceName, id, Notification.ResourceName); + return BuildSelfRelationshipLink(ResourceName, id, Notification.ResourceName); } public static string BuildSelfRelationshipTransitsLink(string id) { - return LinksBuilder.BuildSelfRelationshipLink(ResourceName, id, Movement.ResourceName); + return BuildSelfRelationshipLink(ResourceName, id, Movement.ResourceName); } public static string BuildRelatedTransitLink(string id) { - return LinksBuilder.BuildSelfLink(Movement.ResourceName, id); + return BuildSelfLink(Movement.ResourceName, id); } public static string BuildRelatedCustomsLink(string id) { - return LinksBuilder.BuildSelfLink(Notification.ResourceName, id); + return BuildSelfLink(Notification.ResourceName, id); } } diff --git a/Btms.Model/Gvms/Gmr.cs b/Btms.Model/Gvms/Gmr.cs index 0bfd258..8669f64 100644 --- a/Btms.Model/Gvms/Gmr.cs +++ b/Btms.Model/Gvms/Gmr.cs @@ -17,6 +17,7 @@ public partial class Gmr : IMongoIdentifiable, IDataEntity { [JsonIgnore] public string Type { get; set; } = "gmrs"; + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _Etag { get; set; } = default!; [Attr] public DateTime? CreatedSource { get; set; } [Attr] public DateTime Created { get; set; } @@ -40,9 +41,9 @@ public string? StringId // [Attr] public string? LocalId { get; set; } - [Attr] public List AuditEntries { get; set; } = new List(); + [Attr] public List AuditEntries { get; set; } = new(); [Attr] [JsonPropertyName("relationships")] - public GmrRelationships Relationships { get; set; } = new GmrRelationships(); + public GmrRelationships Relationships { get; set; } = new(); } \ No newline at end of file diff --git a/Btms.Model/Ipaffs/ImportNotification.cs b/Btms.Model/Ipaffs/ImportNotification.cs index d4569ef..3c94ae1 100644 --- a/Btms.Model/Ipaffs/ImportNotification.cs +++ b/Btms.Model/Ipaffs/ImportNotification.cs @@ -30,7 +30,9 @@ public virtual string? Id } [ChangeSetIgnore] + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _Etag { get; set; } = default!; + [Attr] public DateTime? CreatedSource { get; set; } [Attr] @@ -55,11 +57,11 @@ public string? StringId // [Attr] public string? LocalId { get; set; } = default!; - [Attr] public List AuditEntries { get; set; } = new List(); + [Attr] public List AuditEntries { get; set; } = new(); [Attr] [JsonPropertyName("relationships")] - public NotificationTdmRelationships Relationships { get; set; } = new NotificationTdmRelationships(); + public NotificationTdmRelationships Relationships { get; set; } = new(); [Attr] public Commodities CommoditiesSummary { get; set; } = default!; @@ -76,6 +78,7 @@ public string? StringId [Attr] [BsonElement("_pointOfEntry")] [ChangeSetIgnore] + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _PointOfEntry { get => PartOne?.PointOfEntry!; @@ -91,6 +94,7 @@ public string _PointOfEntry [Attr] [BsonElement("_pointOfEntryControlPoint")] [ChangeSetIgnore] + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _PointOfEntryControlPoint { get => PartOne?.PointOfEntryControlPoint!; @@ -105,6 +109,7 @@ public string _PointOfEntryControlPoint [BsonElement("_matchReferences")] [ChangeSetIgnore] + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _MatchReference { get @@ -122,7 +127,7 @@ public string _MatchReference public void AddRelationship(TdmRelationshipObject relationship) { - bool linked = false; + var linked = false; Relationships.Movements.Links ??= relationship.Links; var dataItems = relationship.Data.Where(dataItem => @@ -139,13 +144,13 @@ public void AddRelationship(TdmRelationshipObject relationship) if (linked) { - AuditEntries.Add(AuditEntry.CreateLinked(String.Empty, Version.GetValueOrDefault(), UpdatedSource)); + AuditEntries.Add(AuditEntry.CreateLinked(string.Empty, Version.GetValueOrDefault(), UpdatedSource)); } } public void Changed(AuditEntry auditEntry) { - this.AuditEntries.Add(auditEntry); + AuditEntries.Add(auditEntry); } public void Create(string auditId) @@ -153,9 +158,9 @@ public void Create(string auditId) var auditEntry = AuditEntry.CreateCreatedEntry( this, auditId, - this.Version.GetValueOrDefault(), - this.UpdatedSource); - this.Changed(auditEntry); + Version.GetValueOrDefault(), + UpdatedSource); + Changed(auditEntry); } public void Skipped(string auditId, int version) @@ -163,21 +168,21 @@ public void Skipped(string auditId, int version) var auditEntry = AuditEntry.CreateSkippedVersion( auditId, version, - this.UpdatedSource); - this.Changed(auditEntry); + UpdatedSource); + Changed(auditEntry); } public void Update(string auditId, ChangeSet changeSet) { var auditEntry = AuditEntry.CreateUpdated(changeSet, auditId, - this.Version.GetValueOrDefault(), - this.UpdatedSource); - this.Changed(auditEntry); + Version.GetValueOrDefault(), + UpdatedSource); + Changed(auditEntry); } public AuditEntry GetLatestAuditEntry() { - return this.AuditEntries.OrderByDescending(x => x.CreatedLocal).First(); + return AuditEntries.OrderByDescending(x => x.CreatedLocal).First(); } } \ No newline at end of file diff --git a/Btms.Model/MatchIdentifier.cs b/Btms.Model/MatchIdentifier.cs index 5e4a06b..8632436 100644 --- a/Btms.Model/MatchIdentifier.cs +++ b/Btms.Model/MatchIdentifier.cs @@ -1,5 +1,3 @@ -using Btms.Model.Ipaffs; - namespace Btms.Model; public struct MatchIdentifier(string identifier) @@ -55,7 +53,7 @@ public static bool TryFromCds(string reference, out MatchIdentifier matchIdentif { try { - matchIdentifier = MatchIdentifier.FromCds(reference); + matchIdentifier = FromCds(reference); return true; } catch (Exception) diff --git a/Btms.Model/Movement.cs b/Btms.Model/Movement.cs index 26e7bc3..70f2c72 100644 --- a/Btms.Model/Movement.cs +++ b/Btms.Model/Movement.cs @@ -24,9 +24,9 @@ public class Movement : IMongoIdentifiable, IDataEntity, IAuditable [ChangeSetIgnore] public string Type { get; set; } = "movements"; - [Attr] public List ClearanceRequests { get; set; } = default!; + [Attr] public required List ClearanceRequests { get; set; } - [Attr] public List Decisions { get; set; } = default!; + [Attr] public List? Decisions { get; set; } [Attr] public List Items { get; set; } = []; @@ -56,15 +56,17 @@ public class Movement : IMongoIdentifiable, IDataEntity, IAuditable [Attr] [ChangeSetIgnore] - public List AuditEntries { get; set; } = new List(); + public List AuditEntries { get; set; } = new(); [Attr] [JsonPropertyName("relationships")] - public MovementTdmRelationships Relationships { get; set; } = new MovementTdmRelationships(); + public MovementTdmRelationships Relationships { get; set; } = new(); + [BsonElement("_matchReferences")] [ChangeSetIgnore] + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public List _MatchReferences { get @@ -94,7 +96,7 @@ public List _MatchReferences public void AddRelationship(TdmRelationshipObject relationship) { - bool linked = false; + var linked = false; Relationships.Notifications.Links ??= relationship.Links; var dataItems = relationship.Data.Where(dataItem => @@ -114,13 +116,13 @@ public void AddRelationship(TdmRelationshipObject relationship) if (linked) { - AuditEntries.Add(AuditEntry.CreateLinked(String.Empty, this.AuditEntries.FirstOrDefault()?.Version ?? 1, UpdatedSource)); + AuditEntries.Add(AuditEntry.CreateLinked(string.Empty, AuditEntries.FirstOrDefault()?.Version ?? 1, UpdatedSource)); } } public void Update(AuditEntry auditEntry) { - this.AuditEntries.Add(auditEntry); + AuditEntries.Add(auditEntry); matchReferences = []; } @@ -129,7 +131,7 @@ public bool MergeDecision(string path, AlvsClearanceRequest clearanceRequest) var before = this.ToJsonString(); foreach (var item in clearanceRequest.Items!) { - var existingItem = this.Items.Find(x => x.ItemNumber == item.ItemNumber); + var existingItem = Items.Find(x => x.ItemNumber == item.ItemNumber); if (existingItem is not null) { @@ -148,7 +150,7 @@ public bool MergeDecision(string path, AlvsClearanceRequest clearanceRequest) { Decisions ??= new List(); Decisions.Add(clearanceRequest); - this.Update(auditEntry); + Update(auditEntry); } return auditEntry.Diff.Any(); @@ -175,9 +177,10 @@ public string? StringId [Attr] [BsonId] - public string? Id { get; set; } = null!; + public string? Id { get; set; } [ChangeSetIgnore] + // ReSharper disable once InconsistentNaming - want to use Mongo DB convention to indicate none core schema properties public string _Etag { get; set; } = null!; [Attr] @@ -189,6 +192,6 @@ public string? StringId public DateTime Updated { get; set; } public AuditEntry GetLatestAuditEntry() { - return this.AuditEntries.OrderByDescending(x => x.CreatedLocal).First(); + return AuditEntries.OrderByDescending(x => x.CreatedLocal).First(); } } \ No newline at end of file diff --git a/Btms.Model/Relationships/RelationshipDataItem.cs b/Btms.Model/Relationships/RelationshipDataItem.cs index d7b0878..db3e7d9 100644 --- a/Btms.Model/Relationships/RelationshipDataItem.cs +++ b/Btms.Model/Relationships/RelationshipDataItem.cs @@ -6,7 +6,7 @@ namespace Btms.Model.Relationships; public sealed class RelationshipDataItem { - [Attr] public bool? Matched { get; set; } = default!; + [Attr] public bool? Matched { get; set; } [Attr] public string Type { get; set; } = default!; @@ -14,9 +14,9 @@ public sealed class RelationshipDataItem [Attr] public ResourceLink Links { get; set; } = default!; - [Attr] public int? SourceItem { get; set; } = default!; + [Attr] public int? SourceItem { get; set; } - [Attr] public int? DestinationItem { get; set; } = default!; + [Attr] public int? DestinationItem { get; set; } public int? MatchingLevel { get; set; } @@ -43,7 +43,7 @@ public sealed class RelationshipDataItem meta.Add("matchingLevel", MatchingLevel); } - if (!string.IsNullOrEmpty(Links?.Self)) + if (!string.IsNullOrEmpty(Links.Self)) { meta.Add("self", Links.Self); } @@ -51,17 +51,9 @@ public sealed class RelationshipDataItem return meta; } - public static RelationshipDataItem CreateFromNotification(ImportNotification notification, Movement movement, - string matchReference, bool matched = true, string reason = null!) + public static RelationshipDataItem CreateFromNotification(ImportNotification notification, Movement movement, string matchReference, bool matched = true) { - Dictionary additionalInfo = new Dictionary() { { "matchingLevel", "1" } }; - - if (!string.IsNullOrEmpty(reason)) - { - additionalInfo.Add("reason", reason); - } - - return new RelationshipDataItem() + return new RelationshipDataItem { Matched = matched, Type = "notifications", @@ -69,32 +61,24 @@ public static RelationshipDataItem CreateFromNotification(ImportNotification not SourceItem = movement.Items .Find(x => x.Documents!.ToList().Exists(d => d.DocumentReference!.Contains(matchReference))) ?.ItemNumber, - DestinationItem = notification.Commodities?.FirstOrDefault()?.ComplementId, - Links = new ResourceLink() { Self = LinksBuilder.Notification.BuildSelfNotificationLink(notification.Id!) }, + DestinationItem = notification.Commodities.FirstOrDefault()?.ComplementId, + Links = new ResourceLink { Self = LinksBuilder.Notification.BuildSelfNotificationLink(notification.Id!) }, MatchingLevel = 1 }; } - public static RelationshipDataItem CreateFromMovement(ImportNotification notification, Movement movement, - string matchReference, bool matched = true, string reason = null!) + public static RelationshipDataItem CreateFromMovement(ImportNotification notification, Movement movement, string matchReference, bool matched = true) { - Dictionary additionalInfo = new Dictionary() { { "matchingLevel", "1" } }; - - if (!string.IsNullOrEmpty(reason)) - { - additionalInfo.Add("reason", reason); - } - - return new RelationshipDataItem() + return new RelationshipDataItem { Matched = matched, Type = "movements", Id = movement.Id!, - SourceItem = notification?.Commodities?.FirstOrDefault()?.ComplementId, + SourceItem = notification.Commodities.FirstOrDefault()?.ComplementId, DestinationItem = movement.Items .Find(x => x.Documents!.ToList().Exists(d => d.DocumentReference!.Contains(matchReference))) ?.ItemNumber, - Links = new ResourceLink() { Self = LinksBuilder.Movement.BuildRelatedMovementLink(movement.Id!) }, + Links = new ResourceLink { Self = LinksBuilder.Movement.BuildRelatedMovementLink(movement.Id!) }, MatchingLevel = 1 }; } diff --git a/Btms.Model/Relationships/RelationshipLinks.cs b/Btms.Model/Relationships/RelationshipLinks.cs index df6f1ab..0c75652 100644 --- a/Btms.Model/Relationships/RelationshipLinks.cs +++ b/Btms.Model/Relationships/RelationshipLinks.cs @@ -12,7 +12,7 @@ public sealed class RelationshipLinks public static RelationshipLinks CreateForMovement(Movement movement) { - return new RelationshipLinks() + return new RelationshipLinks { Self = LinksBuilder.Movement.BuildSelfMovementLink(movement.Id!), Related = LinksBuilder.Movement.BuildRelatedMovementLink(movement.Id!) @@ -21,7 +21,7 @@ public static RelationshipLinks CreateForMovement(Movement movement) public static RelationshipLinks CreateForNotification(ImportNotification notification) { - return new RelationshipLinks() + return new RelationshipLinks { Self = LinksBuilder.Notification.BuildSelfNotificationLink(notification.Id!), Related = LinksBuilder.Notification.BuildRelatedMovementLink(notification.Id!) diff --git a/Btms.Model/Relationships/TdmRelationshipObject.cs b/Btms.Model/Relationships/TdmRelationshipObject.cs index aea6d22..5f5cd4f 100644 --- a/Btms.Model/Relationships/TdmRelationshipObject.cs +++ b/Btms.Model/Relationships/TdmRelationshipObject.cs @@ -4,9 +4,9 @@ namespace Btms.Model.Relationships; public sealed class TdmRelationshipObject { - [Attr] public bool? Matched { get; set; } = default!; + [Attr] public bool Matched { get; set; } - [Attr] public RelationshipLinks Links { get; set; } = default!; + [Attr] public RelationshipLinks? Links { get; set; } [Attr] public List Data { get; set; } = []; diff --git a/Btms.SensitiveData.Tests/SensitiveDataSerializerTests.cs b/Btms.SensitiveData.Tests/SensitiveDataSerializerTests.cs index 0eee8c5..a052987 100644 --- a/Btms.SensitiveData.Tests/SensitiveDataSerializerTests.cs +++ b/Btms.SensitiveData.Tests/SensitiveDataSerializerTests.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using Btms.SensitiveData; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; @@ -13,16 +12,15 @@ public class SensitiveDataSerializerTests public void WhenDoNotIncludeSensitiveData_ThenDataShouldBeRedacted() { // ARRANGE - SensitiveDataOptions options = new SensitiveDataOptions { Getter = s => "TestRedacted", Include = false }; + var options = new SensitiveDataOptions { Getter = _ => "TestRedacted", Include = false }; var serializer = new SensitiveDataSerializer(Options.Create(options), NullLogger.Instance); - var simpleClass = new SimpleClass() + var simpleClass = new SimpleClass { SimpleStringOne = "Test String One", SimpleStringTwo = "Test String Two", - SimpleStringArrayOne = - new[] { "Test String Array One Item One", "Test String Array One Item Two" }, - SimpleStringArrayTwo = new[] { "Test String Array Two Item One", "Test String Array Two Item Two" } + SimpleStringArrayOne = ["Test String Array One Item One", "Test String Array One Item Two"], + SimpleStringArrayTwo = ["Test String Array Two Item One", "Test String Array Two Item Two"] }; var json = JsonSerializer.Serialize(simpleClass); @@ -43,16 +41,16 @@ public void WhenDoNotIncludeSensitiveData_ThenDataShouldBeRedacted() public void WhenIncludeSensitiveData_ThenDataShouldNotBeRedacted() { // ARRANGE - SensitiveDataOptions options = new SensitiveDataOptions { Getter = s => "TestRedacted", Include = true }; + var options = new SensitiveDataOptions { Getter = _ => "TestRedacted", Include = true }; var serializer = new SensitiveDataSerializer(Options.Create(options), NullLogger.Instance); - var simpleClass = new SimpleClass() + var simpleClass = new SimpleClass { SimpleStringOne = "Test String One", SimpleStringTwo = "Test String Two", SimpleStringArrayOne = - new[] { "Test String Array One Item One", "Test String Array One Item Two" }, - SimpleStringArrayTwo = new[] { "Test String Array Two Item One", "Test String Array Two Item Two" } + ["Test String Array One Item One", "Test String Array One Item Two"], + SimpleStringArrayTwo = ["Test String Array Two Item One", "Test String Array Two Item Two"] }; var json = JsonSerializer.Serialize(simpleClass); @@ -73,25 +71,25 @@ public void WhenIncludeSensitiveData_ThenDataShouldNotBeRedacted() public void WhenDoNotIncludeSensitiveData_AndRequestForRawJson_ThenDataShouldBeRedacted() { // ARRANGE - SensitiveDataOptions options = new SensitiveDataOptions { Getter = s => "TestRedacted", Include = false }; + var options = new SensitiveDataOptions { Getter = _ => "TestRedacted", Include = false }; var serializer = new SensitiveDataSerializer(Options.Create(options), NullLogger.Instance); - var simpleClass = new SimpleClass() + var simpleClass = new SimpleClass { SimpleStringOne = "Test String One", SimpleStringTwo = "Test String Two", SimpleStringArrayOne = - new[] { "Test String Array One Item One", "Test String Array One Item Two" }, - SimpleStringArrayTwo = new[] { "Test String Array Two Item One", "Test String Array Two Item Two" } + ["Test String Array One Item One", "Test String Array One Item Two"], + SimpleStringArrayTwo = ["Test String Array Two Item One", "Test String Array Two Item Two"] }; - var json = JsonSerializer.Serialize(simpleClass, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase}); + var json = JsonSerializer.Serialize(simpleClass, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase}); // ACT var result = serializer.RedactRawJson(json, typeof(SimpleClass)); // ASSERT - var resultClass = JsonSerializer.Deserialize(result, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); + var resultClass = JsonSerializer.Deserialize(result, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); resultClass?.SimpleStringOne.Should().Be("TestRedacted"); resultClass?.SimpleStringTwo.Should().Be("Test String Two"); resultClass?.SimpleStringArrayOne[0].Should().Be("TestRedacted"); diff --git a/Btms.SensitiveData.Tests/SimpleClass.cs b/Btms.SensitiveData.Tests/SimpleClass.cs index 3ba0813..2a888e9 100644 --- a/Btms.SensitiveData.Tests/SimpleClass.cs +++ b/Btms.SensitiveData.Tests/SimpleClass.cs @@ -1,15 +1,12 @@ -using Btms.SensitiveData; +namespace Btms.SensitiveData.Tests; -namespace Btms.SensitiveData.Tests +public class SimpleClass { - public class SimpleClass - { - [SensitiveData] public string SimpleStringOne { get; set; } = null!; + [SensitiveData] public string SimpleStringOne { get; set; } = null!; - public string SimpleStringTwo { get; set; } = null!; + public string SimpleStringTwo { get; set; } = null!; - [SensitiveData] public string[] SimpleStringArrayOne { get; set; } = null!; + [SensitiveData] public string[] SimpleStringArrayOne { get; set; } = null!; - public string[] SimpleStringArrayTwo { get; set; } = null!; - } + public string[] SimpleStringArrayTwo { get; set; } = null!; } \ No newline at end of file diff --git a/Btms.SensitiveData/SensitiveDataOptions.cs b/Btms.SensitiveData/SensitiveDataOptions.cs index 0dcf7c7..28534e1 100644 --- a/Btms.SensitiveData/SensitiveDataOptions.cs +++ b/Btms.SensitiveData/SensitiveDataOptions.cs @@ -10,12 +10,12 @@ public class SensitiveDataOptions public Func Getter { get; set; } = Sha256; - static string Sha256(string input) + private static string Sha256(string input) { var crypt = SHA256.Create(); - StringBuilder hash = new StringBuilder(); - byte[] crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(input)); - foreach (byte theByte in crypto) + var hash = new StringBuilder(); + var crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(input)); + foreach (var theByte in crypto) { hash.Append(theByte.ToString("x2")); } diff --git a/Btms.SensitiveData/SensitiveDataSerializer.cs b/Btms.SensitiveData/SensitiveDataSerializer.cs index 4189d11..ffd3aef 100644 --- a/Btms.SensitiveData/SensitiveDataSerializer.cs +++ b/Btms.SensitiveData/SensitiveDataSerializer.cs @@ -12,19 +12,19 @@ namespace Btms.SensitiveData; public class SensitiveDataSerializer(IOptions options, ILogger logger) : ISensitiveDataSerializer { - private readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions() + private readonly JsonSerializerOptions jsonOptions = new() { TypeInfoResolver = new SensitiveDataTypeInfoResolver(options.Value), PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString }; - public T Deserialize(string json, Action optionsOverride = null!) + public T Deserialize(string json, Action? optionsOverride = null) { - JsonSerializerOptions newOptions = jsonOptions; + var newOptions = jsonOptions; if (optionsOverride is not null) { - newOptions = new JsonSerializerOptions() + newOptions = new JsonSerializerOptions { TypeInfoResolver = new SensitiveDataTypeInfoResolver(options.Value), PropertyNameCaseInsensitive = true, diff --git a/Btms.SensitiveData/SensitiveDataTypeInfoResolver.cs b/Btms.SensitiveData/SensitiveDataTypeInfoResolver.cs index 7f4c212..e156b61 100644 --- a/Btms.SensitiveData/SensitiveDataTypeInfoResolver.cs +++ b/Btms.SensitiveData/SensitiveDataTypeInfoResolver.cs @@ -7,7 +7,7 @@ public class SensitiveDataTypeInfoResolver(SensitiveDataOptions sensitiveDataOpt { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { - JsonTypeInfo typeInfo = base.GetTypeInfo(type, options); + var typeInfo = base.GetTypeInfo(type, options); if (typeInfo.Kind == JsonTypeInfoKind.Object) { diff --git a/Btms.SensitiveData/SensitiveFieldsProvider.cs b/Btms.SensitiveData/SensitiveFieldsProvider.cs index 1589aca..b43d049 100644 --- a/Btms.SensitiveData/SensitiveFieldsProvider.cs +++ b/Btms.SensitiveData/SensitiveFieldsProvider.cs @@ -6,13 +6,13 @@ namespace Btms.SensitiveData; public static class SensitiveFieldsProvider { - private static Dictionary> cache = new(); - private static readonly object cacheLock = new (); + private static Dictionary> _cache = new(); + private static readonly object CacheLock = new (); public static List Get() { - lock (cacheLock) + lock (CacheLock) { - if (cache.TryGetValue(typeof(T), out var value)) + if (_cache.TryGetValue(typeof(T), out var value)) { return value; } @@ -20,7 +20,7 @@ public static List Get() var type = typeof(T); var list = GetSensitiveFields(string.Empty, type); - cache.Add(typeof(T), list); + _cache.Add(typeof(T), list); return list; } @@ -29,15 +29,15 @@ public static List Get() public static List Get(Type type) { - lock (cacheLock) + lock (CacheLock) { - if (cache.TryGetValue(type, out var value)) + if (_cache.TryGetValue(type, out var value)) { return value; } var list = GetSensitiveFields(string.Empty, type); - cache.Add(type, list); + _cache.Add(type, list); return list; } @@ -61,11 +61,11 @@ private static List GetSensitiveFields(string root, Type type) } else { - Type elementType = GetElementType(property)!; + var elementType = GetElementType(property); if (elementType != null && elementType.Namespace != "System") { - list.AddRange(GetSensitiveFields($"{currentPath}", elementType!)); + list.AddRange(GetSensitiveFields($"{currentPath}", elementType)); } } } diff --git a/Btms.SensitiveData/StringArraySensitiveDataRedactedConverter.cs b/Btms.SensitiveData/StringArraySensitiveDataRedactedConverter.cs index f26f6ca..14984fd 100644 --- a/Btms.SensitiveData/StringArraySensitiveDataRedactedConverter.cs +++ b/Btms.SensitiveData/StringArraySensitiveDataRedactedConverter.cs @@ -30,7 +30,7 @@ public override string[] Read(ref Utf8JsonReader reader, Type typeToConvert, Jso throw new JsonException(); } - string? value = sensitiveDataOptions.Getter(reader.GetString()!); + var value = sensitiveDataOptions.Getter(reader.GetString()!); items.Add(value); } diff --git a/Btms.SyncJob/Extensions/ServiceCollectionExtensions.cs b/Btms.SyncJob/Extensions/ServiceCollectionExtensions.cs index c6aa763..aa14c90 100644 --- a/Btms.SyncJob/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.SyncJob/Extensions/ServiceCollectionExtensions.cs @@ -1,14 +1,13 @@ using Microsoft.Extensions.DependencyInjection; -namespace Btms.SyncJob.Extensions +namespace Btms.SyncJob.Extensions; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + public static IServiceCollection AddSyncJob(this IServiceCollection services) { - public static IServiceCollection AddSyncJob(this IServiceCollection services) - { - services.AddSingleton(); + services.AddSingleton(); - return services; - } + return services; } } \ No newline at end of file diff --git a/Btms.SyncJob/SyncJobStore.cs b/Btms.SyncJob/SyncJobStore.cs index e11c4cd..62fc993 100644 --- a/Btms.SyncJob/SyncJobStore.cs +++ b/Btms.SyncJob/SyncJobStore.cs @@ -1,27 +1,26 @@ -namespace Btms.SyncJob +namespace Btms.SyncJob; + +public class SyncJobStore : ISyncJobStore { - public class SyncJobStore : ISyncJobStore + private readonly IDictionary jobs = new Dictionary(); + public SyncJob? GetJob(Guid id) + { + return jobs.TryGetValue(id, out var job) ? job : null; + } + public List GetJobs() { - private readonly IDictionary jobs = new Dictionary(); - public SyncJob? GetJob(Guid id) - { - return jobs.TryGetValue(id, out var job) ? job : null; - } - public List GetJobs() - { - return jobs.Values.ToList(); - } + return jobs.Values.ToList(); + } - public SyncJob CreateJob(Guid id, string timespan, string resource) - { - var syncJob = new SyncJob(id, timespan, resource); - jobs[id] = syncJob; - return syncJob; - } + public SyncJob CreateJob(Guid id, string timespan, string resource) + { + var syncJob = new SyncJob(id, timespan, resource); + jobs[id] = syncJob; + return syncJob; + } - public void ClearSyncJobs() - { - jobs.Clear(); - } + public void ClearSyncJobs() + { + jobs.Clear(); } -} +} \ No newline at end of file diff --git a/Btms.Types.Alvs.Mapping.V1.Tests/CheckMapperTests.cs b/Btms.Types.Alvs.Mapping.V1.Tests/CheckMapperTests.cs index eb5c4af..738648e 100644 --- a/Btms.Types.Alvs.Mapping.V1.Tests/CheckMapperTests.cs +++ b/Btms.Types.Alvs.Mapping.V1.Tests/CheckMapperTests.cs @@ -1,6 +1,4 @@ using AutoBogus; -using Btms.Types.Alvs; -using Btms.Types.Alvs.Mapping; using FluentAssertions; using Xunit; diff --git a/Btms.Types.Alvs.Mapping.V1.Tests/DocumentMapperTests.cs b/Btms.Types.Alvs.Mapping.V1.Tests/DocumentMapperTests.cs index 3fed17e..95ee060 100644 --- a/Btms.Types.Alvs.Mapping.V1.Tests/DocumentMapperTests.cs +++ b/Btms.Types.Alvs.Mapping.V1.Tests/DocumentMapperTests.cs @@ -1,6 +1,4 @@ using AutoBogus; -using Btms.Types.Alvs; -using Btms.Types.Alvs.Mapping; using FluentAssertions; using Xunit; diff --git a/Btms.Types.Alvs.Mapping.V1.Tests/HeaderMapperTests.cs b/Btms.Types.Alvs.Mapping.V1.Tests/HeaderMapperTests.cs index 1d4a5d2..741f91d 100644 --- a/Btms.Types.Alvs.Mapping.V1.Tests/HeaderMapperTests.cs +++ b/Btms.Types.Alvs.Mapping.V1.Tests/HeaderMapperTests.cs @@ -1,35 +1,32 @@ using AutoBogus; -using Btms.Types.Alvs; -using Btms.Types.Alvs.Mapping; using FluentAssertions; using Xunit; -namespace Btms.Types.Alvs.Mapping.V1.Tests +namespace Btms.Types.Alvs.Mapping.V1.Tests; + +public class HeaderMapperTests { - public class HeaderMapperTests + [Fact] + public void SimpleMapperTest() { - [Fact] - public void SimpleMapperTest() - { - var faker = AutoFaker.Create(); - var sourceHeader = faker.Generate
(); + var faker = AutoFaker.Create(); + var sourceHeader = faker.Generate
(); - var mappedHeader = HeaderMapper.Map(sourceHeader); + var mappedHeader = HeaderMapper.Map(sourceHeader); - mappedHeader.EntryReference.Should().Be(sourceHeader.EntryReference); - mappedHeader.EntryVersionNumber.Should().Be(sourceHeader.EntryVersionNumber); - mappedHeader.PreviousVersionNumber.Should().Be(sourceHeader.PreviousVersionNumber); - mappedHeader.DeclarationUcr.Should().Be(sourceHeader.DeclarationUcr); - mappedHeader.DeclarationPartNumber.Should().Be(sourceHeader.DeclarationPartNumber); - mappedHeader.DeclarationType.Should().Be(sourceHeader.DeclarationType); - mappedHeader.ArrivesAt.Should().Be(sourceHeader.ArrivalDateTime); - mappedHeader.SubmitterTurn.Should().Be(sourceHeader.SubmitterTurn); - mappedHeader.DeclarantId.Should().Be(sourceHeader.DeclarantId); + mappedHeader.EntryReference.Should().Be(sourceHeader.EntryReference); + mappedHeader.EntryVersionNumber.Should().Be(sourceHeader.EntryVersionNumber); + mappedHeader.PreviousVersionNumber.Should().Be(sourceHeader.PreviousVersionNumber); + mappedHeader.DeclarationUcr.Should().Be(sourceHeader.DeclarationUcr); + mappedHeader.DeclarationPartNumber.Should().Be(sourceHeader.DeclarationPartNumber); + mappedHeader.DeclarationType.Should().Be(sourceHeader.DeclarationType); + mappedHeader.ArrivesAt.Should().Be(sourceHeader.ArrivalDateTime); + mappedHeader.SubmitterTurn.Should().Be(sourceHeader.SubmitterTurn); + mappedHeader.DeclarantId.Should().Be(sourceHeader.DeclarantId); - mappedHeader.DeclarantName.Should().Be(sourceHeader.DeclarantName); - mappedHeader.DispatchCountryCode.Should().Be(sourceHeader.DispatchCountryCode); - mappedHeader.GoodsLocationCode.Should().Be(sourceHeader.GoodsLocationCode); - mappedHeader.MasterUcr.Should().Be(sourceHeader.MasterUcr); - } + mappedHeader.DeclarantName.Should().Be(sourceHeader.DeclarantName); + mappedHeader.DispatchCountryCode.Should().Be(sourceHeader.DispatchCountryCode); + mappedHeader.GoodsLocationCode.Should().Be(sourceHeader.GoodsLocationCode); + mappedHeader.MasterUcr.Should().Be(sourceHeader.MasterUcr); } } \ No newline at end of file diff --git a/Btms.Types.Alvs.Mapping.V1.Tests/ItemsMapperTests.cs b/Btms.Types.Alvs.Mapping.V1.Tests/ItemsMapperTests.cs index ed21ff8..b1cdb39 100644 --- a/Btms.Types.Alvs.Mapping.V1.Tests/ItemsMapperTests.cs +++ b/Btms.Types.Alvs.Mapping.V1.Tests/ItemsMapperTests.cs @@ -1,6 +1,4 @@ using AutoBogus; -using Btms.Types.Alvs; -using Btms.Types.Alvs.Mapping; using FluentAssertions; using Xunit; diff --git a/Btms.Types.Alvs.Mapping.V1.Tests/ServiceHeaderMapperTests.cs b/Btms.Types.Alvs.Mapping.V1.Tests/ServiceHeaderMapperTests.cs index 3a2fb20..02ed7f4 100644 --- a/Btms.Types.Alvs.Mapping.V1.Tests/ServiceHeaderMapperTests.cs +++ b/Btms.Types.Alvs.Mapping.V1.Tests/ServiceHeaderMapperTests.cs @@ -1,6 +1,4 @@ using AutoBogus; -using Btms.Types.Alvs; -using Btms.Types.Alvs.Mapping; using FluentAssertions; using Xunit; diff --git a/Btms.Types.Alvs.V1/AlvsClearanceRequest.g.cs b/Btms.Types.Alvs.V1/AlvsClearanceRequest.g.cs index 8394ecf..629eda7 100644 --- a/Btms.Types.Alvs.V1/AlvsClearanceRequest.g.cs +++ b/Btms.Types.Alvs.V1/AlvsClearanceRequest.g.cs @@ -23,21 +23,21 @@ public partial class AlvsClearanceRequest // /// /// - /// [JsonPropertyName("serviceHeader")] public ServiceHeader? ServiceHeader { get; set; } /// /// - /// [JsonPropertyName("header")] public Header? Header { get; set; } /// /// - /// [JsonPropertyName("items")] public Items[]? Items { get; set; } diff --git a/Btms.Types.Alvs.V1/AlvsClearanceRequestPost.g.cs b/Btms.Types.Alvs.V1/AlvsClearanceRequestPost.g.cs index 606915a..0bb5533 100644 --- a/Btms.Types.Alvs.V1/AlvsClearanceRequestPost.g.cs +++ b/Btms.Types.Alvs.V1/AlvsClearanceRequestPost.g.cs @@ -23,35 +23,35 @@ public partial class AlvsClearanceRequestPost // /// /// - /// [JsonPropertyName("xmlSchemaVersion")] public string? XmlSchemaVersion { get; set; } /// /// - /// [JsonPropertyName("userIdentification")] public string? UserIdentification { get; set; } /// /// - /// [JsonPropertyName("userPassword")] public string? UserPassword { get; set; } /// /// - /// [JsonPropertyName("sendingDate")] public DateTime? SendingDate { get; set; } /// /// - /// [JsonPropertyName("alvsClearanceRequest")] public AlvsClearanceRequest? AlvsClearanceRequest { get; set; } diff --git a/Btms.Types.Alvs.V1/AlvsClearanceRequestPostResult.g.cs b/Btms.Types.Alvs.V1/AlvsClearanceRequestPostResult.g.cs index 03d0650..8cee8af 100644 --- a/Btms.Types.Alvs.V1/AlvsClearanceRequestPostResult.g.cs +++ b/Btms.Types.Alvs.V1/AlvsClearanceRequestPostResult.g.cs @@ -23,28 +23,28 @@ public partial class AlvsClearanceRequestPostResult // /// /// - /// [JsonPropertyName("xmlSchemaVersion")] public string? XmlSchemaVersion { get; set; } /// /// - /// [JsonPropertyName("sendingDate")] public DateTime? SendingDate { get; set; } /// /// - /// [JsonPropertyName("operationCode")] public int? OperationCode { get; set; } /// /// - /// [JsonPropertyName("requestIdentifier")] public string? RequestIdentifier { get; set; } diff --git a/Btms.Types.Alvs.V1/Check.cs b/Btms.Types.Alvs.V1/Check.cs index 680e108..abd5329 100644 --- a/Btms.Types.Alvs.V1/Check.cs +++ b/Btms.Types.Alvs.V1/Check.cs @@ -22,14 +22,14 @@ public partial class Check // { /// /// - /// [JsonPropertyName("decisionCode")] public string? DecisionCode { get; set; } /// /// - /// [JsonPropertyName("decisionsValidUntil")] public DateTime? DecisionsValidUntil { get; set; } diff --git a/Btms.Types.Alvs.V1/Check.g.cs b/Btms.Types.Alvs.V1/Check.g.cs index e40b389..0727788 100644 --- a/Btms.Types.Alvs.V1/Check.g.cs +++ b/Btms.Types.Alvs.V1/Check.g.cs @@ -23,14 +23,14 @@ public partial class Check // /// /// - /// [JsonPropertyName("checkCode")] public string? CheckCode { get; set; } /// /// - /// [JsonPropertyName("departmentCode")] public string? DepartmentCode { get; set; } diff --git a/Btms.Types.Alvs.V1/ClearanceRequestExtensions.cs b/Btms.Types.Alvs.V1/ClearanceRequestExtensions.cs index 72900eb..0c85cc8 100644 --- a/Btms.Types.Alvs.V1/ClearanceRequestExtensions.cs +++ b/Btms.Types.Alvs.V1/ClearanceRequestExtensions.cs @@ -26,20 +26,20 @@ public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, Jso } } - var s_epoch = DateTime.UnixEpoch; + var epoch = DateTime.UnixEpoch; // 1723127967 - DEV // 1712851200000 - SND if (number > 10000000000) { - return s_epoch.AddMilliseconds(number); + return epoch.AddMilliseconds(number); } else if (number > 0) { - return s_epoch.AddSeconds(number); + return epoch.AddSeconds(number); } - return s_epoch; + return epoch; } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) diff --git a/Btms.Types.Alvs.V1/Document.g.cs b/Btms.Types.Alvs.V1/Document.g.cs index 7b9b002..d12e3ed 100644 --- a/Btms.Types.Alvs.V1/Document.g.cs +++ b/Btms.Types.Alvs.V1/Document.g.cs @@ -23,35 +23,35 @@ public partial class Document // /// /// - /// [JsonPropertyName("documentCode")] public string? DocumentCode { get; set; } /// /// - /// [JsonPropertyName("documentReference")] public string? DocumentReference { get; set; } /// /// - /// [JsonPropertyName("documentStatus")] public string? DocumentStatus { get; set; } /// /// - /// [JsonPropertyName("documentControl")] public string? DocumentControl { get; set; } /// /// - /// [JsonPropertyName("documentQuantity")] public decimal? DocumentQuantity { get; set; } diff --git a/Btms.Types.Alvs.V1/Header.g.cs b/Btms.Types.Alvs.V1/Header.g.cs index 037eddf..51a49ce 100644 --- a/Btms.Types.Alvs.V1/Header.g.cs +++ b/Btms.Types.Alvs.V1/Header.g.cs @@ -24,49 +24,49 @@ public partial class Header // /// /// - /// [JsonPropertyName("entryReference")] public string? EntryReference { get; set; } /// /// - /// [JsonPropertyName("entryVersionNumber")] public int? EntryVersionNumber { get; set; } /// /// - /// [JsonPropertyName("previousVersionNumber")] public int? PreviousVersionNumber { get; set; } /// /// - /// [JsonPropertyName("declarationUCR")] public string? DeclarationUcr { get; set; } /// /// - /// [JsonPropertyName("declarationPartNumber")] public string? DeclarationPartNumber { get; set; } /// /// - /// [JsonPropertyName("declarationType")] public string? DeclarationType { get; set; } /// /// - /// [JsonPropertyName("arrivalDateTime")] [JsonConverter(typeof(DateTimeConverterUsingDateTimeParse))] public DateTime? ArrivalDateTime { get; set; } @@ -74,42 +74,42 @@ public partial class Header // /// /// - /// [JsonPropertyName("submitterTURN")] public string? SubmitterTurn { get; set; } /// /// - /// [JsonPropertyName("declarantId")] public string? DeclarantId { get; set; } /// /// - /// [JsonPropertyName("declarantName")] public string? DeclarantName { get; set; } /// /// - /// [JsonPropertyName("dispatchCountryCode")] public string? DispatchCountryCode { get; set; } /// /// - /// [JsonPropertyName("goodsLocationCode")] public string? GoodsLocationCode { get; set; } /// /// - /// [JsonPropertyName("masterUCR")] public string? MasterUcr { get; set; } diff --git a/Btms.Types.Alvs.V1/Items.g.cs b/Btms.Types.Alvs.V1/Items.g.cs index 1d98120..a26b677 100644 --- a/Btms.Types.Alvs.V1/Items.g.cs +++ b/Btms.Types.Alvs.V1/Items.g.cs @@ -23,84 +23,84 @@ public partial class Items // /// /// - /// [JsonPropertyName("itemNumber")] public int? ItemNumber { get; set; } /// /// - /// [JsonPropertyName("customsProcedureCode")] public string? CustomsProcedureCode { get; set; } /// /// - /// [JsonPropertyName("taricCommodityCode")] public string? TaricCommodityCode { get; set; } /// /// - /// [JsonPropertyName("goodsDescription")] public string? GoodsDescription { get; set; } /// /// - /// [JsonPropertyName("consigneeId")] public string? ConsigneeId { get; set; } /// /// - /// [JsonPropertyName("consigneeName")] public string? ConsigneeName { get; set; } /// /// - /// [JsonPropertyName("itemNetMass")] public decimal? ItemNetMass { get; set; } /// /// - /// [JsonPropertyName("itemSupplementaryUnits")] public decimal? ItemSupplementaryUnits { get; set; } /// /// - /// [JsonPropertyName("itemThirdQuantity")] public decimal? ItemThirdQuantity { get; set; } /// /// - /// [JsonPropertyName("itemOriginCountryCode")] public string? ItemOriginCountryCode { get; set; } /// /// - /// [JsonPropertyName("documents")] public Document[]? Documents { get; set; } /// /// - /// [JsonPropertyName("checks")] public Check[]? Checks { get; set; } diff --git a/Btms.Types.Alvs.V1/ServiceHeader.g.cs b/Btms.Types.Alvs.V1/ServiceHeader.g.cs index 128f8ae..a98e2e5 100644 --- a/Btms.Types.Alvs.V1/ServiceHeader.g.cs +++ b/Btms.Types.Alvs.V1/ServiceHeader.g.cs @@ -24,28 +24,28 @@ public partial class ServiceHeader // /// /// - /// [JsonPropertyName("sourceSystem")] public string? SourceSystem { get; set; } /// /// - /// [JsonPropertyName("destinationSystem")] public string? DestinationSystem { get; set; } /// /// - /// [JsonPropertyName("correlationId")] public string? CorrelationId { get; set; } /// /// - /// [JsonPropertyName("serviceCallTimestamp")] [JsonConverter(typeof(DateTimeConverterUsingDateTimeParse))] public DateTime? ServiceCallTimestamp { get; set; } diff --git a/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs b/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs index 338ef41..f543d95 100644 --- a/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs +++ b/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs @@ -5,7 +5,7 @@ namespace Btms.Types.Gvms.Mapping; public static class GrmWithTransformMapper { - public static Btms.Model.Gvms.Gmr MapWithTransform(Btms.Types.Gvms.Gmr from) + public static Btms.Model.Gvms.Gmr MapWithTransform(Gmr? from) { if (from is null) { @@ -22,14 +22,14 @@ private static void Map(Gmr from, Btms.Model.Gvms.Gmr to) to.CreatedSource = from.UpdatedSource; if (from.Declarations?.Customs is not null) { - to.Relationships.Customs = new TdmRelationshipObject() + to.Relationships.Customs = new TdmRelationshipObject { - Links = new RelationshipLinks() + Links = new RelationshipLinks { Self = LinksBuilder.Gmr.BuildSelfRelationshipCustomsLink(":id"), Related = LinksBuilder.Gmr.BuildRelatedCustomsLink(":id"), }, - Data = from.Declarations.Customs.Select(x => new RelationshipDataItem() + Data = from.Declarations.Customs.Select(x => new RelationshipDataItem { Id = x.Id!, Type = "import-notifications" @@ -39,14 +39,14 @@ private static void Map(Gmr from, Btms.Model.Gvms.Gmr to) if (from.Declarations?.Transits is not null) { - to.Relationships.Transits = new TdmRelationshipObject() + to.Relationships.Transits = new TdmRelationshipObject { - Links = new RelationshipLinks() + Links = new RelationshipLinks { Self = LinksBuilder.Gmr.BuildSelfRelationshipTransitsLink(":id"), Related = LinksBuilder.Gmr.BuildRelatedTransitLink(":id"), }, - Data = from.Declarations.Transits.Select(x => new RelationshipDataItem() + Data = from.Declarations.Transits.Select(x => new RelationshipDataItem { Id = x.Id!, Type = "movement" diff --git a/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs b/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs index 1399ed2..6275fc8 100644 --- a/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs +++ b/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs @@ -1,21 +1,20 @@ -namespace Btms.Types.Ipaffs.Mapping +namespace Btms.Types.Ipaffs.Mapping; + +public static class DictionaryMapper { - public static class DictionaryMapper + public static IDictionary Map(IDictionary? from) { - public static IDictionary Map(IDictionary? from) + if (from == null) { - if (from == null) - { - return default!; - } - - var dic = new Dictionary(); - foreach (var item in from) - { - dic.Add(item.Key, item.Value); - } + return default!; + } - return dic; + var dic = new Dictionary(); + foreach (var item in from) + { + dic.Add(item.Key, item.Value); } + + return dic; } } \ No newline at end of file diff --git a/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs b/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs index a19f3e4..9f5cc08 100644 --- a/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs +++ b/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs @@ -2,7 +2,7 @@ namespace Btms.Types.Ipaffs.Mapping; public static class ImportNotificationWithTransformMapper { - public static Btms.Model.Ipaffs.ImportNotification MapWithTransform(this Types.Ipaffs.ImportNotification from) + public static Btms.Model.Ipaffs.ImportNotification MapWithTransform(this ImportNotification? from) { if (from is null) { @@ -21,13 +21,13 @@ private static string FromSnakeCase(this string input) return "netWeight"; } - var pascal = input.Split(new[] { "_" }, StringSplitOptions.RemoveEmptyEntries) + var pascal = input.Split(["_"], StringSplitOptions.RemoveEmptyEntries) .Select(s => char.ToUpperInvariant(s[0]) + s.Substring(1, s.Length - 1)) .Aggregate(string.Empty, (s1, s2) => s1 + s2); return char.ToLower(pascal[0]) + pascal[1..]; } - private static IDictionary FromSnakeCase(this IDictionary input) + private static IDictionary FromSnakeCase(this IDictionary? input) { if (input == null) { @@ -41,15 +41,15 @@ private static IDictionary FromSnakeCase(this IDictionary value, JsonSerializerOptions options) { - var list = value.Select(x => new KeyDataPair() { Key = x.Key, Data = x.Value?.ToString() }); + var list = value.Select(x => new KeyDataPair { Key = x.Key, Data = x.Value?.ToString() }); JsonSerializer.Serialize(writer, list, options); } diff --git a/TestDataGenerator/ClearanceRequestBuilder.cs b/TestDataGenerator/ClearanceRequestBuilder.cs index c51cac5..0f0d441 100644 --- a/TestDataGenerator/ClearanceRequestBuilder.cs +++ b/TestDataGenerator/ClearanceRequestBuilder.cs @@ -10,7 +10,7 @@ public class ClearanceRequestBuilder(string file) : ClearanceRequestBuilder : BuilderBase> where T : AlvsClearanceRequest, new() { - private ClearanceRequestBuilder() : base() + private ClearanceRequestBuilder() { } @@ -52,8 +52,8 @@ public ClearanceRequestBuilder WithEntryDate(DateTime entryDate) public ClearanceRequestBuilder WithArrivalDateTimeOffset(DateOnly? date, TimeOnly? time, int maxHoursOffset = 12, int maxMinsOffset = 30) { - DateOnly d = date ?? DateTime.Today.ToDate(); - TimeOnly t = time ?? DateTime.Now.ToTime(); + var d = date ?? DateTime.Today.ToDate(); + var t = time ?? DateTime.Now.ToTime(); var hoursOffset = CreateRandomInt(maxHoursOffset * -1, maxHoursOffset); var minsOffset = CreateRandomInt(maxMinsOffset * -1, maxMinsOffset); diff --git a/TestDataGenerator/Generator.cs b/TestDataGenerator/Generator.cs index 17cc4c1..319c35c 100644 --- a/TestDataGenerator/Generator.cs +++ b/TestDataGenerator/Generator.cs @@ -16,11 +16,11 @@ internal async Task Cleardown(string rootPath) public async Task Generate(int scenario, ScenarioConfig config, string rootPath) { - int days = config.CreationDateRange; - int count = config.Count; - ScenarioGenerator generator = config.Generator; + var days = config.CreationDateRange; + var count = config.Count; + var generator = config.Generator; - logger.LogInformation("Generating {Count}x{Days} {Generator}.", count, days, generator); + logger.LogInformation("Generating {Count}x{Days} {@Generator}", count, days, generator); for (var d = -days + 1; d <= 0; d++) { diff --git a/TestDataGenerator/Helpers/BuilderExtensions.cs b/TestDataGenerator/Helpers/BuilderExtensions.cs index ad0dc2e..bb8f6fc 100644 --- a/TestDataGenerator/Helpers/BuilderExtensions.cs +++ b/TestDataGenerator/Helpers/BuilderExtensions.cs @@ -1,6 +1,5 @@ using Btms.BlobService; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using TestDataGenerator.Scenarios; diff --git a/TestDataGenerator/ImportNotificationBuilder.cs b/TestDataGenerator/ImportNotificationBuilder.cs index d052f83..a3a8514 100644 --- a/TestDataGenerator/ImportNotificationBuilder.cs +++ b/TestDataGenerator/ImportNotificationBuilder.cs @@ -1,6 +1,5 @@ using Btms.Common.Extensions; using Btms.Types.Ipaffs; -using Json.Patch; using TestDataGenerator.Helpers; namespace TestDataGenerator; @@ -31,7 +30,7 @@ public static ImportNotificationBuilder Default() public class ImportNotificationBuilder : BuilderBase> where T : ImportNotification, new() { - protected ImportNotificationBuilder() : base() + protected ImportNotificationBuilder() { } diff --git a/TestDataGenerator/Program.cs b/TestDataGenerator/Program.cs index 97ef1a3..c35f996 100644 --- a/TestDataGenerator/Program.cs +++ b/TestDataGenerator/Program.cs @@ -1,5 +1,3 @@ -using Btms.BlobService; -using Btms.Common.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -7,12 +5,11 @@ using TestDataGenerator.Config; using TestDataGenerator.Scenarios; using Btms.BlobService.Extensions; -using Microsoft.Extensions.Options; using TestDataGenerator.Helpers; namespace TestDataGenerator; -class Program +internal class Program { private static async Task Main(string[] args) { @@ -139,7 +136,7 @@ private static async Task Main(string[] args) foreach (var dataset in setsToRun) { - logger.LogInformation("{scenariosCount} scenario(s) configured", dataset.Scenarios.Count()); + logger.LogInformation("{ScenariosCount} scenario(s) configured", dataset.Scenarios.Count()); await generator.Cleardown(dataset.RootPath); @@ -149,7 +146,7 @@ private static async Task Main(string[] args) scenario++; } - logger.LogInformation("{dataset} Done", dataset.Dataset); + logger.LogInformation("{Dataset} Done", dataset.Dataset); } logger.LogInformation("Done"); diff --git a/TestDataGenerator/Scenarios/ChedAManyCommoditiesScenarioGenerator.cs b/TestDataGenerator/Scenarios/ChedAManyCommoditiesScenarioGenerator.cs index 2ca8430..843c50a 100644 --- a/TestDataGenerator/Scenarios/ChedAManyCommoditiesScenarioGenerator.cs +++ b/TestDataGenerator/Scenarios/ChedAManyCommoditiesScenarioGenerator.cs @@ -13,7 +13,7 @@ public override GeneratorResult Generate(int scenario, int item, DateTime entryD .WithRandomArrivalDateTime(config.ArrivalDateRange) .WithReferenceNumber(ImportNotificationTypeEnum.Cveda, scenario, entryDate, item) .WithRandomCommodities(10, 100) - .ValidateAndBuild()!; + .ValidateAndBuild(); logger.LogInformation("Created {NotificationReferenceNumber}", notification.ReferenceNumber); diff --git a/TestDataGenerator/Scenarios/ChedANoMatchScenarioGenerator.cs b/TestDataGenerator/Scenarios/ChedANoMatchScenarioGenerator.cs index 49b0baa..bbee560 100644 --- a/TestDataGenerator/Scenarios/ChedANoMatchScenarioGenerator.cs +++ b/TestDataGenerator/Scenarios/ChedANoMatchScenarioGenerator.cs @@ -11,7 +11,7 @@ public override GeneratorResult Generate(int scenario, int item, DateTime entryD .WithEntryDate(entryDate) .WithRandomArrivalDateTime(config.ArrivalDateRange) .WithReferenceNumber(ImportNotificationTypeEnum.Cveda, scenario, entryDate, item) - .ValidateAndBuild()!; + .ValidateAndBuild(); logger.LogInformation("Created {NotificationReferenceNumber}", notification.ReferenceNumber); diff --git a/TestDataGenerator/Scenarios/ChedASimpleMatchScenarioGenerator.cs b/TestDataGenerator/Scenarios/ChedASimpleMatchScenarioGenerator.cs index c6ee62a..f7bc53a 100644 --- a/TestDataGenerator/Scenarios/ChedASimpleMatchScenarioGenerator.cs +++ b/TestDataGenerator/Scenarios/ChedASimpleMatchScenarioGenerator.cs @@ -13,7 +13,7 @@ public override GeneratorResult Generate(int scenario, int item, DateTime entryD .WithEntryDate(entryDate) .WithRandomArrivalDateTime(config.ArrivalDateRange) .WithReferenceNumber(ImportNotificationTypeEnum.Cveda, scenario, entryDate, item) - .ValidateAndBuild()!; + .ValidateAndBuild(); logger.LogInformation("Created {NotificationReferenceNumber}", notification.ReferenceNumber); diff --git a/TestDataGenerator/Scenarios/ScenarioFactory.cs b/TestDataGenerator/Scenarios/ScenarioFactory.cs index a77859f..7312195 100644 --- a/TestDataGenerator/Scenarios/ScenarioFactory.cs +++ b/TestDataGenerator/Scenarios/ScenarioFactory.cs @@ -1,10 +1,5 @@ -using Btms.BlobService; -using Btms.BlobService.Extensions; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using TestDataGenerator.Config; namespace TestDataGenerator.Scenarios; From 65c627bf563e215b7a7cb6bf3ce434d4b4d9ba8f Mon Sep 17 00:00:00 2001 From: Craig Edmunds Date: Tue, 10 Dec 2024 12:13:06 +0000 Subject: [PATCH 02/12] CDMS-179 fixes errors when no matches found (#9) --- Btms.Analytics/ImportNotificationsAggregationService.cs | 5 ++++- Btms.Analytics/MovementsAggregationService.cs | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Btms.Analytics/ImportNotificationsAggregationService.cs b/Btms.Analytics/ImportNotificationsAggregationService.cs index f2af39a..48f622c 100644 --- a/Btms.Analytics/ImportNotificationsAggregationService.cs +++ b/Btms.Analytics/ImportNotificationsAggregationService.cs @@ -72,7 +72,10 @@ public Task ByCommodityCount(DateTime from, DateTime to) .GroupBy(r => new { r.Key.ImportNotificationType, r.Key.Linked }) .ToList(); - var maxCommodities = result.Max(r => r.Max(i => i.Key.CommodityCount)); + // var maxCommodities = result.Max(r => r.Max(i => i.Key.CommodityCount)); + + var maxCommodities = result.Count > 0 ? + result.Max(r => r.Any() ? r.Max(i => i.Key.CommodityCount) : 0) : 0; var list = result .SelectMany(g => diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 4d91fa6..940c5f1 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -68,8 +68,8 @@ public Task ByItemCount(DateTime from, DateTime to) var dictionary = mongoResult .ToDictionary(g => new { Title = AnalyticsHelpers.GetLinkedName(g.Linked), g.ItemCount }, g => g.Count); - var maxCount = mongoResult - .Max(r => r.Count); + var maxCount = mongoResult.Count > 0 ? + mongoResult.Max(r => r.Count) : 0; return Task.FromResult(AnalyticsHelpers.GetMovementSegments() .Select(title => new MultiSeriesDataset(title, "Item Count") { @@ -114,7 +114,8 @@ public Task ByUniqueDocumentReferenceCount(DateTime from, g => new { Title = AnalyticsHelpers.GetLinkedName(g.Linked), g.DocumentReferenceCount }, g => g.MovementCount); - var maxReferences = mongoResult.Max(r => r.DocumentReferenceCount); + var maxReferences = mongoResult.Count > 0 ? + mongoResult.Max(r => r.DocumentReferenceCount) : 0; return Task.FromResult(AnalyticsHelpers.GetMovementSegments() .Select(title => new MultiSeriesDataset(title, "Document Reference Count") { From f9fe8b2c16a81c58b3d914b185841264625a7be5 Mon Sep 17 00:00:00 2001 From: Craig Edmunds Date: Tue, 10 Dec 2024 13:29:50 +0000 Subject: [PATCH 03/12] CDMS-179 optimises Movements ByItemCount analytics for bigger datasets (#10) --- Btms.Analytics/MovementsAggregationService.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 940c5f1..314130d 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -7,6 +7,7 @@ using MongoDB.Driver; using Btms.Analytics.Extensions; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; namespace Btms.Analytics; @@ -52,17 +53,11 @@ public Task ByItemCount(DateTime from, DateTime to) var mongoQuery = context .Movements .Where(n => n.CreatedSource >= from && n.CreatedSource < to) - .GroupBy(m => new { Linked = m.Relationships.Notifications.Data.Count > 0, Items = m.Items.Count }) - .GroupBy(g => g.Key.Linked); - + .GroupBy(m => new { Linked = m.Relationships.Notifications.Data.Count > 0, ItemCount = m.Items.Count }) + .Select(g => new { g.Key.Linked, g.Key.ItemCount, Count = g.Count() }); + var mongoResult = mongoQuery .Execute(logger) - .SelectMany(g => g.Select(l => new - { - Linked = g.Key, - ItemCount = l.Key.Items, - Count = l.Count() - })) .ToList(); var dictionary = mongoResult From f4185827b099c19f9bcf07800f636cc6e45d40fc Mon Sep 17 00:00:00 2001 From: Craig Edmunds Date: Tue, 10 Dec 2024 13:42:51 +0000 Subject: [PATCH 04/12] CDMS-179 optimises Movements ByItemCount analytics for bigger datasets (#11) --- Btms.Analytics/MovementsAggregationService.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 314130d..9ebe36a 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -92,17 +92,9 @@ public Task ByUniqueDocumentReferenceCount(DateTime from, .Distinct() .Count() }) - .GroupBy(g => g.Key.Linked); - - var mongoResult = mongoQuery - .Execute(logger) - .SelectMany(g => g.Select(l => new - { - Linked = g.Key, - l.Key.DocumentReferenceCount, - MovementCount = l.Count() - })) - .ToList(); + .Select(g => new { g.Key.Linked, g.Key.DocumentReferenceCount, MovementCount = g.Count() }); + + var mongoResult = mongoQuery.Execute(logger).ToList(); var dictionary = mongoResult .ToDictionary( From bda769a86f8d3605e53ea2b34e4eb1f2e49c293c Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Tue, 10 Dec 2024 08:42:34 +0000 Subject: [PATCH 05/12] Fixed almost all outstanding ReSharper warnings --- Btms.Analytics/MovementsAggregationService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 9ebe36a..f22a802 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -5,9 +5,7 @@ using Btms.Model; using MongoDB.Bson; using MongoDB.Driver; - using Btms.Analytics.Extensions; -using Microsoft.EntityFrameworkCore.Query.SqlExpressions; namespace Btms.Analytics; From da8bf6017df3cb39ec3b100bfbaa502a3fd6489b Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Tue, 10 Dec 2024 14:32:59 +0000 Subject: [PATCH 06/12] Fixed missed warning --- Btms.Model/Relationships/RelationshipDataItem.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Btms.Model/Relationships/RelationshipDataItem.cs b/Btms.Model/Relationships/RelationshipDataItem.cs index db3e7d9..9a66878 100644 --- a/Btms.Model/Relationships/RelationshipDataItem.cs +++ b/Btms.Model/Relationships/RelationshipDataItem.cs @@ -8,11 +8,11 @@ public sealed class RelationshipDataItem { [Attr] public bool? Matched { get; set; } - [Attr] public string Type { get; set; } = default!; + [Attr] public string? Type { get; set; } - [Attr] public string Id { get; set; } = default!; + [Attr] public string? Id { get; set; } - [Attr] public ResourceLink Links { get; set; } = default!; + [Attr] public ResourceLink? Links { get; set; } [Attr] public int? SourceItem { get; set; } @@ -43,7 +43,7 @@ public sealed class RelationshipDataItem meta.Add("matchingLevel", MatchingLevel); } - if (!string.IsNullOrEmpty(Links.Self)) + if (!string.IsNullOrEmpty(Links?.Self)) { meta.Add("self", Links.Self); } From 452df2686b7af5d73d79cf3196f64e716a89e5b9 Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Tue, 10 Dec 2024 14:51:04 +0000 Subject: [PATCH 07/12] Removed spare lines --- Btms.Analytics.Tests/MovementsByCreatedDateTests.cs | 4 ++-- Btms.Analytics.Tests/MovementsByStatusTests.cs | 1 - Btms.Analytics/MovementsAggregationService.cs | 1 - .../GenerateModels/DescriptorModel/PropertyDescriptor.cs | 4 ---- .../GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs | 2 -- .../GenerateAlvsModel/Commands/XmlSchemaExtensions.cs | 3 --- Btms.Backend.IntegrationTests/GmrTests.cs | 1 - Btms.Backend/Program.cs | 2 -- .../Commands/SyncClearanceRequestsCommandTests.cs | 2 -- Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs | 1 - Btms.Common/Extensions/OptionsExtensions.cs | 1 - Btms.Consumers/GmrConsumer.cs | 1 - 12 files changed, 2 insertions(+), 21 deletions(-) diff --git a/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs b/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs index a762775..a490518 100644 --- a/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs +++ b/Btms.Analytics.Tests/MovementsByCreatedDateTests.cs @@ -10,8 +10,8 @@ namespace Btms.Analytics.Tests; [Collection(nameof(BasicSampleDataTestCollection))] public class MovementsByCreatedDateTests( BasicSampleDataTestFixture basicSampleDataTestFixture, - ITestOutputHelper testOutputHelper) { - + ITestOutputHelper testOutputHelper) +{ [Fact] public async Task WhenCalledLast48Hours_ReturnExpectedAggregation() { diff --git a/Btms.Analytics.Tests/MovementsByStatusTests.cs b/Btms.Analytics.Tests/MovementsByStatusTests.cs index ae9f02b..006ab2f 100644 --- a/Btms.Analytics.Tests/MovementsByStatusTests.cs +++ b/Btms.Analytics.Tests/MovementsByStatusTests.cs @@ -12,7 +12,6 @@ public class MovementsByStatusTests( BasicSampleDataTestFixture basicSampleDataTestFixture, ITestOutputHelper testOutputHelper) { - [Fact] public async Task WhenCalledLastWeek_ReturnExpectedAggregation() { diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index f22a802..594ff10 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -11,7 +11,6 @@ namespace Btms.Analytics; public class MovementsAggregationService(IMongoDbContext context, ILogger logger) : IMovementsAggregationService { - /// /// Aggregates movements by createdSource and returns counts by date period. Could be refactored to use a generic/interface in time /// diff --git a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs index 7faa78b..bf0d383 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs @@ -61,7 +61,6 @@ public PropertyDescriptor(string sourceName, string internalName, string type, s public string Mapper { get; set; } = null!; - public bool MappingInline { get; set; } public bool ExcludedFromInternal { get; set; } = false; @@ -88,7 +87,6 @@ public string GetSourcePropertyName() return $"{_classNamePrefix}{SourceName.Dehumanize()}"; } - if (_isArray) { n = n.Pluralize(); @@ -116,7 +114,6 @@ public string GetInternalPropertyName() return $"{_classNamePrefix}{InternalName.Dehumanize()}"; } - if (_isArray) { n = n.Pluralize(); @@ -139,7 +136,6 @@ public string GetPropertyType() return t; } - if (_isReferenceType && !Type.Equals("Result") && !Type.Equals("Unit") && !Type.Equals("string") && !Type.Equals("InspectionRequired")) { diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs index 576f8af..338b545 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs @@ -23,7 +23,6 @@ internal class GenerateAlvsModelCommand : IRequest public class Handler : AsyncRequestHandler { - protected override async Task Handle(GenerateAlvsModelCommand request, CancellationToken cancellationToken) { #pragma warning disable S1075 @@ -81,7 +80,6 @@ private void BuildClass(CSharpDescriptor cSharpDescriptor, XmlSchemaComplexType classDescriptor.Properties.Add(propertyDescriptor); } - } } diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs index d265e06..bcf8a74 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/XmlSchemaExtensions.cs @@ -20,10 +20,8 @@ public static string GetDescription(this XmlSchemaComplexType complexType) return string.Empty; } - public static string GetSchemaType(this XmlSchemaElement schemaElement) { - if (schemaElement.SchemaType is not null) { if (schemaElement.SchemaType is XmlSchemaSimpleType { Content: XmlSchemaSimpleTypeRestriction simpleTypeRestriction }) @@ -66,7 +64,6 @@ public static string GetSchemaType(this XmlSchemaElement schemaElement) return complexType.Name!; } - } } diff --git a/Btms.Backend.IntegrationTests/GmrTests.cs b/Btms.Backend.IntegrationTests/GmrTests.cs index 5fb2cf0..11b693a 100644 --- a/Btms.Backend.IntegrationTests/GmrTests.cs +++ b/Btms.Backend.IntegrationTests/GmrTests.cs @@ -47,7 +47,6 @@ await MakeSyncGmrsRequest(new SyncGmrsCommand [Fact] public void FetchSingleGmrTest() { - //Act var jsonClientResponse = client.AsJsonApiClient().GetById("GMRAPOQSPDUG", "api/gmrs"); diff --git a/Btms.Backend/Program.cs b/Btms.Backend/Program.cs index 68b2c57..9026e40 100644 --- a/Btms.Backend/Program.cs +++ b/Btms.Backend/Program.cs @@ -43,7 +43,6 @@ var app = CreateWebApplication(args); await app.RunAsync(); - [ExcludeFromCodeCoverage] static WebApplication CreateWebApplication(string[] args) { @@ -86,7 +85,6 @@ static void ConfigureWebApplication(WebApplicationBuilder builder) builder.Configuration.GetSection("AuthKeyStore").Bind(options); }); - // Load certificates into Trust Store - Note must happen before Mongo and Http client connections builder.Services.AddCustomTrustStore(logger); diff --git a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs index 4c79019..5a383ea 100644 --- a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs @@ -25,7 +25,6 @@ public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInterna var jobStore = new SyncJobStore(); jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); - var bus = Substitute.For(); var blob = Substitute.For(); blob.GetResourcesAsync(Arg.Any(), Arg.Any()) @@ -36,7 +35,6 @@ public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInterna blob.GetResource(Arg.Any(), Arg.Any()) .Returns(clearanceRequest.ToJsonString()); - var handler = new SyncClearanceRequestsCommand.Handler( new SyncMetrics(new DummyMeterFactory()), bus, diff --git a/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs b/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs index dcc7f0c..9c32a07 100644 --- a/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs @@ -35,7 +35,6 @@ public async Task WhenDecisionBlobsExist_ThenTheyShouldBePlacedOnInternalBus() blob.GetResource(Arg.Any(), Arg.Any()) .Returns(clearanceRequest.ToJsonString()); - var handler = new SyncDecisionsCommand.Handler( new SyncMetrics(new DummyMeterFactory()), bus, diff --git a/Btms.Common/Extensions/OptionsExtensions.cs b/Btms.Common/Extensions/OptionsExtensions.cs index 944089a..8da4202 100644 --- a/Btms.Common/Extensions/OptionsExtensions.cs +++ b/Btms.Common/Extensions/OptionsExtensions.cs @@ -23,7 +23,6 @@ public static OptionsBuilder BtmsAddOptions(this public static OptionsBuilder BtmsAddOptions(this IServiceCollection services, IConfiguration configuration, string section) where TOptions : class { - var s = services .AddOptions() .Bind(configuration.GetSection(section)) diff --git a/Btms.Consumers/GmrConsumer.cs b/Btms.Consumers/GmrConsumer.cs index 76b464c..98832dc 100644 --- a/Btms.Consumers/GmrConsumer.cs +++ b/Btms.Consumers/GmrConsumer.cs @@ -18,7 +18,6 @@ public async Task OnHandle(SearchGmrsForDeclarationIdsResponse message) var auditId = Context.Headers["messageId"].ToString(); if (existingGmr is null) { - var auditEntry = AuditEntry.CreateCreatedEntry(internalGmr, auditId!, 1, gmr.UpdatedSource); internalGmr.AuditEntries.Add(auditEntry); From 1b1428a99787ab687a8826b0a95203257157ed96 Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Thu, 12 Dec 2024 10:30:58 +0000 Subject: [PATCH 08/12] Fixed comment --- Btms.Business/Pipelines/PreProcessing/MovementPreProcessor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Btms.Business/Pipelines/PreProcessing/MovementPreProcessor.cs b/Btms.Business/Pipelines/PreProcessing/MovementPreProcessor.cs index 3598d45..45472cc 100644 --- a/Btms.Business/Pipelines/PreProcessing/MovementPreProcessor.cs +++ b/Btms.Business/Pipelines/PreProcessing/MovementPreProcessor.cs @@ -19,7 +19,6 @@ public async Task> Process(PreProcessingContext Date: Tue, 10 Dec 2024 14:05:12 +0000 Subject: [PATCH 09/12] rearranged domain services, added decisions skeleton --- .../Decisions/DecisionServiceTests.cs | 19 ++++++ .../Finders/ChedADecisionFinderTests.cs | 19 ++++++ .../Finders/ChedDDecisionFinderTests.cs | 19 ++++++ .../Finders/ChedPDecisionFinderTests.cs | 19 ++++++ .../Finders/ChedPPDecisionFinderTests.cs | 19 ++++++ .../{ => Linking}/LinkingServiceTests.cs | 4 +- Btms.Business/Btms.Business.csproj | 4 ++ .../Extensions/ServiceCollectionExtensions.cs | 4 +- .../Services/Decisions/DecisionCode.cs | 15 +++++ .../Services/Decisions/DecisionContext.cs | 10 ++++ .../Services/Decisions/DecisionResult.cs | 3 + .../Services/Decisions/DecisionService.cs | 58 +++++++++++++++++++ .../Decisions/Finders/ChedADecisionFinder.cs | 11 ++++ .../Decisions/Finders/ChedDDecisionFinder.cs | 11 ++++ .../Decisions/Finders/ChedPDecisionFinder.cs | 11 ++++ .../Decisions/Finders/ChedPPDecisionFinder.cs | 11 ++++ .../Decisions/Finders/IDecisionFinder.cs | 8 +++ .../Services/Decisions/IDecisionService.cs | 6 ++ .../Services/{ => Linking}/ILinkingService.cs | 2 +- .../ImportNotificationLinkContext.cs | 2 +- .../Services/{ => Linking}/LinkContext.cs | 2 +- .../Services/{ => Linking}/LinkException.cs | 2 +- .../Services/{ => Linking}/LinkOutcome.cs | 2 +- .../Services/{ => Linking}/LinkResult.cs | 2 +- .../Services/{ => Linking}/LinkingService.cs | 2 +- .../{ => Linking}/MovementLinkContext.cs | 2 +- .../ClearanceRequestConsumerTests.cs | 2 +- .../NotificationsConsumerTests.cs | 2 +- .../AlvsClearanceRequestConsumer.cs | 2 +- Btms.Consumers/NotificationConsumer.cs | 2 +- 30 files changed, 260 insertions(+), 15 deletions(-) create mode 100644 Btms.Business.Tests/Services/Decisions/DecisionServiceTests.cs create mode 100644 Btms.Business.Tests/Services/Decisions/Finders/ChedADecisionFinderTests.cs create mode 100644 Btms.Business.Tests/Services/Decisions/Finders/ChedDDecisionFinderTests.cs create mode 100644 Btms.Business.Tests/Services/Decisions/Finders/ChedPDecisionFinderTests.cs create mode 100644 Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs rename Btms.Business.Tests/Services/{ => Linking}/LinkingServiceTests.cs (99%) create mode 100644 Btms.Business/Services/Decisions/DecisionCode.cs create mode 100644 Btms.Business/Services/Decisions/DecisionContext.cs create mode 100644 Btms.Business/Services/Decisions/DecisionResult.cs create mode 100644 Btms.Business/Services/Decisions/DecisionService.cs create mode 100644 Btms.Business/Services/Decisions/Finders/ChedADecisionFinder.cs create mode 100644 Btms.Business/Services/Decisions/Finders/ChedDDecisionFinder.cs create mode 100644 Btms.Business/Services/Decisions/Finders/ChedPDecisionFinder.cs create mode 100644 Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs create mode 100644 Btms.Business/Services/Decisions/Finders/IDecisionFinder.cs create mode 100644 Btms.Business/Services/Decisions/IDecisionService.cs rename Btms.Business/Services/{ => Linking}/ILinkingService.cs (76%) rename Btms.Business/Services/{ => Linking}/ImportNotificationLinkContext.cs (87%) rename Btms.Business/Services/{ => Linking}/LinkContext.cs (93%) rename Btms.Business/Services/{ => Linking}/LinkException.cs (66%) rename Btms.Business/Services/{ => Linking}/LinkOutcome.cs (56%) rename Btms.Business/Services/{ => Linking}/LinkResult.cs (86%) rename Btms.Business/Services/{ => Linking}/LinkingService.cs (99%) rename Btms.Business/Services/{ => Linking}/MovementLinkContext.cs (86%) diff --git a/Btms.Business.Tests/Services/Decisions/DecisionServiceTests.cs b/Btms.Business.Tests/Services/Decisions/DecisionServiceTests.cs new file mode 100644 index 0000000..6433285 --- /dev/null +++ b/Btms.Business.Tests/Services/Decisions/DecisionServiceTests.cs @@ -0,0 +1,19 @@ +using Btms.Business.Services.Decisions; +using Xunit; + +namespace Btms.Business.Tests.Services.Decisions; + +public class DecisionServiceTests +{ + [Fact] + public async Task DeriveDecision() + { + // Arrange + var sut = new DecisionService(); + + // Act + + // Assert + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Btms.Business.Tests/Services/Decisions/Finders/ChedADecisionFinderTests.cs b/Btms.Business.Tests/Services/Decisions/Finders/ChedADecisionFinderTests.cs new file mode 100644 index 0000000..afba8cc --- /dev/null +++ b/Btms.Business.Tests/Services/Decisions/Finders/ChedADecisionFinderTests.cs @@ -0,0 +1,19 @@ +using Btms.Business.Services.Decisions.Finders; +using Xunit; + +namespace Btms.Business.Tests.Services.Decisions.Finders; + +public class ChedADecisionFinderTests +{ + [Fact] + public async Task Find_Should_DoThings() + { + // Arrange + var sut = new ChedADecisionFinder(); + + // Act + + // Assert + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Btms.Business.Tests/Services/Decisions/Finders/ChedDDecisionFinderTests.cs b/Btms.Business.Tests/Services/Decisions/Finders/ChedDDecisionFinderTests.cs new file mode 100644 index 0000000..323a9f3 --- /dev/null +++ b/Btms.Business.Tests/Services/Decisions/Finders/ChedDDecisionFinderTests.cs @@ -0,0 +1,19 @@ +using Btms.Business.Services.Decisions.Finders; +using Xunit; + +namespace Btms.Business.Tests.Services.Decisions.Finders; + +public class ChedDDecisionFinderTests +{ + [Fact] + public async Task Find_Should_DoThings() + { + // Arrange + var sut = new ChedDDecisionFinder(); + + // Act + + // Assert + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Btms.Business.Tests/Services/Decisions/Finders/ChedPDecisionFinderTests.cs b/Btms.Business.Tests/Services/Decisions/Finders/ChedPDecisionFinderTests.cs new file mode 100644 index 0000000..e49d7d0 --- /dev/null +++ b/Btms.Business.Tests/Services/Decisions/Finders/ChedPDecisionFinderTests.cs @@ -0,0 +1,19 @@ +using Btms.Business.Services.Decisions.Finders; +using Xunit; + +namespace Btms.Business.Tests.Services.Decisions.Finders; + +public class ChedPDecisionFinderTests +{ + [Fact] + public async Task Find_Should_DoThings() + { + // Arrange + var sut = new ChedPDecisionFinder(); + + // Act + + // Assert + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs b/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs new file mode 100644 index 0000000..c242a76 --- /dev/null +++ b/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs @@ -0,0 +1,19 @@ +using Btms.Business.Services.Decisions.Finders; +using Xunit; + +namespace Btms.Business.Tests.Services.Decisions.Finders; + +public class ChedPPDecisionFinderTests +{ + [Fact] + public async Task Find_Should_DoThings() + { + // Arrange + var sut = new ChedPPDecisionFinder(); + + // Act + + // Assert + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Btms.Business.Tests/Services/LinkingServiceTests.cs b/Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs similarity index 99% rename from Btms.Business.Tests/Services/LinkingServiceTests.cs rename to Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs index ccd934d..92076b2 100644 --- a/Btms.Business.Tests/Services/LinkingServiceTests.cs +++ b/Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs @@ -1,6 +1,6 @@ using Btms.Backend.Data; using Btms.Backend.Data.InMemory; -using Btms.Business.Services; +using Btms.Business.Services.Linking; using Btms.Metrics; using Btms.Model.Alvs; using Btms.Model.ChangeLog; @@ -12,7 +12,7 @@ using Items = Btms.Model.Alvs.Items; using Movement = Btms.Model.Movement; -namespace Btms.Business.Tests.Services; +namespace Btms.Business.Tests.Services.Linking; public class LinkingServiceTests { diff --git a/Btms.Business/Btms.Business.csproj b/Btms.Business/Btms.Business.csproj index 0057217..2e59068 100644 --- a/Btms.Business/Btms.Business.csproj +++ b/Btms.Business/Btms.Business.csproj @@ -35,4 +35,8 @@ + + + + diff --git a/Btms.Business/Extensions/ServiceCollectionExtensions.cs b/Btms.Business/Extensions/ServiceCollectionExtensions.cs index 33a3cd5..75675c5 100644 --- a/Btms.Business/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Business/Extensions/ServiceCollectionExtensions.cs @@ -2,7 +2,6 @@ using Btms.Business.Pipelines; using Btms.Business.Pipelines.Matching; using Btms.Business.Pipelines.Matching.Rules; -using Btms.Business.Services; using Btms.Backend.Data.Extensions; using Btms.BlobService; using Btms.BlobService.Extensions; @@ -14,6 +13,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Btms.Business.Pipelines.PreProcessing; +using Btms.Business.Services.Decisions; +using Btms.Business.Services.Linking; using Btms.Types.Alvs; namespace Btms.Business.Extensions; @@ -61,6 +62,7 @@ public static IServiceCollection AddBusinessServices(this IServiceCollection ser }); services.AddScoped(); + services.AddScoped(); services.AddScoped, ImportNotificationPreProcessor>(); services.AddScoped, MovementPreProcessor>(); diff --git a/Btms.Business/Services/Decisions/DecisionCode.cs b/Btms.Business/Services/Decisions/DecisionCode.cs new file mode 100644 index 0000000..7f916bd --- /dev/null +++ b/Btms.Business/Services/Decisions/DecisionCode.cs @@ -0,0 +1,15 @@ +namespace Btms.Business.Services.Decisions; + +public enum DecisionCode +{ + E03, + C03, + C05, + C06, + C07, + C08, + N02, + N03, + N04, + N07 +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/DecisionContext.cs b/Btms.Business/Services/Decisions/DecisionContext.cs new file mode 100644 index 0000000..f4a5d87 --- /dev/null +++ b/Btms.Business/Services/Decisions/DecisionContext.cs @@ -0,0 +1,10 @@ +using Btms.Model; +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions; + +public class DecisionContext +{ + public List Notifications { get; set; } = new(); + public List Movements { get; set; } = new(); +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/DecisionResult.cs b/Btms.Business/Services/Decisions/DecisionResult.cs new file mode 100644 index 0000000..67f02dd --- /dev/null +++ b/Btms.Business/Services/Decisions/DecisionResult.cs @@ -0,0 +1,3 @@ +namespace Btms.Business.Services.Decisions; + +public record DecisionResult(DecisionCode DecisionCode); \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/DecisionService.cs b/Btms.Business/Services/Decisions/DecisionService.cs new file mode 100644 index 0000000..800441f --- /dev/null +++ b/Btms.Business/Services/Decisions/DecisionService.cs @@ -0,0 +1,58 @@ +using Btms.Business.Services.Decisions.Finders; +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions; + +public class DecisionService : IDecisionService +{ + public async Task DeriveDecision(DecisionContext decisionContext) + { + // Validate and prerequisite checks + + var decisions = decisionContext.Notifications.Select(x => (x.Id, GetDecision(x))).ToList(); + + foreach (var movement in decisionContext.Movements) + { + // Generate list matched items -> decisions + + foreach (var item in movement.Items) + { + // check decisions list for match reference, if no match then drop out with "no-match" + + } + + // Return decision based on prioritisation from confluence + } + + await Task.CompletedTask; + return new DecisionResult(DecisionCode.N02); + } + + private DecisionResult GetDecision(ImportNotification notification) + { + // get decision finder - fold IUU stuff into the decision finder for fish? + IDecisionFinder finder; + switch (notification.ImportNotificationType) + { + case ImportNotificationTypeEnum.Ced: + finder = new ChedDDecisionFinder(); + break; + + case ImportNotificationTypeEnum.Cveda: + finder = new ChedADecisionFinder(); + break; + + case ImportNotificationTypeEnum.Cvedp: + finder = new ChedPDecisionFinder(); + break; + + case ImportNotificationTypeEnum.Chedpp: + finder = new ChedPPDecisionFinder(); + break; + + default: throw new InvalidOperationException("Invalid ImportNotificationType"); + } + + return finder.FindDecision(notification); + } +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/Finders/ChedADecisionFinder.cs b/Btms.Business/Services/Decisions/Finders/ChedADecisionFinder.cs new file mode 100644 index 0000000..b9b2c37 --- /dev/null +++ b/Btms.Business/Services/Decisions/Finders/ChedADecisionFinder.cs @@ -0,0 +1,11 @@ +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions.Finders; + +public class ChedADecisionFinder : IDecisionFinder +{ + public DecisionResult FindDecision(ImportNotification notification) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/Finders/ChedDDecisionFinder.cs b/Btms.Business/Services/Decisions/Finders/ChedDDecisionFinder.cs new file mode 100644 index 0000000..3d289f4 --- /dev/null +++ b/Btms.Business/Services/Decisions/Finders/ChedDDecisionFinder.cs @@ -0,0 +1,11 @@ +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions.Finders; + +public class ChedDDecisionFinder : IDecisionFinder +{ + public DecisionResult FindDecision(ImportNotification notification) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/Finders/ChedPDecisionFinder.cs b/Btms.Business/Services/Decisions/Finders/ChedPDecisionFinder.cs new file mode 100644 index 0000000..3f6bf36 --- /dev/null +++ b/Btms.Business/Services/Decisions/Finders/ChedPDecisionFinder.cs @@ -0,0 +1,11 @@ +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions.Finders; + +public class ChedPDecisionFinder : IDecisionFinder +{ + public DecisionResult FindDecision(ImportNotification notification) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs b/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs new file mode 100644 index 0000000..c9f4265 --- /dev/null +++ b/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs @@ -0,0 +1,11 @@ +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions.Finders; + +public class ChedPPDecisionFinder : IDecisionFinder +{ + public DecisionResult FindDecision(ImportNotification notification) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/Finders/IDecisionFinder.cs b/Btms.Business/Services/Decisions/Finders/IDecisionFinder.cs new file mode 100644 index 0000000..1863489 --- /dev/null +++ b/Btms.Business/Services/Decisions/Finders/IDecisionFinder.cs @@ -0,0 +1,8 @@ +using Btms.Model.Ipaffs; + +namespace Btms.Business.Services.Decisions.Finders; + +public interface IDecisionFinder +{ + DecisionResult FindDecision(ImportNotification notification); +} \ No newline at end of file diff --git a/Btms.Business/Services/Decisions/IDecisionService.cs b/Btms.Business/Services/Decisions/IDecisionService.cs new file mode 100644 index 0000000..c1483ae --- /dev/null +++ b/Btms.Business/Services/Decisions/IDecisionService.cs @@ -0,0 +1,6 @@ +namespace Btms.Business.Services.Decisions; + +public interface IDecisionService +{ + public Task DeriveDecision(DecisionContext decisionContext); +} \ No newline at end of file diff --git a/Btms.Business/Services/ILinkingService.cs b/Btms.Business/Services/Linking/ILinkingService.cs similarity index 76% rename from Btms.Business/Services/ILinkingService.cs rename to Btms.Business/Services/Linking/ILinkingService.cs index b918b92..61482f6 100644 --- a/Btms.Business/Services/ILinkingService.cs +++ b/Btms.Business/Services/Linking/ILinkingService.cs @@ -1,5 +1,5 @@ -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public interface ILinkingService { diff --git a/Btms.Business/Services/ImportNotificationLinkContext.cs b/Btms.Business/Services/Linking/ImportNotificationLinkContext.cs similarity index 87% rename from Btms.Business/Services/ImportNotificationLinkContext.cs rename to Btms.Business/Services/Linking/ImportNotificationLinkContext.cs index d8b3821..ab482bb 100644 --- a/Btms.Business/Services/ImportNotificationLinkContext.cs +++ b/Btms.Business/Services/Linking/ImportNotificationLinkContext.cs @@ -1,7 +1,7 @@ using Btms.Model.ChangeLog; using Btms.Model.Ipaffs; -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public record ImportNotificationLinkContext(ImportNotification PersistedImportNotification, ChangeSet? ChangeSet) : LinkContext { diff --git a/Btms.Business/Services/LinkContext.cs b/Btms.Business/Services/Linking/LinkContext.cs similarity index 93% rename from Btms.Business/Services/LinkContext.cs rename to Btms.Business/Services/Linking/LinkContext.cs index 93b5be8..e996c05 100644 --- a/Btms.Business/Services/LinkContext.cs +++ b/Btms.Business/Services/Linking/LinkContext.cs @@ -2,7 +2,7 @@ using Btms.Model.ChangeLog; using Btms.Model.Ipaffs; -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public abstract record LinkContext { diff --git a/Btms.Business/Services/LinkException.cs b/Btms.Business/Services/Linking/LinkException.cs similarity index 66% rename from Btms.Business/Services/LinkException.cs rename to Btms.Business/Services/Linking/LinkException.cs index c820f12..23c5014 100644 --- a/Btms.Business/Services/LinkException.cs +++ b/Btms.Business/Services/Linking/LinkException.cs @@ -1,3 +1,3 @@ -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public class LinkException(Exception inner) : Exception("Failed to link", inner); \ No newline at end of file diff --git a/Btms.Business/Services/LinkOutcome.cs b/Btms.Business/Services/Linking/LinkOutcome.cs similarity index 56% rename from Btms.Business/Services/LinkOutcome.cs rename to Btms.Business/Services/Linking/LinkOutcome.cs index 7507e58..d4922b6 100644 --- a/Btms.Business/Services/LinkOutcome.cs +++ b/Btms.Business/Services/Linking/LinkOutcome.cs @@ -1,4 +1,4 @@ -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public enum LinkOutcome { diff --git a/Btms.Business/Services/LinkResult.cs b/Btms.Business/Services/Linking/LinkResult.cs similarity index 86% rename from Btms.Business/Services/LinkResult.cs rename to Btms.Business/Services/Linking/LinkResult.cs index acd48fc..9f6b3ad 100644 --- a/Btms.Business/Services/LinkResult.cs +++ b/Btms.Business/Services/Linking/LinkResult.cs @@ -1,7 +1,7 @@ using Btms.Model; using Btms.Model.Ipaffs; -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public class LinkResult(LinkOutcome state) { diff --git a/Btms.Business/Services/LinkingService.cs b/Btms.Business/Services/Linking/LinkingService.cs similarity index 99% rename from Btms.Business/Services/LinkingService.cs rename to Btms.Business/Services/Linking/LinkingService.cs index 67521c5..b8fcc46 100644 --- a/Btms.Business/Services/LinkingService.cs +++ b/Btms.Business/Services/Linking/LinkingService.cs @@ -8,7 +8,7 @@ using Btms.Model.Relationships; using Microsoft.Extensions.Logging; -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public static partial class LinkingServiceLogging { diff --git a/Btms.Business/Services/MovementLinkContext.cs b/Btms.Business/Services/Linking/MovementLinkContext.cs similarity index 86% rename from Btms.Business/Services/MovementLinkContext.cs rename to Btms.Business/Services/Linking/MovementLinkContext.cs index e55fe31..0826c6d 100644 --- a/Btms.Business/Services/MovementLinkContext.cs +++ b/Btms.Business/Services/Linking/MovementLinkContext.cs @@ -1,7 +1,7 @@ using Btms.Model; using Btms.Model.ChangeLog; -namespace Btms.Business.Services; +namespace Btms.Business.Services.Linking; public record MovementLinkContext(Movement PersistedMovement, ChangeSet? ChangeSet) : LinkContext { diff --git a/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs b/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs index 3dcf1b5..c1daa4c 100644 --- a/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs +++ b/Btms.Consumers.Tests/ClearanceRequestConsumerTests.cs @@ -1,5 +1,5 @@ using Btms.Business.Pipelines.PreProcessing; -using Btms.Business.Services; +using Btms.Business.Services.Linking; using Btms.Consumers.Extensions; using Btms.Model; using Btms.Model.Auditing; diff --git a/Btms.Consumers.Tests/NotificationsConsumerTests.cs b/Btms.Consumers.Tests/NotificationsConsumerTests.cs index a8921de..891941b 100644 --- a/Btms.Consumers.Tests/NotificationsConsumerTests.cs +++ b/Btms.Consumers.Tests/NotificationsConsumerTests.cs @@ -1,5 +1,5 @@ using Btms.Business.Pipelines.PreProcessing; -using Btms.Business.Services; +using Btms.Business.Services.Linking; using Btms.Consumers.Extensions; using Btms.Model.Auditing; using Btms.Types.Ipaffs; diff --git a/Btms.Consumers/AlvsClearanceRequestConsumer.cs b/Btms.Consumers/AlvsClearanceRequestConsumer.cs index dc7f38c..94a9729 100644 --- a/Btms.Consumers/AlvsClearanceRequestConsumer.cs +++ b/Btms.Consumers/AlvsClearanceRequestConsumer.cs @@ -1,9 +1,9 @@ -using Btms.Business.Services; using Btms.Types.Alvs; using Microsoft.Extensions.Logging; using SlimMessageBus; using Btms.Consumers.Extensions; using Btms.Business.Pipelines.PreProcessing; +using Btms.Business.Services.Linking; namespace Btms.Consumers; diff --git a/Btms.Consumers/NotificationConsumer.cs b/Btms.Consumers/NotificationConsumer.cs index 249c4fb..122d242 100644 --- a/Btms.Consumers/NotificationConsumer.cs +++ b/Btms.Consumers/NotificationConsumer.cs @@ -1,9 +1,9 @@ -using Btms.Business.Services; using Btms.Types.Ipaffs; using SlimMessageBus; using Btms.Consumers.Extensions; using Microsoft.Extensions.Logging; using Btms.Business.Pipelines.PreProcessing; +using Btms.Business.Services.Linking; namespace Btms.Consumers; From 28b6080ba618ae46caf1d8b70e8a43ce426476be Mon Sep 17 00:00:00 2001 From: Craig Edmunds Date: Tue, 10 Dec 2024 16:25:57 +0000 Subject: [PATCH 10/12] Feature/cdms 188 configure concurrency (#15) * CDMS-188 setting concurency * CDMS-188 options for concurrency working * Fixed test --- .../SyncClearanceRequestsCommandTests.cs | 73 ++++++----- Btms.Business/BusinessOptions.cs | 39 +++++- .../Commands/SyncClearanceRequestsCommand.cs | 7 +- .../Commands/SyncDecisionsCommand.cs | 4 +- Btms.Business/Commands/SyncGmrsCommand.cs | 4 +- Btms.Business/Commands/SyncHandler.cs | 25 ++-- .../Commands/SyncNotificationsCommand.cs | 88 ++++++------- Btms.Consumers/ConsumerOptions.cs | 15 +++ .../Extensions/ServiceCollectionExtensions.cs | 117 ++++++++++-------- 9 files changed, 224 insertions(+), 148 deletions(-) create mode 100644 Btms.Consumers/ConsumerOptions.cs diff --git a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs index 5a383ea..63f3a89 100644 --- a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs @@ -5,6 +5,8 @@ using Btms.SensitiveData; using Btms.SyncJob; using Btms.Types.Alvs; +using Btms.Types.Ipaffs; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using NSubstitute; @@ -13,41 +15,44 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Business.Tests.Commands; - -public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) +namespace Btms.Business.Tests.Commands { - [Fact] - public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() + public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) { - var clearanceRequest = ClearanceRequestBuilder.Default().Build(); - var command = new SyncClearanceRequestsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); - - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()) - .ToAsyncEnumerator()); - - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(clearanceRequest.ToJsonString()); - - var handler = new SyncClearanceRequestsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); - - await handler.Handle(command, CancellationToken.None); - - // ASSERT - await bus.Received(1).Publish(Arg.Any(), "ALVS", - Arg.Any>(), Arg.Any()); + [Fact] + public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() + { + var clearanceRequest = ClearanceRequestBuilder.Default().Build(); + var command = new SyncClearanceRequestsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); + + + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns( + new TestBlobItem(clearanceRequest!.Header!.EntryReference!, clearanceRequest.ToJsonString()) + .ToAsyncEnumerator()); + + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(clearanceRequest.ToJsonString()); + + + var handler = new SyncClearanceRequestsCommand.Handler( + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); + + await handler.Handle(command, CancellationToken.None); + + // ASSERT + await bus.Received(1).Publish(Arg.Any(), "CLEARANCEREQUESTS", + Arg.Any>(), Arg.Any()); + } } } \ No newline at end of file diff --git a/Btms.Business/BusinessOptions.cs b/Btms.Business/BusinessOptions.cs index 5f57e62..75424df 100644 --- a/Btms.Business/BusinessOptions.cs +++ b/Btms.Business/BusinessOptions.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Btms.Business.Commands; namespace Btms.Business; @@ -6,6 +7,42 @@ public class BusinessOptions { public const string SectionName = nameof(BusinessOptions); - [Required] public string DmpBlobRootFolder { get; set; } = "RAW"; + private readonly int defaultDegreeOfParallelism = Math.Max(Environment.ProcessorCount / 4, 1); + [Required] public string DmpBlobRootFolder { get; set; } = "RAW"; + + public Dictionary> ConcurrencyConfiguration { get; set; } + + public enum Feature + { + BlobPaths, + BlobItems + } + public BusinessOptions() + { + ConcurrencyConfiguration = new Dictionary> + { + { + nameof(SyncNotificationsCommand), new Dictionary() + { + { Feature.BlobPaths, defaultDegreeOfParallelism }, { Feature.BlobItems, defaultDegreeOfParallelism } + } + }, + { + nameof(SyncClearanceRequestsCommand), new Dictionary() + { + { Feature.BlobPaths, defaultDegreeOfParallelism }, { Feature.BlobItems, defaultDegreeOfParallelism } + } + } + }; + } + + public int GetConcurrency(Feature feature) + { + if (ConcurrencyConfiguration.TryGetValue(typeof(T).Name, out var degreeOfParallelismDictionary)) + { + return degreeOfParallelismDictionary.GetValueOrDefault(feature, defaultDegreeOfParallelism); + } + return defaultDegreeOfParallelism; + } } \ No newline at end of file diff --git a/Btms.Business/Commands/SyncClearanceRequestsCommand.cs b/Btms.Business/Commands/SyncClearanceRequestsCommand.cs index 0d59a93..94e9e80 100644 --- a/Btms.Business/Commands/SyncClearanceRequestsCommand.cs +++ b/Btms.Business/Commands/SyncClearanceRequestsCommand.cs @@ -19,15 +19,14 @@ internal class Handler( IBlobService blobService, IOptions businessOptions, ISyncJobStore syncJobStore) - : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, - blobService, syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, businessOptions, syncJobStore) { public override async Task Handle(SyncClearanceRequestsCommand request, CancellationToken cancellationToken) { var rootFolder = string.IsNullOrEmpty(request.RootFolder) - ? businessOptions.Value.DmpBlobRootFolder + ? Options.DmpBlobRootFolder : request.RootFolder; - await SyncBlobPaths(request.SyncPeriod, "ALVS", request.JobId, cancellationToken,$"{rootFolder}/ALVS"); + await SyncBlobPaths(request.SyncPeriod, "CLEARANCEREQUESTS", request.JobId, cancellationToken,$"{rootFolder}/ALVS"); } } diff --git a/Btms.Business/Commands/SyncDecisionsCommand.cs b/Btms.Business/Commands/SyncDecisionsCommand.cs index ace4dc0..c9a5497 100644 --- a/Btms.Business/Commands/SyncDecisionsCommand.cs +++ b/Btms.Business/Commands/SyncDecisionsCommand.cs @@ -19,12 +19,12 @@ internal class Handler( IBlobService blobService, IOptions businessOptions, ISyncJobStore syncJobStore) - : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, businessOptions, syncJobStore) { public override async Task Handle(SyncDecisionsCommand request, CancellationToken cancellationToken) { var rootFolder = string.IsNullOrEmpty(request.RootFolder) - ? businessOptions.Value.DmpBlobRootFolder + ? Options.DmpBlobRootFolder : request.RootFolder; await SyncBlobPaths(request.SyncPeriod, "DECISIONS", request.JobId, cancellationToken,$"{rootFolder}/DECISIONS"); diff --git a/Btms.Business/Commands/SyncGmrsCommand.cs b/Btms.Business/Commands/SyncGmrsCommand.cs index 02c9fa3..7565b96 100644 --- a/Btms.Business/Commands/SyncGmrsCommand.cs +++ b/Btms.Business/Commands/SyncGmrsCommand.cs @@ -19,12 +19,12 @@ internal class Handler( IBlobService blobService, IOptions businessOptions, ISyncJobStore syncJobStore) - : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, blobService, businessOptions, syncJobStore) { public override async Task Handle(SyncGmrsCommand request, CancellationToken cancellationToken) { var rootFolder = string.IsNullOrEmpty(request.RootFolder) - ? businessOptions.Value.DmpBlobRootFolder + ? Options.DmpBlobRootFolder : request.RootFolder; await SyncBlobPaths(request.SyncPeriod, "GMR", request.JobId, cancellationToken, $"{rootFolder}/GVMSAPIRESPONSE"); diff --git a/Btms.Business/Commands/SyncHandler.cs b/Btms.Business/Commands/SyncHandler.cs index e71d2e9..15ca9f5 100644 --- a/Btms.Business/Commands/SyncHandler.cs +++ b/Btms.Business/Commands/SyncHandler.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Text.Json.Serialization; using Btms.Metrics; +using Microsoft.Extensions.Options; using IRequest = MediatR.IRequest; namespace Btms.Business.Commands; @@ -51,12 +52,14 @@ internal abstract class Handler( ILogger logger, ISensitiveDataSerializer sensitiveDataSerializer, IBlobService blobService, + IOptions options, ISyncJobStore syncJobStore) : MediatR.IRequestHandler where T : IRequest { - private readonly int maxDegreeOfParallelism = Math.Max(Environment.ProcessorCount / 4, 1); - + // private readonly int defaultDegreeOfParallelism = Math.Max(Environment.ProcessorCount / 4, 1); + protected readonly BusinessOptions Options = options.Value; + public const string ActivityName = "Btms.ProcessBlob"; public abstract Task Handle(T request, CancellationToken cancellationToken); @@ -65,20 +68,21 @@ protected async Task SyncBlobPaths(SyncPeriod period, string topic, Gu { var job = syncJobStore.GetJob(jobId); job?.Start(); + var degreeOfParallelism = options.Value.GetConcurrency(BusinessOptions.Feature.BlobPaths); using (logger.BeginScope(new List> { new("JobId", job?.JobId!), new("SyncPeriod", period.ToString()), - new("Parallelism", maxDegreeOfParallelism), + new("Parallelism", degreeOfParallelism), new("ProcessorCount", Environment.ProcessorCount), new("Command", typeof(T).Name), })) { - logger.SyncStarted(job?.JobId.ToString()!, period.ToString(), maxDegreeOfParallelism, Environment.ProcessorCount, typeof(T).Name); + logger.SyncStarted(job?.JobId.ToString()!, period.ToString(), degreeOfParallelism, Environment.ProcessorCount, typeof(T).Name); try { await Parallel.ForEachAsync(paths, - new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, + new ParallelOptions { MaxDegreeOfParallelism = degreeOfParallelism }, async (path, _) => { using (logger.BeginScope(new List> { new("SyncPath", path), })) @@ -100,23 +104,24 @@ await Parallel.ForEachAsync(paths, } } - protected async Task SyncBlobPath(string path, SyncPeriod period, string topic, SyncJob.SyncJob job, - CancellationToken cancellationToken) + protected async Task SyncBlobPath(string path, SyncPeriod period, string topic, SyncJob.SyncJob job, CancellationToken cancellationToken) { var result = blobService.GetResourcesAsync($"{path}{period.GetPeriodPath()}", cancellationToken); + var degreeOfParallelism = options.Value.GetConcurrency(BusinessOptions.Feature.BlobItems); - await Parallel.ForEachAsync(result, new ParallelOptions { CancellationToken = cancellationToken, MaxDegreeOfParallelism = maxDegreeOfParallelism }, async (item, _) => + await Parallel.ForEachAsync(result, new ParallelOptions() { CancellationToken = cancellationToken, MaxDegreeOfParallelism = degreeOfParallelism }, async (item, token) => { await SyncBlob(path, topic, item, job, cancellationToken); }); } - protected async Task SyncBlobs(SyncPeriod period, string topic, Guid jobId, CancellationToken cancellationToken, params string[] paths) { var job = syncJobStore.GetJob(jobId); + var degreeOfParallelism = options.Value.GetConcurrency(BusinessOptions.Feature.BlobItems); + job?.Start(); - logger.LogInformation("SyncNotifications period: {Period}, maxDegreeOfParallelism={MaxDegreeOfParallelism}, Environment.ProcessorCount={ProcessorCount}", period.ToString(), maxDegreeOfParallelism, Environment.ProcessorCount); + logger.LogInformation("SyncNotifications period: {Period}, maxDegreeOfParallelism={degreeOfParallelism}, Environment.ProcessorCount={ProcessorCount}", period.ToString(), degreeOfParallelism, Environment.ProcessorCount); try { foreach (var path in paths) diff --git a/Btms.Business/Commands/SyncNotificationsCommand.cs b/Btms.Business/Commands/SyncNotificationsCommand.cs index 5c6c920..11b8bc6 100644 --- a/Btms.Business/Commands/SyncNotificationsCommand.cs +++ b/Btms.Business/Commands/SyncNotificationsCommand.cs @@ -1,3 +1,4 @@ +using Azure.Core; using Btms.BlobService; using Btms.Metrics; using Btms.SensitiveData; @@ -7,60 +8,61 @@ using Microsoft.Extensions.Options; using SlimMessageBus; -namespace Btms.Business.Commands; - -public class SyncNotificationsCommand : SyncCommand +namespace Btms.Business.Commands { - public string[] ChedTypes { get; set; } = []; - public override string Resource => "ImportNotification"; + public class SyncNotificationsCommand : SyncCommand + { + public string[] ChedTypes { get; set; } = []; + public override string Resource => "ImportNotification"; - public string[] BlobFiles { get; set; } = []; + public string[] BlobFiles { get; set; } = []; - internal class Handler( - SyncMetrics syncMetrics, - IPublishBus bus, - ILogger logger, - ISensitiveDataSerializer sensitiveDataSerializer, - IBlobService blobService, - IOptions businessOptions, - ISyncJobStore syncJobStore) - : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, - blobService, syncJobStore) - { - public override async Task Handle(SyncNotificationsCommand request, CancellationToken cancellationToken) + internal class Handler( + SyncMetrics syncMetrics, + IPublishBus bus, + ILogger logger, + ISensitiveDataSerializer sensitiveDataSerializer, + IBlobService blobService, + IOptions businessOptions, + ISyncJobStore syncJobStore) + : Handler(syncMetrics, bus, logger, sensitiveDataSerializer, + blobService, businessOptions, syncJobStore) { - var rootFolder = string.IsNullOrEmpty(request.RootFolder) - ? businessOptions.Value.DmpBlobRootFolder - : request.RootFolder; - - if (request.BlobFiles.Any()) + public override async Task Handle(SyncNotificationsCommand request, CancellationToken cancellationToken) { - await SyncBlobs(request.SyncPeriod, "NOTIFICATIONS", - request.JobId, - cancellationToken, - request.BlobFiles.Select(x => $"{rootFolder}/IPAFFS/{x}").ToArray()); - return; - } + var rootFolder = string.IsNullOrEmpty(request.RootFolder) + ? Options.DmpBlobRootFolder + : request.RootFolder; - var chedTypesToSync = new List(); + if (request.BlobFiles.Any()) + { + await SyncBlobs(request.SyncPeriod, "NOTIFICATIONS", + request.JobId, + cancellationToken, + request.BlobFiles.Select(x => $"{rootFolder}/IPAFFS/{x}").ToArray()); + return; + } - AddIf(chedTypesToSync, request, rootFolder, "CHEDA"); - AddIf(chedTypesToSync, request, rootFolder, "CHEDD"); - AddIf(chedTypesToSync, request, rootFolder, "CHEDP"); - AddIf(chedTypesToSync, request, rootFolder, "CHEDPP"); + var chedTypesToSync = new List(); - await SyncBlobPaths(request.SyncPeriod, "NOTIFICATIONS", - request.JobId, - cancellationToken, - chedTypesToSync.ToArray()); - } + AddIf(chedTypesToSync, request, rootFolder, "CHEDA"); + AddIf(chedTypesToSync, request, rootFolder, "CHEDD"); + AddIf(chedTypesToSync, request, rootFolder, "CHEDP"); + AddIf(chedTypesToSync, request, rootFolder, "CHEDPP"); - private static void AddIf(List chedTypesToSync, SyncNotificationsCommand request, string rootFolder, string chedType) - { - if (!request.ChedTypes.Any() || request.ChedTypes.Contains(chedType)) + await SyncBlobPaths(request.SyncPeriod, "NOTIFICATIONS", + request.JobId, + cancellationToken, + chedTypesToSync.ToArray()); + } + + private static void AddIf(List chedTypesToSync, SyncNotificationsCommand request, string rootFolder, string chedType) { - chedTypesToSync.Add($"{rootFolder}/IPAFFS/{chedType}"); + if (!request.ChedTypes.Any() || request.ChedTypes.Contains(chedType)) + { + chedTypesToSync.Add($"{rootFolder}/IPAFFS/{chedType}"); + } } } } diff --git a/Btms.Consumers/ConsumerOptions.cs b/Btms.Consumers/ConsumerOptions.cs new file mode 100644 index 0000000..8ea4430 --- /dev/null +++ b/Btms.Consumers/ConsumerOptions.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using Btms.Azure; + +namespace Btms.Consumers; + +public class ConsumerOptions +{ + public const string SectionName = nameof(ConsumerOptions); + + public int InMemoryNotifications { get; set; } = 2; + public int InMemoryGmrs { get; set; } = 2; + public int InMemoryClearanceRequests { get; set; } = 2; + public int InMemoryDecisions { get; set; } = 2; + +} \ No newline at end of file diff --git a/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs b/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs index 3cebb59..83545f4 100644 --- a/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using Btms.Common.Extensions; using Btms.Consumers.Interceptors; using Btms.Consumers.MemoryQueue; using Btms.Metrics.Extensions; @@ -10,61 +11,73 @@ using SlimMessageBus.Host.Memory; using AlvsClearanceRequest = Btms.Types.Alvs.AlvsClearanceRequest; -namespace Btms.Consumers.Extensions; - -public static class ServiceCollectionExtensions +namespace Btms.Consumers.Extensions { - public static IServiceCollection AddConsumers(this IServiceCollection services, - IConfiguration configuration) + public static class ServiceCollectionExtensions { - services.AddBtmsMetrics(); - services.AddSingleton(); - services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(MetricsInterceptor<>)); - services.AddSingleton(typeof(IPublishInterceptor<>), typeof(MetricsInterceptor<>)); - services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); - services.AddSingleton(typeof(IPublishInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); - services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(JobConsumerInterceptor<>)); - services.AddSingleton(typeof(IMemoryConsumerErrorHandler<>), typeof(InMemoryConsumerErrorHandler<>)); - - //Message Bus - services.AddSlimMessageBus(mbb => + public static IServiceCollection AddConsumers(this IServiceCollection services, + IConfiguration configuration) { - mbb - .AddChildBus("InMemory", cbb => - { - cbb.WithProviderMemory(cfg => - { - cfg.EnableBlockingPublish = false; - cfg.EnableMessageHeaders = true; - }) - .AddServicesFromAssemblyContaining( - consumerLifetime: ServiceLifetime.Scoped) - .Produce(x => x.DefaultTopic("NOTIFICATIONS")) - .Consume(x => - { - x.Instances(2); - x.Topic("NOTIFICATIONS").WithConsumer(); - }) - .Produce(x => x.DefaultTopic("GMR")) - .Consume(x => - { - x.Instances(2); - x.Topic("GMR").WithConsumer(); - }) - .Produce(x => x.DefaultTopic(nameof(AlvsClearanceRequest))) - .Consume(x => - { - x.Instances(2); - x.Topic("ALVS").WithConsumer(); - }) - .Consume(x => - { - x.Instances(2); - x.Topic("DECISIONS").WithConsumer(); - }); - }); - }); + services.BtmsAddOptions(configuration, ConsumerOptions.SectionName); + + var consumerOpts = configuration + .GetSection(ConsumerOptions.SectionName) + .Get() ?? new ConsumerOptions(); + + // services.BtmsAddOptions(configuration, ConsumerOptions.SectionName); + // + // var consumerOpts = services.GetRequiredService>(); + + + services.AddBtmsMetrics(); + services.AddSingleton(); + services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(MetricsInterceptor<>)); + services.AddSingleton(typeof(IPublishInterceptor<>), typeof(MetricsInterceptor<>)); + services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); + services.AddSingleton(typeof(IPublishInterceptor<>), typeof(InMemoryQueueStatusInterceptor<>)); + services.AddSingleton(typeof(IConsumerInterceptor<>), typeof(JobConsumerInterceptor<>)); + services.AddSingleton(typeof(IMemoryConsumerErrorHandler<>), typeof(InMemoryConsumerErrorHandler<>)); + + //Message Bus + services.AddSlimMessageBus(mbb => + { + mbb + .AddChildBus("InMemory", cbb => + { + cbb.WithProviderMemory(cfg => + { + cfg.EnableBlockingPublish = false; + cfg.EnableMessageHeaders = true; + }) + .AddServicesFromAssemblyContaining( + consumerLifetime: ServiceLifetime.Scoped) + .Produce(x => x.DefaultTopic("NOTIFICATIONS")) + .Consume(x => + { + x.Instances(consumerOpts.InMemoryNotifications); + x.Topic("NOTIFICATIONS").WithConsumer(); + }) + .Produce(x => x.DefaultTopic("GMR")) + .Consume(x => + { + x.Instances(consumerOpts.InMemoryGmrs); + x.Topic("GMR").WithConsumer(); + }) + .Produce(x => x.DefaultTopic(nameof(AlvsClearanceRequest))) + .Consume(x => + { + x.Instances(consumerOpts.InMemoryClearanceRequests); + x.Topic("CLEARANCEREQUESTS").WithConsumer(); + }) + .Consume(x => + { + x.Instances(consumerOpts.InMemoryDecisions); + x.Topic("DECISIONS").WithConsumer(); + }); + }); + }); - return services; + return services; + } } } \ No newline at end of file From 1e36712f373d46f356ebf8315e9209ed5f0bb06f Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Tue, 10 Dec 2024 08:42:34 +0000 Subject: [PATCH 11/12] Fixed almost all outstanding ReSharper warnings --- Btms.Analytics/MovementsAggregationService.cs | 2 +- .../DescriptorModel/PropertyDescriptor.cs | 4 +- .../Commands/GenerateAlvsModelCommand.cs | 1 - .../SyncClearanceRequestsCommandTests.cs | 75 +++++++++---------- .../Commands/SyncDecisionsCommandTests.cs | 57 +++++++------- .../Commands/SyncNotificationsCommand.cs | 1 - 6 files changed, 67 insertions(+), 73 deletions(-) diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 594ff10..387da2a 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -1,11 +1,11 @@ using Microsoft.Extensions.Logging; using System.Linq.Expressions; +using Btms.Analytics.Extensions; using Btms.Backend.Data; using Btms.Model.Extensions; using Btms.Model; using MongoDB.Bson; using MongoDB.Driver; -using Btms.Analytics.Extensions; namespace Btms.Analytics; diff --git a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs index bf0d383..55e036e 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/DescriptorModel/PropertyDescriptor.cs @@ -63,9 +63,9 @@ public PropertyDescriptor(string sourceName, string internalName, string type, s public bool MappingInline { get; set; } - public bool ExcludedFromInternal { get; set; } = false; + public bool ExcludedFromInternal { get; set; } - public bool ExcludedFromSource { get; set; } = false; + public bool ExcludedFromSource { get; set; } public void OverrideType(string type) { diff --git a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs index 338b545..0db2672 100644 --- a/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs +++ b/Btms.Backend.Cli/Features/GenerateModels/GenerateAlvsModel/Commands/GenerateAlvsModelCommand.cs @@ -79,7 +79,6 @@ private void BuildClass(CSharpDescriptor cSharpDescriptor, XmlSchemaComplexType classNamePrefix: ClassNamePrefix); classDescriptor.Properties.Add(propertyDescriptor); } - } } diff --git a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs index 63f3a89..4c79019 100644 --- a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs @@ -5,8 +5,6 @@ using Btms.SensitiveData; using Btms.SyncJob; using Btms.Types.Alvs; -using Btms.Types.Ipaffs; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using NSubstitute; @@ -15,44 +13,43 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Business.Tests.Commands +namespace Btms.Business.Tests.Commands; + +public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) { - public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) + [Fact] + public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() { - [Fact] - public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() - { - var clearanceRequest = ClearanceRequestBuilder.Default().Build(); - var command = new SyncClearanceRequestsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); - - - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(clearanceRequest!.Header!.EntryReference!, clearanceRequest.ToJsonString()) - .ToAsyncEnumerator()); - - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(clearanceRequest.ToJsonString()); - - - var handler = new SyncClearanceRequestsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); - - await handler.Handle(command, CancellationToken.None); - - // ASSERT - await bus.Received(1).Publish(Arg.Any(), "CLEARANCEREQUESTS", - Arg.Any>(), Arg.Any()); - } + var clearanceRequest = ClearanceRequestBuilder.Default().Build(); + var command = new SyncClearanceRequestsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); + + + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns( + new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()) + .ToAsyncEnumerator()); + + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(clearanceRequest.ToJsonString()); + + + var handler = new SyncClearanceRequestsCommand.Handler( + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); + + await handler.Handle(command, CancellationToken.None); + + // ASSERT + await bus.Received(1).Publish(Arg.Any(), "ALVS", + Arg.Any>(), Arg.Any()); } } \ No newline at end of file diff --git a/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs b/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs index 9c32a07..def5cb5 100644 --- a/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncDecisionsCommandTests.cs @@ -13,41 +13,40 @@ using Xunit; using Xunit.Abstractions; -namespace Btms.Business.Tests.Commands; - -public class SyncDecisionsCommandTests(ITestOutputHelper outputHelper) +namespace Btms.Business.Tests.Commands { - [Fact] - public async Task WhenDecisionBlobsExist_ThenTheyShouldBePlacedOnInternalBus() + public class SyncDecisionsCommandTests(ITestOutputHelper outputHelper) { - var clearanceRequest = ClearanceRequestBuilder.Default().Build(); - var command = new SyncDecisionsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "Test Job"); + [Fact] + public async Task WhenDecisionBlobsExist_ThenTheyShouldBePlacedOnInternalBus() + { + var clearanceRequest = ClearanceRequestBuilder.Default().Build(); + var command = new SyncDecisionsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "Test Job"); - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()) - .ToAsyncEnumerator()); + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns(new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()).ToAsyncEnumerator()); - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(clearanceRequest.ToJsonString()); + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(clearanceRequest.ToJsonString()); - var handler = new SyncDecisionsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); + var handler = new SyncDecisionsCommand.Handler( + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); - await handler.Handle(command, CancellationToken.None); + await handler.Handle(command, CancellationToken.None); - // ASSERT - await bus.Received(1).Publish(Arg.Any(), "DECISIONS", - Arg.Any>(), Arg.Any()); + // ASSERT + await bus.Received(1).Publish(Arg.Any(), "DECISIONS", + Arg.Any>(), Arg.Any()); + } } } \ No newline at end of file diff --git a/Btms.Business/Commands/SyncNotificationsCommand.cs b/Btms.Business/Commands/SyncNotificationsCommand.cs index 11b8bc6..6161bfa 100644 --- a/Btms.Business/Commands/SyncNotificationsCommand.cs +++ b/Btms.Business/Commands/SyncNotificationsCommand.cs @@ -1,4 +1,3 @@ -using Azure.Core; using Btms.BlobService; using Btms.Metrics; using Btms.SensitiveData; From e193f1df03a41de5ecac49cfd524a780e5e90b7a Mon Sep 17 00:00:00 2001 From: Ian Shimmings Date: Thu, 12 Dec 2024 11:23:16 +0000 Subject: [PATCH 12/12] Fixed up warnings introduced in merge --- Btms.Analytics/MovementsAggregationService.cs | 2 - .../SyncClearanceRequestsCommandTests.cs | 71 +++++++++---------- .../Finders/ChedPPDecisionFinderTests.cs | 1 + .../Services/Linking/LinkingServiceTests.cs | 8 ++- Btms.Business/BusinessOptions.cs | 1 - Btms.Business/Commands/SyncHandler.cs | 4 +- .../Decisions/Finders/ChedPPDecisionFinder.cs | 1 + Btms.Consumers/ConsumerOptions.cs | 3 - .../Extensions/ServiceCollectionExtensions.cs | 2 - .../GrmWithTransformMapper.cs | 1 + .../DateTimeMapper.cs | 1 + .../DictionaryMapper.cs | 1 + .../ImportNotificationWithTransformMapper.cs | 1 + ...rsToDictionaryStringObjectJsonConverter.cs | 1 + 14 files changed, 49 insertions(+), 49 deletions(-) diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 7a6bf1a..387da2a 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -6,8 +6,6 @@ using Btms.Model; using MongoDB.Bson; using MongoDB.Driver; -using Btms.Analytics.Extensions; -using Microsoft.EntityFrameworkCore.Query.SqlExpressions; namespace Btms.Analytics; diff --git a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs index 612b77d..f247f4a 100644 --- a/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs +++ b/Btms.Business.Tests/Commands/SyncClearanceRequestsCommandTests.cs @@ -17,40 +17,39 @@ namespace Btms.Business.Tests.Commands; public class SyncClearanceRequestsCommandTests(ITestOutputHelper outputHelper) { - [Fact] - public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() - { - var clearanceRequest = ClearanceRequestBuilder.Default().Build(); - var command = new SyncClearanceRequestsCommand(); - var jobStore = new SyncJobStore(); - jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); - - - var bus = Substitute.For(); - var blob = Substitute.For(); - blob.GetResourcesAsync(Arg.Any(), Arg.Any()) - .Returns( - new TestBlobItem(clearanceRequest!.Header!.EntryReference!, clearanceRequest.ToJsonString()) - .ToAsyncEnumerator()); - - blob.GetResource(Arg.Any(), Arg.Any()) - .Returns(clearanceRequest.ToJsonString()); - - - var handler = new SyncClearanceRequestsCommand.Handler( - new SyncMetrics(new DummyMeterFactory()), - bus, - TestLogger.Create(outputHelper), - new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), - blob, - Options.Create(new BusinessOptions()), - jobStore); - - await handler.Handle(command, CancellationToken.None); - - // ASSERT - await bus.Received(1).Publish(Arg.Any(), "CLEARANCEREQUESTS", - Arg.Any>(), Arg.Any()); - } + [Fact] + public async Task WhenClearanceRequestBlobsExist_ThenTheyShouldBePlacedOnInternalBus() + { + var clearanceRequest = ClearanceRequestBuilder.Default().Build(); + var command = new SyncClearanceRequestsCommand(); + var jobStore = new SyncJobStore(); + jobStore.CreateJob(command.JobId, SyncPeriod.All.ToString(), "ClearanceRequests"); + + + var bus = Substitute.For(); + var blob = Substitute.For(); + blob.GetResourcesAsync(Arg.Any(), Arg.Any()) + .Returns( + new TestBlobItem(clearanceRequest.Header!.EntryReference!, clearanceRequest.ToJsonString()) + .ToAsyncEnumerator()); + + blob.GetResource(Arg.Any(), Arg.Any()) + .Returns(clearanceRequest.ToJsonString()); + + + var handler = new SyncClearanceRequestsCommand.Handler( + new SyncMetrics(new DummyMeterFactory()), + bus, + TestLogger.Create(outputHelper), + new SensitiveDataSerializer(Options.Create(SensitiveDataOptions.WithSensitiveData), NullLogger.Instance), + blob, + Options.Create(new BusinessOptions()), + jobStore); + + await handler.Handle(command, CancellationToken.None); + + // ASSERT + await bus.Received(1).Publish(Arg.Any(), "CLEARANCEREQUESTS", + Arg.Any>(), Arg.Any()); } -} \ No newline at end of file +} diff --git a/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs b/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs index c242a76..0ec8c9c 100644 --- a/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs +++ b/Btms.Business.Tests/Services/Decisions/Finders/ChedPPDecisionFinderTests.cs @@ -3,6 +3,7 @@ namespace Btms.Business.Tests.Services.Decisions.Finders; +// ReSharper disable once InconsistentNaming public class ChedPPDecisionFinderTests { [Fact] diff --git a/Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs b/Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs index ff0e02a..02f3735 100644 --- a/Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs +++ b/Btms.Business.Tests/Services/Linking/LinkingServiceTests.cs @@ -16,7 +16,7 @@ namespace Btms.Business.Tests.Services.Linking; public class LinkingServiceTests { - private static readonly Random random = new (); + private static readonly Random Random = new (); private readonly IMongoDbContext dbContext = new MemoryMongoDbContext(); private readonly LinkingMetrics linkingMetrics = new(new DummyMeterFactory()); private static string GenerateDocumentReference(int id) => $"GBCVD2024.{id}"; @@ -295,7 +295,8 @@ private MovementLinkContext CreateMovementContext(Movement? movement, List new Items { Documents = [ new Document { DocumentReference = GenerateDocumentReference(x) } ] - }).ToList() + }).ToList(), + ClearanceRequests = new() }; var existingMovement = createExistingMovement ? @@ -308,7 +309,8 @@ private MovementLinkContext CreateMovementContext(Movement? movement, List(string path, SyncPeriod period, stri var result = blobService.GetResourcesAsync($"{path}{period.GetPeriodPath()}", cancellationToken); var degreeOfParallelism = options.Value.GetConcurrency(BusinessOptions.Feature.BlobItems); - await Parallel.ForEachAsync(result, new ParallelOptions() { CancellationToken = cancellationToken, MaxDegreeOfParallelism = degreeOfParallelism }, async (item, token) => + await Parallel.ForEachAsync(result, new ParallelOptions() { CancellationToken = cancellationToken, MaxDegreeOfParallelism = degreeOfParallelism }, async (item, _) => { await SyncBlob(path, topic, item, job, cancellationToken); }); @@ -121,7 +121,7 @@ protected async Task SyncBlobs(SyncPeriod period, string topic, Guid j var degreeOfParallelism = options.Value.GetConcurrency(BusinessOptions.Feature.BlobItems); job?.Start(); - logger.LogInformation("SyncNotifications period: {Period}, maxDegreeOfParallelism={degreeOfParallelism}, Environment.ProcessorCount={ProcessorCount}", period.ToString(), degreeOfParallelism, Environment.ProcessorCount); + logger.LogInformation("SyncNotifications period: {Period}, maxDegreeOfParallelism={DegreeOfParallelism}, Environment.ProcessorCount={ProcessorCount}", period.ToString(), degreeOfParallelism, Environment.ProcessorCount); try { foreach (var path in paths) diff --git a/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs b/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs index c9f4265..2518164 100644 --- a/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs +++ b/Btms.Business/Services/Decisions/Finders/ChedPPDecisionFinder.cs @@ -2,6 +2,7 @@ namespace Btms.Business.Services.Decisions.Finders; +// ReSharper disable once InconsistentNaming public class ChedPPDecisionFinder : IDecisionFinder { public DecisionResult FindDecision(ImportNotification notification) diff --git a/Btms.Consumers/ConsumerOptions.cs b/Btms.Consumers/ConsumerOptions.cs index 8ea4430..7b64d5a 100644 --- a/Btms.Consumers/ConsumerOptions.cs +++ b/Btms.Consumers/ConsumerOptions.cs @@ -1,6 +1,3 @@ -using System.ComponentModel.DataAnnotations; -using Btms.Azure; - namespace Btms.Consumers; public class ConsumerOptions diff --git a/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs b/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs index 5078f2e..83545f4 100644 --- a/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs +++ b/Btms.Consumers/Extensions/ServiceCollectionExtensions.cs @@ -1,4 +1,3 @@ -using System.Configuration; using Btms.Common.Extensions; using Btms.Consumers.Interceptors; using Btms.Consumers.MemoryQueue; @@ -7,7 +6,6 @@ using Btms.Types.Ipaffs; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using SlimMessageBus.Host; using SlimMessageBus.Host.Interceptor; using SlimMessageBus.Host.Memory; diff --git a/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs b/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs index f543d95..6df2a5c 100644 --- a/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs +++ b/Btms.Types.Gvms.Mapping.V1/GrmWithTransformMapper.cs @@ -1,6 +1,7 @@ using Btms.Model.Extensions; using Btms.Model.Relationships; +// ReSharper disable once CheckNamespace namespace Btms.Types.Gvms.Mapping; public static class GrmWithTransformMapper diff --git a/Btms.Types.Ipaffs.Mapping.V1/DateTimeMapper.cs b/Btms.Types.Ipaffs.Mapping.V1/DateTimeMapper.cs index a98215d..6ab5b6f 100644 --- a/Btms.Types.Ipaffs.Mapping.V1/DateTimeMapper.cs +++ b/Btms.Types.Ipaffs.Mapping.V1/DateTimeMapper.cs @@ -1,3 +1,4 @@ +// ReSharper disable once CheckNamespace namespace Btms.Types.Ipaffs.Mapping; public static class DateTimeMapper diff --git a/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs b/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs index 6275fc8..0eb0ea1 100644 --- a/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs +++ b/Btms.Types.Ipaffs.Mapping.V1/DictionaryMapper.cs @@ -1,3 +1,4 @@ +// ReSharper disable once CheckNamespace namespace Btms.Types.Ipaffs.Mapping; public static class DictionaryMapper diff --git a/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs b/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs index 9f5cc08..e92e69b 100644 --- a/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs +++ b/Btms.Types.Ipaffs.Mapping.V1/ImportNotificationWithTransformMapper.cs @@ -1,3 +1,4 @@ +// ReSharper disable once CheckNamespace namespace Btms.Types.Ipaffs.Mapping; public static class ImportNotificationWithTransformMapper diff --git a/Btms.Types.Ipaffs.V1/KeyDataPairsToDictionaryStringObjectJsonConverter.cs b/Btms.Types.Ipaffs.V1/KeyDataPairsToDictionaryStringObjectJsonConverter.cs index daf1891..4fc568c 100644 --- a/Btms.Types.Ipaffs.V1/KeyDataPairsToDictionaryStringObjectJsonConverter.cs +++ b/Btms.Types.Ipaffs.V1/KeyDataPairsToDictionaryStringObjectJsonConverter.cs @@ -1,6 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; +// ReSharper disable once CheckNamespace namespace Btms.Types.Ipaffs; public class KeyDataPairsToDictionaryStringObjectJsonConverter : JsonConverter>