From c5f06d71016cf7823326d10ef889ae3dfd2ff458 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Sat, 14 Dec 2024 07:49:54 +0000 Subject: [PATCH] added new tests to improve coverage --- .../DomainServiceHelperTests.cs | 65 +++++ .../DummyFileProcessorDomainService.cs | 37 ++- .../FileProcessorDomainServiceTests.cs | 257 +++++++++++++++++- .../MediatorTests.cs | 24 +- .../Requests/FileCommands.cs | 2 + .../Requests/FileQueries.cs | 2 + .../Services/FileProcessorDomainService.cs | 8 +- FileProcessor.Testing/TestData.cs | 9 + FileProcessor/Bootstrapper/MiscRegistry.cs | 28 +- FileProcessor/Controllers/ResultExtensions.cs | 61 ----- 10 files changed, 396 insertions(+), 97 deletions(-) create mode 100644 FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs delete mode 100644 FileProcessor/Controllers/ResultExtensions.cs diff --git a/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs b/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs new file mode 100644 index 0000000..1b264b1 --- /dev/null +++ b/FileProcessor.BusinessLogic.Tests/DomainServiceHelperTests.cs @@ -0,0 +1,65 @@ +using System; +using FileProcessor.BusinessLogic.Services; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Identity.Client; +using Shouldly; +using SimpleResults; +using Xunit; + +namespace FileProcessor.BusinessLogic.Tests; + +public class DomainServiceHelperTests +{ + public DomainServiceHelperTests() { + Shared.Logger.Logger.Initialise(NullLogger.Instance); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_SuccessfulGet_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.Success(new TestAggregate + { + AggregateId = aggregateId + }); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, true); + handleResult.IsSuccess.ShouldBeTrue(); + handleResult.Data.ShouldBeOfType(typeof(TestAggregate)); + handleResult.Data.AggregateId.ShouldBe(aggregateId); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_FailedGet_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.Failure("Failed Get"); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, true); + handleResult.IsFailed.ShouldBeTrue(); + handleResult.Message.ShouldBe("Failed Get"); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_FailedGet_NotFoundButIsError_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.NotFound("Failed Get"); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, true); + handleResult.IsFailed.ShouldBeTrue(); + handleResult.Message.ShouldBe("Failed Get"); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_FailedGet_NotFoundButIsNotError_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.NotFound("Failed Get"); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, false); + handleResult.IsSuccess.ShouldBeTrue(); + handleResult.Data.ShouldBeOfType(typeof(TestAggregate)); + handleResult.Data.AggregateId.ShouldBe(aggregateId); + } +} \ No newline at end of file diff --git a/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs b/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs index 30b752f..d698a27 100644 --- a/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs +++ b/FileProcessor.BusinessLogic.Tests/DummyFileProcessorDomainService.cs @@ -1,4 +1,7 @@ -using FileProcessor.DataTransferObjects; +using System.Collections.Generic; +using FileProcessor.BusinessLogic.Managers; +using FileProcessor.DataTransferObjects; +using FileProcessor.Models; using SimpleResults; namespace FileProcessor.BusinessLogic.Tests; @@ -20,4 +23,36 @@ public async Task ProcessUploadedFile(FileCommands.ProcessUploadedFileCo public async Task ProcessTransactionForFileLine(FileCommands.ProcessTransactionForFileLineCommand command, CancellationToken cancellationToken) => Result.Success(); +} + +public class DummyFileProcessorManager : IFileProcessorManager { + public async Task>> GetAllFileProfiles(CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> GetFileProfile(Guid fileProfileId, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task>> GetFileImportLogs(Guid estateId, + DateTime startDateTime, + DateTime endDateTime, + Guid? merchantId, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> GetFileImportLog(Guid fileImportLogId, + Guid estateId, + Guid? merchantId, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> GetFile(Guid fileId, + Guid estateId, + CancellationToken cancellationToken) { + return Result.Success(); + } } \ No newline at end of file diff --git a/FileProcessor.BusinessLogic.Tests/FileProcessorDomainServiceTests.cs b/FileProcessor.BusinessLogic.Tests/FileProcessorDomainServiceTests.cs index 4d9ac76..84e583e 100644 --- a/FileProcessor.BusinessLogic.Tests/FileProcessorDomainServiceTests.cs +++ b/FileProcessor.BusinessLogic.Tests/FileProcessorDomainServiceTests.cs @@ -1,14 +1,17 @@ -using SimpleResults; +using EstateManagement.DataTransferObjects.Responses.Operator; +using SimpleResults; namespace FileProcessor.BusinessLogic.Tests; using System; +using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.IO.Abstractions.TestingHelpers; using System.Threading; using System.Threading.Tasks; using EstateManagement.Client; +using EstateManagement.DataTransferObjects.Responses.Contract; using FileAggregate; using FileFormatHandlers; using FileImportLogAggregate; @@ -98,6 +101,36 @@ public async Task FileRequestHandler_UploadFileRequest_RequestIsHandled() result.Data.ShouldNotBe(Guid.Empty); } + [Fact] + public async Task FileRequestHandler_UploadFileRequest_SaveFailed_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileImportLogAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFileImportLogAggregate())); + this.FileImportLogAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure); + + this.FileSystem.AddFile(TestData.FilePathWithName, new MockFileData("D,1,1,1")); + this.FileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom"); + + Result result = await this.FileProcessorDomainService.UploadFile(TestData.UploadFileCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task FileRequestHandler_UploadFileRequest_ExceptionThrown_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileImportLogAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFileImportLogAggregate())); + this.FileImportLogAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ThrowsAsync(new Exception()); + + this.FileSystem.AddFile(TestData.FilePathWithName, new MockFileData("D,1,1,1")); + this.FileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom"); + + Result result = await this.FileProcessorDomainService.UploadFile(TestData.UploadFileCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + [Fact] public async Task FileRequestHandler_UploadFileRequest_MerchantIdNotProvided_ErrorThrown() { FileCommands.UploadFileCommand command = TestData.UploadFileCommand with { MerchantId = Guid.Empty }; @@ -246,9 +279,33 @@ public async Task FileRequestHandler_ProcessUploadedFileRequest_NoFileProfiles_R result.IsFailed.ShouldBeTrue(); result.Status.ShouldBe(ResultStatus.NotFound); } - + [Fact] - public async Task FileRequestHandler_ProcessUploadedFileRequest_OperatorNotFound_RequestIsHandled() + public async Task FileRequestHandler_ProcessUploadedFileRequest_GetFileProfileFailed_RequestIsHandled() + { + this.FileProcessorManager.SetupSequence(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.FileProfileSafaricom)) + .ReturnsAsync(Result.Failure()); + + this.FileImportLogAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEmptyFileImportLogAggregate())); + this.FileAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCreatedFileAggregate())); + + this.FileSystem.AddFile(TestData.FilePathWithName, new MockFileData("D,1,1,1")); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.EstateClient.Setup(e => e.GetOperators(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.OperatorList); + + Result result = await this.FileProcessorDomainService.ProcessUploadedFile(TestData.ProcessUploadedFileCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Failure); + } + + + [Fact] + public async Task FileRequestHandler_ProcessUploadedFileRequest_NoOperatorsFound_RequestIsHandled() { this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); @@ -268,7 +325,29 @@ public async Task FileRequestHandler_ProcessUploadedFileRequest_OperatorNotFound result.IsFailed.ShouldBeTrue(); result.Status.ShouldBe(ResultStatus.NotFound); } - + + [Fact] + public async Task FileRequestHandler_ProcessUploadedFileRequest_ProfileOperatorNotFound_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileImportLogAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEmptyFileImportLogAggregate())); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCreatedFileAggregate())); + this.FileAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.FileSystem.AddFile(TestData.FilePathWithName, new MockFileData("D,1,1,1")); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.EstateClient.Setup(e => e.GetOperators(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(new List())); + + Result result = await this.FileProcessorDomainService.ProcessUploadedFile(TestData.ProcessUploadedFileCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); + } + [Fact] public async Task FileRequestHandler_ProcessUploadedFileRequest_NullOperatorList_RequestIsHandled() { @@ -362,7 +441,33 @@ public async Task FileRequestHandler_ProcessUploadedFileRequest_FileIsEmpty_Requ this.FileAggregateRepository.Verify(f => f.SaveChanges(It.IsAny(), It.IsAny()), Times.Exactly(2)); this.VerifyFileProcessing("home/txnproc/bulkfiles/safaricom/processed"); } - + + [Fact] + public async Task FileRequestHandler_ProcessUploadedFileRequest_FileIsInFailedFolder_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCreatedFileAggregate())); + this.FileAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + + this.FileSystem.AddFile(TestData.FailedSafaricomFilePathWithName, new MockFileData(String.Empty)); + + this.FileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom/inprogress"); + this.FileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom/processed"); + this.FileSystem.AddDirectory("home/txnproc/bulkfiles/safaricom/failed"); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.EstateClient.Setup(e => e.GetOperators(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.OperatorList); + + Result result = await this.FileProcessorDomainService.ProcessUploadedFile(TestData.ProcessUploadedFileCommand, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + this.FileAggregateRepository.Verify(f => f.SaveChanges(It.IsAny(), It.IsAny()), Times.Exactly(2)); + this.VerifyFileProcessing("home/txnproc/bulkfiles/safaricom/processed"); + } + [Theory] [InlineData("Safaricom")] @@ -393,7 +498,65 @@ public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_Reques result.IsSuccess.ShouldBeTrue(); } - + [Theory] + [InlineData("Safaricom")] + [InlineData("Voucher")] + public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_SaveFailed_RequestIsHandled(String operatorName) + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetFileProfile(operatorName)); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + this.FileAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure); + + this.TransactionProcessorClient.Setup(t => t.PerformTransaction(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.SerialisedMessageResponseSale); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator); + + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantContractsResponse())); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FileFormatHandler.Setup(f => f.FileLineCanBeIgnored(It.IsAny())).Returns(false); + this.FileFormatHandler.Setup(f => f.ParseFileLine(It.IsAny())).Returns(TestData.TransactionMetadata); + + Result result = await this.FileProcessorDomainService.ProcessTransactionForFileLine(TestData.ProcessTransactionForFileLineCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Theory] + [InlineData("Safaricom")] + [InlineData("Voucher")] + public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_ExceptionThrown_RequestIsHandled(String operatorName) + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetFileProfile(operatorName)); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + this.FileAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + + this.TransactionProcessorClient.Setup(t => t.PerformTransaction(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.SerialisedMessageResponseSale); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator); + + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantContractsResponse())); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FileFormatHandler.Setup(f => f.FileLineCanBeIgnored(It.IsAny())).Returns(false); + this.FileFormatHandler.Setup(f => f.ParseFileLine(It.IsAny())).Returns(TestData.TransactionMetadata); + + Result result = await this.FileProcessorDomainService.ProcessTransactionForFileLine(TestData.ProcessTransactionForFileLineCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_WithOperatorName_RequestIsHandled() { @@ -622,6 +785,62 @@ public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_NoMerc result.Status.ShouldBe(ResultStatus.NotFound); } + [Fact] + public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_EmptyMerchantContractsArray_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + this.TransactionProcessorClient.Setup(t => t.PerformTransaction(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.SerialisedMessageResponseSale); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator); + + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(new List())); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FileFormatHandler.Setup(f => f.FileLineCanBeIgnored(It.IsAny())).Returns(false); + this.FileFormatHandler.Setup(f => f.ParseFileLine(It.IsAny())).Returns(TestData.TransactionMetadata); + + var result = await this.FileProcessorDomainService.ProcessTransactionForFileLine(TestData.ProcessTransactionForFileLineCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); + } + + [Fact] + public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_ContractNotFoundInMerchantContracts_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + this.TransactionProcessorClient.Setup(t => t.PerformTransaction(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.SerialisedMessageResponseSale); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator); + + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(new List { + new ContractResponse { + OperatorName = "Other Operator" + } + })); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FileFormatHandler.Setup(f => f.FileLineCanBeIgnored(It.IsAny())).Returns(false); + this.FileFormatHandler.Setup(f => f.ParseFileLine(It.IsAny())).Returns(TestData.TransactionMetadata); + + var result = await this.FileProcessorDomainService.ProcessTransactionForFileLine(TestData.ProcessTransactionForFileLineCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); + } + [Fact] public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_NoMerchantContractForFileOperatorFound_RequestIsHandled() { @@ -674,6 +893,32 @@ public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_Mercha result.Status.ShouldBe(ResultStatus.NotFound); } + [Fact] + public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_TransactionNotSuccessfulResult_RequestIsHandled() + { + this.FileProcessorManager.Setup(f => f.GetFileProfile(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.FileProfileSafaricom); + + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + this.TransactionProcessorClient.Setup(t => t.PerformTransaction(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure()); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator); + + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantContractsResponse())); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FileFormatHandler.Setup(f => f.FileLineCanBeIgnored(It.IsAny())).Returns(false); + this.FileFormatHandler.Setup(f => f.ParseFileLine(It.IsAny())).Returns(TestData.TransactionMetadata); + + var result = await this.FileProcessorDomainService.ProcessTransactionForFileLine(TestData.ProcessTransactionForFileLineCommand, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Failure); + } + [Fact] public async Task FileRequestHandler_ProcessTransactionForFileLineRequest_TransactionNotSuccessful_RequestIsHandled() { diff --git a/FileProcessor.BusinessLogic.Tests/MediatorTests.cs b/FileProcessor.BusinessLogic.Tests/MediatorTests.cs index 9cdeac4..8c13726 100644 --- a/FileProcessor.BusinessLogic.Tests/MediatorTests.cs +++ b/FileProcessor.BusinessLogic.Tests/MediatorTests.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using FileProcessor.BusinessLogic.Managers; using Xunit; namespace FileProcessor.BusinessLogic.Tests @@ -17,6 +18,8 @@ namespace FileProcessor.BusinessLogic.Tests using Lamar; using Microsoft.Extensions.DependencyInjection; using Services; + using Shared.DomainDrivenDesign.EventSourcing; + using Shared.EventStore.Aggregate; public class MediatorTests { @@ -27,6 +30,9 @@ public MediatorTests() this.Requests.Add(TestData.UploadFileCommand); this.Requests.Add(TestData.ProcessUploadedFileCommand); this.Requests.Add(TestData.ProcessTransactionForFileLineCommand); + this.Requests.Add(TestData.GetFileQuery); + this.Requests.Add(TestData.GetImportLogsQuery); + this.Requests.Add(TestData.GetImportLogQuery); } [Fact] @@ -100,7 +106,23 @@ private void AddTestRegistrations(ServiceRegistry services, services.AddSingleton(hostingEnvironment); services.AddSingleton(Startup.Configuration); - services.OverrideServices(s => { s.AddSingleton(); }); + services.OverrideServices(s => { + s.AddSingleton(); + s.AddSingleton(); + }); + } + } + + public record TestAggregate : Aggregate + { + public override void PlayEvent(IDomainEvent domainEvent) + { + + } + + protected override Object GetMetadata() + { + return new Object(); } } } diff --git a/FileProcessor.BusinessLogic/Requests/FileCommands.cs b/FileProcessor.BusinessLogic/Requests/FileCommands.cs index 1f0e7a8..e0b5bba 100644 --- a/FileProcessor.BusinessLogic/Requests/FileCommands.cs +++ b/FileProcessor.BusinessLogic/Requests/FileCommands.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; namespace FileProcessor.BusinessLogic.Requests; +[ExcludeFromCodeCoverage] public record FileCommands { public record ProcessTransactionForFileLineCommand(Guid FileId, Int32 LineNumber, String FileLine) : IRequest; diff --git a/FileProcessor.BusinessLogic/Requests/FileQueries.cs b/FileProcessor.BusinessLogic/Requests/FileQueries.cs index fff80c1..7916629 100644 --- a/FileProcessor.BusinessLogic/Requests/FileQueries.cs +++ b/FileProcessor.BusinessLogic/Requests/FileQueries.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using FileProcessor.Models; using MediatR; using SimpleResults; namespace FileProcessor.BusinessLogic.Requests; +[ExcludeFromCodeCoverage] public record FileQueries { public record GetFileQuery(Guid FileId, Guid EstateId) : IRequest>; diff --git a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs index 90e155a..bf2f97e 100644 --- a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs +++ b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs @@ -1,4 +1,5 @@ -using System.Reflection.Metadata.Ecma335; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata.Ecma335; using FileProcessor.Models; using Shared.Results; using SimpleResults; @@ -346,11 +347,11 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran return ResultHelpers.CreateFailure(getContractsResult); } - var contracts = getContractsResult.Data; + List contracts = getContractsResult.Data; if (contracts.Any() == false) { - throw new NotFoundException($"No contracts found for Merchant Id {fileDetails.MerchantId} on estate Id {fileDetails.EstateId}"); + return Result.NotFound($"No contracts found for Merchant Id {fileDetails.MerchantId} on estate Id {fileDetails.EstateId}"); } ContractResponse? contract = null; @@ -553,6 +554,7 @@ private Dictionary ParseFileLine(String domainEventFileLine, private TokenResponse TokenResponse; + [ExcludeFromCodeCoverage] private async Task GetToken(CancellationToken cancellationToken) { // Get a token to talk to the estate service diff --git a/FileProcessor.Testing/TestData.cs b/FileProcessor.Testing/TestData.cs index 7467601..f263d7f 100644 --- a/FileProcessor.Testing/TestData.cs +++ b/FileProcessor.Testing/TestData.cs @@ -38,6 +38,7 @@ public class TestData public static String FilePath = "home/txnproc/bulkfiles"; public static String FilePathWithName = "home/txnproc/bulkfiles/Example.csv"; public static String InProgressSafaricomFilePathWithName = "home/txnproc/bulkfiles/safaricom/inprogress/Example.csv"; + public static String FailedSafaricomFilePathWithName = "home/txnproc/bulkfiles/safaricom/failed/Example.csv"; public static Guid FileProfileId = Guid.Parse("D0D3A4E5-870E-42F6-AD0E-5E24252BC95E"); @@ -321,6 +322,7 @@ public static FileAggregate GetFileAggregateWithLinesAlreadyProcessed() ["AppSettings:TemporaryFileLocation"] = "C:\\Temp", ["AppSettings:FileProfilePollingWindowInSeconds"] = "30", ["ConnectionStrings:HealthCheck"] = "HeathCheckConnString", + ["ConnectionStrings:EstateReportingReadModel"] = "EstateReportingReadModel", ["SecurityConfiguration:Authority"] = "https://127.0.0.1", ["EventStoreSettings:ConnectionString"] = "esdb://127.0.0.1:2113", ["EventStoreSettings:ConnectionName"] = "UnitTestConnection", @@ -861,5 +863,12 @@ public static List GetMerchantContractsResponseNoNullValueProd public static FileCommands.ProcessTransactionForFileLineCommand ProcessTransactionForFileLineCommand => new (TestData.FileId, TestData.LineNumber, TestData.FileLine); + public static FileQueries.GetFileQuery GetFileQuery => new(FileId, EstateId); + + public static FileQueries.GetImportLogsQuery GetImportLogsQuery => new FileQueries.GetImportLogsQuery(EstateId, LogQueryStartDate, LogQueryEndDate, MerchantId); + public static FileQueries.GetImportLogQuery GetImportLogQuery => new FileQueries.GetImportLogQuery(FileImportLogId, EstateId, MerchantId); + + public static DateTime LogQueryStartDate = new DateTime(2024, 12, 12); + public static DateTime LogQueryEndDate = new DateTime(2024, 12, 12); } } diff --git a/FileProcessor/Bootstrapper/MiscRegistry.cs b/FileProcessor/Bootstrapper/MiscRegistry.cs index c9b7e9e..6746936 100644 --- a/FileProcessor/Bootstrapper/MiscRegistry.cs +++ b/FileProcessor/Bootstrapper/MiscRegistry.cs @@ -26,9 +26,9 @@ public MiscRegistry() this.AddSingleton(); this.AddSingleton(); - bool logRequests = ConfigurationReaderExtensions.GetValueOrDefault("MiddlewareLogging", "LogRequests", true); - bool logResponses = ConfigurationReaderExtensions.GetValueOrDefault("MiddlewareLogging", "LogResponses", true); - LogLevel middlewareLogLevel = ConfigurationReaderExtensions.GetValueOrDefault("MiddlewareLogging", "MiddlewareLogLevel", LogLevel.Warning); + bool logRequests = ConfigurationReader.GetValueOrDefault("MiddlewareLogging", "LogRequests", true); + bool logResponses = ConfigurationReader.GetValueOrDefault("MiddlewareLogging", "LogResponses", true); + LogLevel middlewareLogLevel = ConfigurationReader.GetValueOrDefault("MiddlewareLogging", "MiddlewareLogLevel", LogLevel.Warning); RequestResponseMiddlewareLoggingConfig config = new RequestResponseMiddlewareLoggingConfig(middlewareLogLevel, logRequests, logResponses); @@ -37,26 +37,4 @@ public MiscRegistry() } #endregion -} - -public static class ConfigurationReaderExtensions -{ - public static T GetValueOrDefault(String sectionName, String keyName, T defaultValue) - { - try - { - var value = ConfigurationReader.GetValue(sectionName, keyName); - - if (String.IsNullOrEmpty(value)) - { - return defaultValue; - } - - return (T)Convert.ChangeType(value, typeof(T)); - } - catch (KeyNotFoundException kex) - { - return defaultValue; - } - } } \ No newline at end of file diff --git a/FileProcessor/Controllers/ResultExtensions.cs b/FileProcessor/Controllers/ResultExtensions.cs deleted file mode 100644 index 1e22c9e..0000000 --- a/FileProcessor/Controllers/ResultExtensions.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Net; -using Microsoft.AspNetCore.Mvc; -using SimpleResults; - -public static class ResultExtensions -{ - public static IActionResult ToActionResultX(this Result result) - { - if (result.IsSuccess) - return new OkObjectResult(result); - - return result.Status switch - { - ResultStatus.Invalid => new BadRequestObjectResult(result), - ResultStatus.NotFound => new NotFoundObjectResult(result), - ResultStatus.Unauthorized => new UnauthorizedObjectResult(result), - ResultStatus.Conflict => new ConflictObjectResult(result), - ResultStatus.Failure => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.CriticalError => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.Forbidden => new ForbidResult(), - _ => CreateObjectResult(result, HttpStatusCode.NotImplemented) - - }; - } - - internal static IActionResult ToActionResultX(this Result result) - { - if (result.IsSuccess) - return new OkObjectResult(result); - - return result.Status switch - { - ResultStatus.Invalid => new BadRequestObjectResult(result), - ResultStatus.NotFound => new NotFoundObjectResult(result), - ResultStatus.Unauthorized => new UnauthorizedObjectResult(result), - ResultStatus.Conflict => new ConflictObjectResult(result), - ResultStatus.Failure => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.CriticalError => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.Forbidden => new ForbidResult(), - _ => CreateObjectResult(result, HttpStatusCode.NotImplemented) - - }; - } - - internal static ObjectResult CreateObjectResult(Result result, - HttpStatusCode statusCode) - { - ObjectResult or = new ObjectResult(result); - or.StatusCode = (Int32)statusCode; - return or; - } - - internal static ObjectResult CreateObjectResult(Result result, - HttpStatusCode statusCode) - { - ObjectResult or = new ObjectResult(result); - or.StatusCode = (Int32)statusCode; - return or; - } -} \ No newline at end of file