From ccc72910d2a76ac42f23e885c33c66adcdcf797b Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 25 Oct 2024 15:38:06 +0100 Subject: [PATCH 01/39] WIP --- .../Performance/ValidatorsPerformanceTests.cs | 11 +- .../Services/ValidationServiceTests.cs | 14 +- .../Clients/CompanyDetailsApiClient.cs | 171 ++++++++++++++++++ .../Clients/ICompanyDetailsApiClient.cs | 18 ++ .../ConfigureServices.cs | 2 + .../Constants/ErrorCode.cs | 2 + .../Constants/FeatureFlags.cs | 7 + ...oducerContentValidation.Application.csproj | 7 + .../CompanyDetailsApiClientException.cs | 23 +++ .../CompanyDetailsApiAuthorisationHandler.cs | 39 ++++ .../ISubsidiaryDetailsRequestBuilder.cs | 10 + .../SubsidiaryDetailsRequestBuilder.cs | 29 +++ .../Services/ValidationService.cs | 94 +++++++++- .../SubsidiaryIdExistenceValidator.cs | 16 ++ .../SubsidiaryIdOrganisationCheck.cs | 16 ++ .../SubsidiaryIdValidator.cs | 1 - .../Config/CompanyDetailsApiConfig.cs | 16 ++ .../EPR.ProducerContentValidation.Data.csproj | 13 ++ .../CompanyDetailsDataItem.cs | 13 ++ .../CompanyDetailsDataResult.cs | 10 + .../Models/Subsidiary/SubsidiaryDetail.cs | 14 ++ .../Subsidiary/SubsidiaryDetailsRequest.cs | 10 + .../Subsidiary/SubsidiaryDetailsResponse.cs | 10 + .../SubsidiaryOrganisationDetail.cs | 12 ++ ...oducerContentValidation.FunctionApp.csproj | 2 +- .../StartUp.cs | 16 ++ .../settings.json | 3 +- src/EPR.ProducerContentValidation.sln | 31 +++- 28 files changed, 596 insertions(+), 14 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs create mode 100644 src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs index acdfc7d..a7e5f13 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using Bogus; +using EPR.ProducerContentValidation.Application.Clients; using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -7,12 +8,14 @@ using EPR.ProducerContentValidation.Application.ReferenceData; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; using EPR.ProducerContentValidation.Application.Validators.Factories; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.FeatureManagement; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -28,6 +31,9 @@ public ValidatorsPerformanceTests() Mock> validationOptionsMock = new(); Mock errorCountServiceMock = new(); Mock> loggerMock = new(); + Mock featureManagerMock = new(); + Mock subsidiaryDetailsRequestBuilderMock = new(); + Mock companyDetailsApiClientMock = new(); var submissionConfigOptions = new Mock>>(); @@ -54,7 +60,10 @@ public ValidatorsPerformanceTests() compositeValidatorUnderTest, AutoMapperHelpers.GetMapper(), errorCountServiceMock.Object, - Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = "ContainerName" })); + Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = "ContainerName" }), + featureManagerMock.Object, + subsidiaryDetailsRequestBuilderMock.Object, + companyDetailsApiClientMock.Object); } [TestMethod] diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 53aa310..635d0b0 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,14 +1,17 @@ using AutoMapper; +using EPR.ProducerContentValidation.Application.Clients; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; +using Microsoft.FeatureManagement; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -29,6 +32,9 @@ public class ValidationServiceTests private Mock _compositeValidatorMock; private Mock _issueCountServiceMock; private Mock> _loggerMock; + private Mock _featureManagerMock; + private Mock _subsidiaryDetailsRequestBuilderMock; + private Mock _companyDetailsApiClientMock; [TestInitialize] public void TestInitialize() @@ -37,6 +43,9 @@ public void TestInitialize() _loggerMock = new Mock>(); _issueCountServiceMock = new Mock(); _mapper = AutoMapperHelpers.GetMapper(); + _featureManagerMock = new Mock(); + _subsidiaryDetailsRequestBuilderMock = new Mock(); + _companyDetailsApiClientMock = new Mock(); _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(ErrorStoreKey)) .ReturnsAsync(100); @@ -88,5 +97,8 @@ private ValidationService CreateSystemUnderTest() => _compositeValidatorMock.Object, _mapper, _issueCountServiceMock.Object, - Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = ContainerName })); + Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = ContainerName }), + _featureManagerMock.Object, + _subsidiaryDetailsRequestBuilderMock.Object, + _companyDetailsApiClientMock.Object); } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs new file mode 100644 index 0000000..d1827ec --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -0,0 +1,171 @@ +using System.Net; +using EPR.ProducerContentValidation.Application.Exceptions; +using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Application.Clients +{ + public class CompanyDetailsApiClient : ICompanyDetailsApiClient + { + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + + public CompanyDetailsApiClient( + HttpClient httpClient, + ILogger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public async Task GetCompanyDetails(string organisationId) + { + try + { + var uriString = $"api/company-details/{organisationId}"; + var response = await _httpClient.GetAsync(uriString); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting company details"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + public async Task GetCompanyDetailsByProducer(string producerOrganisationId) + { + try + { + var uriString = $"api/company-details-by-producer/{producerOrganisationId}"; + var response = await _httpClient.GetAsync(uriString); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting company details"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + public async Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest) + { + try + { + var uriString = "api/subsidiary-details"; + var httpContent = CreateHttpContent(subsidiaryDetailsRequest); + + var response = await _httpClient.PostAsync(uriString, httpContent); + + response.EnsureSuccessStatusCode(); + + return await DeserializeResponseData(response); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Error occurred while requesting subsidiary details"); + throw; + } + } + + public async Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId) + { + try + { + var uriString = $"api/company-details/{organisationId}/compliance-scheme/{complianceSchemeId}"; + var response = await _httpClient.GetAsync(uriString); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting compliance scheme member list"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + public async Task GetRemainingProducerDetails(IEnumerable referenceNumbers) + { + try + { + var uriString = $"api/company-details"; + + var json = JsonConvert.SerializeObject(referenceNumbers); + var httpContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); + + var response = await _httpClient.PostAsync(uriString, httpContent); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting remaining producer company details"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + private static async Task DeserializeCompanyDetailsData(HttpResponseMessage response) + { + if (!string.IsNullOrEmpty(await response.Content.ReadAsStringAsync())) + { + return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + } + + return new CompanyDetailsDataResult(); + } + + private static async Task DeserializeResponseData(HttpResponseMessage response) + { + var content = await response.Content.ReadAsStringAsync(); + + if (!string.IsNullOrEmpty(content)) + { + return JsonConvert.DeserializeObject(content); + } + + return default; + } + + private StringContent CreateHttpContent(object data) + { + var json = JsonConvert.SerializeObject(data); + return new StringContent(json, System.Text.Encoding.UTF8, "application/json"); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs new file mode 100644 index 0000000..82d171e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -0,0 +1,18 @@ +using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Clients +{ + public interface ICompanyDetailsApiClient + { + Task GetCompanyDetails(string organisationId); + + Task GetCompanyDetailsByProducer(string producerOrganisationId); + + Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId); + + Task GetRemainingProducerDetails(IEnumerable referenceNumbers); + + Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index fd38cbb..a8583b9 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; using EPR.ProducerContentValidation.Application.Validators.Factories; using EPR.ProducerContentValidation.Application.Validators.Factories.Interfaces; @@ -88,6 +89,7 @@ private static IServiceCollection RegisterValidators(this IServiceCollection ser services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs b/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs index 56bac4f..e96214f 100644 --- a/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs +++ b/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs @@ -54,6 +54,8 @@ public static class ErrorCode public const string WarningOnlyOnePackagingMaterialReported = "62"; public const string WarningPackagingTypePackagingMaterial = "63"; public const string WarningPackagingTypeQuantityUnitsLessThanQuantityKgs = "64"; + public const string SubsidiaryIdDoesNotExist = "70"; + public const string SubsidiaryIdIsAssignedToADifferentOrganisation = "71"; /* Issue codes 80 through 89 should be reserved for Issues from the Check Splitter API */ public const string UncaughtExceptionErrorCode = "99"; diff --git a/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs new file mode 100644 index 0000000..72ef6a1 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs @@ -0,0 +1,7 @@ +namespace EPR.ProducerContentValidation.Application.Constants +{ + public static class FeatureFlags + { + public const string EnableSubsidiaryValidation = "EnableSubsidiaryValidation"; + } +} diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index 401dfd8..eda8453 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -8,6 +8,8 @@ + + @@ -18,8 +20,13 @@ + + + + + \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs b/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs new file mode 100644 index 0000000..6f415be --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs @@ -0,0 +1,23 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Application.Exceptions +{ + [ExcludeFromCodeCoverage] + [Serializable] + public class CompanyDetailsApiClientException : Exception + { + public CompanyDetailsApiClientException() + { + } + + public CompanyDetailsApiClientException(string message) + : base(message) + { + } + + public CompanyDetailsApiClientException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs new file mode 100644 index 0000000..8513db8 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs @@ -0,0 +1,39 @@ +using System.Diagnostics.CodeAnalysis; +using System.Net.Http.Headers; +using Azure.Core; +using Azure.Identity; +using EPR.ProducerContentValidation.Data.Config; +using Microsoft.Extensions.Options; + +namespace EPR.ProducerContentValidation.Application.Handlers +{ + [ExcludeFromCodeCoverage(Justification = "Dependency on Azure to acquire token, will be assured via end to end testing.")] + public class CompanyDetailsApiAuthorisationHandler : DelegatingHandler + { + private const string BearerScheme = "Bearer"; + private readonly TokenRequestContext _tokenRequestContext; + private readonly DefaultAzureCredential? _credentials; + + public CompanyDetailsApiAuthorisationHandler(IOptions options) + { + if (string.IsNullOrEmpty(options.Value.ClientId)) + { + return; + } + + _tokenRequestContext = new TokenRequestContext(new[] { options.Value.ClientId }); + _credentials = new DefaultAzureCredential(); + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (_credentials != null) + { + var tokenResult = await _credentials.GetTokenAsync(_tokenRequestContext, cancellationToken); + request.Headers.Authorization = new AuthenticationHeaderValue(BearerScheme, tokenResult.Token); + } + + return await base.SendAsync(request, cancellationToken); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs new file mode 100644 index 0000000..c4eda28 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Subsidiary +{ + public interface ISubsidiaryDetailsRequestBuilder + { + SubsidiaryDetailsRequest CreateRequest(List rows); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs new file mode 100644 index 0000000..c5e794f --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -0,0 +1,29 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Subsidiary +{ + public class SubsidiaryDetailsRequestBuilder : ISubsidiaryDetailsRequestBuilder + { + public SubsidiaryDetailsRequest CreateRequest(List rows) + { + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = rows + .GroupBy(row => row.ProducerId) + .Select(group => new SubsidiaryOrganisationDetail + { + OrganisationReference = group.Key, + SubsidiaryDetails = group + .Where(row => !string.IsNullOrEmpty(row.SubsidiaryId)) + .Select(row => new SubsidiaryDetail + { + ReferenceNumber = row.SubsidiaryId, + }).ToList(), + }) + .ToList(), + }; + return subsidiaryDetailsRequest; + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index a2893ed..39378c3 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -1,13 +1,16 @@ using AutoMapper; +using EPR.ProducerContentValidation.Application.Clients; using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.FeatureManagement; namespace EPR.ProducerContentValidation.Application.Services; @@ -18,19 +21,28 @@ public class ValidationService : IValidationService private readonly IMapper _mapper; private readonly IIssueCountService _issueCountService; private readonly StorageAccountOptions _storageAccountOptions; + private readonly ISubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; + private readonly ICompanyDetailsApiClient _companyDetailsApiClient; + private IFeatureManager _featureManager; public ValidationService( ILogger logger, ICompositeValidator compositeValidator, IMapper mapper, IIssueCountService issueCountService, - IOptions storageAccountOptions) + IOptions storageAccountOptions, + IFeatureManager featureManager, + ISubsidiaryDetailsRequestBuilder subsidiaryDetailsRequestBuilder, + ICompanyDetailsApiClient companyDetailsApiClient) { _logger = logger; _compositeValidator = compositeValidator; _mapper = mapper; _issueCountService = issueCountService; _storageAccountOptions = storageAccountOptions.Value; + _featureManager = featureManager; + _subsidiaryDetailsRequestBuilder = subsidiaryDetailsRequestBuilder; + _companyDetailsApiClient = companyDetailsApiClient; } public async Task ValidateAsync(Producer producer) @@ -63,8 +75,88 @@ public async Task ValidateAsync(Producer producer) producerValidationOutRequest.ValidationErrors.AddRange(errors); producerValidationOutRequest.ValidationWarnings.AddRange(warnings); + if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + { + List subValidationResult = await ValidateSubsidiary(producer.Rows); + producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); + } + _logger.LogExit(); return producerValidationOutRequest; } + + public async Task> ValidateSubsidiary(List rows) + { + List validationErrors = new(); + try + { + var subsidiaryDetailsRequest = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + if (subsidiaryDetailsRequest == null || subsidiaryDetailsRequest.SubsidiaryOrganisationDetails == null || !subsidiaryDetailsRequest.SubsidiaryOrganisationDetails.Any()) + { + return validationErrors; + } + + var result = await _companyDetailsApiClient.GetSubsidiaryDetails(subsidiaryDetailsRequest); + + for (int i = 0; i < rows.Count; i++) + { + var matchingOrg = result.SubsidiaryOrganisationDetails + .FirstOrDefault(org => org.OrganisationReference == rows[i].ProducerId); + + if (matchingOrg == null) + { + continue; + } + + var matchingSub = matchingOrg.SubsidiaryDetails + .FirstOrDefault(sub => sub.ReferenceNumber == rows[i].SubsidiaryId); + + if (matchingSub == null) + { + continue; + } + + if (!matchingSub.SubsidiaryExists) + { + var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdDoesNotExist); + var errorMessage = $"Subsidiary ID does not exist"; + + LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); // Idris - remove? + validationErrors.Add(error); + continue; + } + + if (!matchingSub.SubsidiaryBelongsToOrganisation) + { + var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + var errorMessage = $"Subsidiary ID is assigned to a different organisation"; + + LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + validationErrors.Add(error); + } + } + + return validationErrors; + } + catch (HttpRequestException exception) + { + _logger.LogError(exception, "Error Subsidiary validation"); + return validationErrors; + } + } + + private void LogValidationWarning(int rowNumber, string errorMessage, string errorCode) + { + _logger.LogWarning( + "Validation error on row {Row} {ErrorMessage} Error code {ErrorCode}", + rowNumber, + errorMessage, + errorCode); + } + + private ProducerValidationEventIssueRequest CreateSubValidationError(ProducerRow row, object subsidiaryIdDoesNotExist) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs new file mode 100644 index 0000000..f725052 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs @@ -0,0 +1,16 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.Models; +using FluentValidation; + +namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators +{ + public class SubsidiaryIdExistenceValidator : AbstractValidator + { + public SubsidiaryIdExistenceValidator() + { + RuleFor(x => x.SubsidiaryId) + .NotEqual("true") + .WithErrorCode(ErrorCode.SubsidiaryIdDoesNotExist); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs new file mode 100644 index 0000000..c92235e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs @@ -0,0 +1,16 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.Models; +using FluentValidation; + +namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators +{ + public class SubsidiaryIdOrganisationCheck : AbstractValidator + { + public SubsidiaryIdOrganisationCheck() + { + RuleFor(x => x.SubsidiaryId) + .NotEqual("true") + .WithErrorCode(ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs index 2fd393b..880e482 100644 --- a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs @@ -1,7 +1,6 @@ namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators; using Constants; -using CustomValidators; using FluentValidation; using Models; diff --git a/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs new file mode 100644 index 0000000..d890038 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace EPR.ProducerContentValidation.Data.Config +{ + public class CompanyDetailsApiConfig + { + public const string Section = "CompanyDetailsApi"; + + [Required] + public string BaseUrl { get; init; } + + public string? ClientId { get; set; } + + public int Timeout { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj b/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj new file mode 100644 index 0000000..3b5b170 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs new file mode 100644 index 0000000..3e7df3e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi +{ + public class CompanyDetailsDataItem + { + [JsonProperty("RN")] + public string ReferenceNumber { get; set; } + + [JsonProperty("CHN")] + public string CompaniesHouseNumber { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs new file mode 100644 index 0000000..0650e48 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi +{ + public class CompanyDetailsDataResult + { + [JsonProperty(nameof(Organisations))] + public IEnumerable Organisations { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs new file mode 100644 index 0000000..cb92f85 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs @@ -0,0 +1,14 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryDetail + { + public string ReferenceNumber { get; set; } + + public bool SubsidiaryExists { get; set; } + + public bool SubsidiaryBelongsToOrganisation { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs new file mode 100644 index 0000000..c3a3f47 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryDetailsRequest + { + public List SubsidiaryOrganisationDetails { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs new file mode 100644 index 0000000..7a82d14 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryDetailsResponse + { + public List SubsidiaryOrganisationDetails { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs new file mode 100644 index 0000000..c467b0c --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryOrganisationDetail + { + public string OrganisationReference { get; set; } + + public List SubsidiaryDetails { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj b/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj index 7377347..efecc77 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj +++ b/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj @@ -5,7 +5,7 @@ net8.0 - + diff --git a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs index 978e3db..60826d1 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs +++ b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs @@ -6,9 +6,15 @@ namespace EPR.ProducerContentValidation.FunctionApp; using System.Diagnostics.CodeAnalysis; +using System.Net.Http.Headers; using Application; +using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Handlers; +using EPR.ProducerContentValidation.Data.Config; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.FeatureManagement; [ExcludeFromCodeCoverage] public class StartUp : FunctionsStartup @@ -17,8 +23,18 @@ public override void Configure(IFunctionsHostBuilder builder) { var services = builder.Services; + services.AddFeatureManagement(); services.AddApplicationServices(); services.AddFunctionServices(); services.AddApplicationInsightsTelemetry(); + + services.AddHttpClient((sp, c) => + { + var companyDetailsApiConfig = sp.GetRequiredService>().Value; + c.BaseAddress = new Uri(companyDetailsApiConfig.BaseUrl); + c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + c.Timeout = TimeSpan.FromSeconds(companyDetailsApiConfig.Timeout); + }) + .AddHttpMessageHandler(); } } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.FunctionApp/settings.json b/src/EPR.ProducerContentValidation.FunctionApp/settings.json index 8cb97f3..2fe27a2 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/settings.json +++ b/src/EPR.ProducerContentValidation.FunctionApp/settings.json @@ -9,6 +9,7 @@ "StorageAccount:PomContainer": "pom-upload-container", "Validation:MaxIssuesToProcess": 1000, "Redis:ConnectionString": "https://localhost:1234", - "Validation:IsLatest": false + "Validation:IsLatest": false, + "FeatureManagement:EnableSubsidiaryValidation": false } } diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index d454113..c7705fe 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -1,24 +1,29 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.FunctionApp", "EPR.ProducerContentValidation.FunctionApp\EPR.ProducerContentValidation.FunctionApp.csproj", "{28E03AA1-AB29-41C5-9749-8E657B523677}" +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.FunctionApp", "EPR.ProducerContentValidation.FunctionApp\EPR.ProducerContentValidation.FunctionApp.csproj", "{28E03AA1-AB29-41C5-9749-8E657B523677}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.FunctionApp.UnitTests", "EPR.ProducerContentValidation.FunctionApp.UnitTests\EPR.ProducerContentValidation.FunctionApp.UnitTests.csproj", "{B320427A-D6E5-4526-850A-4CD6395B40A3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.FunctionApp.UnitTests", "EPR.ProducerContentValidation.FunctionApp.UnitTests\EPR.ProducerContentValidation.FunctionApp.UnitTests.csproj", "{B320427A-D6E5-4526-850A-4CD6395B40A3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Application", "EPR.ProducerContentValidation.Application\EPR.ProducerContentValidation.Application.csproj", "{05AFF197-3A91-4785-A053-C949984A0168}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Application", "EPR.ProducerContentValidation.Application\EPR.ProducerContentValidation.Application.csproj", "{05AFF197-3A91-4785-A053-C949984A0168}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Application.UnitTests", "EPR.ProducerContentValidation.Application.UnitTests\EPR.ProducerContentValidation.Application.UnitTests.csproj", "{41F0031E-EFF7-4C25-9934-5C5D9A95C85C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Application.UnitTests", "EPR.ProducerContentValidation.Application.UnitTests\EPR.ProducerContentValidation.Application.UnitTests.csproj", "{41F0031E-EFF7-4C25-9934-5C5D9A95C85C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.TestSupport", "EPR.ProducerContentValidation.TestSupport\EPR.ProducerContentValidation.TestSupport.csproj", "{3CFB967D-D84E-44E0-91A4-55B44EEC5215}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.TestSupport", "EPR.ProducerContentValidation.TestSupport\EPR.ProducerContentValidation.TestSupport.csproj", "{3CFB967D-D84E-44E0-91A4-55B44EEC5215}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0408BD47-B8AF-4972-9D34-41078B6EE09E}" ProjectSection(SolutionItems) = preProject - Directory.Build.props = Directory.Build.props - stylecop.ruleset = stylecop.ruleset - ..\README.md = ..\README.md ..\CONTRIBUTING.md = ..\CONTRIBUTING.md + Directory.Build.props = Directory.Build.props ..\LICENCE.md = ..\LICENCE.md + ..\README.md = ..\README.md + stylecop.ruleset = stylecop.ruleset EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,5 +50,15 @@ Global {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.Build.0 = Release|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0DBBE26A-4E2C-4007-8F12-99D10A5FB5BC} EndGlobalSection EndGlobal From 96f35bf3f8c8cc3b354ca1d2cd409888342d3e69 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 25 Oct 2024 17:38:41 +0100 Subject: [PATCH 02/39] WIP --- .gitignore | 1 + .../Clients/CompanyDetailsApiClient.cs | 115 +----------------- .../Clients/ICompanyDetailsApiClient.cs | 11 +- .../CompanyDetailsDataItem.cs | 13 -- .../CompanyDetailsDataResult.cs | 10 -- .../settings.json | 3 + 6 files changed, 6 insertions(+), 147 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs delete mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs diff --git a/.gitignore b/.gitignore index d342c2f..b72df34 100644 --- a/.gitignore +++ b/.gitignore @@ -414,3 +414,4 @@ FodyWeavers.xsd # AppSettings Development file **/appSettings.Development.json /src/EPR.ProducerContentValidation.FunctionApp/localSettings.json +/src/EPR.ProducerContentValidation.FunctionApp/local.settings 18.json diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs index d1827ec..05c886b 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -1,7 +1,4 @@ -using System.Net; -using EPR.ProducerContentValidation.Application.Exceptions; -using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -20,54 +17,6 @@ public CompanyDetailsApiClient( _logger = logger; } - public async Task GetCompanyDetails(string organisationId) - { - try - { - var uriString = $"api/company-details/{organisationId}"; - var response = await _httpClient.GetAsync(uriString); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting company details"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - - public async Task GetCompanyDetailsByProducer(string producerOrganisationId) - { - try - { - var uriString = $"api/company-details-by-producer/{producerOrganisationId}"; - var response = await _httpClient.GetAsync(uriString); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting company details"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - public async Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest) { try @@ -88,68 +37,6 @@ public async Task GetSubsidiaryDetails(SubsidiaryDeta } } - public async Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId) - { - try - { - var uriString = $"api/company-details/{organisationId}/compliance-scheme/{complianceSchemeId}"; - var response = await _httpClient.GetAsync(uriString); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting compliance scheme member list"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - - public async Task GetRemainingProducerDetails(IEnumerable referenceNumbers) - { - try - { - var uriString = $"api/company-details"; - - var json = JsonConvert.SerializeObject(referenceNumbers); - var httpContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); - - var response = await _httpClient.PostAsync(uriString, httpContent); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting remaining producer company details"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - - private static async Task DeserializeCompanyDetailsData(HttpResponseMessage response) - { - if (!string.IsNullOrEmpty(await response.Content.ReadAsStringAsync())) - { - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - } - - return new CompanyDetailsDataResult(); - } - private static async Task DeserializeResponseData(HttpResponseMessage response) { var content = await response.Content.ReadAsStringAsync(); diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs index 82d171e..79086d9 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -1,18 +1,9 @@ -using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Clients { public interface ICompanyDetailsApiClient { - Task GetCompanyDetails(string organisationId); - - Task GetCompanyDetailsByProducer(string producerOrganisationId); - - Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId); - - Task GetRemainingProducerDetails(IEnumerable referenceNumbers); - Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest); } } diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs deleted file mode 100644 index 3e7df3e..0000000 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi -{ - public class CompanyDetailsDataItem - { - [JsonProperty("RN")] - public string ReferenceNumber { get; set; } - - [JsonProperty("CHN")] - public string CompaniesHouseNumber { get; set; } - } -} diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs deleted file mode 100644 index 0650e48..0000000 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi -{ - public class CompanyDetailsDataResult - { - [JsonProperty(nameof(Organisations))] - public IEnumerable Organisations { get; set; } - } -} diff --git a/src/EPR.ProducerContentValidation.FunctionApp/settings.json b/src/EPR.ProducerContentValidation.FunctionApp/settings.json index 2fe27a2..9d0d533 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/settings.json +++ b/src/EPR.ProducerContentValidation.FunctionApp/settings.json @@ -5,6 +5,9 @@ "ServiceBus:ConnectionString": "Endpoint=sb://devrwdinfsb1401.servicebus.windows.net/", "ServiceBus:SplitQueueName": "defra.epr.producer.data", "SubmissionApi:BaseUrl": "https://localhost:1234", + "CompanyDetailsApi:BaseUrl": "http://localhost:7076/", + "CompanyDetailsApi:Timeout": 10, + "CompanyDetailsApi:ClientId": "", "Validation:Disabled": false, "StorageAccount:PomContainer": "pom-upload-container", "Validation:MaxIssuesToProcess": 1000, From 05d9eb356f28e30e3629dd408b121b86ed815873 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Sun, 27 Oct 2024 21:08:41 +0000 Subject: [PATCH 03/39] Unit tests for subsidiary validation --- .../Services/ValidationServiceTests.cs | 168 ++++++++++++++++++ .../Services/ValidationService.cs | 2 +- ...ProducerContentValidation.UnitTests.csproj | 50 ++++++ .../Properties/AssemblyInfo.cs | 20 +++ .../UnitTest1.cs | 14 ++ src/EPR.ProducerContentValidation.sln | 2 +- 6 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj create mode 100644 src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs create mode 100644 src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 635d0b0..a1fbafc 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,5 +1,6 @@ using AutoMapper; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -8,6 +9,7 @@ using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; @@ -91,6 +93,172 @@ public async Task ValidateAsync_ValidatesForErrorsAndWarnings_DoesNotCallComposi _compositeValidatorMock.Verify(x => x.ValidateDuplicatesAndGroupedData(producerRows, new List(), It.IsAny>(), BlobName), Times.Never); } + [TestMethod] + public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List + { + new SubsidiaryOrganisationDetail + { + OrganisationReference = "OrgRef", + SubsidiaryDetails = new List + { + new SubsidiaryDetail + { + ReferenceNumber = "SubRef", + SubsidiaryExists = true, + SubsidiaryBelongsToOrganisation = true + } + } + } + } + }; + + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(rows)) + .Returns(subsidiaryDetailsRequest); + + _companyDetailsApiClientMock + .Setup(x => x.GetSubsidiaryDetails(subsidiaryDetailsRequest)) + .ReturnsAsync(subsidiaryDetailsResponse); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiary(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(rows)) + .Returns((SubsidiaryDetailsRequest)null); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiary(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + var exception = new HttpRequestException("An error occurred while creating the request."); + + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(It.IsAny>())) + .Throws(exception); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiary(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + _loggerMock.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((v, t) => v.ToString().Contains("Error Subsidiary validation")), + It.Is(ex => ex == exception), + It.IsAny>()), + Times.Once); + } + + [TestMethod] + public async Task ValidateAsync_WithSubsidiaryValidationEnabled_PerformsSubsidiaryValidation() + { + // Arrange + var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var validationErrors = new List(); + + _featureManagerMock + .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + .ReturnsAsync(true); + + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(producer.Rows)) + .Returns(new SubsidiaryDetailsRequest() + { + SubsidiaryOrganisationDetails = new List() + { + new SubsidiaryOrganisationDetail() + { } + } + }); + + var subsidiaryOrganisationDetails = new List(); + subsidiaryOrganisationDetails.Add(new SubsidiaryOrganisationDetail + { + OrganisationReference = "sds", + SubsidiaryDetails = new List() + }); + var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse(); + subsidiaryDetailsResponse.SubsidiaryOrganisationDetails = subsidiaryOrganisationDetails; + + _companyDetailsApiClientMock + .Setup(x => x.GetSubsidiaryDetails(It.IsAny())) + .ReturnsAsync(subsidiaryDetailsResponse); + + _issueCountServiceMock + .Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())) + .ReturnsAsync(1); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(producer.Rows), Times.Once); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); + } + + [TestMethod] + public async Task ValidateAsync_WithSubsidiaryValidationDisabled_SkipsSubsidiaryValidation() + { + // Arrange + var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + // Mock feature flag to disable subsidiary validation + _featureManagerMock + .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + .ReturnsAsync(false); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); + result.ValidationErrors.Should().BeEmpty(); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 39378c3..4056839 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -122,7 +122,7 @@ public async Task> ValidateSubsidiary( var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdDoesNotExist); var errorMessage = $"Subsidiary ID does not exist"; - LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); // Idris - remove? + LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); validationErrors.Add(error); continue; } diff --git a/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj b/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj new file mode 100644 index 0000000..6783e83 --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj @@ -0,0 +1,50 @@ + + + + + Debug + AnyCPU + {E7C40F24-549B-494A-AEF1-325C5658C9A0} + Library + Properties + EPR.ProducerContentValidation.UnitTests + EPR.ProducerContentValidation.UnitTests + v4.7.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs b/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..917489b --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("EPR.ProducerContentValidation.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("EPR.ProducerContentValidation.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("e7c40f24-549b-494a-aef1-325c5658c9a0")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs b/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs new file mode 100644 index 0000000..0f13eca --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs @@ -0,0 +1,14 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace EPR.ProducerContentValidation.UnitTests +{ + [TestClass] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + } + } +} diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index c7705fe..d092b76 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -22,7 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution stylecop.ruleset = stylecop.ruleset EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 8d5253b2e65e44ce89f690ffa4458b49925f7e24 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Mon, 28 Oct 2024 00:37:01 +0000 Subject: [PATCH 04/39] Unit tests --- .../SubsidiaryDetailsRequestBuilder.cs | 1 + .../SubsidiaryIdExistenceValidator.cs | 16 - .../SubsidiaryIdOrganisationCheck.cs | 16 - .../Clients/CompanyDetailsApiClientTests.cs | 109 +++++++ ....ProducerContentValidation.UnitTest.csproj | 30 ++ .../SubsidiaryDetailsRequestBuilderTests.cs | 291 ++++++++++++++++++ ...ProducerContentValidation.UnitTests.csproj | 50 --- .../Properties/AssemblyInfo.cs | 20 -- .../UnitTest1.cs | 14 - src/EPR.ProducerContentValidation.sln | 6 + 10 files changed, 437 insertions(+), 116 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs delete mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs create mode 100644 src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs create mode 100644 src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj create mode 100644 src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs delete mode 100644 src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj delete mode 100644 src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs index c5e794f..8084dcb 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -11,6 +11,7 @@ public SubsidiaryDetailsRequest CreateRequest(List rows) { SubsidiaryOrganisationDetails = rows .GroupBy(row => row.ProducerId) + .Where(group => group.Any(row => !string.IsNullOrEmpty(row.SubsidiaryId))) .Select(group => new SubsidiaryOrganisationDetail { OrganisationReference = group.Key, diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs deleted file mode 100644 index f725052..0000000 --- a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using EPR.ProducerContentValidation.Application.Constants; -using EPR.ProducerContentValidation.Application.Models; -using FluentValidation; - -namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators -{ - public class SubsidiaryIdExistenceValidator : AbstractValidator - { - public SubsidiaryIdExistenceValidator() - { - RuleFor(x => x.SubsidiaryId) - .NotEqual("true") - .WithErrorCode(ErrorCode.SubsidiaryIdDoesNotExist); - } - } -} diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs deleted file mode 100644 index c92235e..0000000 --- a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs +++ /dev/null @@ -1,16 +0,0 @@ -using EPR.ProducerContentValidation.Application.Constants; -using EPR.ProducerContentValidation.Application.Models; -using FluentValidation; - -namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators -{ - public class SubsidiaryIdOrganisationCheck : AbstractValidator - { - public SubsidiaryIdOrganisationCheck() - { - RuleFor(x => x.SubsidiaryId) - .NotEqual("true") - .WithErrorCode(ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - } - } -} diff --git a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs new file mode 100644 index 0000000..59c6c17 --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs @@ -0,0 +1,109 @@ +using System.Net; +using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Data.Config; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Moq.Protected; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.UnitTest.Clients +{ + [TestClass] + public class CompanyDetailsApiClientTests + { + private CompanyDetailsApiConfig? _config; + + [TestInitialize] + public void Setup() + { + _config = new CompanyDetailsApiConfig + { + BaseUrl = "https://www.testurl.com", + ClientId = "test-client-id", + Timeout = 5, + }; + } + + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSuccess() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var content = JsonConvert.SerializeObject(request); + var responseMessage = new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }; + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeEquivalentTo(request); + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } + + [DataRow(HttpStatusCode.Conflict)] + [DataRow(HttpStatusCode.BadRequest)] + [DataRow(HttpStatusCode.BadGateway)] + [DataRow(HttpStatusCode.Unauthorized)] + [TestMethod] + public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(HttpStatusCode statusCode) + { + // Arrange + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = statusCode, + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + Func act = () => sut.GetSubsidiaryDetails(new SubsidiaryDetailsRequest()); + + // Assert + await act.Should().ThrowAsync(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj new file mode 100644 index 0000000..36e4698 --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs new file mode 100644 index 0000000..00cf5fc --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -0,0 +1,291 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; + +namespace EPR.ProducerContentValidation.UnitTest.Services.Subsidiary +{ + [TestClass] + public class SubsidiaryDetailsRequestBuilderTests + { + private SubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; + + [TestInitialize] + public void Setup() + { + _subsidiaryDetailsRequestBuilder = new SubsidiaryDetailsRequestBuilder(); + } + + [TestMethod] + public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() + { + // Arrange + var rows = new List(); + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.IsNotNull(result.SubsidiaryOrganisationDetails); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } + + [TestMethod] + public void CreateRequest_ShouldGroupByOrganisationReference_AndCreateSubsidiaryDetails() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 2", + DataSubmissionPeriod: "Submission Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Producer Type 2", + ProducerSize: "Producer Size 2", + WasteType: "Waste Type 2", + PackagingCategory: "Packaging Category 2", + MaterialType: "Material Type 2", + MaterialSubType: "Material SubType 2", + FromHomeNation: "From Nation 2", + ToHomeNation: "To Home Nation 2", + QuantityKg: "57567", + QuantityUnits: "95982", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 3", + DataSubmissionPeriod: "Submission Period 3", + ProducerId: "3", + RowNumber: 3, + ProducerType: "Producer Type 3", + ProducerSize: "Producer Size 3", + WasteType: "Waste Type 3", + PackagingCategory: "Packaging Category 3", + MaterialType: "Material Type 3", + MaterialSubType: "Material SubType 3", + FromHomeNation: "From Nation 3", + ToHomeNation: "To Home Nation 3", + QuantityKg: "57563467", + QuantityUnits: "9598345432", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); + + var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + Assert.IsNotNull(org1); + Assert.AreEqual(1, org1.SubsidiaryDetails.Count); + Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + + var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); + Assert.IsNotNull(org2); + Assert.AreEqual(1, org2.SubsidiaryDetails.Count); + Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + } + + [TestMethod] + public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Submission Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Producer Type 2", + ProducerSize: "Producer Size 2", + WasteType: "Waste Type 2", + PackagingCategory: "Packaging Category 2", + MaterialType: "Material Type 2", + MaterialSubType: "Material SubType 2", + FromHomeNation: "From Nation 2", + ToHomeNation: "To Home Nation 2", + QuantityKg: "57567", + QuantityUnits: "95982", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 2", + DataSubmissionPeriod: "Submission Period 3", + ProducerId: "2", + RowNumber: 3, + ProducerType: "Producer Type 3", + ProducerSize: "Producer Size 3", + WasteType: "Waste Type 3", + PackagingCategory: "Packaging Category 3", + MaterialType: "Material Type 3", + MaterialSubType: "Material SubType 3", + FromHomeNation: "From Nation 3", + ToHomeNation: "To Home Nation 3", + QuantityKg: "57563467", + QuantityUnits: "9598345432", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); + + var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + Assert.IsNotNull(org1); + Assert.AreEqual(1, org1.SubsidiaryDetails.Count); + Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + + var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); + Assert.IsNotNull(org2); + Assert.AreEqual(1, org2.SubsidiaryDetails.Count); + Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + } + + [TestMethod] + public void CreateRequest_WhenSingleSubIsEmptyRecord_ThenReturnCorrectRequest() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } + + [TestMethod] + public void CreateRequest_ShouldHandleMultipleOrganisations() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 2", + DataSubmissionPeriod: "Submission Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Producer Type 2", + ProducerSize: "Producer Size 2", + WasteType: "Waste Type 2", + PackagingCategory: "Packaging Category 2", + MaterialType: "Material Type 2", + MaterialSubType: "Material SubType 2", + FromHomeNation: "From Nation 2", + ToHomeNation: "To Home Nation 2", + QuantityKg: "57567", + QuantityUnits: "95982", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + new ProducerRow( + SubsidiaryId: "SubsidiaryId", + DataSubmissionPeriod: "Submission Period 3", + ProducerId: "3", + RowNumber: 3, + ProducerType: "Producer Type 3", + ProducerSize: "Producer Size 3", + WasteType: "Waste Type 3", + PackagingCategory: "Packaging Category 3", + MaterialType: "Material Type 3", + MaterialSubType: "Material SubType 3", + FromHomeNation: "From Nation 3", + ToHomeNation: "To Home Nation 3", + QuantityKg: "57563467", + QuantityUnits: "9598345432", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); + + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "1")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "2")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "3")); + } + } +} diff --git a/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj b/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj deleted file mode 100644 index 6783e83..0000000 --- a/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj +++ /dev/null @@ -1,50 +0,0 @@ - - - - - Debug - AnyCPU - {E7C40F24-549B-494A-AEF1-325C5658C9A0} - Library - Properties - EPR.ProducerContentValidation.UnitTests - EPR.ProducerContentValidation.UnitTests - v4.7.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs b/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 917489b..0000000 --- a/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("EPR.ProducerContentValidation.UnitTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("EPR.ProducerContentValidation.UnitTests")] -[assembly: AssemblyCopyright("Copyright © 2024")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("e7c40f24-549b-494a-aef1-325c5658c9a0")] - -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs b/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs deleted file mode 100644 index 0f13eca..0000000 --- a/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; - -namespace EPR.ProducerContentValidation.UnitTests -{ - [TestClass] - public class UnitTest1 - { - [TestMethod] - public void TestMethod1() - { - } - } -} diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index d092b76..ad67399 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -24,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,6 +56,10 @@ Global {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.Build.0 = Debug|Any CPU {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.ActiveCfg = Release|Any CPU {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.Build.0 = Release|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d7cef534dea7dda8234d949159a3a8bec82de025 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Mon, 28 Oct 2024 12:16:33 +0000 Subject: [PATCH 05/39] Attending to SonarQube feedbACK --- .../SubsidiaryDetailsRequestBuilderTests.cs | 302 +++++++----------- 1 file changed, 113 insertions(+), 189 deletions(-) diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index 00cf5fc..663796f 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -17,75 +17,52 @@ public void Setup() [TestMethod] public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() { - // Arrange var rows = new List(); - - // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.SubsidiaryOrganisationDetails); Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); } [TestMethod] - public void CreateRequest_ShouldGroupByOrganisationReference_AndCreateSubsidiaryDetails() + public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() { // Arrange var rows = new List { new ProducerRow( SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Submission Period 1", + DataSubmissionPeriod: "Period 1", ProducerId: "1", RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1"), + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), new ProducerRow( - SubsidiaryId: "Subsidiary Id 2", - DataSubmissionPeriod: "Submission Period 2", - ProducerId: "2", + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", RowNumber: 2, - ProducerType: "Producer Type 2", - ProducerSize: "Producer Size 2", - WasteType: "Waste Type 2", - PackagingCategory: "Packaging Category 2", - MaterialType: "Material Type 2", - MaterialSubType: "Material SubType 2", - FromHomeNation: "From Nation 2", - ToHomeNation: "To Home Nation 2", - QuantityKg: "57567", - QuantityUnits: "95982", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), - new ProducerRow( - SubsidiaryId: "Subsidiary Id 3", - DataSubmissionPeriod: "Submission Period 3", - ProducerId: "3", - RowNumber: 3, - ProducerType: "Producer Type 3", - ProducerSize: "Producer Size 3", - WasteType: "Waste Type 3", - PackagingCategory: "Packaging Category 3", - MaterialType: "Material Type 3", - MaterialSubType: "Material SubType 3", - FromHomeNation: "From Nation 3", - ToHomeNation: "To Home Nation 3", - QuantityKg: "57563467", - QuantityUnits: "9598345432", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") }; // Act @@ -93,77 +70,35 @@ public void CreateRequest_ShouldGroupByOrganisationReference_AndCreateSubsidiary // Assert Assert.IsNotNull(result); - Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); - - var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); - Assert.IsNotNull(org1); - Assert.AreEqual(1, org1.SubsidiaryDetails.Count); - Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); - Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); - - var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); - Assert.IsNotNull(org2); - Assert.AreEqual(1, org2.SubsidiaryDetails.Count); - Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); + var org = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + Assert.IsNotNull(org); + Assert.AreEqual(1, org.SubsidiaryDetails.Count); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); } [TestMethod] - public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() + public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() { // Arrange var rows = new List { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Submission Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1"), new ProducerRow( SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Submission Period 2", + DataSubmissionPeriod: "Period 1", ProducerId: "1", - RowNumber: 2, - ProducerType: "Producer Type 2", - ProducerSize: "Producer Size 2", - WasteType: "Waste Type 2", - PackagingCategory: "Packaging Category 2", - MaterialType: "Material Type 2", - MaterialSubType: "Material SubType 2", - FromHomeNation: "From Nation 2", - ToHomeNation: "To Home Nation 2", - QuantityKg: "57567", - QuantityUnits: "95982", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), - new ProducerRow( - SubsidiaryId: "Subsidiary Id 2", - DataSubmissionPeriod: "Submission Period 3", - ProducerId: "2", - RowNumber: 3, - ProducerType: "Producer Type 3", - ProducerSize: "Producer Size 3", - WasteType: "Waste Type 3", - PackagingCategory: "Packaging Category 3", - MaterialType: "Material Type 3", - MaterialSubType: "Material SubType 3", - FromHomeNation: "From Nation 3", - ToHomeNation: "To Home Nation 3", - QuantityKg: "57563467", - QuantityUnits: "9598345432", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") }; // Act @@ -171,42 +106,47 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() // Assert Assert.IsNotNull(result); - Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); - - var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); - Assert.IsNotNull(org1); - Assert.AreEqual(1, org1.SubsidiaryDetails.Count); - Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); - - var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); - Assert.IsNotNull(org2); - Assert.AreEqual(1, org2.SubsidiaryDetails.Count); - Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); } [TestMethod] - public void CreateRequest_WhenSingleSubIsEmptyRecord_ThenReturnCorrectRequest() + public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds() { // Arrange var rows = new List { new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Submission Period 1", + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", ProducerId: "1", RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1") + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") }; // Act @@ -214,66 +154,52 @@ public void CreateRequest_WhenSingleSubIsEmptyRecord_ThenReturnCorrectRequest() // Assert Assert.IsNotNull(result); - Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); + var org = result.SubsidiaryOrganisationDetails.First(); + Assert.AreEqual("1", org.OrganisationReference); + Assert.AreEqual(2, org.SubsidiaryDetails.Count); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId1")); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId2")); } [TestMethod] - public void CreateRequest_ShouldHandleMultipleOrganisations() + public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryIds() { // Arrange var rows = new List { new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Submission Period 1", + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", ProducerId: "1", RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1"), + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), new ProducerRow( - SubsidiaryId: "Subsidiary Id 2", - DataSubmissionPeriod: "Submission Period 2", + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", ProducerId: "2", RowNumber: 2, - ProducerType: "Producer Type 2", - ProducerSize: "Producer Size 2", - WasteType: "Waste Type 2", - PackagingCategory: "Packaging Category 2", - MaterialType: "Material Type 2", - MaterialSubType: "Material SubType 2", - FromHomeNation: "From Nation 2", - ToHomeNation: "To Home Nation 2", - QuantityKg: "57567", - QuantityUnits: "95982", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), - new ProducerRow( - SubsidiaryId: "SubsidiaryId", - DataSubmissionPeriod: "Submission Period 3", - ProducerId: "3", - RowNumber: 3, - ProducerType: "Producer Type 3", - ProducerSize: "Producer Size 3", - WasteType: "Waste Type 3", - PackagingCategory: "Packaging Category 3", - MaterialType: "Material Type 3", - MaterialSubType: "Material SubType 3", - FromHomeNation: "From Nation 3", - ToHomeNation: "To Home Nation 3", - QuantityKg: "57563467", - QuantityUnits: "9598345432", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") }; // Act @@ -281,11 +207,9 @@ public void CreateRequest_ShouldHandleMultipleOrganisations() // Assert Assert.IsNotNull(result); - Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); - - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "1")); - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "2")); - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "3")); + Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "1")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "2")); } } } From be6fe8e070b0724a6dce6a88d3f87b59fb2290bb Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 00:35:05 +0000 Subject: [PATCH 06/39] refactoring and more tests --- .../Performance/ValidatorsPerformanceTests.cs | 7 +- .../Helpers/FindMatchingProducerTests.cs | 126 ++++++++++ .../Helpers/OrganisationMatcherTests.cs | 128 ++++++++++ .../ProducerValidationEventFormatterTests.cs | 138 +++++++++++ .../Services/Helpers/RequestValidatorTests.cs | 79 +++++++ .../Helpers/SubsidiaryMatcherTests.cs | 177 ++++++++++++++ .../SubsidiaryValidationEvaluatorTests.cs | 172 ++++++++++++++ ...idationServiceProducerRowValidatorTests.cs | 218 ++++++++++++++++++ .../Services/ValidationServiceTests.cs | 199 ++++++++++------ .../ConfigureServices.cs | 10 +- .../Services/Helpers/FindMatchingProducer.cs | 38 +++ .../Services/Helpers/IFindMatchingProducer.cs | 11 + .../Services/Helpers/IOrganisationMatcher.cs | 10 + ...cerValidationEventIssueRequestFormatter.cs | 10 + .../Services/Helpers/IRequestValidator.cs | 9 + .../Services/Helpers/ISubsidiaryMatcher.cs | 10 + .../Helpers/ISubsidiaryValidationEvaluator.cs | 11 + .../IValidationServiceProducerRowValidator.cs | 12 + .../Services/Helpers/OrganisationMatcher.cs | 14 ++ ...cerValidationEventIssueRequestFormatter.cs | 30 +++ .../Services/Helpers/RequestValidator.cs | 10 + .../Services/Helpers/SubsidiaryMatcher.cs | 14 ++ .../Helpers/SubsidiaryValidationEvaluator.cs | 42 ++++ .../ValidationServiceProducerRowValidator.cs | 33 +++ .../Services/ValidationService.cs | 87 +++---- 25 files changed, 1469 insertions(+), 126 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs index 465d3fb..b44832e 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs @@ -7,6 +7,7 @@ using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.ReferenceData; using EPR.ProducerContentValidation.Application.Services; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; @@ -34,6 +35,8 @@ public ValidatorsPerformanceTests() Mock featureManagerMock = new(); Mock subsidiaryDetailsRequestBuilderMock = new(); Mock companyDetailsApiClientMock = new(); + Mock requestValidatorMock = new(); + Mock validationServiceProducerRowValidatorMock = new(); var submissionConfigOptions = new Mock>>(); @@ -63,7 +66,9 @@ public ValidatorsPerformanceTests() Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = "ContainerName" }), featureManagerMock.Object, subsidiaryDetailsRequestBuilderMock.Object, - companyDetailsApiClientMock.Object); + companyDetailsApiClientMock.Object, + requestValidatorMock.Object, + validationServiceProducerRowValidatorMock.Object); } [TestMethod] diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs new file mode 100644 index 0000000..51ef897 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -0,0 +1,126 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class FindMatchingProducerTests + { + private readonly Mock _organisationMatcherMock; + private readonly Mock _subsidiaryMatcherMock; + private readonly Mock _subsidiaryValidationEvaluatorMock; + private readonly FindMatchingProducer _findMatchingProducer; + + public FindMatchingProducerTests() + { + _organisationMatcherMock = new Mock(); + _subsidiaryMatcherMock = new Mock(); + _subsidiaryValidationEvaluatorMock = new Mock(); + + _findMatchingProducer = new FindMatchingProducer( + _organisationMatcherMock.Object, + _subsidiaryMatcherMock.Object, + _subsidiaryValidationEvaluatorMock.Object); + } + + [TestMethod] + public void Match_NoMatchingOrganisation_ReturnsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns((SubsidiaryOrganisationDetail?)null); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + Assert.IsNull(result); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(It.IsAny(), It.IsAny()), Times.Never); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void Match_NoMatchingSubsidiary_ReturnsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + var matchingOrg = new SubsidiaryOrganisationDetail(); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns(matchingOrg); + + _subsidiaryMatcherMock + .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) + .Returns((SubsidiaryDetail?)null); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + Assert.IsNull(result); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void Match_MatchingOrganisationAndSubsidiary_ReturnsValidationResult() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + var matchingOrg = new SubsidiaryOrganisationDetail(); + var matchingSub = new SubsidiaryDetail(); + var expectedValidationResult = new ProducerValidationEventIssueRequest( + SubsidiaryId: "S123", + DataSubmissionPeriod: "2024-Q1", + RowNumber: 1, + ProducerId: "P456", + ProducerType: "Large", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "Containers", + MaterialType: "Polyethylene", + MaterialSubType: "High-Density", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + BlobName: "ExampleBlobName", + ErrorCodes: new List { "E001", "E002" }); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns(matchingOrg); + + _subsidiaryMatcherMock + .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) + .Returns(matchingSub); + + _subsidiaryValidationEvaluatorMock + .Setup(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1)) + .Returns(expectedValidationResult); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + Assert.AreEqual(expectedValidationResult, result); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1), Times.Once); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs new file mode 100644 index 0000000..b69492d --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -0,0 +1,128 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class OrganisationMatcherTests + { + private readonly OrganisationMatcher _organisationMatcher; + + public OrganisationMatcherTests() + { + _organisationMatcher = new OrganisationMatcher(); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnOrganisation_WhenMatchExists() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var matchingOrg = new SubsidiaryOrganisationDetail + { + OrganisationReference = "Org456" + }; + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List { matchingOrg } + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("Org456", result.OrganisationReference); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnNull_WhenNoMatchExists() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org789", // This ID does not match any in the response + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var nonMatchingOrg = new SubsidiaryOrganisationDetail + { + OrganisationReference = "Org456" // Different ID than the row's ProducerId + }; + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List { nonMatchingOrg } + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnNull_WhenResponseIsEmpty() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List() // Empty list + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + Assert.IsNull(result); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs new file mode 100644 index 0000000..45ddfa1 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -0,0 +1,138 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class ProducerValidationEventFormatterTests + { + private readonly IProducerValidationEventIssueRequestFormatter _formatter; + + public ProducerValidationEventFormatterTests() + { + _formatter = new ProducerValidationEventIssueRequestFormatter(); + } + + [TestMethod] + public void Format_ShouldReturnFormattedRequest_WithAllFieldsProvided() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + string errorCode = "ErrorCode123"; + + // Act + var result = _formatter.Format(row, errorCode); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("Sub123", result.SubsidiaryId); + Assert.AreEqual("2023-Q1", result.DataSubmissionPeriod); + Assert.AreEqual(1, result.RowNumber); + Assert.AreEqual("Org456", result.ProducerId); + Assert.AreEqual("TypeA", result.ProducerType); + Assert.AreEqual("Large", result.ProducerSize); + Assert.AreEqual("Plastic", result.WasteType); + Assert.AreEqual("CategoryA", result.PackagingCategory); + Assert.AreEqual("MaterialX", result.MaterialType); + Assert.AreEqual("SubMaterialX", result.MaterialSubType); + Assert.AreEqual("UK", result.FromHomeNation); + Assert.AreEqual("Germany", result.ToHomeNation); + Assert.AreEqual("100", result.QuantityKg); + Assert.AreEqual("200", result.QuantityUnits); + CollectionAssert.Contains(result.ErrorCodes, errorCode); + } + + [TestMethod] + public void Format_ShouldHandleNullFields_InProducerRow() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: null, + DataSubmissionPeriod: null, + ProducerId: null, + RowNumber: 1, + ProducerType: null, + ProducerSize: null, + WasteType: null, + PackagingCategory: null, + MaterialType: null, + MaterialSubType: null, + FromHomeNation: null, + ToHomeNation: null, + QuantityKg: null, + QuantityUnits: null, + SubmissionPeriod: "2023"); + + string errorCode = "ErrorCode123"; + + // Act + var result = _formatter.Format(row, errorCode); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(string.Empty, result.SubsidiaryId); + Assert.AreEqual(string.Empty, result.DataSubmissionPeriod); + Assert.AreEqual(1, result.RowNumber); + Assert.AreEqual(string.Empty, result.ProducerId); + Assert.AreEqual(string.Empty, result.ProducerType); + Assert.AreEqual(string.Empty, result.ProducerSize); + Assert.AreEqual(string.Empty, result.WasteType); + Assert.AreEqual(string.Empty, result.PackagingCategory); + Assert.AreEqual(string.Empty, result.MaterialType); + Assert.AreEqual(string.Empty, result.MaterialSubType); + Assert.AreEqual(string.Empty, result.FromHomeNation); + Assert.AreEqual(string.Empty, result.ToHomeNation); + Assert.AreEqual(string.Empty, result.QuantityKg); + Assert.AreEqual(string.Empty, result.QuantityUnits); + CollectionAssert.Contains(result.ErrorCodes, errorCode); + } + + [TestMethod] + public void Format_ShouldReturnSingleErrorCode() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + string errorCode = "SingleError"; + + // Act + var result = _formatter.Format(row, errorCode); + + // Assert + Assert.AreEqual(1, result.ErrorCodes.Count, "Expected exactly one error code in the list."); + Assert.AreEqual("SingleError", result.ErrorCodes[0]); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs new file mode 100644 index 0000000..41e9a88 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -0,0 +1,79 @@ +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class RequestValidatorTests + { + private RequestValidator _validator; + + [TestInitialize] + public void Setup() + { + _validator = new RequestValidator(); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenRequestIsNull() + { + // Act + var result = _validator.IsInvalidRequest(null); + + // Assert + Assert.IsTrue(result, "Expected IsInvalidRequest to return true for null request."); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsNull() + { + // Arrange + var request = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = null + }; + + // Act + var result = _validator.IsInvalidRequest(request); + + // Assert + Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is null."); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = new List() + }; + + // Act + var result = _validator.IsInvalidRequest(request); + + // Assert + Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is empty."); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnFalse_WhenSubsidiaryOrganisationDetailsIsNotEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = new List + { + new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } + } + }; + + // Act + var result = _validator.IsInvalidRequest(request); + + // Assert + Assert.IsFalse(result, "Expected IsInvalidRequest to return false when SubsidiaryOrganisationDetails is not empty."); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs new file mode 100644 index 0000000..49685c9 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -0,0 +1,177 @@ +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class SubsidiaryMatcherTests + { + private SubsidiaryMatcher _matcher; + + [TestInitialize] + public void SetUp() + { + _matcher = new SubsidiaryMatcher(); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnMatchingSubsidiary_WhenReferenceNumberMatches() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("123", result?.ReferenceNumber); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenNoMatchingReferenceNumber() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "789", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryDetailsIsEmpty() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = new List() + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { + SubsidiaryId = null, + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNull(result); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs new file mode 100644 index 0000000..ca7abc2 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -0,0 +1,172 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class SubsidiaryValidationEvaluatorTests + { + private Mock _mockLogger; + private Mock _mockFormatter; + private SubsidiaryValidationEvaluator _evaluator; + + [TestInitialize] + public void Setup() + { + _mockLogger = new Mock(); + _mockFormatter = new Mock(); + _evaluator = new SubsidiaryValidationEvaluator(_mockLogger.Object, _mockFormatter.Object); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarningAndReturnFormattedRequest() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToOrganisation = true }; + var expectedRequest = new ProducerValidationEventIssueRequest( + row.SubsidiaryId, + row.DataSubmissionPeriod, + row.RowNumber, + row.ProducerId, + row.ProducerType, + row.ProducerSize, + row.WasteType, + row.PackagingCategory, + row.MaterialType, + row.MaterialSubType, + row.FromHomeNation, + row.ToHomeNation, + row.QuantityKg, + row.QuantityUnits, + ErrorCodes: new List { ErrorCode.SubsidiaryIdDoesNotExist }); + + _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist)).Returns(expectedRequest); + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(expectedRequest, result); + + // _mockLogger.Verify( + // l => l.LogWarning( + // It.Is(s => s == "Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})"), + // It.Is(o => + // (int)o[0] == row.RowNumber + 1 && + // (string)o[1] == "Subsidiary ID does not exist" && + // (string)o[2] == ErrorCode.SubsidiaryIdDoesNotExist)), + // Times.Once); + _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisation_ShouldLogWarningAndReturnFormattedRequest() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = false }; + var expectedRequest = new ProducerValidationEventIssueRequest( + row.SubsidiaryId, + row.DataSubmissionPeriod, + row.RowNumber, + row.ProducerId, + row.ProducerType, + row.ProducerSize, + row.WasteType, + row.PackagingCategory, + row.MaterialType, + row.MaterialSubType, + row.FromHomeNation, + row.ToHomeNation, + row.QuantityKg, + row.QuantityUnits, + ErrorCodes: new List { ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation }); + + _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation)).Returns(expectedRequest); + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(expectedRequest, result); + + // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), row.RowNumber + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); + _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = true }; + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + Assert.IsNull(result); + + // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs new file mode 100644 index 0000000..ecf39a0 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -0,0 +1,218 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class ValidationServiceProducerRowValidatorTests + { + private Mock _mockFindMatchingProducer; + private ValidationServiceProducerRowValidator _validator; + + [TestInitialize] + public void Setup() + { + _mockFindMatchingProducer = new Mock(); + _validator = new ValidationServiceProducerRowValidator(_mockFindMatchingProducer.Object); + } + + [TestMethod] + public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() + { + // Arrange + var producerRow = ModelGenerator.CreateProducerRow(1); + var producerRowTwo = ModelGenerator.CreateProducerRow(2); + var producerRows = new List { producerRow, producerRowTwo }; + + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + var rows = new List + { + row1, + row2 + }; + + var response = new SubsidiaryDetailsResponse + { + // Initialize your response data + }; + + _mockFindMatchingProducer.Setup(x => x.Match(It.IsAny(), response, It.IsAny())).Returns((ProducerValidationEventIssueRequest)null); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + Assert.IsNotNull(result); + Assert.IsFalse(result.Any()); + } + + [TestMethod] + public void ProcessRowsForValidationErrors_SingleValidationError_ReturnsListWithOneError() + { + // Arrange + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + var rows = new List + { + row1, + row2 + }; + + var response = new SubsidiaryDetailsResponse + { + // Initialize your response data + }; + + var errorRequest = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); + + _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest); + _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns((ProducerValidationEventIssueRequest)null); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.Count()); + Assert.AreEqual(errorRequest, result.First()); + } + + [TestMethod] + public void ProcessRowsForValidationErrors_MultipleValidationErrors_ReturnsListWithAllErrors() + { + // Arrange + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + var rows = new List + { + row1, + row2 + }; + + var response = new SubsidiaryDetailsResponse + { + // Initialize your response data + }; + + var errorRequest1 = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); + var errorRequest2 = new ProducerValidationEventIssueRequest("Sub2", "2024Q1", 2, "Prod2", "TypeB", "Small", "WasteTypeB", "CategoryB", "MaterialB", "SubTypeB", "NationA", "NationB", "200", "20", ErrorCodes: new List { "Error2" }); + + _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest1); + _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns(errorRequest2); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count()); + Assert.IsTrue(result.Contains(errorRequest1)); + Assert.IsTrue(result.Contains(errorRequest2)); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index a1fbafc..e2e46a1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,11 +1,11 @@ using AutoMapper; using EPR.ProducerContentValidation.Application.Clients; -using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; @@ -37,6 +37,9 @@ public class ValidationServiceTests private Mock _featureManagerMock; private Mock _subsidiaryDetailsRequestBuilderMock; private Mock _companyDetailsApiClientMock; + private Mock _requestValidatorMock; + private Mock _validationServiceProducerRowValidatorMock; + private Mock _mockLogger; [TestInitialize] public void TestInitialize() @@ -46,8 +49,11 @@ public void TestInitialize() _issueCountServiceMock = new Mock(); _mapper = AutoMapperHelpers.GetMapper(); _featureManagerMock = new Mock(); + _requestValidatorMock = new Mock(); _subsidiaryDetailsRequestBuilderMock = new Mock(); _companyDetailsApiClientMock = new Mock(); + _validationServiceProducerRowValidatorMock = new Mock(); + _mockLogger = new Mock(); _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(ErrorStoreKey)) .ReturnsAsync(100); @@ -130,7 +136,7 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateSubsidiary(rows); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert Assert.IsNotNull(result); @@ -138,18 +144,36 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() } [TestMethod] - public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyList() + public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() { // Arrange - var rows = new List { /* example ProducerRow data */ }; - _subsidiaryDetailsRequestBuilderMock - .Setup(x => x.CreateRequest(rows)) - .Returns((SubsidiaryDetailsRequest)null); + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + var rows = new List { row }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(true); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateSubsidiary(rows); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert Assert.IsNotNull(result); @@ -157,106 +181,135 @@ public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyL } [TestMethod] - public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmptyList() + public async Task ValidateSubsidiaryAsync_ValidRequest_ReturnsValidationErrors() { // Arrange - var rows = new List { /* example ProducerRow data */ }; - var exception = new HttpRequestException("An error occurred while creating the request."); - - _subsidiaryDetailsRequestBuilderMock - .Setup(x => x.CreateRequest(It.IsAny>())) - .Throws(exception); + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + var rows = new List { row }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse(); + var validationErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }) + }; + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(false); + _companyDetailsApiClientMock.Setup(x => x.GetSubsidiaryDetails(subsidiaryDetailsRequest)).ReturnsAsync(subsidiaryDetailsResponse); + _validationServiceProducerRowValidatorMock.Setup(x => x.ProcessRowsForValidationErrors(rows, subsidiaryDetailsResponse)).Returns(validationErrors); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateSubsidiary(rows); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); - _loggerMock.Verify( - x => x.Log( - LogLevel.Error, - It.IsAny(), - It.Is((v, t) => v.ToString().Contains("Error Subsidiary validation")), - It.Is(ex => ex == exception), - It.IsAny>()), - Times.Once); + Assert.AreEqual(1, result.Count); + Assert.AreEqual(validationErrors.First(), result.First()); } [TestMethod] - public async Task ValidateAsync_WithSubsidiaryValidationEnabled_PerformsSubsidiaryValidation() + public async Task ValidateSubsidiaryAsync_HttpRequestException_LogsErrorAndReturnsEmptyList() { // Arrange - var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; - var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); - - var validationErrors = new List(); + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + var rows = new List { row }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); - _featureManagerMock - .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) - .ReturnsAsync(true); + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(false); + _companyDetailsApiClientMock.Setup(x => x.GetSubsidiaryDetails(subsidiaryDetailsRequest)).ThrowsAsync(new HttpRequestException()); + var service = CreateSystemUnderTest(); - _subsidiaryDetailsRequestBuilderMock - .Setup(x => x.CreateRequest(producer.Rows)) - .Returns(new SubsidiaryDetailsRequest() - { - SubsidiaryOrganisationDetails = new List() - { - new SubsidiaryOrganisationDetail() - { } - } - }); + // Act + var result = await service.ValidateSubsidiaryAsync(rows); - var subsidiaryOrganisationDetails = new List(); - subsidiaryOrganisationDetails.Add(new SubsidiaryOrganisationDetail - { - OrganisationReference = "sds", - SubsidiaryDetails = new List() - }); - var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse(); - subsidiaryDetailsResponse.SubsidiaryOrganisationDetails = subsidiaryOrganisationDetails; + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); - _companyDetailsApiClientMock - .Setup(x => x.GetSubsidiaryDetails(It.IsAny())) - .ReturnsAsync(subsidiaryDetailsResponse); + // _mockLogger.Verify(x => x.LogError(It.IsAny(), "Error during subsidiary validation."), Times.Once); + } - _issueCountServiceMock - .Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())) - .ReturnsAsync(1); + // End + [TestMethod] + public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(rows)) + .Returns((SubsidiaryDetailsRequest)null); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateAsync(producer); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert - _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(producer.Rows), Times.Once); - _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); } [TestMethod] - public async Task ValidateAsync_WithSubsidiaryValidationDisabled_SkipsSubsidiaryValidation() + public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmptyList() { // Arrange - var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; - var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + var rows = new List { /* example ProducerRow data */ }; + var exception = new HttpRequestException("An error occurred while creating the request."); - // Mock feature flag to disable subsidiary validation - _featureManagerMock - .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) - .ReturnsAsync(false); + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(It.IsAny>())) + .Throws(exception); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateAsync(producer); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert - _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); - _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); - result.ValidationErrors.Should().BeEmpty(); + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + _loggerMock.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((v, t) => v.ToString().Contains("Error during subsidiary validation.")), + It.Is(ex => ex == exception), + It.IsAny>()), + Times.Once); } private ValidationService CreateSystemUnderTest() => @@ -268,5 +321,7 @@ private ValidationService CreateSystemUnderTest() => Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = ContainerName }), _featureManagerMock.Object, _subsidiaryDetailsRequestBuilderMock.Object, - _companyDetailsApiClientMock.Object); + _companyDetailsApiClientMock.Object, + _requestValidatorMock.Object, + _validationServiceProducerRowValidatorMock.Object); } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index a8583b9..30683d6 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -4,6 +4,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; @@ -33,7 +34,14 @@ private static void RegisterServices(this IServiceCollection services) .AddScoped() .AddScoped() .AddSingleton(ConnectionMultiplexer.Connect(redisOptions.ConnectionString)) - .AddSingleton(); + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(); } private static IServiceCollection ConfigureOptions(this IServiceCollection services) diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs new file mode 100644 index 0000000..e8814b0 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -0,0 +1,38 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class FindMatchingProducer : IFindMatchingProducer + { + private readonly IOrganisationMatcher _organisationMatcher; + private readonly ISubsidiaryMatcher _subsidiaryMatcher; + private readonly ISubsidiaryValidationEvaluator _subsidiaryValidationEvaluator; + + public FindMatchingProducer(IOrganisationMatcher organisationMatcher, ISubsidiaryMatcher subsidiaryMatcher, ISubsidiaryValidationEvaluator subsidiaryValidationEvaluator) + { + _organisationMatcher = organisationMatcher; + _subsidiaryMatcher = subsidiaryMatcher; + _subsidiaryValidationEvaluator = subsidiaryValidationEvaluator; + } + + public ProducerValidationEventIssueRequest? Match( + ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex) + { + var matchingOrg = _organisationMatcher.FindMatchingOrganisation(row, response); + if (matchingOrg == null) + { + return null; + } + + var matchingSub = _subsidiaryMatcher.FindMatchingSubsidiary(row, matchingOrg); + if (matchingSub == null) + { + return null; + } + + return _subsidiaryValidationEvaluator.EvaluateSubsidiaryValidation(row, matchingSub, rowIndex); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs new file mode 100644 index 0000000..6b8040a --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs @@ -0,0 +1,11 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IFindMatchingProducer + { + ProducerValidationEventIssueRequest? Match(ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs new file mode 100644 index 0000000..e990a26 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IOrganisationMatcher + { + SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs new file mode 100644 index 0000000..b196450 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IProducerValidationEventIssueRequestFormatter + { + ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs new file mode 100644 index 0000000..4e54b82 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs @@ -0,0 +1,9 @@ +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IRequestValidator + { + bool IsInvalidRequest(SubsidiaryDetailsRequest request); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs new file mode 100644 index 0000000..5f3b696 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface ISubsidiaryMatcher + { + SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs new file mode 100644 index 0000000..0d19fe0 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs @@ -0,0 +1,11 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface ISubsidiaryValidationEvaluator + { + ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs new file mode 100644 index 0000000..2ed81ec --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs @@ -0,0 +1,12 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IValidationServiceProducerRowValidator + { + IEnumerable ProcessRowsForValidationErrors( + List rows, SubsidiaryDetailsResponse response); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs new file mode 100644 index 0000000..036b944 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -0,0 +1,14 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class OrganisationMatcher : IOrganisationMatcher + { + public SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) + { + return response.SubsidiaryOrganisationDetails + .FirstOrDefault(org => org.OrganisationReference == row.ProducerId); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs new file mode 100644 index 0000000..52c6b53 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs @@ -0,0 +1,30 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class ProducerValidationEventIssueRequestFormatter : IProducerValidationEventIssueRequestFormatter + { + public ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode) + { + var errorCodes = new List { errorCode }; + + return new ProducerValidationEventIssueRequest( + SubsidiaryId: row.SubsidiaryId ?? string.Empty, + DataSubmissionPeriod: row.DataSubmissionPeriod ?? string.Empty, + RowNumber: row.RowNumber, + ProducerId: row.ProducerId ?? string.Empty, + ProducerType: row.ProducerType ?? string.Empty, + ProducerSize: row.ProducerSize ?? string.Empty, + WasteType: row.WasteType ?? string.Empty, + PackagingCategory: row.PackagingCategory ?? string.Empty, + MaterialType: row.MaterialType ?? string.Empty, + MaterialSubType: row.MaterialSubType ?? string.Empty, + FromHomeNation: row.FromHomeNation ?? string.Empty, + ToHomeNation: row.ToHomeNation ?? string.Empty, + QuantityKg: row.QuantityKg ?? string.Empty, + QuantityUnits: row.QuantityUnits ?? string.Empty, + ErrorCodes: errorCodes); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs new file mode 100644 index 0000000..8fe3cb8 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class RequestValidator : IRequestValidator + { + public bool IsInvalidRequest(SubsidiaryDetailsRequest request) => + request?.SubsidiaryOrganisationDetails == null || !request.SubsidiaryOrganisationDetails.Any(); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs new file mode 100644 index 0000000..88935f4 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -0,0 +1,14 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class SubsidiaryMatcher : ISubsidiaryMatcher + { + public SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) + { + return org.SubsidiaryDetails + .FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs new file mode 100644 index 0000000..af22a83 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -0,0 +1,42 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.Extensions.Logging; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class SubsidiaryValidationEvaluator : ISubsidiaryValidationEvaluator + { + private readonly ILogger _logger; + private readonly IProducerValidationEventIssueRequestFormatter _producerValidationEventIssueRequestFormatter; + + public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIssueRequestFormatter producerValidationEventIssueRequestFormatter) + { + _logger = logger; + _producerValidationEventIssueRequestFormatter = producerValidationEventIssueRequestFormatter; + } + + public ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex) + { + if (!subsidiary.SubsidiaryExists) + { + LogValidationWarning(rowIndex + 1, "Subsidiary ID does not exist", ErrorCode.SubsidiaryIdDoesNotExist); + return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdDoesNotExist); + } + + if (!subsidiary.SubsidiaryBelongsToOrganisation) + { + LogValidationWarning(rowIndex + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + } + + return null; + } + + private void LogValidationWarning(int rowNumber, string message, string errorCode) + { + _logger.LogWarning("Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})", rowNumber, message, errorCode); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs new file mode 100644 index 0000000..b150b2a --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -0,0 +1,33 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class ValidationServiceProducerRowValidator : IValidationServiceProducerRowValidator + { + private readonly IFindMatchingProducer _findMatchingProducer; + + public ValidationServiceProducerRowValidator(IFindMatchingProducer findMatchingProducer) + { + _findMatchingProducer = findMatchingProducer; + } + + public IEnumerable ProcessRowsForValidationErrors( + List rows, SubsidiaryDetailsResponse response) + { + var validationErrors = new List(); + + for (int i = 0; i < rows.Count; i++) + { + var error = _findMatchingProducer.Match(rows[i], response, i); + if (error != null) + { + validationErrors.Add(error); + } + } + + return validationErrors; + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 4056839..51c88b0 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -5,9 +5,11 @@ using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.FeatureManagement; @@ -23,7 +25,9 @@ public class ValidationService : IValidationService private readonly StorageAccountOptions _storageAccountOptions; private readonly ISubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; private readonly ICompanyDetailsApiClient _companyDetailsApiClient; - private IFeatureManager _featureManager; + private readonly IFeatureManager _featureManager; + private readonly IRequestValidator _requestValidator; + private readonly IValidationServiceProducerRowValidator _validationServiceProducerRowValidator; public ValidationService( ILogger logger, @@ -33,7 +37,9 @@ public ValidationService( IOptions storageAccountOptions, IFeatureManager featureManager, ISubsidiaryDetailsRequestBuilder subsidiaryDetailsRequestBuilder, - ICompanyDetailsApiClient companyDetailsApiClient) + ICompanyDetailsApiClient companyDetailsApiClient, + IRequestValidator requestValidator, + IValidationServiceProducerRowValidator validationServiceProducerRowValidator) { _logger = logger; _compositeValidator = compositeValidator; @@ -43,6 +49,8 @@ public ValidationService( _featureManager = featureManager; _subsidiaryDetailsRequestBuilder = subsidiaryDetailsRequestBuilder; _companyDetailsApiClient = companyDetailsApiClient; + _requestValidator = requestValidator; + _validationServiceProducerRowValidator = validationServiceProducerRowValidator; } public async Task ValidateAsync(Producer producer) @@ -77,7 +85,7 @@ public async Task ValidateAsync(Producer producer) if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) { - List subValidationResult = await ValidateSubsidiary(producer.Rows); + List subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); } @@ -86,66 +94,46 @@ public async Task ValidateAsync(Producer producer) return producerValidationOutRequest; } - public async Task> ValidateSubsidiary(List rows) + public async Task> ValidateSubsidiaryAsync(List rows) { - List validationErrors = new(); + var validationErrors = new List(); + try { - var subsidiaryDetailsRequest = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - if (subsidiaryDetailsRequest == null || subsidiaryDetailsRequest.SubsidiaryOrganisationDetails == null || !subsidiaryDetailsRequest.SubsidiaryOrganisationDetails.Any()) + var subsidiaryDetailsRequest = BuildSubsidiaryRequest(rows); + if (_requestValidator.IsInvalidRequest(subsidiaryDetailsRequest)) { return validationErrors; } - var result = await _companyDetailsApiClient.GetSubsidiaryDetails(subsidiaryDetailsRequest); - - for (int i = 0; i < rows.Count; i++) - { - var matchingOrg = result.SubsidiaryOrganisationDetails - .FirstOrDefault(org => org.OrganisationReference == rows[i].ProducerId); - - if (matchingOrg == null) - { - continue; - } - - var matchingSub = matchingOrg.SubsidiaryDetails - .FirstOrDefault(sub => sub.ReferenceNumber == rows[i].SubsidiaryId); - - if (matchingSub == null) - { - continue; - } - - if (!matchingSub.SubsidiaryExists) - { - var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdDoesNotExist); - var errorMessage = $"Subsidiary ID does not exist"; - - LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); - validationErrors.Add(error); - continue; - } - - if (!matchingSub.SubsidiaryBelongsToOrganisation) - { - var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - var errorMessage = $"Subsidiary ID is assigned to a different organisation"; - - LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - validationErrors.Add(error); - } - } + var subsidiaryDetailsResponse = await FetchSubsidiaryDetailsAsync(subsidiaryDetailsRequest); + validationErrors.AddRange(_validationServiceProducerRowValidator.ProcessRowsForValidationErrors(rows, subsidiaryDetailsResponse)); return validationErrors; } catch (HttpRequestException exception) { - _logger.LogError(exception, "Error Subsidiary validation"); + LogRequestError(exception); return validationErrors; } } + // Helper Methods + private SubsidiaryDetailsRequest BuildSubsidiaryRequest(List rows) => + _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + private async Task FetchSubsidiaryDetailsAsync(SubsidiaryDetailsRequest request) => + await _companyDetailsApiClient.GetSubsidiaryDetails(request); + + private SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) => + response.SubsidiaryOrganisationDetails.FirstOrDefault(org => org.OrganisationReference == row.ProducerId); + + private SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) => + org.SubsidiaryDetails.FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); + + private void LogRequestError(HttpRequestException exception) => + _logger.LogError(exception, "Error during subsidiary validation."); + private void LogValidationWarning(int rowNumber, string errorMessage, string errorCode) { _logger.LogWarning( @@ -154,9 +142,4 @@ private void LogValidationWarning(int rowNumber, string errorMessage, string err errorMessage, errorCode); } - - private ProducerValidationEventIssueRequest CreateSubValidationError(ProducerRow row, object subsidiaryIdDoesNotExist) - { - throw new NotImplementedException(); - } } \ No newline at end of file From 694fffb031ca5f3fcfd006ac251f39da769bb661 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 11:14:53 +0000 Subject: [PATCH 07/39] added tests --- .../Clients/CompanyDetailsApiClientTests.cs | 110 ++++++++ .../CompanyDetailsDataItem.cs | 12 + .../CompanyDetailsDataResult.cs | 9 + .../SubsidiaryDetailsRequestBuilderTests.cs | 244 +++++++++--------- 4 files changed, 255 insertions(+), 120 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs new file mode 100644 index 0000000..5a4431e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -0,0 +1,110 @@ +using System.Net; +using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Data.Config; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Moq.Protected; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Clients +{ + [TestClass] + public class CompanyDetailsApiClientTests + { + private CompanyDetailsApiConfig? _config; + + [TestInitialize] + public void Setup() + { + _config = new CompanyDetailsApiConfig + { + BaseUrl = "https://www.testurl.com", + ClientId = "test-client-id", + Timeout = 5, + }; + } + + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSuccess() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var content = JsonConvert.SerializeObject(request); + var responseMessage = new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }; + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeEquivalentTo(request); + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } + + [DataRow(HttpStatusCode.Conflict)] + [DataRow(HttpStatusCode.BadRequest)] + [DataRow(HttpStatusCode.BadGateway)] + [DataRow(HttpStatusCode.Unauthorized)] + [TestMethod] + public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(HttpStatusCode statusCode) + { + // Arrange + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = statusCode, + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + Func act = () => sut.GetSubsidiaryDetails(new SubsidiaryDetailsRequest()); + + // Assert + await act.Should().ThrowAsync(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs new file mode 100644 index 0000000..81a58ee --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -0,0 +1,12 @@ +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; + +using Newtonsoft.Json; + +public class CompanyDetailsDataItem +{ + [JsonProperty("RN")] + public string ReferenceNumber { get; set; } + + [JsonProperty("CHN")] + public string CompaniesHouseNumber { get; set; } +} \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs new file mode 100644 index 0000000..25a585e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -0,0 +1,9 @@ +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; + +using Newtonsoft.Json; + +public class CompanyDetailsDataResult +{ + [JsonProperty(nameof(Organisations))] + public IEnumerable Organisations { get; set; } +} diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index 663796f..cc0b806 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -17,9 +17,13 @@ public void Setup() [TestMethod] public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() { + // Arrange var rows = new List(); + + // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.SubsidiaryOrganisationDetails); Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); @@ -30,40 +34,40 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -82,24 +86,24 @@ public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1") - }; + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -114,40 +118,40 @@ public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -167,40 +171,40 @@ public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryId { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "2", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); From aa3999e50f00255f23b584dd375358a0a9cfb5ef Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 13:01:35 +0000 Subject: [PATCH 08/39] Correction of error thrown up in the Build Docker Image satge of the build pipeline --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index 30f9ead..bfabcea 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,6 +8,7 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. +COPY EPR.RegistrationValidation.Data/. ./EPR.RegistrationValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From 9db9f185f79e7006b890141c69662c6e1c582edc Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 15:09:25 +0000 Subject: [PATCH 09/39] Corrected filename in Dockerfile --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index bfabcea..dfe992d 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,7 +8,7 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. -COPY EPR.RegistrationValidation.Data/. ./EPR.RegistrationValidation.Data/. +COPY EPR.ProducerContentValidation.Data/. ./EPR.ProducerContentValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From d41fb58b2b138f5fddfd3dc944d019127bce80b9 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 15:32:03 +0000 Subject: [PATCH 10/39] Added more tests --- .../Services/ValidationServiceTests.cs | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index e2e46a1..467b7db 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,5 +1,6 @@ using AutoMapper; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -144,7 +145,7 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() } [TestMethod] - public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() + public async Task ValidateSubsidiaryAsyncInvalidRequestReturnsEmptyList() { // Arrange var row = ModelGenerator.CreateProducerRow(1) with @@ -312,6 +313,60 @@ public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmp Times.Once); } + [TestMethod] + public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryValidation() + { + // Arrange + var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(false); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); + Assert.IsNotNull(result); + } + + [TestMethod] + public async Task ValidateAsync_WhenRemainingWarningCapacityIsZero_OnlyErrorsAreValidated() + { + // Arrange + var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync("test-blob:error")).ReturnsAsync(100); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync("test-blob:warning")).ReturnsAsync(0); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + Assert.IsNotNull(result); + Assert.IsTrue(result.ValidationWarnings.Count == 0); + } + + [TestMethod] + public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() + { + // Arrange + var rows = new List { ModelGenerator.CreateProducerRow(1) }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiaryAsync(rows); + + // Assert + Assert.AreEqual(0, result.Count); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, From f788bdcffcdcbbd4f7e961608e95baa099df189e Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 16:53:11 +0000 Subject: [PATCH 11/39] Added more tests --- .../Services/ValidationServiceTests.cs | 47 +++ .../Services/ValidationService.cs | 9 - .../SubsidiaryDetailsRequestBuilderTests.cs | 277 ++++++++++-------- 3 files changed, 202 insertions(+), 131 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 467b7db..9d4ccb1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -331,6 +331,25 @@ public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryVal Assert.IsNotNull(result); } + [TestMethod] + public async Task ValidateAsync_WhenFeatureFlagIsOn_DoesPerformSubsidiaryValidation() + { + // Arrange + var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(true); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(1); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Once); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); + Assert.IsNotNull(result); + } + [TestMethod] public async Task ValidateAsync_WhenRemainingWarningCapacityIsZero_OnlyErrorsAreValidated() { @@ -367,6 +386,34 @@ public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() Assert.AreEqual(0, result.Count); } + [TestMethod] + public async Task ValidateAsync_WhenWarningCapacityReached_LogsWarning() + { + // Arrange + var rows = new List { ModelGenerator.CreateProducerRow(1) }; + var producer = new Producer(_submissionId, ProducerId, BlobName, rows); + + // Simulate reaching warning capacity + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(WarningStoreKey)).ReturnsAsync(0); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _loggerMock.Verify( + x => x.Log( + LogLevel.Warning, + It.IsAny(), + It.Is((v, t) => v.ToString().Contains("No capacity left to process issues.")), + It.IsAny(), + It.IsAny>()), + Times.Never); + Assert.IsNotNull(result); + Assert.AreEqual(0, result.ValidationWarnings.Count); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 51c88b0..654118d 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -133,13 +133,4 @@ private async Task FetchSubsidiaryDetailsAsync(Subsid private void LogRequestError(HttpRequestException exception) => _logger.LogError(exception, "Error during subsidiary validation."); - - private void LogValidationWarning(int rowNumber, string errorMessage, string errorCode) - { - _logger.LogWarning( - "Validation error on row {Row} {ErrorMessage} Error code {ErrorCode}", - rowNumber, - errorMessage, - errorCode); - } } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index cc0b806..3041710 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -34,40 +34,40 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -75,10 +75,11 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() // Assert Assert.IsNotNull(result); Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); - var org = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + var org = result.SubsidiaryOrganisationDetails.First(); Assert.IsNotNull(org); + Assert.AreEqual("1", org.OrganisationReference); Assert.AreEqual(1, org.SubsidiaryDetails.Count); - Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + Assert.AreEqual("Subsidiary Id 1", org.SubsidiaryDetails[0].ReferenceNumber); } [TestMethod] @@ -86,24 +87,24 @@ public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1") - }; + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -118,40 +119,40 @@ public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -171,40 +172,40 @@ public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryId { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "2", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -215,5 +216,37 @@ public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryId Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "1")); Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "2")); } + + [TestMethod] + public void CreateRequest_ShouldIgnoreRowsWithWhitespaceSubsidiaryId() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } } } From c45a0513fbd3fb0d828028d3f12708ed673eeea5 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 10:31:49 +0000 Subject: [PATCH 12/39] Added more tests --- .../Services/ValidationServiceTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 9d4ccb1..e059a82 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -260,8 +260,6 @@ public async Task ValidateSubsidiaryAsync_HttpRequestException_LogsErrorAndRetur // Assert Assert.IsNotNull(result); Assert.AreEqual(0, result.Count); - - // _mockLogger.Verify(x => x.LogError(It.IsAny(), "Error during subsidiary validation."), Times.Once); } // End From b4de89eb392a4be73c0cc800cd5a455009f230c0 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 11:40:46 +0000 Subject: [PATCH 13/39] Added more tests --- .../Services/ValidationServiceTests.cs | 4 ++-- .../ConfigureServices.cs | 4 ++-- .../Constants/FeatureFlags.cs | 2 +- .../EPR.ProducerContentValidation.Application.csproj | 4 ++++ .../Services/ValidationService.cs | 8 +------- .../settings.json | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index e059a82..56138f1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -316,7 +316,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryVal { // Arrange var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); - _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(false); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(false); var service = CreateSystemUnderTest(); @@ -334,7 +334,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOn_DoesPerformSubsidiaryValidat { // Arrange var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); - _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(true); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(1); var service = CreateSystemUnderTest(); diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index 30683d6..a6b7767 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -31,7 +31,6 @@ private static void RegisterServices(this IServiceCollection services) { var redisOptions = services.BuildServiceProvider().GetRequiredService>().Value; services - .AddScoped() .AddScoped() .AddSingleton(ConnectionMultiplexer.Connect(redisOptions.ConnectionString)) .AddSingleton() @@ -41,7 +40,8 @@ private static void RegisterServices(this IServiceCollection services) .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton(); + .AddSingleton() + .AddScoped(); } private static IServiceCollection ConfigureOptions(this IServiceCollection services) diff --git a/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs index 72ef6a1..c9cb1a9 100644 --- a/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs +++ b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs @@ -2,6 +2,6 @@ { public static class FeatureFlags { - public const string EnableSubsidiaryValidation = "EnableSubsidiaryValidation"; + public const string EnableSubsidiaryValidationPom = "EnableSubsidiaryValidationPom"; } } diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index eda8453..a951d38 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -29,4 +29,8 @@ + + + + \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 654118d..79b10d6 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -83,7 +83,7 @@ public async Task ValidateAsync(Producer producer) producerValidationOutRequest.ValidationErrors.AddRange(errors); producerValidationOutRequest.ValidationWarnings.AddRange(warnings); - if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)) { List subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); @@ -125,12 +125,6 @@ private SubsidiaryDetailsRequest BuildSubsidiaryRequest(List rows) private async Task FetchSubsidiaryDetailsAsync(SubsidiaryDetailsRequest request) => await _companyDetailsApiClient.GetSubsidiaryDetails(request); - private SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) => - response.SubsidiaryOrganisationDetails.FirstOrDefault(org => org.OrganisationReference == row.ProducerId); - - private SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) => - org.SubsidiaryDetails.FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); - private void LogRequestError(HttpRequestException exception) => _logger.LogError(exception, "Error during subsidiary validation."); } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.FunctionApp/settings.json b/src/EPR.ProducerContentValidation.FunctionApp/settings.json index 9d0d533..d89bf2a 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/settings.json +++ b/src/EPR.ProducerContentValidation.FunctionApp/settings.json @@ -13,6 +13,6 @@ "Validation:MaxIssuesToProcess": 1000, "Redis:ConnectionString": "https://localhost:1234", "Validation:IsLatest": false, - "FeatureManagement:EnableSubsidiaryValidation": false + "FeatureManagement:EnableSubsidiaryValidationPom": false } } From eafe6d1afee015037f8030c9c72e155891ac85ca Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 11:48:51 +0000 Subject: [PATCH 14/39] Added more tests --- .../Performance/ValidatorsPerformanceTests.cs | 2 +- .../Services/Helpers/FindMatchingProducerTests.cs | 1 + .../Services/Helpers/ProducerValidationEventFormatterTests.cs | 1 + .../Services/Helpers/SubsidiaryValidationEvaluatorTests.cs | 1 + .../Helpers/ValidationServiceProducerRowValidatorTests.cs | 1 + .../Services/ValidationServiceTests.cs | 2 +- .../ConfigureServices.cs | 1 + .../EPR.ProducerContentValidation.Application.csproj | 4 ---- .../Services/Helpers/FindMatchingProducer.cs | 1 + .../Helpers/{ => Interfaces}/IFindMatchingProducer.cs | 2 +- .../Services/Helpers/{ => Interfaces}/IOrganisationMatcher.cs | 2 +- .../IProducerValidationEventIssueRequestFormatter.cs | 2 +- .../Services/Helpers/{ => Interfaces}/IRequestValidator.cs | 2 +- .../Services/Helpers/{ => Interfaces}/ISubsidiaryMatcher.cs | 2 +- .../{ => Interfaces}/ISubsidiaryValidationEvaluator.cs | 2 +- .../IValidationServiceProducerRowValidator.cs | 2 +- .../Services/Helpers/OrganisationMatcher.cs | 1 + .../Helpers/ProducerValidationEventIssueRequestFormatter.cs | 1 + .../Services/Helpers/RequestValidator.cs | 3 ++- .../Services/Helpers/SubsidiaryMatcher.cs | 1 + .../Services/Helpers/SubsidiaryValidationEvaluator.cs | 1 + .../Services/Helpers/ValidationServiceProducerRowValidator.cs | 1 + .../Services/ValidationService.cs | 2 +- 23 files changed, 23 insertions(+), 15 deletions(-) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IFindMatchingProducer.cs (96%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IOrganisationMatcher.cs (95%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IProducerValidationEventIssueRequestFormatter.cs (95%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IRequestValidator.cs (93%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/ISubsidiaryMatcher.cs (95%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/ISubsidiaryValidationEvaluator.cs (96%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IValidationServiceProducerRowValidator.cs (96%) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs index b44832e..eaad95b 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs @@ -7,7 +7,7 @@ using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.ReferenceData; using EPR.ProducerContentValidation.Application.Services; -using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index 51ef897..c392c06 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs index 45ddfa1..45a6b4a 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index ca7abc2..75ea1cc 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -2,6 +2,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index ecf39a0..88d7f9a 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 56138f1..1d96497 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -6,7 +6,7 @@ using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; -using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index a6b7767..352e80d 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index a951d38..eda8453 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -29,8 +29,4 @@ - - - - \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs index e8814b0..dcb12fb 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs similarity index 96% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs index 6b8040a..e27f943 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs @@ -2,7 +2,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IFindMatchingProducer { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs similarity index 95% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs index e990a26..ba25656 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IOrganisationMatcher { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs similarity index 95% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs index b196450..cef13c5 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IProducerValidationEventIssueRequestFormatter { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs similarity index 93% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs index 4e54b82..321a86f 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IRequestValidator { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs similarity index 95% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs index 5f3b696..8e97c6d 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface ISubsidiaryMatcher { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs similarity index 96% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs index 0d19fe0..2979b17 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs @@ -2,7 +2,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface ISubsidiaryValidationEvaluator { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs similarity index 96% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs index 2ed81ec..8793799 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs @@ -2,7 +2,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IValidationServiceProducerRowValidator { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs index 036b944..02192da 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -1,4 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs index 52c6b53..52e56da 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs index 8fe3cb8..a0db7c9 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -1,4 +1,5 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs index 88935f4..7137043 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -1,4 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index af22a83..15e2000 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index b150b2a..7e7d95f 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 79b10d6..18525f6 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -5,7 +5,7 @@ using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; -using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; From d3f232b322fa45715fbf62e3f215b2b86b379ac8 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 12:51:21 +0000 Subject: [PATCH 15/39] Edited gitignore to remove local.settings 18.json --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b72df34..d342c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -414,4 +414,3 @@ FodyWeavers.xsd # AppSettings Development file **/appSettings.Development.json /src/EPR.ProducerContentValidation.FunctionApp/localSettings.json -/src/EPR.ProducerContentValidation.FunctionApp/local.settings 18.json From 0ed65b4822e5667c9bb8cfc024abbea97d1c5c32 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 13:33:28 +0000 Subject: [PATCH 16/39] Added more tests --- .../CompanyDetailsDataItemTests.cs | 82 +++++++++++++++++++ ...cerContentValidation.Data.UnitTests.csproj | 22 +++++ src/EPR.ProducerContentValidation.sln | 8 +- 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs create mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs new file mode 100644 index 0000000..a81b851 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs @@ -0,0 +1,82 @@ +using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.UnitTests +{ + [TestClass] + public class CompanyDetailsDataItemTests + { + [TestMethod] + public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = "REF123", + CompaniesHouseNumber = "CHN456" + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + Assert.IsTrue(json.Contains("\"RN\":\"REF123\""), "Serialized JSON should contain 'RN' with correct value."); + Assert.IsTrue(json.Contains("\"CHN\":\"CHN456\""), "Serialized JSON should contain 'CHN' with correct value."); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() + { + // Arrange + var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; + + // Act + var companyDetails = JsonConvert.DeserializeObject(json); + + // Assert + Assert.IsNotNull(companyDetails, "Deserialized object should not be null."); + Assert.AreEqual("REF123", companyDetails.ReferenceNumber, "ReferenceNumber should match the JSON value."); + Assert.AreEqual("CHN456", companyDetails.CompaniesHouseNumber, "CompaniesHouseNumber should match the JSON value."); + } + + [TestMethod] + public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = null, + CompaniesHouseNumber = null + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + Assert.IsTrue(json.Contains("\"RN\":null"), "Serialized JSON should contain 'RN' with a null value."); + Assert.IsTrue(json.Contains("\"CHN\":null"), "Serialized JSON should contain 'CHN' with a null value."); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() + { + // Arrange + var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; + var jsonWithoutKeys = "{}"; + + // Act + var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); + var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); + + // Assert + Assert.IsNotNull(companyDetailsWithNulls, "Deserialized object with nulls should not be null."); + Assert.IsNull(companyDetailsWithNulls.ReferenceNumber, "ReferenceNumber should be null if JSON contains null."); + Assert.IsNull(companyDetailsWithNulls.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON contains null."); + + Assert.IsNotNull(companyDetailsWithoutKeys, "Deserialized object without keys should not be null."); + Assert.IsNull(companyDetailsWithoutKeys.ReferenceNumber, "ReferenceNumber should be null if JSON key is missing."); + Assert.IsNull(companyDetailsWithoutKeys.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON key is missing."); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj new file mode 100644 index 0000000..72dda96 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index ad67399..6fb7ebb 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -24,7 +24,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data.UnitTests", "EPR.ProducerContentValidation.Data.UnitTests\EPR.ProducerContentValidation.Data.UnitTests.csproj", "{F3E90F69-1835-460D-ACCA-890229303A0E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -60,6 +62,10 @@ Global {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.Build.0 = Debug|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.Build.0 = Release|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 2fe906308e8620256188ae398b9b198a67c3465a Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 15:42:03 +0000 Subject: [PATCH 17/39] Added more tests --- .../EPR.ProducerContentValidation.Data.UnitTests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj index 72dda96..ae6b92c 100644 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj @@ -9,10 +9,10 @@ - + - + From dded9ac906a75e241be5457f95247d79f3821ef0 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 17:15:22 +0000 Subject: [PATCH 18/39] Added more tests --- .../Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename src/{EPR.ProducerContentValidation.UnitTest => EPR.ProducerContentValidation.Application.UnitTests}/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs (98%) diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs similarity index 98% rename from src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs rename to src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index 3041710..f8f82d6 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -1,7 +1,8 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Subsidiary; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.UnitTest.Services.Subsidiary +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Subsidiary { [TestClass] public class SubsidiaryDetailsRequestBuilderTests From a5d0788e7bd207c25825cad6702eeb55384dddda Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 17:41:49 +0000 Subject: [PATCH 19/39] Excluded CompanyDetailsDataItem and CompanyDetailsDataResult from coverage --- .../Models/CompanyDetailsApi/CompanyDetailsDataItem.cs | 2 ++ .../Models/CompanyDetailsApi/CompanyDetailsDataResult.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs index 81a58ee..9d0fe95 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -1,7 +1,9 @@ namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; +[ExcludeFromCodeCoverage] public class CompanyDetailsDataItem { [JsonProperty("RN")] diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs index 25a585e..9b57696 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -1,7 +1,9 @@ namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; +[ExcludeFromCodeCoverage] public class CompanyDetailsDataResult { [JsonProperty(nameof(Organisations))] From ca9429de34265579a3b6db6feabccb614a4d53b2 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 09:13:46 +0000 Subject: [PATCH 20/39] Added more tests --- .../Clients/CompanyDetailsApiClientTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index 5a4431e..fb0f622 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -106,5 +106,45 @@ public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(Ht // Assert await act.Should().ThrowAsync(); } + + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnDefault_WhenResponseContentIsEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(string.Empty), // Simulate empty content + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeNull(); // Since default for reference type is null + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } } } From f609d7dec937f6ea089d5a5f502987d787290704 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 10:53:37 +0000 Subject: [PATCH 21/39] Made changes to reflect changes that came out of QA of User Story 448425 --- .../SubsidiaryValidationEvaluatorTests.cs | 16 +++------------- .../Services/ValidationServiceTests.cs | 2 +- .../Helpers/SubsidiaryValidationEvaluator.cs | 2 +- .../Models/Subsidiary/SubsidiaryDetail.cs | 2 +- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index 75ea1cc..b443b0a 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -47,7 +47,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarning QuantityKg = "100", QuantityUnits = "Units" }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToOrganisation = true }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToAnyOtherOrganisation = true }; var expectedRequest = new ProducerValidationEventIssueRequest( row.SubsidiaryId, row.DataSubmissionPeriod, @@ -74,14 +74,6 @@ public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarning Assert.IsNotNull(result); Assert.AreEqual(expectedRequest, result); - // _mockLogger.Verify( - // l => l.LogWarning( - // It.Is(s => s == "Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})"), - // It.Is(o => - // (int)o[0] == row.RowNumber + 1 && - // (string)o[1] == "Subsidiary ID does not exist" && - // (string)o[2] == ErrorCode.SubsidiaryIdDoesNotExist)), - // Times.Once); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); } @@ -106,7 +98,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisatio QuantityKg = "100", QuantityUnits = "Units" }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = false }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = true }; var expectedRequest = new ProducerValidationEventIssueRequest( row.SubsidiaryId, row.DataSubmissionPeriod, @@ -133,7 +125,6 @@ public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisatio Assert.IsNotNull(result); Assert.AreEqual(expectedRequest, result); - // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), row.RowNumber + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); } @@ -158,7 +149,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() QuantityKg = "100", QuantityUnits = "Units" }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = true }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = false }; // Act var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); @@ -166,7 +157,6 @@ public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() // Assert Assert.IsNull(result); - // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 1d96497..686ec25 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -119,7 +119,7 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() { ReferenceNumber = "SubRef", SubsidiaryExists = true, - SubsidiaryBelongsToOrganisation = true + SubsidiaryBelongsToAnyOtherOrganisation = true } } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index 15e2000..026fae2 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -26,7 +26,7 @@ public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIss return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdDoesNotExist); } - if (!subsidiary.SubsidiaryBelongsToOrganisation) + if (subsidiary.SubsidiaryBelongsToAnyOtherOrganisation) { LogValidationWarning(rowIndex + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs index cb92f85..3ab3452 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs @@ -9,6 +9,6 @@ public class SubsidiaryDetail public bool SubsidiaryExists { get; set; } - public bool SubsidiaryBelongsToOrganisation { get; set; } + public bool SubsidiaryBelongsToAnyOtherOrganisation { get; set; } } } From c0ef4bcabc8d769bb2669fe15bf20ab562b69127 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 14:41:27 +0000 Subject: [PATCH 22/39] Made changes to merge the errorcodes for same producer into one collection --- ...rValidationEventIssueRequestMergerTests.cs | 270 ++++++++++++++++++ .../Services/ValidationServiceTests.cs | 125 ++++++++ ...oducerValidationEventIssueRequestMerger.cs | 56 ++++ .../Services/ValidationService.cs | 16 +- 4 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs new file mode 100644 index 0000000..89324b4 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs @@ -0,0 +1,270 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class ProducerValidationEventIssueRequestMergerTests + { + [TestMethod] + public void MergeRequests_IdenticalEntries_ShouldMergeErrorCodes() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error1" }); + var request2 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error2" }); + + var list1 = new List { request1 }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(1); + result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error1", "Error2" }); + } + + [TestMethod] + public void MergeRequests_UniqueEntries_ShouldRetainBothEntries() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error1" }); + var request2 = new ProducerValidationEventIssueRequest( + "456", + "2024-02", + 2, + "Producer2", + "TypeB", + "Medium", + "WasteType", + "CategoryB", + "MaterialY", + "SubTypeY", + "Nation3", + "Nation4", + "200", + "Units", + ErrorCodes: new List { "Error3" }); + + var list1 = new List { request1 }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(2); + result.Should().ContainEquivalentOf(request1); + result.Should().ContainEquivalentOf(request2); + } + + [TestMethod] + public void MergeRequests_MixedEntries_ShouldMergeIdenticalAndRetainUnique() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error1" }); + + var request2 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error2" }); + + var uniqueRequest = new ProducerValidationEventIssueRequest( + SubsidiaryId: "789", + DataSubmissionPeriod: "2024-03", + RowNumber: 3, + ProducerId: "Producer3", + ProducerType: "TypeC", + ProducerSize: "Small", + WasteType: "WasteType", + PackagingCategory: "CategoryC", + MaterialType: "MaterialZ", + MaterialSubType: "SubTypeZ", + FromHomeNation: "Nation5", + ToHomeNation: "Nation6", + QuantityKg: "300", + QuantityUnits: "Units", + ErrorCodes: new List { "Error4" }); + + var list1 = new List { request1, uniqueRequest }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(2); + result.Should().ContainSingle(r => r.SubsidiaryId == "123" && r.ErrorCodes.Contains("Error1") && r.ErrorCodes.Contains("Error2")); + result.Should().ContainEquivalentOf(uniqueRequest); + } + + [TestMethod] + public void MergeRequests_EmptyList_ShouldReturnOtherList() + { + // Arrange + var request = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error1" }); + + var list1 = new List { request }; + var list2 = new List(); + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(1); + result.Should().ContainEquivalentOf(request); + } + + [TestMethod] + public void MergeRequests_BothEmpty_ShouldReturnEmpty() + { + // Arrange + var list1 = new List(); + var list2 = new List(); + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().BeEmpty(); + } + + [TestMethod] + public void MergeRequests_NullErrorCodes_ShouldHandleGracefully() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: null); + + var request2 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error2" }); + + var list1 = new List { request1 }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(1); + result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error2" }); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 686ec25..38dcab1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -412,6 +412,131 @@ public async Task ValidateAsync_WhenWarningCapacityReached_LogsWarning() Assert.AreEqual(0, result.ValidationWarnings.Count); } + [TestMethod] + public async Task ValidateAsync_CollectsWarningsAndValidatesSubsidiaries_LimitedByErrorCapacity() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1), + ModelGenerator.CreateProducerRow(2) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + + var expectedWarnings = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Warning1" }) + }; + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + warnings.AddRange(expectedWarnings); + errors.AddRange(expectedErrors); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(ErrorStoreKey)).ReturnsAsync(10); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(WarningStoreKey)).ReturnsAsync(5); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEquivalentTo(expectedWarnings); + result.ValidationErrors.Should().BeEquivalentTo(expectedErrors.Take(5)); // Limited by error capacity + } + + [TestMethod] + public async Task ValidateAsync_EnabledSubsidiaryValidation_NoErrorsFromSubsidiaryValidation_AggregatesErrors() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + // No warnings + errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" })); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Should().BeEquivalentTo(expectedErrors); + } + + [TestMethod] + public async Task ValidateAsync_DisabledSubsidiaryValidation_DoesNotValidateSubsidiaries() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(false); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + errors.AddRange(expectedErrors); + }); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Should().BeEquivalentTo(expectedErrors); + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs new file mode 100644 index 0000000..54e928b --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs @@ -0,0 +1,56 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public static class ProducerValidationEventIssueRequestMerger + { + public static List MergeRequests( + List list1, + List list2) + { + // Combine both lists + var combinedList = list1.Concat(list2); + + // Use a dictionary to group and merge ErrorCodes for identical records + var mergedDict = new Dictionary<(string, string, int, string, string, string, string, string, string, string, string, string, string, string, string), ProducerValidationEventIssueRequest>(); + + foreach (var request in combinedList) + { + var key = ( + request.SubsidiaryId, + request.DataSubmissionPeriod, + request.RowNumber, + request.ProducerId, + request.ProducerType, + request.ProducerSize, + request.WasteType, + request.PackagingCategory, + request.MaterialType, + request.MaterialSubType, + request.FromHomeNation, + request.ToHomeNation, + request.QuantityKg, + request.QuantityUnits, + request.BlobName); + + if (mergedDict.TryGetValue(key, out var existingRequest)) + { + // Merge ErrorCodes if they exist + var mergedErrorCodes = existingRequest.ErrorCodes?.Union(request.ErrorCodes ?? new List()).ToList() + ?? request.ErrorCodes ?? new List(); + + // Update the dictionary with the merged ErrorCodes + mergedDict[key] = existingRequest with { ErrorCodes = mergedErrorCodes }; + } + else + { + // Add the request to the dictionary if it doesn't exist + mergedDict[key] = request; + } + } + + // Return the merged list + return mergedDict.Values.ToList(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 18525f6..a231601 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; @@ -76,17 +77,26 @@ public async Task ValidateAsync(Producer producer) var errors = new List(); var warnings = new List(); + var subValidationResult = new List(); await _compositeValidator.ValidateAndFetchForIssuesAsync(producer.Rows, errors, warnings, producer.BlobName); await _compositeValidator.ValidateDuplicatesAndGroupedData(producer.Rows, errors, warnings, producer.BlobName); - producerValidationOutRequest.ValidationErrors.AddRange(errors); producerValidationOutRequest.ValidationWarnings.AddRange(warnings); if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)) { - List subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); - producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); + subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); + } + + if (subValidationResult.Count > 0) + { + var subValidationResultLimitedToRemainingErrorCapacity = subValidationResult.Take(remainingErrorCapacity - errors.Count); + ProducerValidationEventIssueRequestMerger.MergeRequests(errors, (List)subValidationResultLimitedToRemainingErrorCapacity); + } + else + { + producerValidationOutRequest.ValidationErrors.AddRange(errors); } _logger.LogExit(); From c88e99148819fa56642b8835ad2c5bbfd8e254df Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 15:42:06 +0000 Subject: [PATCH 23/39] Made changes to merge the errorcodes for same producer into one collection --- .../Services/ValidationServiceTests.cs | 45 +++++++++++++++++++ .../Services/ValidationService.cs | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 38dcab1..ebb2e75 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -498,6 +498,51 @@ public async Task ValidateAsync_EnabledSubsidiaryValidation_NoErrorsFromSubsidia result.ValidationErrors.Should().BeEquivalentTo(expectedErrors); } + [TestMethod] + public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiaryValidation_AggregatesErrors() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + var validationErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }) + }; + + _validationServiceProducerRowValidatorMock.Setup(x => x.ProcessRowsForValidationErrors(It.IsAny>(), It.IsAny())).Returns(validationErrors); + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + // No warnings + errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" })); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Count.Should().Be(2); + } + [TestMethod] public async Task ValidateAsync_DisabledSubsidiaryValidation_DoesNotValidateSubsidiaries() { diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index a231601..1f37e23 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -91,8 +91,8 @@ public async Task ValidateAsync(Producer producer) if (subValidationResult.Count > 0) { - var subValidationResultLimitedToRemainingErrorCapacity = subValidationResult.Take(remainingErrorCapacity - errors.Count); - ProducerValidationEventIssueRequestMerger.MergeRequests(errors, (List)subValidationResultLimitedToRemainingErrorCapacity); + var mergedErrors = ProducerValidationEventIssueRequestMerger.MergeRequests(errors, subValidationResult); + producerValidationOutRequest.ValidationErrors.AddRange(mergedErrors.Take(remainingErrorCapacity - errors.Count)); } else { From c1c9af31252d309c3a15bd5946bf135df9f91bcb Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:28:00 +0000 Subject: [PATCH 24/39] Changed FindMatchingProducerTests to use fluent validation --- .../Services/Helpers/FindMatchingProducerTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index c392c06..dcf323c 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -4,6 +4,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -44,7 +45,7 @@ public void Match_NoMatchingOrganisation_ReturnsNull() var result = _findMatchingProducer.Match(row, response, 1); // Assert - Assert.IsNull(result); + result.Should().BeNull(); _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(It.IsAny(), It.IsAny()), Times.Never); _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); @@ -70,7 +71,7 @@ public void Match_NoMatchingSubsidiary_ReturnsNull() var result = _findMatchingProducer.Match(row, response, 1); // Assert - Assert.IsNull(result); + result.Should().BeNull(); _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); @@ -118,7 +119,7 @@ public void Match_MatchingOrganisationAndSubsidiary_ReturnsValidationResult() var result = _findMatchingProducer.Match(row, response, 1); // Assert - Assert.AreEqual(expectedValidationResult, result); + result.Should().Be(expectedValidationResult); _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1), Times.Once); From 2c4001f74fdf4c37a06ddf7a252d0f3f79c8790b Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:34:33 +0000 Subject: [PATCH 25/39] Changed FindMatchingProducerTests to use fluent validation --- .../Clients/CompanyDetailsApiClientTests.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs index 59c6c17..717a780 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs @@ -39,17 +39,17 @@ public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSu }; var handlerMock = new Mock(MockBehavior.Strict); handlerMock - .Protected() - .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(content), - }) - .Verifiable(); + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); var httpClient = new HttpClient(handlerMock.Object) { BaseAddress = new Uri(_config.BaseUrl), From 01d7e1abfd0ebdc9135d147e4bca020dbae605d3 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:52:28 +0000 Subject: [PATCH 26/39] Changed CompanyDetailsDataItemTests.cs to use fluent validation --- .../CompanyDetailsDataItemTests.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs index a81b851..6fb725f 100644 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs @@ -1,4 +1,5 @@ using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; @@ -21,8 +22,8 @@ public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNa var json = JsonConvert.SerializeObject(companyDetails); // Assert - Assert.IsTrue(json.Contains("\"RN\":\"REF123\""), "Serialized JSON should contain 'RN' with correct value."); - Assert.IsTrue(json.Contains("\"CHN\":\"CHN456\""), "Serialized JSON should contain 'CHN' with correct value."); + json.Should().Contain("\"RN\":\"REF123\"") + .And.Contain("\"CHN\":\"CHN456\""); } [TestMethod] @@ -35,9 +36,9 @@ public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues( var companyDetails = JsonConvert.DeserializeObject(json); // Assert - Assert.IsNotNull(companyDetails, "Deserialized object should not be null."); - Assert.AreEqual("REF123", companyDetails.ReferenceNumber, "ReferenceNumber should match the JSON value."); - Assert.AreEqual("CHN456", companyDetails.CompaniesHouseNumber, "CompaniesHouseNumber should match the JSON value."); + companyDetails.Should().NotBeNull(); + companyDetails!.ReferenceNumber.Should().Be("REF123"); + companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); } [TestMethod] @@ -54,8 +55,8 @@ public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() var json = JsonConvert.SerializeObject(companyDetails); // Assert - Assert.IsTrue(json.Contains("\"RN\":null"), "Serialized JSON should contain 'RN' with a null value."); - Assert.IsTrue(json.Contains("\"CHN\":null"), "Serialized JSON should contain 'CHN' with a null value."); + json.Should().Contain("\"RN\":null") + .And.Contain("\"CHN\":null"); } [TestMethod] @@ -70,13 +71,13 @@ public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreN var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); // Assert - Assert.IsNotNull(companyDetailsWithNulls, "Deserialized object with nulls should not be null."); - Assert.IsNull(companyDetailsWithNulls.ReferenceNumber, "ReferenceNumber should be null if JSON contains null."); - Assert.IsNull(companyDetailsWithNulls.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON contains null."); + companyDetailsWithNulls.Should().NotBeNull(); + companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); + companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); - Assert.IsNotNull(companyDetailsWithoutKeys, "Deserialized object without keys should not be null."); - Assert.IsNull(companyDetailsWithoutKeys.ReferenceNumber, "ReferenceNumber should be null if JSON key is missing."); - Assert.IsNull(companyDetailsWithoutKeys.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON key is missing."); + companyDetailsWithoutKeys.Should().NotBeNull(); + companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); + companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); } } } From f0c3dbf2d7cef59edabf01b48a5af208c92eb81c Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:58:42 +0000 Subject: [PATCH 27/39] Changed OrganisationMatcherTests to use fluent validation --- .../Services/Helpers/OrganisationMatcherTests.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs index b69492d..ad17f13 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -50,8 +51,8 @@ public void FindMatchingOrganisation_ShouldReturnOrganisation_WhenMatchExists() var result = _organisationMatcher.FindMatchingOrganisation(row, response); // Assert - Assert.IsNotNull(result); - Assert.AreEqual("Org456", result.OrganisationReference); + result.Should().NotBeNull(); + result!.OrganisationReference.Should().Be("Org456"); } [TestMethod] @@ -89,7 +90,7 @@ public void FindMatchingOrganisation_ShouldReturnNull_WhenNoMatchExists() var result = _organisationMatcher.FindMatchingOrganisation(row, response); // Assert - Assert.IsNull(result); + result.Should().BeNull(); } [TestMethod] @@ -122,7 +123,7 @@ public void FindMatchingOrganisation_ShouldReturnNull_WhenResponseIsEmpty() var result = _organisationMatcher.FindMatchingOrganisation(row, response); // Assert - Assert.IsNull(result); + result.Should().BeNull(); } } } From 977adad25d66ac2436a8bbc11d6561c7d8dc6335 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:03:44 +0000 Subject: [PATCH 28/39] Changed ProducerValidationEventFormatterTests to use fluent validation --- .../ProducerValidationEventFormatterTests.cs | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs index 45a6b4a..953cb31 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -42,22 +43,22 @@ public void Format_ShouldReturnFormattedRequest_WithAllFieldsProvided() var result = _formatter.Format(row, errorCode); // Assert - Assert.IsNotNull(result); - Assert.AreEqual("Sub123", result.SubsidiaryId); - Assert.AreEqual("2023-Q1", result.DataSubmissionPeriod); - Assert.AreEqual(1, result.RowNumber); - Assert.AreEqual("Org456", result.ProducerId); - Assert.AreEqual("TypeA", result.ProducerType); - Assert.AreEqual("Large", result.ProducerSize); - Assert.AreEqual("Plastic", result.WasteType); - Assert.AreEqual("CategoryA", result.PackagingCategory); - Assert.AreEqual("MaterialX", result.MaterialType); - Assert.AreEqual("SubMaterialX", result.MaterialSubType); - Assert.AreEqual("UK", result.FromHomeNation); - Assert.AreEqual("Germany", result.ToHomeNation); - Assert.AreEqual("100", result.QuantityKg); - Assert.AreEqual("200", result.QuantityUnits); - CollectionAssert.Contains(result.ErrorCodes, errorCode); + result.Should().NotBeNull(); + result.SubsidiaryId.Should().Be("Sub123"); + result.DataSubmissionPeriod.Should().Be("2023-Q1"); + result.RowNumber.Should().Be(1); + result.ProducerId.Should().Be("Org456"); + result.ProducerType.Should().Be("TypeA"); + result.ProducerSize.Should().Be("Large"); + result.WasteType.Should().Be("Plastic"); + result.PackagingCategory.Should().Be("CategoryA"); + result.MaterialType.Should().Be("MaterialX"); + result.MaterialSubType.Should().Be("SubMaterialX"); + result.FromHomeNation.Should().Be("UK"); + result.ToHomeNation.Should().Be("Germany"); + result.QuantityKg.Should().Be("100"); + result.QuantityUnits.Should().Be("200"); + result.ErrorCodes.Should().Contain(errorCode); } [TestMethod] @@ -87,22 +88,22 @@ public void Format_ShouldHandleNullFields_InProducerRow() var result = _formatter.Format(row, errorCode); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(string.Empty, result.SubsidiaryId); - Assert.AreEqual(string.Empty, result.DataSubmissionPeriod); - Assert.AreEqual(1, result.RowNumber); - Assert.AreEqual(string.Empty, result.ProducerId); - Assert.AreEqual(string.Empty, result.ProducerType); - Assert.AreEqual(string.Empty, result.ProducerSize); - Assert.AreEqual(string.Empty, result.WasteType); - Assert.AreEqual(string.Empty, result.PackagingCategory); - Assert.AreEqual(string.Empty, result.MaterialType); - Assert.AreEqual(string.Empty, result.MaterialSubType); - Assert.AreEqual(string.Empty, result.FromHomeNation); - Assert.AreEqual(string.Empty, result.ToHomeNation); - Assert.AreEqual(string.Empty, result.QuantityKg); - Assert.AreEqual(string.Empty, result.QuantityUnits); - CollectionAssert.Contains(result.ErrorCodes, errorCode); + result.Should().NotBeNull(); + result.SubsidiaryId.Should().BeEmpty(); + result.DataSubmissionPeriod.Should().BeEmpty(); + result.RowNumber.Should().Be(1); + result.ProducerId.Should().BeEmpty(); + result.ProducerType.Should().BeEmpty(); + result.ProducerSize.Should().BeEmpty(); + result.WasteType.Should().BeEmpty(); + result.PackagingCategory.Should().BeEmpty(); + result.MaterialType.Should().BeEmpty(); + result.MaterialSubType.Should().BeEmpty(); + result.FromHomeNation.Should().BeEmpty(); + result.ToHomeNation.Should().BeEmpty(); + result.QuantityKg.Should().BeEmpty(); + result.QuantityUnits.Should().BeEmpty(); + result.ErrorCodes.Should().Contain(errorCode); } [TestMethod] @@ -132,8 +133,8 @@ public void Format_ShouldReturnSingleErrorCode() var result = _formatter.Format(row, errorCode); // Assert - Assert.AreEqual(1, result.ErrorCodes.Count, "Expected exactly one error code in the list."); - Assert.AreEqual("SingleError", result.ErrorCodes[0]); + result.ErrorCodes.Should().HaveCount(1, "Expected exactly one error code in the list.") + .And.ContainSingle(e => e == "SingleError"); } } } From 09aa5280812cf05a4b9092e6dd3111598fabaee6 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:14:13 +0000 Subject: [PATCH 29/39] Changed RequestValidatorTests to use fluent validation --- .../Services/Helpers/RequestValidatorTests.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs index 41e9a88..b47650c 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -22,7 +23,7 @@ public void IsInvalidRequest_ShouldReturnTrue_WhenRequestIsNull() var result = _validator.IsInvalidRequest(null); // Assert - Assert.IsTrue(result, "Expected IsInvalidRequest to return true for null request."); + result.Should().BeTrue("because the request is null and should be considered invalid."); } [TestMethod] @@ -38,7 +39,7 @@ public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsI var result = _validator.IsInvalidRequest(request); // Assert - Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is null."); + result.Should().BeTrue("because SubsidiaryOrganisationDetails is null and the request should be invalid."); } [TestMethod] @@ -54,7 +55,7 @@ public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsI var result = _validator.IsInvalidRequest(request); // Assert - Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is empty."); + result.Should().BeTrue("because SubsidiaryOrganisationDetails is empty and should be considered invalid."); } [TestMethod] @@ -64,16 +65,16 @@ public void IsInvalidRequest_ShouldReturnFalse_WhenSubsidiaryOrganisationDetails var request = new SubsidiaryDetailsRequest { SubsidiaryOrganisationDetails = new List - { - new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } - } + { + new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } + } }; // Act var result = _validator.IsInvalidRequest(request); // Assert - Assert.IsFalse(result, "Expected IsInvalidRequest to return false when SubsidiaryOrganisationDetails is not empty."); + result.Should().BeFalse("because SubsidiaryOrganisationDetails contains entries and should be considered valid."); } } } From 84b52b9124289dd077be61d5ca13f5b6c3b8da71 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:20:37 +0000 Subject: [PATCH 30/39] Changed SubsidiaryMatcherTests to use fluent validation --- .../Services/Helpers/SubsidiaryMatcherTests.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs index 49685c9..910f4e4 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -54,8 +55,8 @@ public void FindMatchingSubsidiary_ShouldReturnMatchingSubsidiary_WhenReferenceN var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNotNull(result); - Assert.AreEqual("123", result?.ReferenceNumber); + result.Should().NotBeNull("because there is a matching subsidiary with the reference number '123'"); + result?.ReferenceNumber.Should().Be("123", "because the reference number should match the subsidiary ID in the row."); } [TestMethod] @@ -96,7 +97,7 @@ public void FindMatchingSubsidiary_ShouldReturnNull_WhenNoMatchingReferenceNumbe var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNull(result); + result.Should().BeNull("because there is no matching subsidiary with the reference number '789'."); } [TestMethod] @@ -131,14 +132,15 @@ public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryDetailsIsEmpty var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNull(result); + result.Should().BeNull("because SubsidiaryDetails is empty and should not contain a matching subsidiary."); } [TestMethod] public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() { // Arrange - var row = ModelGenerator.CreateProducerRow(1) with { + var row = ModelGenerator.CreateProducerRow(1) with + { SubsidiaryId = null, DataSubmissionPeriod = "2024Q1", ProducerId = "456", @@ -171,7 +173,7 @@ public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNull(result); + result.Should().BeNull("because the row's SubsidiaryId is null and cannot match any reference number."); } } } From c0d869763f60fe14289559f93e23f068b84c074c Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:26:05 +0000 Subject: [PATCH 31/39] Changed SubsidiaryValidationEvaluatorTests to use fluent validation --- .../Helpers/SubsidiaryValidationEvaluatorTests.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index b443b0a..9be42eb 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -71,8 +72,8 @@ public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarning var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(expectedRequest, result); + result.Should().NotBeNull("because a request should be returned if the subsidiary does not exist.") + .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); } @@ -122,8 +123,8 @@ public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisatio var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(expectedRequest, result); + result.Should().NotBeNull("because a request should be returned if the subsidiary belongs to a different organisation.") + .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); } @@ -155,7 +156,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); // Assert - Assert.IsNull(result); + result.Should().BeNull("because the subsidiary is valid and should not generate any validation issue."); _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); } From 878e919fb0b1674c191f9b4e92ddac590114778b Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:37:32 +0000 Subject: [PATCH 32/39] Changed ValidationServiceProducerRowValidatorTests to use fluent validation --- ...idationServiceProducerRowValidatorTests.cs | 143 +++++++++--------- 1 file changed, 70 insertions(+), 73 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index 88d7f9a..6e32a08 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -4,6 +4,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -28,52 +29,11 @@ public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() // Arrange var producerRow = ModelGenerator.CreateProducerRow(1); var producerRowTwo = ModelGenerator.CreateProducerRow(2); - var producerRows = new List { producerRow, producerRowTwo }; - - var row1 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub1", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteTypeA", - PackagingCategory = "CategoryA", - MaterialType = "MaterialA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "100", - QuantityUnits = "10" - }; - - var row2 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub2", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod2", - RowNumber = 2, - ProducerType = "TypeB", - ProducerSize = "Small", - WasteType = "WasteTypeB", - PackagingCategory = "CategoryB", - MaterialType = "MaterialB", - MaterialSubType = "SubTypeB", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "200", - QuantityUnits = "20" - }; - var rows = new List - { - row1, - row2 - }; + var rows = new List { producerRow, producerRowTwo }; var response = new SubsidiaryDetailsResponse { - // Initialize your response data + // Initialize response data if needed }; _mockFindMatchingProducer.Setup(x => x.Match(It.IsAny(), response, It.IsAny())).Returns((ProducerValidationEventIssueRequest)null); @@ -82,8 +42,8 @@ public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() var result = _validator.ProcessRowsForValidationErrors(rows, response); // Assert - Assert.IsNotNull(result); - Assert.IsFalse(result.Any()); + result.Should().NotBeNull("the result should not be null, even if it contains no errors.") + .And.BeEmpty("because there are no validation errors expected in this case."); } [TestMethod] @@ -125,29 +85,40 @@ public void ProcessRowsForValidationErrors_SingleValidationError_ReturnsListWith QuantityKg = "200", QuantityUnits = "20" }; - var rows = new List - { - row1, - row2 - }; + var rows = new List { row1, row2 }; var response = new SubsidiaryDetailsResponse { - // Initialize your response data + // Initialize response data if needed }; - var errorRequest = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); - - _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest); - _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns((ProducerValidationEventIssueRequest)null); + var errorRequest = new ProducerValidationEventIssueRequest( + "Sub1", + "2024Q1", + 1, + "Prod1", + "TypeA", + "Large", + "WasteTypeA", + "CategoryA", + "MaterialA", + "SubTypeA", + "NationA", + "NationB", + "100", + "10", + ErrorCodes: new List { "Error1" }); + + _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest); + _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns((ProducerValidationEventIssueRequest)null); // Act var result = _validator.ProcessRowsForValidationErrors(rows, response); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(1, result.Count()); - Assert.AreEqual(errorRequest, result.First()); + result.Should().NotBeNull("the result should contain errors if one row has a validation issue.") + .And.HaveCount(1, "because there is only one expected validation error.") + .And.ContainSingle(error => error.Equals(errorRequest), "the single error returned should match the expected error request."); } [TestMethod] @@ -189,31 +160,57 @@ public void ProcessRowsForValidationErrors_MultipleValidationErrors_ReturnsListW QuantityKg = "200", QuantityUnits = "20" }; - var rows = new List - { - row1, - row2 - }; + var rows = new List { row1, row2 }; var response = new SubsidiaryDetailsResponse { - // Initialize your response data + // Initialize response data if needed }; - var errorRequest1 = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); - var errorRequest2 = new ProducerValidationEventIssueRequest("Sub2", "2024Q1", 2, "Prod2", "TypeB", "Small", "WasteTypeB", "CategoryB", "MaterialB", "SubTypeB", "NationA", "NationB", "200", "20", ErrorCodes: new List { "Error2" }); - - _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest1); - _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns(errorRequest2); + var errorRequest1 = new ProducerValidationEventIssueRequest( + "Sub1", + "2024Q1", + 1, + "Prod1", + "TypeA", + "Large", + "WasteTypeA", + "CategoryA", + "MaterialA", + "SubTypeA", + "NationA", + "NationB", + "100", + "10", + ErrorCodes: new List { "Error1" }); + + var errorRequest2 = new ProducerValidationEventIssueRequest( + "Sub2", + "2024Q1", + 2, + "Prod2", + "TypeB", + "Small", + "WasteTypeB", + "CategoryB", + "MaterialB", + "SubTypeB", + "NationA", + "NationB", + "200", + "20", + ErrorCodes: new List { "Error2" }); + + _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest1); + _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns(errorRequest2); // Act var result = _validator.ProcessRowsForValidationErrors(rows, response); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(2, result.Count()); - Assert.IsTrue(result.Contains(errorRequest1)); - Assert.IsTrue(result.Contains(errorRequest2)); + result.Should().NotBeNull("the result should contain all validation errors if multiple rows have issues.") + .And.HaveCount(2, "because two validation errors are expected.") + .And.Contain(new[] { errorRequest1, errorRequest2 }, "the list of errors returned should match the expected errors."); } } } From a4153702fc66e69820820f7059d0ee84b12a3a7a Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:58:07 +0000 Subject: [PATCH 33/39] Changed ValidationServiceTests to use fluent validation --- .../Services/ValidationServiceTests.cs | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index ebb2e75..9fbc6e4 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -140,8 +140,8 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(0, "because there are no validation errors expected in this case."); } [TestMethod] @@ -177,8 +177,8 @@ public async Task ValidateSubsidiaryAsyncInvalidRequestReturnsEmptyList() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(0, "because there are no validation errors expected in this case."); } [TestMethod] @@ -220,9 +220,9 @@ public async Task ValidateSubsidiaryAsync_ValidRequest_ReturnsValidationErrors() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(1, result.Count); - Assert.AreEqual(validationErrors.First(), result.First()); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(1, "because there is only one expected validation error.") + .And.ContainSingle(error => error.Equals(validationErrors.First()), "the single error returned should match the expected validation error."); } [TestMethod] @@ -258,8 +258,8 @@ public async Task ValidateSubsidiaryAsync_HttpRequestException_LogsErrorAndRetur var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null") + .And.HaveCount(0, "because we expect no validation errors."); } // End @@ -278,8 +278,8 @@ public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyL var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull(); + result.Should().BeEmpty(); } [TestMethod] @@ -299,8 +299,9 @@ public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmp var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(0, "because we expect zero validation errors."); + _loggerMock.Verify( x => x.Log( LogLevel.Error, @@ -308,7 +309,8 @@ public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmp It.Is((v, t) => v.ToString().Contains("Error during subsidiary validation.")), It.Is(ex => ex == exception), It.IsAny>()), - Times.Once); + Times.Once, + "the logger should log an error when validation fails."); } [TestMethod] @@ -326,7 +328,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryVal // Assert _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); - Assert.IsNotNull(result); + result.Should().NotBeNull("the result should not be null"); } [TestMethod] @@ -345,7 +347,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOn_DoesPerformSubsidiaryValidat // Assert _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Once); _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); - Assert.IsNotNull(result); + result.Should().NotBeNull("the result should not be null."); } [TestMethod] @@ -362,8 +364,8 @@ public async Task ValidateAsync_WhenRemainingWarningCapacityIsZero_OnlyErrorsAre var result = await service.ValidateAsync(producer); // Assert - Assert.IsNotNull(result); - Assert.IsTrue(result.ValidationWarnings.Count == 0); + result.Should().NotBeNull("the result should not be null."); + result.ValidationWarnings.Should().BeEmpty("because there should be no validation warnings."); } [TestMethod] @@ -381,7 +383,7 @@ public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.AreEqual(0, result.Count); + result.Should().HaveCount(0, "because there are no validation errors expected in this case."); } [TestMethod] @@ -408,8 +410,10 @@ public async Task ValidateAsync_WhenWarningCapacityReached_LogsWarning() It.IsAny(), It.IsAny>()), Times.Never); - Assert.IsNotNull(result); - Assert.AreEqual(0, result.ValidationWarnings.Count); + + // Use FluentAssertions for result validation + result.Should().NotBeNull("the result should not be null."); + result.ValidationWarnings.Should().BeEmpty("because there should be no validation warnings."); } [TestMethod] From 605c6757bdd62d1774de8bbdccf348148aaf5376 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 11:19:17 +0000 Subject: [PATCH 34/39] Resolved a review comment --- .../Services/Helpers/ValidationServiceProducerRowValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index 7e7d95f..de6fec1 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -19,7 +19,7 @@ public IEnumerable ProcessRowsForValidation { var validationErrors = new List(); - for (int i = 0; i < rows.Count; i++) + for (var i = 0; i < rows.Count; i++) { var error = _findMatchingProducer.Match(rows[i], response, i); if (error != null) From c37c36f9ebca0bc2330fe6cc2bd9cd8a28106108 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 12:27:14 +0000 Subject: [PATCH 35/39] Removed Data project, moving functional contents to Application --- .../Clients/CompanyDetailsApiClientTests.cs | 2 +- .../Config/CompanyDetailsApiConfig.cs | 0 .../Data/CompanyDetailsDataItemTests.cs | 83 +++++++++++++++++++ .../Helpers/FindMatchingProducerTests.cs | 2 +- .../Helpers/OrganisationMatcherTests.cs | 2 +- .../Services/Helpers/RequestValidatorTests.cs | 4 +- .../Helpers/SubsidiaryMatcherTests.cs | 4 +- .../SubsidiaryValidationEvaluatorTests.cs | 2 +- ...idationServiceProducerRowValidatorTests.cs | 2 +- .../Services/ValidationServiceTests.cs | 2 +- .../Clients/CompanyDetailsApiClient.cs | 2 +- .../Clients/ICompanyDetailsApiClient.cs | 2 +- .../Config/CompanyDetailsApiConfig.cs | 16 ++++ ...oducerContentValidation.Application.csproj | 4 - .../CompanyDetailsApiAuthorisationHandler.cs | 2 +- .../CompanyDetailsDataItem.cs | 2 +- .../CompanyDetailsDataResult.cs | 2 +- .../Models/Subsidiary/SubsidiaryDetail.cs | 2 +- .../Subsidiary/SubsidiaryDetailsRequest.cs | 2 +- .../Subsidiary/SubsidiaryDetailsResponse.cs | 2 +- .../SubsidiaryOrganisationDetail.cs | 2 +- .../Services/Helpers/FindMatchingProducer.cs | 2 +- .../Interfaces/IFindMatchingProducer.cs | 2 +- .../Interfaces/IOrganisationMatcher.cs | 2 +- .../Helpers/Interfaces/IRequestValidator.cs | 2 +- .../Helpers/Interfaces/ISubsidiaryMatcher.cs | 2 +- .../ISubsidiaryValidationEvaluator.cs | 2 +- .../IValidationServiceProducerRowValidator.cs | 2 +- .../Services/Helpers/OrganisationMatcher.cs | 2 +- .../Services/Helpers/RequestValidator.cs | 4 +- .../Services/Helpers/SubsidiaryMatcher.cs | 2 +- .../Helpers/SubsidiaryValidationEvaluator.cs | 2 +- .../ValidationServiceProducerRowValidator.cs | 2 +- .../ISubsidiaryDetailsRequestBuilder.cs | 2 +- .../SubsidiaryDetailsRequestBuilder.cs | 2 +- .../Services/ValidationService.cs | 2 +- ...cerContentValidation.Data.UnitTests.csproj | 4 - .../StartUp.cs | 2 +- .../Clients/CompanyDetailsApiClientTests.cs | 4 +- ....ProducerContentValidation.UnitTest.csproj | 1 - src/EPR.ProducerContentValidation.sln | 12 --- 41 files changed, 137 insertions(+), 59 deletions(-) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application.UnitTests}/Config/CompanyDetailsApiConfig.cs (100%) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs (77%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs (75%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryDetail.cs (81%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryDetailsRequest.cs (76%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryDetailsResponse.cs (76%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryOrganisationDetail.cs (79%) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index fb0f622..67fa909 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -1,7 +1,7 @@ using System.Net; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Data.Config; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs similarity index 100% rename from src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs rename to src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs new file mode 100644 index 0000000..ec3639d --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs @@ -0,0 +1,83 @@ +using EPR.ProducerContentValidation.Application.Models.CompanyDetailsApi; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.UnitTests +{ + [TestClass] + public class CompanyDetailsDataItemTests + { + [TestMethod] + public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = "REF123", + CompaniesHouseNumber = "CHN456" + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + json.Should().Contain("\"RN\":\"REF123\"") + .And.Contain("\"CHN\":\"CHN456\""); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() + { + // Arrange + var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; + + // Act + var companyDetails = JsonConvert.DeserializeObject(json); + + // Assert + companyDetails.Should().NotBeNull(); + companyDetails!.ReferenceNumber.Should().Be("REF123"); + companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); + } + + [TestMethod] + public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = null, + CompaniesHouseNumber = null + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + json.Should().Contain("\"RN\":null") + .And.Contain("\"CHN\":null"); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() + { + // Arrange + var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; + var jsonWithoutKeys = "{}"; + + // Act + var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); + var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); + + // Assert + companyDetailsWithNulls.Should().NotBeNull(); + companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); + companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); + + companyDetailsWithoutKeys.Should().NotBeNull(); + companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); + companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index dcf323c..f482ae5 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -1,8 +1,8 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs index ad17f13..5759154 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs index b47650c..9920490 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -1,5 +1,5 @@ -using EPR.ProducerContentValidation.Application.Services.Helpers; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs index 910f4e4..09c9103 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -1,5 +1,5 @@ -using EPR.ProducerContentValidation.Application.Services.Helpers; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index 9be42eb..0b5bfea 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -1,9 +1,9 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index 6e32a08..48b27a3 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -1,8 +1,8 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 9fbc6e4..635d368 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -3,6 +3,7 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; @@ -10,7 +11,6 @@ using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs index 05c886b..c08c2db 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -1,4 +1,4 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using Microsoft.Extensions.Logging; using Newtonsoft.Json; diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs index 79086d9..a197b06 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -1,4 +1,4 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Clients { diff --git a/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs new file mode 100644 index 0000000..35cdd8d --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace EPR.ProducerContentValidation.Application.Config +{ + public class CompanyDetailsApiConfig + { + public const string Section = "CompanyDetailsApi"; + + [Required] + public string BaseUrl { get; init; } + + public string? ClientId { get; set; } + + public int Timeout { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index eda8453..a63ccb9 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -25,8 +25,4 @@ - - - - \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs index 8513db8..1b3e179 100644 --- a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs +++ b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs @@ -2,7 +2,7 @@ using System.Net.Http.Headers; using Azure.Core; using Azure.Identity; -using EPR.ProducerContentValidation.Data.Config; +using EPR.ProducerContentValidation.Application.Config; using Microsoft.Extensions.Options; namespace EPR.ProducerContentValidation.Application.Handlers diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs similarity index 77% rename from src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs rename to src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs index 9d0fe95..ec4b324 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -1,4 +1,4 @@ -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +namespace EPR.ProducerContentValidation.Application.Models.CompanyDetailsApi; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs similarity index 75% rename from src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs rename to src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs index 9b57696..cd5b99e 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -1,4 +1,4 @@ -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +namespace EPR.ProducerContentValidation.Application.Models.CompanyDetailsApi; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs similarity index 81% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs index 3ab3452..415cd8c 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryDetail diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs similarity index 76% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs index c3a3f47..edecc9d 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryDetailsRequest diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs similarity index 76% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs index 7a82d14..669fff7 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryDetailsResponse diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs similarity index 79% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs index c467b0c..9ca2695 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryOrganisationDetail diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs index dcb12fb..5d4474e 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs index e27f943..97bc2b2 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs index ba25656..2aca078 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs index 321a86f..f332719 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs @@ -1,4 +1,4 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs index 8e97c6d..bed05ee 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs index 2979b17..41781d4 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs index 8793799..09e628a 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs index 02192da..514ef72 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs index a0db7c9..0818036 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -1,5 +1,5 @@ -using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs index 7137043..cf29478 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index 026fae2..1a28614 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -1,8 +1,8 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index de6fec1..d681b9c 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs index c4eda28..cdc1b25 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Subsidiary { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs index 8084dcb..6342e2b 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Subsidiary { diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 1f37e23..b921611 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -4,13 +4,13 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.FeatureManagement; diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj index ae6b92c..cd4452f 100644 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs index 60826d1..ca27672 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs +++ b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs @@ -9,8 +9,8 @@ namespace EPR.ProducerContentValidation.FunctionApp; using System.Net.Http.Headers; using Application; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Config; using EPR.ProducerContentValidation.Application.Handlers; -using EPR.ProducerContentValidation.Data.Config; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; diff --git a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs index 717a780..db9437b 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs @@ -1,7 +1,7 @@ using System.Net; using EPR.ProducerContentValidation.Application.Clients; -using EPR.ProducerContentValidation.Data.Config; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Config; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Moq; diff --git a/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj index 36e4698..345a1b6 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj +++ b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj @@ -20,7 +20,6 @@ - diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index 6fb7ebb..db18649 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -22,12 +22,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution stylecop.ruleset = stylecop.ruleset EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data.UnitTests", "EPR.ProducerContentValidation.Data.UnitTests\EPR.ProducerContentValidation.Data.UnitTests.csproj", "{F3E90F69-1835-460D-ACCA-890229303A0E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,18 +50,10 @@ Global {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.Build.0 = Release|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.Build.0 = Release|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.Build.0 = Debug|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.Build.0 = Release|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From ca3556ad0d3552ae053aaab4f7ebb56a0eb62a61 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 12:52:34 +0000 Subject: [PATCH 36/39] Some refactoring --- .../Clients/CompanyDetailsApiClientTests.cs | 2 +- .../Config/CompanyDetailsApiConfig.cs | 16 ---------------- .../Data/CompanyDetailsDataItemTests.cs | 2 +- 3 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index 67fa909..65c41b5 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -1,7 +1,7 @@ using System.Net; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Config; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -using EPR.ProducerContentValidation.Data.Config; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs deleted file mode 100644 index d890038..0000000 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace EPR.ProducerContentValidation.Data.Config -{ - public class CompanyDetailsApiConfig - { - public const string Section = "CompanyDetailsApi"; - - [Required] - public string BaseUrl { get; init; } - - public string? ClientId { get; set; } - - public int Timeout { get; set; } - } -} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs index ec3639d..8e5b027 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs @@ -3,7 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace EPR.ProducerContentValidation.Data.UnitTests +namespace EPR.ProducerContentValidation.Application.UnitTests { [TestClass] public class CompanyDetailsDataItemTests From e73f2f2387d3935ba73aa76aac4ad454a59610c4 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 13:05:36 +0000 Subject: [PATCH 37/39] Some refactoring --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index dfe992d..30f9ead 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,7 +8,6 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. -COPY EPR.ProducerContentValidation.Data/. ./EPR.ProducerContentValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From dcda9dab2f973e548c42cb166fa2aa9a75c981b9 Mon Sep 17 00:00:00 2001 From: Fahad Ali Date: Fri, 1 Nov 2024 13:19:16 +0000 Subject: [PATCH 38/39] project removed from docker file --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index dfe992d..30f9ead 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,7 +8,6 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. -COPY EPR.ProducerContentValidation.Data/. ./EPR.ProducerContentValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From 753f96d87277f5469d34b5c9d90605d290473d43 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 13:33:46 +0000 Subject: [PATCH 39/39] Some refactoring --- .../CompanyDetailsDataItemTests.cs | 83 ------------------- ...cerContentValidation.Data.UnitTests.csproj | 18 ---- .../EPR.ProducerContentValidation.Data.csproj | 13 --- 3 files changed, 114 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs delete mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj delete mode 100644 src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs deleted file mode 100644 index 6fb725f..0000000 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs +++ /dev/null @@ -1,83 +0,0 @@ -using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; - -namespace EPR.ProducerContentValidation.Data.UnitTests -{ - [TestClass] - public class CompanyDetailsDataItemTests - { - [TestMethod] - public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() - { - // Arrange - var companyDetails = new CompanyDetailsDataItem - { - ReferenceNumber = "REF123", - CompaniesHouseNumber = "CHN456" - }; - - // Act - var json = JsonConvert.SerializeObject(companyDetails); - - // Assert - json.Should().Contain("\"RN\":\"REF123\"") - .And.Contain("\"CHN\":\"CHN456\""); - } - - [TestMethod] - public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() - { - // Arrange - var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; - - // Act - var companyDetails = JsonConvert.DeserializeObject(json); - - // Assert - companyDetails.Should().NotBeNull(); - companyDetails!.ReferenceNumber.Should().Be("REF123"); - companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); - } - - [TestMethod] - public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() - { - // Arrange - var companyDetails = new CompanyDetailsDataItem - { - ReferenceNumber = null, - CompaniesHouseNumber = null - }; - - // Act - var json = JsonConvert.SerializeObject(companyDetails); - - // Assert - json.Should().Contain("\"RN\":null") - .And.Contain("\"CHN\":null"); - } - - [TestMethod] - public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() - { - // Arrange - var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; - var jsonWithoutKeys = "{}"; - - // Act - var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); - var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); - - // Assert - companyDetailsWithNulls.Should().NotBeNull(); - companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); - companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); - - companyDetailsWithoutKeys.Should().NotBeNull(); - companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); - companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); - } - } -} diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj deleted file mode 100644 index cd4452f..0000000 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - - - - - - - - - diff --git a/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj b/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj deleted file mode 100644 index 3b5b170..0000000 --- a/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - -