From b46c8222818d4a2b175758d77c148958b1f8e899 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 23 Feb 2026 12:04:54 +0000 Subject: [PATCH] Refactor tests into domain-specific files for clarity Split ContractEventTests.cs into dedicated test files for merchants, statements, operators, file import logs, and estates, improving organization and maintainability. Updated SaveChangesAsync to SaveChangesWithDuplicateHandling for reconciliation events. Added ReconciliationHasStartedEvent to test data. No changes to test logic or coverage. --- .../ContractEventTests.cs | 209 +----------------- .../EstateEventTests.cs | 49 ++++ .../FileImportLogEventTests.cs | 49 ++++ .../MerchantEventTests.cs | 97 ++++++++ .../OperatorEventTests.cs | 30 +++ .../StatementEventTests.cs | 28 +++ ...TransactionProcessorReadModelRepository.cs | 2 +- TransactionProcessor.Testing/TestData.cs | 2 + 8 files changed, 265 insertions(+), 201 deletions(-) create mode 100644 TransactionProcessor.DatabaseTests/EstateEventTests.cs create mode 100644 TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs create mode 100644 TransactionProcessor.DatabaseTests/MerchantEventTests.cs create mode 100644 TransactionProcessor.DatabaseTests/OperatorEventTests.cs create mode 100644 TransactionProcessor.DatabaseTests/StatementEventTests.cs diff --git a/TransactionProcessor.DatabaseTests/ContractEventTests.cs b/TransactionProcessor.DatabaseTests/ContractEventTests.cs index e8607cc0..54518827 100644 --- a/TransactionProcessor.DatabaseTests/ContractEventTests.cs +++ b/TransactionProcessor.DatabaseTests/ContractEventTests.cs @@ -13,138 +13,28 @@ namespace TransactionProcessor.DatabaseTests { - public class MerchantEventTests : BaseTest { - [Fact] - public async Task AddMerchant_MerchantIsAdded() - { - Result result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - Merchant? merchant = await context.Merchants.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.MerchantCreatedEvent.MerchantId); - merchant.ShouldNotBeNull(); - } - - [Fact] - public async Task AddMerchant_EventReplayHandled() { - Result result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - - [Fact] - public async Task AddMerchantDevice_MerchantContractIsAdded() - { - Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - } - - [Fact] - public async Task AddMerchantDevice_EventReplayHandled() { - Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - - [Fact] - public async Task SwapMerchantDevice_MerchantContractIsAdded() - { - Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceIdentifier); - merchantDevice.IsEnabled.ShouldBeFalse(); - - merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceSwappedForMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); - merchantDevice.IsEnabled.ShouldBeTrue(); - } - - [Fact] - public async Task SwapMerchantDevice_EventReplayHandled() - { - Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceIdentifier); - merchantDevice.IsEnabled.ShouldBeFalse(); - - merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceSwappedForMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); - merchantDevice.IsEnabled.ShouldBeTrue(); - - result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - - merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceIdentifier); - merchantDevice.IsEnabled.ShouldBeFalse(); - - merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceSwappedForMerchantEvent.DeviceId); - merchantDevice.ShouldNotBeNull(); - merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); - merchantDevice.IsEnabled.ShouldBeTrue(); - } - } - - - public class StatementEventTests : BaseTest { + public class ReconciliationEventTests : BaseTest + { [Fact] - public async Task CreateStatement_StatementIsAdded() + public async Task AddReconciliation_ReconciliationIsAdded() { - Result result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + Result result = await this.Repository.StartReconciliation(TestData.DomainEvents.ReconciliationHasStartedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); EstateManagementContext context = this.GetContext(); - StatementHeader? statement = await context.StatementHeaders.SingleOrDefaultAsync(c => c.StatementId == TestData.DomainEvents.StatementCreatedEvent.MerchantStatementId); - statement.ShouldNotBeNull(); + Reconciliation? reconciliation = await context.Reconciliations.SingleOrDefaultAsync(c => c.TransactionId == TestData.DomainEvents.ReconciliationHasStartedEvent.TransactionId); + reconciliation.ShouldNotBeNull(); } [Fact] - public async Task CreateStatement_EventReplayHandled() - { - Result result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + public async Task AddReconciliation_EventReplayHandled() { + Result result = await this.Repository.StartReconciliation(TestData.DomainEvents.ReconciliationHasStartedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); - result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + result = await this.Repository.StartReconciliation(TestData.DomainEvents.ReconciliationHasStartedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } } public class ContractEventTests : BaseTest { - [Fact] - public async Task AddOperator_OperatorIsAdded() - { - Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - Operator? @operator = await context.Operators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorCreatedEvent.OperatorId); - @operator.ShouldNotBeNull(); - } - - [Fact] - public async Task AddOperator_EventReplayHandled() - { - Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - - result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - [Fact] public async Task AddContract_ContractIsAdded() { @@ -221,86 +111,5 @@ public async Task AddContractProductTransactionFee_EventReplayHandled() result = await this.Repository.AddContractProductTransactionFee(TestData.DomainEvents.TransactionFeeForProductAddedToContractEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } - - [Fact] - public async Task AddFileImportLog_FileImportLogIsAdded() - { - Result result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var fileImportLog = await context.FileImportLogs.SingleOrDefaultAsync(f => f.FileImportLogId == TestData.DomainEvents.ImportLogCreatedEvent.FileImportLogId); - fileImportLog.ShouldNotBeNull(); - } - - [Fact] - public async Task AddFileImportLog_EventReplayHandled() - { - Result result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - - result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - - [Fact] - public async Task AddFileImportLogFile_FileImportLogIsAdded() - { - Result result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var fileImportLogFile = await context.FileImportLogFiles.SingleOrDefaultAsync(f => f.FileImportLogId == TestData.DomainEvents.FileAddedToImportLogEvent.FileImportLogId && f.FileId == TestData.DomainEvents.FileAddedToImportLogEvent.FileId); - fileImportLogFile.ShouldNotBeNull(); - } - - [Fact] - public async Task AddFileImportLogFile_EventReplayHandled() - { - Result result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - - result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - - - [Fact] - public async Task AddEstate_EstateIsAdded() - { - Result result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var estate = await context.Estates.SingleOrDefaultAsync(f => f.EstateId == TestData.DomainEvents.EstateCreatedEvent.EstateId); - estate.ShouldNotBeNull(); - } - - [Fact] - public async Task AddEstate_EventReplayHandled() - { - Result result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - - result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - - [Fact] - public async Task AddEstateSecurityUser_EstateIsAdded() - { - Result result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - EstateManagementContext context = this.GetContext(); - var estateSecurityUser = await context.EstateSecurityUsers.SingleOrDefaultAsync(f => f.EstateId == TestData.DomainEvents.EstateSecurityUserAddedEvent.EstateId && f.SecurityUserId == TestData.DomainEvents.EstateSecurityUserAddedEvent.SecurityUserId); - estateSecurityUser.ShouldNotBeNull(); - } - - [Fact] - public async Task AddEstateSecurityUser_EventReplayHandled() - { - Result result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - - result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } } } diff --git a/TransactionProcessor.DatabaseTests/EstateEventTests.cs b/TransactionProcessor.DatabaseTests/EstateEventTests.cs new file mode 100644 index 00000000..b2ab58d7 --- /dev/null +++ b/TransactionProcessor.DatabaseTests/EstateEventTests.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Testing; + +namespace TransactionProcessor.DatabaseTests; + +public class EstateEventTests : BaseTest { + [Fact] + public async Task AddEstate_EstateIsAdded() + { + Result result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var estate = await context.Estates.SingleOrDefaultAsync(f => f.EstateId == TestData.DomainEvents.EstateCreatedEvent.EstateId); + estate.ShouldNotBeNull(); + } + + [Fact] + public async Task AddEstate_EventReplayHandled() + { + Result result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddEstate(TestData.DomainEvents.EstateCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddEstateSecurityUser_EstateIsAdded() + { + Result result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var estateSecurityUser = await context.EstateSecurityUsers.SingleOrDefaultAsync(f => f.EstateId == TestData.DomainEvents.EstateSecurityUserAddedEvent.EstateId && f.SecurityUserId == TestData.DomainEvents.EstateSecurityUserAddedEvent.SecurityUserId); + estateSecurityUser.ShouldNotBeNull(); + } + + [Fact] + public async Task AddEstateSecurityUser_EventReplayHandled() + { + Result result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddEstateSecurityUser(TestData.DomainEvents.EstateSecurityUserAddedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } +} \ No newline at end of file diff --git a/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs b/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs new file mode 100644 index 00000000..405d787d --- /dev/null +++ b/TransactionProcessor.DatabaseTests/FileImportLogEventTests.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Testing; + +namespace TransactionProcessor.DatabaseTests; + +public class FileImportLogEventTests : BaseTest { + [Fact] + public async Task AddFileImportLog_FileImportLogIsAdded() + { + Result result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var fileImportLog = await context.FileImportLogs.SingleOrDefaultAsync(f => f.FileImportLogId == TestData.DomainEvents.ImportLogCreatedEvent.FileImportLogId); + fileImportLog.ShouldNotBeNull(); + } + + [Fact] + public async Task AddFileImportLog_EventReplayHandled() + { + Result result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddFileImportLog(TestData.DomainEvents.ImportLogCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddFileImportLogFile_FileImportLogIsAdded() + { + Result result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var fileImportLogFile = await context.FileImportLogFiles.SingleOrDefaultAsync(f => f.FileImportLogId == TestData.DomainEvents.FileAddedToImportLogEvent.FileImportLogId && f.FileId == TestData.DomainEvents.FileAddedToImportLogEvent.FileId); + fileImportLogFile.ShouldNotBeNull(); + } + + [Fact] + public async Task AddFileImportLogFile_EventReplayHandled() + { + Result result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddFileToImportLog(TestData.DomainEvents.FileAddedToImportLogEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } +} \ No newline at end of file diff --git a/TransactionProcessor.DatabaseTests/MerchantEventTests.cs b/TransactionProcessor.DatabaseTests/MerchantEventTests.cs new file mode 100644 index 00000000..a68c4566 --- /dev/null +++ b/TransactionProcessor.DatabaseTests/MerchantEventTests.cs @@ -0,0 +1,97 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Database.Entities; +using TransactionProcessor.Testing; + +namespace TransactionProcessor.DatabaseTests; + +public class MerchantEventTests : BaseTest { + [Fact] + public async Task AddMerchant_MerchantIsAdded() + { + Result result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + Merchant? merchant = await context.Merchants.SingleOrDefaultAsync(c => c.MerchantId == TestData.DomainEvents.MerchantCreatedEvent.MerchantId); + merchant.ShouldNotBeNull(); + } + + [Fact] + public async Task AddMerchant_EventReplayHandled() { + Result result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchant(TestData.DomainEvents.MerchantCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task AddMerchantDevice_MerchantContractIsAdded() + { + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + } + + [Fact] + public async Task AddMerchantDevice_EventReplayHandled() { + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task SwapMerchantDevice_MerchantDeviceIsAdded() + { + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceIdentifier); + merchantDevice.IsEnabled.ShouldBeFalse(); + + merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceSwappedForMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); + merchantDevice.IsEnabled.ShouldBeTrue(); + } + + [Fact] + public async Task SwapMerchantDevice_EventReplayHandled() + { + Result result = await this.Repository.AddMerchantDevice(TestData.DomainEvents.DeviceAddedToMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + var merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceIdentifier); + merchantDevice.IsEnabled.ShouldBeFalse(); + + merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceSwappedForMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); + merchantDevice.IsEnabled.ShouldBeTrue(); + + result = await this.Repository.SwapMerchantDevice(TestData.DomainEvents.DeviceSwappedForMerchantEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceAddedToMerchantEvent.DeviceIdentifier); + merchantDevice.IsEnabled.ShouldBeFalse(); + + merchantDevice = await context.MerchantDevices.SingleOrDefaultAsync(c => c.DeviceId == TestData.DomainEvents.DeviceSwappedForMerchantEvent.DeviceId); + merchantDevice.ShouldNotBeNull(); + merchantDevice.DeviceIdentifier.ShouldBe(TestData.DomainEvents.DeviceSwappedForMerchantEvent.NewDeviceIdentifier); + merchantDevice.IsEnabled.ShouldBeTrue(); + } +} \ No newline at end of file diff --git a/TransactionProcessor.DatabaseTests/OperatorEventTests.cs b/TransactionProcessor.DatabaseTests/OperatorEventTests.cs new file mode 100644 index 00000000..554c4380 --- /dev/null +++ b/TransactionProcessor.DatabaseTests/OperatorEventTests.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Database.Entities; +using TransactionProcessor.Testing; + +namespace TransactionProcessor.DatabaseTests; + +public class OperatorEventTests : BaseTest { + [Fact] + public async Task AddOperator_OperatorIsAdded() + { + Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + Operator? @operator = await context.Operators.SingleOrDefaultAsync(c => c.OperatorId == TestData.DomainEvents.OperatorCreatedEvent.OperatorId); + @operator.ShouldNotBeNull(); + } + + [Fact] + public async Task AddOperator_EventReplayHandled() + { + Result result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + + result = await this.Repository.AddOperator(TestData.DomainEvents.OperatorCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } +} \ No newline at end of file diff --git a/TransactionProcessor.DatabaseTests/StatementEventTests.cs b/TransactionProcessor.DatabaseTests/StatementEventTests.cs new file mode 100644 index 00000000..1344bcea --- /dev/null +++ b/TransactionProcessor.DatabaseTests/StatementEventTests.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using Shouldly; +using SimpleResults; +using TransactionProcessor.Database.Contexts; +using TransactionProcessor.Database.Entities; +using TransactionProcessor.Testing; + +namespace TransactionProcessor.DatabaseTests; + +public class StatementEventTests : BaseTest { + [Fact] + public async Task CreateStatement_StatementIsAdded() + { + Result result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + EstateManagementContext context = this.GetContext(); + StatementHeader? statement = await context.StatementHeaders.SingleOrDefaultAsync(c => c.StatementId == TestData.DomainEvents.StatementCreatedEvent.MerchantStatementId); + statement.ShouldNotBeNull(); + } + [Fact] + public async Task CreateStatement_EventReplayHandled() + { + Result result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result = await this.Repository.CreateStatement(TestData.DomainEvents.StatementCreatedEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } +} \ No newline at end of file diff --git a/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs b/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs index 9479bc46..1f29de8d 100644 --- a/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs +++ b/TransactionProcessor.Repository/ITransactionProcessorReadModelRepository.cs @@ -1353,7 +1353,7 @@ public async Task StartReconciliation(ReconciliationDomainEvents.Reconci await context.Reconciliations.AddAsync(reconciliation, cancellationToken); - return await context.SaveChangesAsync(cancellationToken); + return await context.SaveChangesWithDuplicateHandling(cancellationToken); } public async Task StartTransaction(TransactionDomainEvents.TransactionHasStartedEvent domainEvent, diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index 35805e39..acb2091d 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -2628,6 +2628,8 @@ public static Models.Merchant.Merchant MerchantModelWithAddressesContactsDevices public static class DomainEvents { + public static ReconciliationDomainEvents.ReconciliationHasStartedEvent ReconciliationHasStartedEvent => new ReconciliationDomainEvents.ReconciliationHasStartedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.TransactionDateTime); + public static TransactionDomainEvents.TransactionHasBeenCompletedEvent TransactionHasBeenCompletedEvent => new TransactionDomainEvents.TransactionHasBeenCompletedEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId,