From 9fe6ef5ed1c6c237aa041add4a076c5dd58f70f2 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Mon, 21 Jul 2025 18:44:02 +0100 Subject: [PATCH 1/3] Add some warning trace on failures --- .../Services/FileProcessorDomainService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs index 4fe98ff..1a1931b 100644 --- a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs +++ b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs @@ -519,6 +519,7 @@ private async Task ProcessFile(Guid fileId, inProgressFile.MoveTo($"{fileProfile.ProcessedDirectory}/{inProgressFile.Name}", true); } else { + Logger.LogWarning($"About to move file {inProgressFile.Name} to [{fileProfile.FailedDirectory}]. Reason(s) [{String.Join(",", result.Errors)}]"); inProgressFile.MoveTo($"{fileProfile.FailedDirectory}/{inProgressFile.Name}", true); } From a8fb7822240eecb6f462d440b8149580098be9a1 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Wed, 23 Jul 2025 15:43:34 +0100 Subject: [PATCH 2/3] try running the integration tests at CI --- .../FileProcessingManagerTests.cs | 298 +++++++----------- .../FileProcessor.BusinessLogic.Tests.csproj | 2 +- .../Common/ModelFactory.cs | 3 +- .../FileProcessor.BusinessLogic.csproj | 6 +- .../Managers/FileProcessorManager.cs | 43 +-- .../FileProcessor.Client.csproj | 4 +- .../FileProcessor.File.DomainEvents.csproj | 2 +- .../FileProcessor.FileAggregate.csproj | 4 +- ...rocessor.FileImportLog.DomainEvents.csproj | 2 +- ...ileProcessor.FileImportLogAggregate.csproj | 2 +- ...rocessor.IntegrationTesting.Helpers.csproj | 2 +- .../Common/DockerHelper.cs | 10 + .../FileProcessor.IntegrationTests.csproj | 4 +- FileProcessor.Testing/TestData.cs | 3 +- .../Bootstrapper/RepositoryRegistry.cs | 36 +-- FileProcessor/FileProcessor.csproj | 6 +- 16 files changed, 176 insertions(+), 251 deletions(-) diff --git a/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs b/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs index e5a6747..a869332 100644 --- a/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs +++ b/FileProcessor.BusinessLogic.Tests/FileProcessingManagerTests.cs @@ -1,62 +1,77 @@ -using System; +using FileProcessor.Models; +using SimpleResults; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using FileProcessor.Models; -using SimpleResults; using TransactionProcessor.Database.Contexts; using TransactionProcessor.Database.Entities; namespace FileProcessor.BusinessLogic.Tests { - using System.Threading; using Common; using FileAggregate; + using FileProcessor.Common; using FileProcessor.Models; using Managers; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; + using Microsoft.EntityFrameworkCore.Internal; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using Moq; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EntityFramework; using Shared.EventStore.Aggregate; using Shared.Exceptions; using Shouldly; + using System.Threading; using Testing; using Xunit; using FileImportLog = FileProcessor.Models.FileImportLog; using FileLine = FileProcessor.Models.FileLine; - public class FileProcessingManagerTests - { + public class FileProcessingManagerTests { + private Mock> FileAggregateRepository; + private FileProcessorManager Manager; + private Mock> DbContextFactory; + private EstateManagementContext Context; + public FileProcessingManagerTests() { + List fileProfiles = TestData.FileProfiles; + this.DbContextFactory = new Mock>(); + this.Context = this.GetContext(Guid.NewGuid().ToString("N")); + ServiceCollection services = new ServiceCollection(); + services.AddTransient(_ => this.Context); + ServiceProvider serviceProvider = services.BuildServiceProvider(); + IServiceScope scope = serviceProvider.CreateScope(); + this.DbContextFactory.Setup(d => d.Resolve(It.IsAny(), It.IsAny())).Returns(new ResolvedDbContext(scope)); + + var modelFactory= new Common.ModelFactory(); + this.FileAggregateRepository = new Mock>(); + this.Manager = new FileProcessorManager(fileProfiles, this.DbContextFactory.Object, modelFactory, this.FileAggregateRepository.Object); + } + + private EstateManagementContext GetContext(String databaseName) + { + EstateManagementContext context = null; + DbContextOptionsBuilder builder = new DbContextOptionsBuilder().UseInMemoryDatabase(databaseName).ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning)); + return new EstateManagementContext(builder.Options); + } + [Fact] public async Task FileProcessingManager_GetAllFileProfiles_AllFileProfilesReturned() { - var fileProfiles = TestData.FileProfiles; - var contextFactory = this.CreateMockContextFactory(); - Mock modelFactory = new Mock(); - Mock> fileAggregateRepository = - new Mock>(); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object,modelFactory.Object, fileAggregateRepository.Object); - - var allFileProfiles = await manager.GetAllFileProfiles(CancellationToken.None); + Result> allFileProfiles = await this.Manager.GetAllFileProfiles(CancellationToken.None); allFileProfiles.ShouldNotBeNull(); allFileProfiles.IsSuccess.ShouldBeTrue(); allFileProfiles.Data.ShouldNotBeEmpty(); } [Fact] - public async Task FileProcessingManager_GetFileProfile_FIleProfileReturned() + public async Task FileProcessingManager_GetFileProfile_FileProfileReturned() { - var fileProfiles = TestData.FileProfiles; - var contextFactory = this.CreateMockContextFactory(); - Mock modelFactory = new Mock(); - Mock> fileAggregateRepository = - new Mock>(); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory.Object, fileAggregateRepository.Object); - - var fileProfile = await manager.GetFileProfile(TestData.SafaricomFileProfileId, CancellationToken.None); + Result fileProfile = await this.Manager.GetFileProfile(TestData.SafaricomFileProfileId, CancellationToken.None); fileProfile.ShouldNotBeNull(); fileProfile.IsSuccess.ShouldBeTrue(); fileProfile.Data.FileProfileId.ShouldBe(TestData.SafaricomFileProfileId); @@ -65,23 +80,13 @@ public async Task FileProcessingManager_GetFileProfile_FIleProfileReturned() [Fact] public async Task FileProcessingManager_GetFileImportLogs_NoMerchantId_ImportLogsReturned() { - var fileProfiles = TestData.FileProfiles; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(),It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - context.FileImportLogs.AddRange(TestData.FileImportLogs); - context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); - context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); - context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); - context.SaveChanges(); - - Mock> fileAggregateRepository = - new Mock>(); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); + this.Context.FileImportLogs.AddRange(TestData.FileImportLogs); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); + this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); + await this.Context.SaveChangesAsync(); - Result> getFileImportLogsResult = await manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, null, CancellationToken.None); + Result> getFileImportLogsResult = await this.Manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, null, CancellationToken.None); getFileImportLogsResult.IsSuccess.ShouldBeTrue(); List importLogs = getFileImportLogsResult.Data; this.VerifyImportLogs(TestData.FileImportLogs,importLogs); @@ -90,24 +95,14 @@ public async Task FileProcessingManager_GetFileImportLogs_NoMerchantId_ImportLog [Fact] public async Task FileProcessingManager_GetFileImportLogs_WithMerchantId_ImportLogsReturned() { - var fileProfiles = TestData.FileProfiles; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - context.FileImportLogs.AddRange(TestData.FileImportLogs); - context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); - context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); - context.Files.AddRange(TestData.Files1); - context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); - context.SaveChanges(); + this.Context.FileImportLogs.AddRange(TestData.FileImportLogs); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); + this.Context.Files.AddRange(TestData.Files1); + this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); + await this.Context.SaveChangesAsync(); - Mock> fileAggregateRepository = - new Mock>(); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var importLogs = await manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, TestData.MerchantId, CancellationToken.None); + Result> importLogs = await this.Manager.GetFileImportLogs(TestData.EstateId, TestData.ImportLogStartDate, TestData.ImportLogEndDate, TestData.MerchantId, CancellationToken.None); this.VerifyImportLogs(TestData.FileImportLogs,importLogs, TestData.MerchantId); } @@ -115,24 +110,14 @@ public async Task FileProcessingManager_GetFileImportLogs_WithMerchantId_ImportL [Fact] public async Task FileProcessingManager_GetFileImportLog_NoMerchantId_ImportLogReturned() { - var fileProfiles = TestData.FileProfiles; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - context.FileImportLogs.AddRange(TestData.FileImportLogs); - context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); - context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); - context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); - context.Files.AddRange(TestData.Files1); - context.SaveChanges(); + this.Context.FileImportLogs.AddRange(TestData.FileImportLogs); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); + this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); + this.Context.Files.AddRange(TestData.Files1); + await this.Context.SaveChangesAsync(); - Mock> fileAggregateRepository = - new Mock>(); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var importLog = await manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, null, CancellationToken.None); + Result importLog = await this.Manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, null, CancellationToken.None); this.VerifyImportLog(TestData.FileImportLogs.First(), importLog); } @@ -140,24 +125,14 @@ public async Task FileProcessingManager_GetFileImportLog_NoMerchantId_ImportLogR [Fact] public async Task FileProcessingManager_GetFileImportLog_WithMerchantId_ImportLogReturned() { - var fileProfiles = TestData.FileProfiles; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - context.FileImportLogs.AddRange(TestData.FileImportLogs); - context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); - context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); - context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName}); - context.Files.AddRange(TestData.Files1); - await context.SaveChangesAsync(); + this.Context.FileImportLogs.AddRange(TestData.FileImportLogs); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog1Files); + this.Context.FileImportLogFiles.AddRange(TestData.FileImportLog2Files); + this.Context.Merchants.Add(new Merchant { MerchantId = TestData.MerchantId, Name = TestData.MerchantName}); + this.Context.Files.AddRange(TestData.Files1); + await Context.SaveChangesAsync(); - Mock> fileAggregateRepository = - new Mock>(); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var importLog = await manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, TestData.MerchantId, CancellationToken.None); + Result importLog = await this.Manager.GetFileImportLog(TestData.FileImportLogId1, TestData.EstateId, TestData.MerchantId, CancellationToken.None); this.VerifyImportLog(TestData.FileImportLogs.First(),importLog, TestData.MerchantId); } @@ -169,17 +144,9 @@ public async Task FileProcessingManager_GetFile_FileReturned() { TestData.FileProfile }; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - Mock> fileAggregateRepository = - new Mock>(); - fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - Result fileDetails = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); + this.FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + Result fileDetails = await this.Manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); fileDetails.IsSuccess.ShouldBeTrue(); this.VerifyFile(TestData.GetFileAggregateWithLines(), fileDetails); @@ -190,18 +157,9 @@ public async Task FileProcessingManager_GetFile_FileReturned() [Fact] public async Task FileProcessingManager_GetFile_FileAggregateFailed_ErrorReturned() { - List fileProfiles = new List(); - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - Mock> fileAggregateRepository = - new Mock>(); - fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - Result fileDetails = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); + FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + + Result fileDetails = await this.Manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); fileDetails.IsFailed.ShouldBeTrue(); } @@ -209,29 +167,17 @@ public async Task FileProcessingManager_GetFile_FileAggregateFailed_ErrorReturne [Fact] public async Task FileProcessingManager_GetFile_FileReturnedWithMerchantName() { - List fileProfiles = new List - { - TestData.FileProfile - }; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - context.Merchants.Add(new Merchant + this.Context.Merchants.Add(new Merchant { EstateId = TestData.EstateId, MerchantReportingId = TestData.MerchantReportingId, MerchantId = TestData.MerchantId, Name = TestData.MerchantName }); - context.SaveChanges(); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - Mock> fileAggregateRepository = - new Mock>(); - fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var fileDetails = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); + await this.Context.SaveChangesAsync(); + FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + Result fileDetails = await this.Manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); fileDetails.IsSuccess.ShouldBeTrue(); this.VerifyFile(TestData.GetFileAggregateWithLines(), fileDetails); @@ -241,28 +187,17 @@ public async Task FileProcessingManager_GetFile_FileReturnedWithMerchantName() [Fact] public async Task FileProcessingManager_GetFile_FileReturnedWithUserEmailAddress() { - List fileProfiles = new List - { - TestData.FileProfile - }; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - context.EstateSecurityUsers.Add(new EstateSecurityUser() + Context.EstateSecurityUsers.Add(new EstateSecurityUser() { EstateId = TestData.EstateId, SecurityUserId = TestData.UserId, EmailAddress = TestData.UserEmailAddress }); - context.SaveChanges(); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - Mock> fileAggregateRepository = - new Mock>(); - fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var fileDetails = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); + await this.Context.SaveChangesAsync(); + + FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + Result fileDetails = await this.Manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); fileDetails.IsSuccess.ShouldBeTrue(); this.VerifyFile(TestData.GetFileAggregateWithLines(), fileDetails); fileDetails.Data.UserEmailAddress.ShouldBe(TestData.UserEmailAddress); @@ -271,7 +206,7 @@ public async Task FileProcessingManager_GetFile_FileReturnedWithUserEmailAddress [Fact] public async Task FileProcessingManager_GetFile_FileReturnedWithFileProfileName() { - var fileProfiles = new List + List fileProfiles = new List { new FileProfile(TestData.FileProfileId, TestData.SafaricomProfileName, @@ -281,24 +216,16 @@ public async Task FileProcessingManager_GetFile_FileReturnedWithFileProfileName( TestData.SafaricomLineTerminator, TestData.SafaricomFileFormatHandler) }; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - context.EstateSecurityUsers.Add(new EstateSecurityUser() + Context.EstateSecurityUsers.Add(new EstateSecurityUser() { EstateId = TestData.EstateId, SecurityUserId = TestData.UserId, EmailAddress = TestData.UserEmailAddress }); - context.SaveChanges(); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - Mock> fileAggregateRepository = - new Mock>(); - fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var fileDetails = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); + await Context.SaveChangesAsync(); + FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetFileAggregateWithLines())); + + Result fileDetails = await this.Manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); fileDetails.IsSuccess.ShouldBeTrue(); this.VerifyFile(TestData.GetFileAggregateWithLines(), fileDetails); fileDetails.Data.FileProfileName.ShouldBe(TestData.SafaricomProfileName); @@ -307,26 +234,18 @@ public async Task FileProcessingManager_GetFile_FileReturnedWithFileProfileName( [Fact] public async Task FileProcessingManager_GetFile_FileNotFound_ErrorThrown() { - var fileProfiles = TestData.FileProfiles; - var context = await this.GetContext(Guid.NewGuid().ToString("N")); - var contextFactory = this.CreateMockContextFactory(); - contextFactory.Setup(c => c.GetContext(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(context); - IModelFactory modelFactory = new ModelFactory(); - - Mock> fileAggregateRepository = - new Mock>(); - fileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFileAggregate())); - FileProcessorManager manager = new FileProcessorManager(fileProfiles, contextFactory.Object, modelFactory, fileAggregateRepository.Object); - - var result = await manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); - result.IsFailed.ShouldBeTrue(); - result.Status.ShouldBe(ResultStatus.NotFound); + FileAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFileAggregate())); + + Result result = await this.Manager.GetFile(TestData.FileId, TestData.EstateId, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.NotFound); } private void VerifyFile(FileAggregate source, Result fileDetails) { - var fileModel = source.GetFile(); + FileDetails fileModel = source.GetFile(); fileDetails.Data.FileId.ShouldBe(fileModel.FileId); fileDetails.Data.FileImportLogId.ShouldBe(fileModel.FileImportLogId); @@ -361,7 +280,7 @@ private void VerifyImportLogs(List i.FileImportLogId == fileImportLog.FileImportLogId); + FileImportLog importLog = importLogs.Data.SingleOrDefault(i => i.FileImportLogId == fileImportLog.FileImportLogId); VerifyImportLog(fileImportLog, importLog, merchantId); } } @@ -379,7 +298,7 @@ private void VerifyImportLog(TransactionProcessor.Database.Entities.FileImportLo foreach (ImportLogFile importLogFile in filesToVerify) { - var file = importLog.Data.Files.SingleOrDefault(impfile => impfile.FileId == importLogFile.FileId); + ImportLogFile file = importLog.Data.Files.SingleOrDefault(impfile => impfile.FileId == importLogFile.FileId); file.ShouldNotBeNull(); file.MerchantId.ShouldBe(importLogFile.MerchantId); file.FilePath.ShouldBe(importLogFile.FilePath); @@ -389,21 +308,18 @@ private void VerifyImportLog(TransactionProcessor.Database.Entities.FileImportLo } } - private Mock> CreateMockContextFactory() - { - return new Mock>(); - } + - private async Task GetContext(String databaseName) - { - EstateManagementContext context = null; + //private async Task GetContext(String databaseName) + //{ + // EstateManagementContext context = null; - DbContextOptionsBuilder builder = new DbContextOptionsBuilder() - .UseInMemoryDatabase(databaseName) - .ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning)); - context = new EstateManagementContext(builder.Options); + // DbContextOptionsBuilder builder = new DbContextOptionsBuilder() + // .UseInMemoryDatabase(databaseName) + // .ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning)); + // context = new EstateManagementContext(builder.Options); - return context; - } + // return context; + //} } } diff --git a/FileProcessor.BusinessLogic.Tests/FileProcessor.BusinessLogic.Tests.csproj b/FileProcessor.BusinessLogic.Tests/FileProcessor.BusinessLogic.Tests.csproj index 8e1e610..07f5731 100644 --- a/FileProcessor.BusinessLogic.Tests/FileProcessor.BusinessLogic.Tests.csproj +++ b/FileProcessor.BusinessLogic.Tests/FileProcessor.BusinessLogic.Tests.csproj @@ -2,7 +2,7 @@ net9.0 - None + Full false diff --git a/FileProcessor.BusinessLogic/Common/ModelFactory.cs b/FileProcessor.BusinessLogic/Common/ModelFactory.cs index 85f98b3..f0520ef 100644 --- a/FileProcessor.BusinessLogic/Common/ModelFactory.cs +++ b/FileProcessor.BusinessLogic/Common/ModelFactory.cs @@ -67,8 +67,7 @@ public List ConvertFrom(Guid estateId, /// public FileImportLog ConvertFrom(Guid estateId, TransactionProcessor.Database.Entities.FileImportLog importLog, - List<(TransactionProcessor.Database.Entities.FileImportLogFile, TransactionProcessor.Database.Entities.File, Merchant)> importLogFilesList) - { + List<(TransactionProcessor.Database.Entities.FileImportLogFile, TransactionProcessor.Database.Entities.File, Merchant)> importLogFilesList) { FileImportLog model = new FileImportLog(); model.FileImportLogId = importLog.FileImportLogId; diff --git a/FileProcessor.BusinessLogic/FileProcessor.BusinessLogic.csproj b/FileProcessor.BusinessLogic/FileProcessor.BusinessLogic.csproj index 591e3e8..f56cd60 100644 --- a/FileProcessor.BusinessLogic/FileProcessor.BusinessLogic.csproj +++ b/FileProcessor.BusinessLogic/FileProcessor.BusinessLogic.csproj @@ -8,10 +8,10 @@ - - + + - + diff --git a/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs b/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs index 02c8189..44c1b46 100644 --- a/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs +++ b/FileProcessor.BusinessLogic/Managers/FileProcessorManager.cs @@ -6,19 +6,20 @@ namespace FileProcessor.BusinessLogic.Managers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Security.Cryptography.X509Certificates; - using System.Threading; - using System.Threading.Tasks; using Common; using FileAggregate; using FileProcessor.Models; using Microsoft.EntityFrameworkCore; using Shared.DomainDrivenDesign.EventSourcing; + using Shared.EntityFramework; using Shared.EventStore.Aggregate; using Shared.Exceptions; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography.X509Certificates; + using System.Threading; + using System.Threading.Tasks; using FileImportLog = FileProcessor.Models.FileImportLog; /// @@ -28,19 +29,15 @@ namespace FileProcessor.BusinessLogic.Managers public class FileProcessorManager : IFileProcessorManager { #region Fields - - /// - /// The file profiles - /// private readonly List FileProfiles; - private readonly Shared.EntityFramework.IDbContextFactory DbContextFactory; + private readonly IDbContextResolver Resolver; + private static readonly String EstateManagementDatabaseName = "TransactionProcessorReadModel"; private readonly IModelFactory ModelFactory; private readonly IAggregateRepository FileAggregateRepository; - private const String ConnectionStringIdentifier = "EstateReportingReadModel"; #endregion @@ -53,12 +50,12 @@ public class FileProcessorManager : IFileProcessorManager /// The database context factory. /// The model factory. public FileProcessorManager(List fileProfiles, - Shared.EntityFramework.IDbContextFactory dbContextFactory, + IDbContextResolver resolver, IModelFactory modelFactory, IAggregateRepository fileAggregateRepository) { this.FileProfiles = fileProfiles; - this.DbContextFactory = dbContextFactory; + this.Resolver = resolver; this.ModelFactory = modelFactory; this.FileAggregateRepository = fileAggregateRepository; } @@ -83,13 +80,20 @@ public async Task> GetFileProfile(Guid fileProfileId, } + private async Task GetContext(Guid estateId) + { + ResolvedDbContext? resolvedContext = this.Resolver.Resolve(EstateManagementDatabaseName, estateId.ToString()); + return resolvedContext.Context; + } + + public async Task>> GetFileImportLogs(Guid estateId, DateTime startDateTime, DateTime endDateTime, Guid? merchantId, CancellationToken cancellationToken) { - EstateManagementContext context = await this.DbContextFactory.GetContext(estateId, ConnectionStringIdentifier, cancellationToken); + EstateManagementContext context = await this.GetContext(estateId); List importLogQuery = await context.FileImportLogs.Where(f => f.ImportLogDateTime >= startDateTime).ToListAsync(cancellationToken); @@ -130,8 +134,8 @@ public async Task> GetFileImportLog(Guid fileImportLogId, Guid? merchantId, CancellationToken cancellationToken) { - EstateManagementContext context = await this.DbContextFactory.GetContext(estateId, ConnectionStringIdentifier, cancellationToken); - + EstateManagementContext context = await this.GetContext(estateId); + // Fetch the import log entry TransactionProcessor.Database.Entities.FileImportLog importLogQuery = await context.FileImportLogs .SingleOrDefaultAsync(f => f.FileImportLogId == fileImportLogId, cancellationToken); @@ -158,7 +162,8 @@ join merchant in context.Merchants on file.MerchantId equals merchant.MerchantId entityData.Add((file.fileImportLogFile, file.file, file.merchant)); } - return this.ModelFactory.ConvertFrom(estateId, importLogQuery, entityData); + var x = this.ModelFactory.ConvertFrom(estateId, importLogQuery, entityData); + return Result.Success(x); } public async Task> GetFile(Guid fileId, @@ -179,7 +184,7 @@ public async Task> GetFile(Guid fileId, FileDetails fileDetails = fileAggregate.GetFile(); - EstateManagementContext context = await this.DbContextFactory.GetContext(estateId, ConnectionStringIdentifier, cancellationToken); + EstateManagementContext context = await this.GetContext(estateId); Merchant merchant = await context.Merchants .SingleOrDefaultAsync(m => m.MerchantId == fileDetails.MerchantId, cancellationToken); diff --git a/FileProcessor.Client/FileProcessor.Client.csproj b/FileProcessor.Client/FileProcessor.Client.csproj index d6accb5..d2be451 100644 --- a/FileProcessor.Client/FileProcessor.Client.csproj +++ b/FileProcessor.Client/FileProcessor.Client.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/FileProcessor.File.DomainEvents/FileProcessor.File.DomainEvents.csproj b/FileProcessor.File.DomainEvents/FileProcessor.File.DomainEvents.csproj index d07678e..5599e66 100644 --- a/FileProcessor.File.DomainEvents/FileProcessor.File.DomainEvents.csproj +++ b/FileProcessor.File.DomainEvents/FileProcessor.File.DomainEvents.csproj @@ -6,7 +6,7 @@ - + diff --git a/FileProcessor.FileAggregate/FileProcessor.FileAggregate.csproj b/FileProcessor.FileAggregate/FileProcessor.FileAggregate.csproj index 9d1db43..7265622 100644 --- a/FileProcessor.FileAggregate/FileProcessor.FileAggregate.csproj +++ b/FileProcessor.FileAggregate/FileProcessor.FileAggregate.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/FileProcessor.FileImportLog.DomainEvents/FileProcessor.FileImportLog.DomainEvents.csproj b/FileProcessor.FileImportLog.DomainEvents/FileProcessor.FileImportLog.DomainEvents.csproj index d744ba4..0b6595f 100644 --- a/FileProcessor.FileImportLog.DomainEvents/FileProcessor.FileImportLog.DomainEvents.csproj +++ b/FileProcessor.FileImportLog.DomainEvents/FileProcessor.FileImportLog.DomainEvents.csproj @@ -6,7 +6,7 @@ - + diff --git a/FileProcessor.FileImportLogAggregate/FileProcessor.FileImportLogAggregate.csproj b/FileProcessor.FileImportLogAggregate/FileProcessor.FileImportLogAggregate.csproj index 1efb365..2f9d707 100644 --- a/FileProcessor.FileImportLogAggregate/FileProcessor.FileImportLogAggregate.csproj +++ b/FileProcessor.FileImportLogAggregate/FileProcessor.FileImportLogAggregate.csproj @@ -7,7 +7,7 @@ - + diff --git a/FileProcessor.IntegrationTesting.Helpers/FileProcessor.IntegrationTesting.Helpers.csproj b/FileProcessor.IntegrationTesting.Helpers/FileProcessor.IntegrationTesting.Helpers.csproj index b5ffbab..1c2cf27 100644 --- a/FileProcessor.IntegrationTesting.Helpers/FileProcessor.IntegrationTesting.Helpers.csproj +++ b/FileProcessor.IntegrationTesting.Helpers/FileProcessor.IntegrationTesting.Helpers.csproj @@ -7,7 +7,7 @@ - + diff --git a/FileProcessor.IntegrationTests/Common/DockerHelper.cs b/FileProcessor.IntegrationTests/Common/DockerHelper.cs index 057ac69..8310cf2 100644 --- a/FileProcessor.IntegrationTests/Common/DockerHelper.cs +++ b/FileProcessor.IntegrationTests/Common/DockerHelper.cs @@ -63,7 +63,17 @@ public override async Task CreateSubscriptions(){ } } + protected override EventStoreClientSettings ConfigureEventStoreSettings() + { + string str = $"esdb://127.0.0.1:{this.EventStoreHttpPort}?tls=false&tlsVerifyCert=false&defaultDeadline=30000"; + if (this.IsSecureEventStore) { + str = $"esdb://admin:changeit@127.0.0.1:{this.EventStoreHttpPort}?tls=true&tlsVerifyCert=false&defaultDeadline=30000"; + } + return EventStoreClientSettings.Create(str); + } + public override async Task StartContainersForScenarioRun(String scenarioName, DockerServices dockerServices){ + await base.StartContainersForScenarioRun(scenarioName, dockerServices); // Setup the base address resolvers diff --git a/FileProcessor.IntegrationTests/FileProcessor.IntegrationTests.csproj b/FileProcessor.IntegrationTests/FileProcessor.IntegrationTests.csproj index ae755f3..e82f84c 100644 --- a/FileProcessor.IntegrationTests/FileProcessor.IntegrationTests.csproj +++ b/FileProcessor.IntegrationTests/FileProcessor.IntegrationTests.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/FileProcessor.Testing/TestData.cs b/FileProcessor.Testing/TestData.cs index 7612e05..7caf0ea 100644 --- a/FileProcessor.Testing/TestData.cs +++ b/FileProcessor.Testing/TestData.cs @@ -147,7 +147,8 @@ public static FileProfile GetFileProfile(String operatorName) public static List FileProfiles => new List { - FileProfileSafaricom + FileProfileSafaricom, + TestData.FileProfile }; public static Guid SafaricomFileProfileId = Guid.Parse("079F1FF5-F51E-4BE0-AF4F-2D4862E6D34F"); public static String SafaricomProfileName = "Safaricom Profile"; diff --git a/FileProcessor/Bootstrapper/RepositoryRegistry.cs b/FileProcessor/Bootstrapper/RepositoryRegistry.cs index 59e1bcb..ee96e3f 100644 --- a/FileProcessor/Bootstrapper/RepositoryRegistry.cs +++ b/FileProcessor/Bootstrapper/RepositoryRegistry.cs @@ -2,15 +2,15 @@ namespace FileProcessor.Bootstrapper; -using System; -using System.Diagnostics.CodeAnalysis; using BusinessLogic.Common; using BusinessLogic.Managers; using FileAggregate; using FileImportLogAggregate; using Lamar; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EntityFramework; using Shared.EntityFramework.ConnectionStringConfiguration; @@ -19,6 +19,8 @@ namespace FileProcessor.Bootstrapper; using Shared.EventStore.SubscriptionWorker; using Shared.General; using Shared.Repositories; +using System; +using System.Diagnostics.CodeAnalysis; [ExcludeFromCodeCoverage] public class RepositoryRegistry : ServiceRegistry @@ -30,26 +32,23 @@ public class RepositoryRegistry : ServiceRegistry /// public RepositoryRegistry() { - Boolean useConnectionStringConfig = bool.Parse(ConfigurationReader.GetValue("AppSettings", "UseConnectionStringConfig")); - - if (useConnectionStringConfig) + this.AddSingleton(typeof(IDbContextResolver<>), typeof(DbContextResolver<>)); + if (Startup.WebHostEnvironment.IsEnvironment("IntegrationTest") || Startup.Configuration.GetValue("ServiceOptions:UseInMemoryDatabase") == true) { - String connectionStringConfigurationConnString = ConfigurationReader.GetConnectionString("ConnectionStringConfiguration"); - this.AddSingleton(); - this.AddTransient(c => { return new ConnectionStringConfigurationContext(connectionStringConfigurationConnString); }); - - // TODO: Read this from a the database and set + this.AddDbContext(builder => builder.UseInMemoryDatabase("TransactionProcessorReadModel")); } else { - String connectionString = Startup.Configuration.GetValue("EventStoreSettings:ConnectionString"); + this.AddDbContext(options => + options.UseSqlServer(ConfigurationReader.GetConnectionString("TransactionProcessorReadModel"))); + } - this.AddEventStoreProjectionManagementClient(connectionString); - this.AddEventStorePersistentSubscriptionsClient(connectionString); + String connectionString = Startup.Configuration.GetValue("EventStoreSettings:ConnectionString"); - this.AddEventStoreClient(connectionString); - this.AddSingleton(); - } + this.AddEventStoreProjectionManagementClient(connectionString); + this.AddEventStorePersistentSubscriptionsClient(connectionString); + + this.AddEventStoreClient(connectionString); this.AddSingleton(); @@ -57,11 +56,6 @@ public RepositoryRegistry() this.AddSingleton, AggregateRepository>(); - this.AddSingleton, DbContextFactory>(); - this.AddSingleton>(cont => connectionString => - { - return new EstateManagementContext(connectionString); - }); this.AddSingleton(); this.AddSingleton>(cont => (esConnString, cacheDuration) => { diff --git a/FileProcessor/FileProcessor.csproj b/FileProcessor/FileProcessor.csproj index a6c2b1c..5ebcf67 100644 --- a/FileProcessor/FileProcessor.csproj +++ b/FileProcessor/FileProcessor.csproj @@ -6,7 +6,7 @@ - + @@ -19,12 +19,12 @@ - + - + From 5853e00aa507d2a7f6945d475b38e1826bb1597d Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Wed, 23 Jul 2025 15:50:33 +0100 Subject: [PATCH 3/3] broken unit test fix --- FileProcessor.Testing/TestData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FileProcessor.Testing/TestData.cs b/FileProcessor.Testing/TestData.cs index 7caf0ea..3a06950 100644 --- a/FileProcessor.Testing/TestData.cs +++ b/FileProcessor.Testing/TestData.cs @@ -322,7 +322,7 @@ public static FileAggregate GetFileAggregateWithLinesAlreadyProcessed() ["AppSettings:TemporaryFileLocation"] = "C:\\Temp", ["AppSettings:FileProfilePollingWindowInSeconds"] = "30", ["ConnectionStrings:HealthCheck"] = "HeathCheckConnString", - ["ConnectionStrings:EstateReportingReadModel"] = "EstateReportingReadModel", + ["ConnectionStrings:TransactionProcessorReadModel"] = "EstateReportingReadModel", ["SecurityConfiguration:Authority"] = "https://127.0.0.1", ["EventStoreSettings:ConnectionString"] = "esdb://127.0.0.1:2113", ["EventStoreSettings:ConnectionName"] = "UnitTestConnection",