From 28245dde28337702854855c98e7a6b0bf12a4e99 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Mon, 2 Dec 2019 20:54:46 +0000 Subject: [PATCH 1/2] Added persistance of transaction --- .github/workflows/createrelease.yml | 1 + .github/workflows/nightlybuild.yml | 1 + .github/workflows/pullrequest.yml | 1 + .../CommandHandler/CommandRouterTests.cs | 1 + .../TransactionCommandHandlerTests.cs | 1 + .../Commands/CommandTests.cs | 2 +- .../Services/TransactionDomainServiceTests.cs | 50 ++++ ...actionProcessor.BusinessLogic.Tests.csproj | 1 - .../TransactionCommandHandler.cs | 3 +- .../ProcessLogonTransactionCommand.cs | 11 +- .../Services/ITransactionDomainService.cs | 4 +- .../Services/TransactionDomainService.cs | 39 ++- .../TransactionProcessor.BusinessLogic.csproj | 2 + .../LogonTransactionResponse.cs | 2 +- .../Common/DockerHelper.cs | 10 + ...ansactionProcessor.IntegrationTests.csproj | 29 +++ .../ProcessLogonTransactionResponse.cs | 2 +- TransactionProcessor.Testing/TestData.cs | 53 +++- .../TransactionProcessor.Testing.csproj | 1 + .../Common/TransactionProcessorWebFactory.cs | 2 +- .../TransactionControllerTests.cs | 2 +- .../TransactionHasBeenCompletedEvent.cs | 135 ++++++++++ ...ransactionHasBeenLocallyAuthorisedEvent.cs | 135 ++++++++++ .../TransactionHasStartedEvent.cs | 149 +++++++++++ ...nProcessor.Transaction.DomainEvents.csproj | 11 + .../DomainEventTests.cs | 83 ++++++ .../TransactionAggregateTests.cs | 194 ++++++++++++++ ...rocessor.TransactionAggregate.Tests.csproj | 28 ++ .../TransactionAggregate.cs | 242 ++++++++++++++++++ ...ctionProcessor.TransactionAggregate.csproj | 15 ++ TransactionProcessor.sln | 27 +- .../Controllers/TransactionController.cs | 5 +- TransactionProcessor/Startup.cs | 50 ++++ TransactionProcessor/appsettings.json | 17 +- 34 files changed, 1287 insertions(+), 22 deletions(-) create mode 100644 TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs create mode 100644 TransactionProcessor.IntegrationTests/Common/DockerHelper.cs create mode 100644 TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj create mode 100644 TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenCompletedEvent.cs create mode 100644 TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenLocallyAuthorisedEvent.cs create mode 100644 TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs create mode 100644 TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj create mode 100644 TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs create mode 100644 TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs create mode 100644 TransactionProcessor.TransactionAggregate.Tests/TransactionProcessor.TransactionAggregate.Tests.csproj create mode 100644 TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs create mode 100644 TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj diff --git a/.github/workflows/createrelease.yml b/.github/workflows/createrelease.yml index 469e1a37..230b3857 100644 --- a/.github/workflows/createrelease.yml +++ b/.github/workflows/createrelease.yml @@ -35,6 +35,7 @@ jobs: echo "ASPNETCORE_ENVIRONMENT are > ${ASPNETCORE_ENVIRONMENT}" dotnet test "TransactionProcessor.BusinessLogic.Tests\TransactionProcessor.BusinessLogic.Tests.csproj" dotnet test "TransactionProcessor.Tests\TransactionProcessor.Tests.csproj" + dotnet test "TransactionProcessor.TransactionAggregate.Tests\TransactionProcessor.TransactionAggregate.Tests.csproj" - name: Build Docker Images run: | diff --git a/.github/workflows/nightlybuild.yml b/.github/workflows/nightlybuild.yml index fe8d53ee..ec463401 100644 --- a/.github/workflows/nightlybuild.yml +++ b/.github/workflows/nightlybuild.yml @@ -31,6 +31,7 @@ jobs: echo "ASPNETCORE_ENVIRONMENT are > ${ASPNETCORE_ENVIRONMENT}" dotnet test "TransactionProcessor.BusinessLogic.Tests\TransactionProcessor.BusinessLogic.Tests.csproj" /p:CollectCoverage=true /p:Exclude="[xunit*]*" /p:ExcludeByAttribute="Obsolete" /p:ExcludeByAttribute="GeneratedCodeAttribute" /p:ExcludeByAttribute="CompilerGeneratedAttribute" /p:ExcludeByAttribute="ExcludeFromCodeCoverageAttribute" /p:CoverletOutput="../lcov1.info" /maxcpucount:1 /p:CoverletOutputFormat="lcov" dotnet test "TransactionProcessor.Tests\TransactionProcessor.Tests.csproj" /p:CollectCoverage=true /p:Exclude="[xunit*]*" /p:ExcludeByAttribute="Obsolete" /p:ExcludeByAttribute="GeneratedCodeAttribute" /p:ExcludeByAttribute="CompilerGeneratedAttribute" /p:ExcludeByAttribute="ExcludeFromCodeCoverageAttribute" /p:CoverletOutput="../lcov2.info" /maxcpucount:1 /p:CoverletOutputFormat="lcov" + dotnet test "TransactionProcessor.TransactionAggregate.Tests\TransactionProcessor.TransactionAggregate.Tests" /p:CollectCoverage=true /p:Exclude="[xunit*]*" /p:ExcludeByAttribute="Obsolete" /p:ExcludeByAttribute="GeneratedCodeAttribute" /p:ExcludeByAttribute="CompilerGeneratedAttribute" /p:ExcludeByAttribute="ExcludeFromCodeCoverageAttribute" /p:CoverletOutput="../lcov3.info" /maxcpucount:1 /p:CoverletOutputFormat="lcov" - name: Setup Node.js for use with actions uses: actions/setup-node@v1.1.0 diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index adcfcc99..c939f991 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -32,6 +32,7 @@ jobs: echo "ASPNETCORE_ENVIRONMENT are > ${ASPNETCORE_ENVIRONMENT}" dotnet test "TransactionProcessor.BusinessLogic.Tests\TransactionProcessor.BusinessLogic.Tests.csproj" dotnet test "TransactionProcessor.Tests\TransactionProcessor.Tests.csproj" + dotnet test "TransactionProcessor.TransactionAggregate.Tests\TransactionProcessor.TransactionAggregate.Tests.csproj" - name: Build Docker Image run: docker build . --file TransactionProcessor/Dockerfile --tag transactionprocessor:latest diff --git a/TransactionProcessor.BusinessLogic.Tests/CommandHandler/CommandRouterTests.cs b/TransactionProcessor.BusinessLogic.Tests/CommandHandler/CommandRouterTests.cs index 6246f91d..e48979fb 100644 --- a/TransactionProcessor.BusinessLogic.Tests/CommandHandler/CommandRouterTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/CommandHandler/CommandRouterTests.cs @@ -7,6 +7,7 @@ namespace TransactionProcessor.BusinessLogic.Tests.CommandHandler using System.Threading; using System.Threading.Tasks; using BusinessLogic.Commands; + using BusinessLogic.Services; using CommandHandlers; using Commands; using Moq; diff --git a/TransactionProcessor.BusinessLogic.Tests/CommandHandler/TransactionCommandHandlerTests.cs b/TransactionProcessor.BusinessLogic.Tests/CommandHandler/TransactionCommandHandlerTests.cs index ef8249ae..54cdb2b4 100644 --- a/TransactionProcessor.BusinessLogic.Tests/CommandHandler/TransactionCommandHandlerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/CommandHandler/TransactionCommandHandlerTests.cs @@ -2,6 +2,7 @@ { using System.Threading; using BusinessLogic.Commands; + using BusinessLogic.Services; using CommandHandlers; using Commands; using Moq; diff --git a/TransactionProcessor.BusinessLogic.Tests/Commands/CommandTests.cs b/TransactionProcessor.BusinessLogic.Tests/Commands/CommandTests.cs index ff788f85..72912d23 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Commands/CommandTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Commands/CommandTests.cs @@ -14,7 +14,7 @@ public class CommandTests [Fact] public void ProcessLogonTransactionCommand_CanBeCreated_IsCreated() { - ProcessLogonTransactionCommand processLogonTransactionCommand = ProcessLogonTransactionCommand.Create(TestData.EstateId, TestData.MerchantId, TestData.IMEINumber,TestData.TransactionType, TestData.TransactionDateTime, + ProcessLogonTransactionCommand processLogonTransactionCommand = ProcessLogonTransactionCommand.Create(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber,TestData.TransactionType, TestData.TransactionDateTime, TestData.TransactionNumber); processLogonTransactionCommand.ShouldNotBeNull(); diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs new file mode 100644 index 00000000..0affbb99 --- /dev/null +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TransactionProcessor.BusinessLogic.Tests.Services +{ + using System.Threading; + using System.Threading.Tasks; + using BusinessLogic.Services; + using Models; + using Moq; + using Shared.DomainDrivenDesign.EventStore; + using Shared.EventStore.EventStore; + using Shouldly; + using Testing; + using TransactionAggregate; + using Xunit; + + public class TransactionDomainServiceTests + { + [Fact] + public async Task TransactionDomainService_ProcessLogonTransaction_TransactionIsProcessed() + { + Mock aggregateRepositoryManager = new Mock(); + Mock> transactionAggregateRepository = new Mock>(); + + aggregateRepositoryManager.Setup(x => x.GetAggregateRepository(It.IsAny())).Returns(transactionAggregateRepository.Object); + transactionAggregateRepository.SetupSequence(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEmptyTransactionAggregate) + .ReturnsAsync(TestData.GetStartedTransactionAggregate) + .ReturnsAsync(TestData.GetLocallyAuthorisedTransactionAggregate) + .ReturnsAsync(TestData.GetCompletedTransactionAggregate); + transactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).Returns(Task.CompletedTask); + + TransactionDomainService transactionDomainService = new TransactionDomainService(aggregateRepositoryManager.Object); + + ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.IMEINumber, + CancellationToken.None); + + response.ShouldNotBeNull(); + response.ResponseCode.ShouldBe(TestData.ResponseCode); + response.ResponseMessage.ShouldBe(TestData.ResponseMessage); + } + } +} diff --git a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj index 506432db..004bf540 100644 --- a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj +++ b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj @@ -24,7 +24,6 @@ - diff --git a/TransactionProcessor.BusinessLogic/CommandHandlers/TransactionCommandHandler.cs b/TransactionProcessor.BusinessLogic/CommandHandlers/TransactionCommandHandler.cs index 1da86ca4..ee74906b 100644 --- a/TransactionProcessor.BusinessLogic/CommandHandlers/TransactionCommandHandler.cs +++ b/TransactionProcessor.BusinessLogic/CommandHandlers/TransactionCommandHandler.cs @@ -56,7 +56,8 @@ public async Task Handle(ICommand command, private async Task HandleCommand(ProcessLogonTransactionCommand command, CancellationToken cancellationToken) { - ProcessLogonTransactionResponse logonResponse = await this.TransactionDomainService.ProcessLogonTransaction(cancellationToken); + ProcessLogonTransactionResponse logonResponse = await this.TransactionDomainService.ProcessLogonTransaction(command.TransactionId, command.EstateId, + command.MerchantId, command.TransactionDateTime, command.TransactionNumber, command.IMEINumber, cancellationToken); command.Response = logonResponse; } diff --git a/TransactionProcessor.BusinessLogic/Commands/ProcessLogonTransactionCommand.cs b/TransactionProcessor.BusinessLogic/Commands/ProcessLogonTransactionCommand.cs index e926ba86..b0be20f8 100644 --- a/TransactionProcessor.BusinessLogic/Commands/ProcessLogonTransactionCommand.cs +++ b/TransactionProcessor.BusinessLogic/Commands/ProcessLogonTransactionCommand.cs @@ -10,6 +10,8 @@ /// public class ProcessLogonTransactionCommand : Command { + public Guid TransactionId { get; private set; } + #region Constructors /// @@ -22,7 +24,8 @@ public class ProcessLogonTransactionCommand : CommandThe transaction date time. /// The transaction number. /// The command identifier. - private ProcessLogonTransactionCommand(Guid estateId, + private ProcessLogonTransactionCommand(Guid transactionId, + Guid estateId, Guid merchantId, String imeiNumber, String transactionType, @@ -30,6 +33,7 @@ private ProcessLogonTransactionCommand(Guid estateId, String transactionNumber, Guid commandId) : base(commandId) { + this.TransactionId = transactionId; this.EstateId = estateId; this.IMEINumber = imeiNumber; this.MerchantId = merchantId; @@ -104,14 +108,15 @@ private ProcessLogonTransactionCommand(Guid estateId, /// The transaction date time. /// The transaction number. /// - public static ProcessLogonTransactionCommand Create(Guid estateId, + public static ProcessLogonTransactionCommand Create(Guid transactionId, + Guid estateId, Guid merchantId, String imeiNumber, String transactionType, DateTime transactionDateTime, String transactionNumber) { - return new ProcessLogonTransactionCommand(estateId, merchantId, imeiNumber, transactionType, transactionDateTime, transactionNumber, Guid.NewGuid()); + return new ProcessLogonTransactionCommand(transactionId, estateId, merchantId, imeiNumber, transactionType, transactionDateTime, transactionNumber, Guid.NewGuid()); } #endregion diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs index 2cc83f9f..878d3d50 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs @@ -1,5 +1,6 @@ namespace TransactionProcessor.BusinessLogic.Services { + using System; using System.Threading; using System.Threading.Tasks; using Models; @@ -16,7 +17,8 @@ public interface ITransactionDomainService /// /// The cancellation token. /// - Task ProcessLogonTransaction(CancellationToken cancellationToken); + Task ProcessLogonTransaction(Guid transactionId, Guid estateId, Guid merchantId, DateTime transactionDateTime, + String transactionNumber, String imeiNumber, CancellationToken cancellationToken); #endregion } diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index 3785dbca..6c4268c0 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -1,8 +1,12 @@ namespace TransactionProcessor.BusinessLogic.Services { + using System; using System.Threading; using System.Threading.Tasks; using Models; + using Shared.DomainDrivenDesign.EventStore; + using Shared.EventStore.EventStore; + using TransactionAggregate; /// /// @@ -10,22 +14,51 @@ /// public class TransactionDomainService : ITransactionDomainService { + private readonly IAggregateRepositoryManager AggregateRepositoryManager; + + public TransactionDomainService(IAggregateRepositoryManager aggregateRepositoryManager) + { + this.AggregateRepositoryManager = aggregateRepositoryManager; + } + #region Methods /// /// Processes the logon transaction. /// + /// + /// + /// + /// + /// + /// /// The cancellation token. /// - public async Task ProcessLogonTransaction(CancellationToken cancellationToken) + public async Task ProcessLogonTransaction(Guid transactionId, Guid estateId, Guid merchantId, DateTime transactionDateTime, + String transactionNumber, String imeiNumber, CancellationToken cancellationToken) { + IAggregateRepository transactionAggregateRepository = this.AggregateRepositoryManager.GetAggregateRepository(estateId); + + TransactionAggregate transactionAggregate = await transactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); + transactionAggregate.StartTransaction(transactionDateTime, transactionNumber, "Logon", estateId, merchantId, imeiNumber); + await transactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); + + transactionAggregate = await transactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); + transactionAggregate.AuthoriseTransactionLocally("ABCD1234", "0000", "SUCCESS"); + await transactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); + + transactionAggregate = await transactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); + transactionAggregate.CompleteTransaction(); + await transactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); + return new ProcessLogonTransactionResponse { - ResponseMessage = "SUCCESS", - ResponseCode = 0 + ResponseMessage = transactionAggregate.ResponseMessage, + ResponseCode = transactionAggregate.ResponseCode }; } + #endregion } } \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj index 1e0a1c46..66ef0e48 100644 --- a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj +++ b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj @@ -7,6 +7,7 @@ + @@ -15,6 +16,7 @@ + diff --git a/TransactionProcessor.DataTransferObjects/LogonTransactionResponse.cs b/TransactionProcessor.DataTransferObjects/LogonTransactionResponse.cs index dc4dff50..0b9ca724 100644 --- a/TransactionProcessor.DataTransferObjects/LogonTransactionResponse.cs +++ b/TransactionProcessor.DataTransferObjects/LogonTransactionResponse.cs @@ -17,7 +17,7 @@ public class LogonTransactionResponse /// /// The response code. /// - public Int32 ResponseCode { get; set; } + public String ResponseCode { get; set; } /// /// Gets or sets the response message. diff --git a/TransactionProcessor.IntegrationTests/Common/DockerHelper.cs b/TransactionProcessor.IntegrationTests/Common/DockerHelper.cs new file mode 100644 index 00000000..786fa6f0 --- /dev/null +++ b/TransactionProcessor.IntegrationTests/Common/DockerHelper.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TransactionProcessor.IntegrationTests.Common +{ + class DockerHelper + { + } +} diff --git a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj new file mode 100644 index 00000000..52226636 --- /dev/null +++ b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj @@ -0,0 +1,29 @@ + + + + netcoreapp3.0 + + false + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/TransactionProcessor.Models/ProcessLogonTransactionResponse.cs b/TransactionProcessor.Models/ProcessLogonTransactionResponse.cs index ded9081e..a72ec4c4 100644 --- a/TransactionProcessor.Models/ProcessLogonTransactionResponse.cs +++ b/TransactionProcessor.Models/ProcessLogonTransactionResponse.cs @@ -17,7 +17,7 @@ public class ProcessLogonTransactionResponse /// /// The response code. /// - public Int32 ResponseCode { get; set; } + public String ResponseCode { get; set; } /// /// Gets or sets the response message. diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index f9c327e1..5b62519b 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -6,6 +6,7 @@ namespace TransactionProcessor.Testing { using BusinessLogic.Commands; using Models; + using TransactionAggregate; public class TestData { @@ -17,22 +18,68 @@ public class TestData public static String ResponseMessage = "SUCCESS"; - public static Int32 ResponseCode= 0; + public static String ResponseCode= "0000"; public static Guid EstateId = Guid.Parse("A522FA27-F9D0-470A-A88D-325DED3B62EE"); public static Guid MerchantId = Guid.Parse("833B5AAC-A5C5-46C2-A499-F2B4252B2942"); + public static Guid TransactionId = Guid.Parse("AE89B2F6-307B-46F4-A8E7-CEF27097D766"); - public static ProcessLogonTransactionCommand ProcessLogonTransactionCommand = ProcessLogonTransactionCommand.Create(TestData.EstateId, TestData.MerchantId, + public static ProcessLogonTransactionCommand ProcessLogonTransactionCommand = ProcessLogonTransactionCommand.Create( TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber, TestData.TransactionType, TestData.TransactionDateTime, TestData.TransactionNumber); public static String IMEINumber = "1234567890"; - public static String TransactionType = "1000"; + public static String TransactionType = "Logon"; public static DateTime TransactionDateTime = DateTime.Now; public static String TransactionNumber = "0001"; + + public static String AuthorisationCode = "ABCD1234"; + + public static Boolean IsAuthorised = true; + + public static TransactionAggregate GetEmptyTransactionAggregate() + { + return TransactionAggregate.Create(TestData.TransactionId); + } + + public static TransactionAggregate GetStartedTransactionAggregate() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + + transactionAggregate.StartTransaction(TestData.TransactionDateTime,TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, + TestData.IMEINumber); + + return transactionAggregate; + } + + public static TransactionAggregate GetLocallyAuthorisedTransactionAggregate() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, + TestData.IMEINumber); + + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + + return transactionAggregate; + } + + public static TransactionAggregate GetCompletedTransactionAggregate() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, + TestData.IMEINumber); + + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + + transactionAggregate.CompleteTransaction(); + + return transactionAggregate; + } } } diff --git a/TransactionProcessor.Testing/TransactionProcessor.Testing.csproj b/TransactionProcessor.Testing/TransactionProcessor.Testing.csproj index 6af20116..248202d0 100644 --- a/TransactionProcessor.Testing/TransactionProcessor.Testing.csproj +++ b/TransactionProcessor.Testing/TransactionProcessor.Testing.csproj @@ -8,6 +8,7 @@ + diff --git a/TransactionProcessor.Tests/Common/TransactionProcessorWebFactory.cs b/TransactionProcessor.Tests/Common/TransactionProcessorWebFactory.cs index ababf495..9f5d0206 100644 --- a/TransactionProcessor.Tests/Common/TransactionProcessorWebFactory.cs +++ b/TransactionProcessor.Tests/Common/TransactionProcessorWebFactory.cs @@ -50,7 +50,7 @@ private Mock CreateCommandRouterMock() command.Response = new ProcessLogonTransactionResponse { ResponseMessage = "SUCCESS", - ResponseCode = 0 + ResponseCode = "0000" }; return Task.CompletedTask; }); diff --git a/TransactionProcessor.Tests/ControllerTests/TransactionControllerTests.cs b/TransactionProcessor.Tests/ControllerTests/TransactionControllerTests.cs index 161ee70e..01cc03b4 100644 --- a/TransactionProcessor.Tests/ControllerTests/TransactionControllerTests.cs +++ b/TransactionProcessor.Tests/ControllerTests/TransactionControllerTests.cs @@ -55,7 +55,7 @@ public async Task TransactionController_POST_LogonTransaction_LogonTransactionRe LogonTransactionResponse responseObject = JsonConvert.DeserializeObject(responseAsJson); responseObject.ShouldNotBeNull(); - responseObject.ResponseCode.ShouldBe(0); + responseObject.ResponseCode.ShouldBe("0000"); responseObject.ResponseMessage.ShouldBe("SUCCESS"); } } diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenCompletedEvent.cs b/TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenCompletedEvent.cs new file mode 100644 index 00000000..6ee19718 --- /dev/null +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenCompletedEvent.cs @@ -0,0 +1,135 @@ +namespace TransactionProcessor.Transaction.DomainEvents +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Newtonsoft.Json; + using Shared.DomainDrivenDesign.EventSourcing; + + /// + /// + /// + /// + [JsonObject] + public class TransactionHasBeenCompletedEvent : DomainEvent + { + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + [ExcludeFromCodeCoverage] + public TransactionHasBeenCompletedEvent() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The aggregate identifier. + /// The event identifier. + /// The estate identifier. + /// The merchant identifier. + /// The response code. + /// The response message. + /// if set to true [is authorised]. + public TransactionHasBeenCompletedEvent(Guid aggregateId, + Guid eventId, + Guid estateId, + Guid merchantId, + String responseCode, + String responseMessage, + Boolean isAuthorised) : base(aggregateId, eventId) + { + this.TransactionId = aggregateId; + this.EstateId = estateId; + this.MerchantId = merchantId; + this.ResponseCode = responseCode; + this.ResponseMessage = responseMessage; + this.IsAuthorised = isAuthorised; + } + + #endregion + + #region Properties + + /// + /// Gets the estate identifier. + /// + /// + /// The estate identifier. + /// + [JsonProperty] + public Guid EstateId { get; private set; } + + /// + /// Gets a value indicating whether this instance is authorised. + /// + /// + /// true if this instance is authorised; otherwise, false. + /// + [JsonProperty] + public Boolean IsAuthorised { get; private set; } + + /// + /// Gets the merchant identifier. + /// + /// + /// The merchant identifier. + /// + [JsonProperty] + public Guid MerchantId { get; private set; } + + /// + /// Gets the response code. + /// + /// + /// The response code. + /// + [JsonProperty] + public String ResponseCode { get; private set; } + + /// + /// Gets the response message. + /// + /// + /// The response message. + /// + [JsonProperty] + public String ResponseMessage { get; private set; } + + /// + /// Gets the transaction identifier. + /// + /// + /// The transaction identifier. + /// + [JsonProperty] + public Guid TransactionId { get; private set; } + + #endregion + + #region Methods + + /// + /// Creates the specified aggregate identifier. + /// + /// The aggregate identifier. + /// The estate identifier. + /// The merchant identifier. + /// The response code. + /// The response message. + /// if set to true [is authorised]. + /// + public static TransactionHasBeenCompletedEvent Create(Guid aggregateId, + Guid estateId, + Guid merchantId, + String responseCode, + String responseMessage, + Boolean isAuthorised) + { + return new TransactionHasBeenCompletedEvent(aggregateId, Guid.NewGuid(), estateId, merchantId, responseCode, responseMessage, isAuthorised); + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenLocallyAuthorisedEvent.cs b/TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenLocallyAuthorisedEvent.cs new file mode 100644 index 00000000..730e53f8 --- /dev/null +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionHasBeenLocallyAuthorisedEvent.cs @@ -0,0 +1,135 @@ +namespace TransactionProcessor.Transaction.DomainEvents +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Newtonsoft.Json; + using Shared.DomainDrivenDesign.EventSourcing; + + /// + /// + /// + /// + [JsonObject] + public class TransactionHasBeenLocallyAuthorisedEvent : DomainEvent + { + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The aggregate identifier. + /// The event identifier. + /// The estate identifier. + /// The merchant identifier. + /// The authorisation code. + /// The response code. + /// The response message. + public TransactionHasBeenLocallyAuthorisedEvent(Guid aggregateId, + Guid eventId, + Guid estateId, + Guid merchantId, + String authorisationCode, + String responseCode, + String responseMessage) : base(aggregateId, eventId) + { + this.TransactionId = aggregateId; + this.EstateId = estateId; + this.MerchantId = merchantId; + this.AuthorisationCode = authorisationCode; + this.ResponseCode = responseCode; + this.ResponseMessage = responseMessage; + } + + /// + /// Initializes a new instance of the class. + /// + [ExcludeFromCodeCoverage] + public TransactionHasBeenLocallyAuthorisedEvent() + { + } + + #endregion + + #region Properties + + /// + /// Gets the authorisation code. + /// + /// + /// The authorisation code. + /// + [JsonProperty] + public String AuthorisationCode { get; private set; } + + /// + /// Gets the estate identifier. + /// + /// + /// The estate identifier. + /// + [JsonProperty] + public Guid EstateId { get; private set; } + + /// + /// Gets the merchant identifier. + /// + /// + /// The merchant identifier. + /// + [JsonProperty] + public Guid MerchantId { get; private set; } + + /// + /// Gets the response code. + /// + /// + /// The response code. + /// + [JsonProperty] + public String ResponseCode { get; private set; } + + /// + /// Gets the response message. + /// + /// + /// The response message. + /// + [JsonProperty] + public String ResponseMessage { get; private set; } + + /// + /// Gets the transaction identifier. + /// + /// + /// The transaction identifier. + /// + [JsonProperty] + public Guid TransactionId { get; private set; } + + #endregion + + #region Methods + + /// + /// Creates the specified aggregate identifier. + /// + /// The aggregate identifier. + /// The estate identifier. + /// The merchant identifier. + /// The authorisation code. + /// The response code. + /// The response message. + /// + public static TransactionHasBeenLocallyAuthorisedEvent Create(Guid aggregateId, + Guid estateId, + Guid merchantId, + String authorisationCode, + String responseCode, + String responseMessage) + { + return new TransactionHasBeenLocallyAuthorisedEvent(aggregateId, Guid.NewGuid(), estateId, merchantId, authorisationCode, responseCode, responseMessage); + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs b/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs new file mode 100644 index 00000000..72375625 --- /dev/null +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs @@ -0,0 +1,149 @@ +namespace TransactionProcessor.Transaction.DomainEvents +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Newtonsoft.Json; + using Shared.DomainDrivenDesign.EventSourcing; + + /// + /// + /// + /// + [JsonObject] + public class TransactionHasStartedEvent : DomainEvent + { + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + [ExcludeFromCodeCoverage] + public TransactionHasStartedEvent() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The aggregate identifier. + /// The event identifier. + /// The estate identifier. + /// The merchant identifier. + /// The transaction date time. + /// The transaction number. + /// Type of the transaction. + /// The imei number. + public TransactionHasStartedEvent(Guid aggregateId, + Guid eventId, + Guid estateId, + Guid merchantId, + DateTime transactionDateTime, + String transactionNumber, + String transactionType, + String imeiNumber) : base(aggregateId, eventId) + { + this.TransactionId = aggregateId; + this.EstateId = estateId; + this.MerchantId = merchantId; + this.TransactionDateTime = transactionDateTime; + this.TransactionNumber = transactionNumber; + this.TransactionType = transactionType; + this.ImeiNumber = imeiNumber; + } + + #endregion + + #region Properties + + /// + /// Gets the estate identifier. + /// + /// + /// The estate identifier. + /// + [JsonProperty] + public Guid EstateId { get; private set; } + + /// + /// Gets the imei number. + /// + /// + /// The imei number. + /// + [JsonProperty] + public String ImeiNumber { get; private set; } + + /// + /// Gets the merchant identifier. + /// + /// + /// The merchant identifier. + /// + [JsonProperty] + public Guid MerchantId { get; private set; } + + /// + /// Gets the transaction date time. + /// + /// + /// The transaction date time. + /// + [JsonProperty] + public DateTime TransactionDateTime { get; private set; } + + /// + /// Gets the transaction identifier. + /// + /// + /// The transaction identifier. + /// + [JsonProperty] + public Guid TransactionId { get; private set; } + + /// + /// Gets the transaction number. + /// + /// + /// The transaction number. + /// + [JsonProperty] + public String TransactionNumber { get; private set; } + + /// + /// Gets the type of the transaction. + /// + /// + /// The type of the transaction. + /// + [JsonProperty] + public String TransactionType { get; private set; } + + #endregion + + #region Methods + + /// + /// Creates the specified aggregate identifier. + /// + /// The aggregate identifier. + /// The estate identifier. + /// The merchant identifier. + /// The transaction date time. + /// The transaction number. + /// Type of the transaction. + /// The imei number. + /// + public static TransactionHasStartedEvent Create(Guid aggregateId, + Guid estateId, + Guid merchantId, + DateTime transactionDateTime, + String transactionNumber, + String transactionType, + String imeiNumber) + { + return new TransactionHasStartedEvent(aggregateId, Guid.NewGuid(), estateId, merchantId, transactionDateTime, transactionNumber, transactionType, imeiNumber); + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj b/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj new file mode 100644 index 00000000..efebda4b --- /dev/null +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.1 + + + + + + + diff --git a/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs b/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs new file mode 100644 index 00000000..c08e76e0 --- /dev/null +++ b/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TransactionProcessor.TransactionAggregate.Tests +{ + using Shouldly; + using Testing; + using Transaction.DomainEvents; + using Xunit; + + public class DomainEventTests + { + [Fact] + public void TransactionHasStartedEvent_CanBeCreated_IsCreated() + { + TransactionHasStartedEvent transactionHasStartedEvent = TransactionHasStartedEvent.Create(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.TransactionType, + TestData.IMEINumber); + transactionHasStartedEvent.ShouldNotBeNull(); + transactionHasStartedEvent.AggregateId.ShouldBe(TestData.TransactionId); + transactionHasStartedEvent.EventCreatedDateTime.ShouldNotBe(DateTime.MinValue); + transactionHasStartedEvent.EventId.ShouldNotBe(Guid.Empty); + transactionHasStartedEvent.TransactionId.ShouldBe(TestData.TransactionId); + transactionHasStartedEvent.EstateId.ShouldBe(TestData.EstateId); + transactionHasStartedEvent.ImeiNumber.ShouldBe(TestData.IMEINumber); + transactionHasStartedEvent.MerchantId.ShouldBe(TestData.MerchantId); + transactionHasStartedEvent.TransactionDateTime.ShouldBe(TestData.TransactionDateTime); + transactionHasStartedEvent.TransactionNumber.ShouldBe(TestData.TransactionNumber); + transactionHasStartedEvent.TransactionType.ShouldBe(TestData.TransactionType); + } + + [Fact] + public void TransactionHasBeenLocallyAuthorisedEvent_CanBeCreated_IsCreated() + { + TransactionHasBeenLocallyAuthorisedEvent transactionHasBeenLocallyAuthorisedEvent = + TransactionHasBeenLocallyAuthorisedEvent.Create(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.AuthorisationCode, + TestData.ResponseCode, + TestData.ResponseMessage); + + transactionHasBeenLocallyAuthorisedEvent.ShouldNotBeNull(); + transactionHasBeenLocallyAuthorisedEvent.AggregateId.ShouldBe(TestData.TransactionId); + transactionHasBeenLocallyAuthorisedEvent.EventCreatedDateTime.ShouldNotBe(DateTime.MinValue); + transactionHasBeenLocallyAuthorisedEvent.EventId.ShouldNotBe(Guid.Empty); + transactionHasBeenLocallyAuthorisedEvent.TransactionId.ShouldBe(TestData.TransactionId); + transactionHasBeenLocallyAuthorisedEvent.EstateId.ShouldBe(TestData.EstateId); + transactionHasBeenLocallyAuthorisedEvent.MerchantId.ShouldBe(TestData.MerchantId); + transactionHasBeenLocallyAuthorisedEvent.AuthorisationCode.ShouldBe(TestData.AuthorisationCode); + transactionHasBeenLocallyAuthorisedEvent.ResponseCode.ShouldBe(TestData.ResponseCode); + transactionHasBeenLocallyAuthorisedEvent.ResponseMessage.ShouldBe(TestData.ResponseMessage); + } + + [Fact] + public void TransactionHasBeenCompletedEvent_CanBeCreated_IsCreated() + { + TransactionHasBeenCompletedEvent transactionHasBeenCompletedEvent = TransactionHasBeenCompletedEvent.Create(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.ResponseCode, + TestData.ResponseMessage, + TestData.IsAuthorised); + + transactionHasBeenCompletedEvent.ShouldNotBeNull(); + transactionHasBeenCompletedEvent.AggregateId.ShouldBe(TestData.TransactionId); + transactionHasBeenCompletedEvent.EventCreatedDateTime.ShouldNotBe(DateTime.MinValue); + transactionHasBeenCompletedEvent.EventId.ShouldNotBe(Guid.Empty); + transactionHasBeenCompletedEvent.TransactionId.ShouldBe(TestData.TransactionId); + transactionHasBeenCompletedEvent.EstateId.ShouldBe(TestData.EstateId); + transactionHasBeenCompletedEvent.MerchantId.ShouldBe(TestData.MerchantId); + transactionHasBeenCompletedEvent.ResponseCode.ShouldBe(TestData.ResponseCode); + transactionHasBeenCompletedEvent.ResponseMessage.ShouldBe(TestData.ResponseMessage); + transactionHasBeenCompletedEvent.IsAuthorised.ShouldBe(TestData.IsAuthorised); + } + + } +} diff --git a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs new file mode 100644 index 00000000..61df6af4 --- /dev/null +++ b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs @@ -0,0 +1,194 @@ +using System; +using TransactionProcessor.Testing; +using Xunit; + +namespace TransactionProcessor.TransactionAggregate.Tests +{ + using Shouldly; + + public class TransactionAggregateTests + { + [Fact] + public void TransactionAggregate_CanBeCreated_IsCreated() + { + TransactionAggregate aggregate = TransactionAggregate.Create(TestData.TransactionId); + + aggregate.AggregateId.ShouldBe(TestData.TransactionId); + } + + [Fact] + public void TransactionAggregate_StartTransaction_TransactionIsStarted() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + + transactionAggregate.IsStarted.ShouldBeTrue(); + transactionAggregate.TransactionDateTime.ShouldBe(TestData.TransactionDateTime); + transactionAggregate.TransactionNumber.ShouldBe(TestData.TransactionNumber); + transactionAggregate.TransactionType.ShouldBe(TestData.TransactionType); + transactionAggregate.EstateId.ShouldBe(TestData.EstateId); + transactionAggregate.MerchantId.ShouldBe(TestData.MerchantId); + transactionAggregate.IMEINumber.ShouldBe(TestData.IMEINumber); + } + + [Fact] + public void TransactionAggregate_StartTransaction_TransactionAlreadyStarted_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + + Should.Throw(() => + { + transactionAggregate.StartTransaction(TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.TransactionType, + TestData.EstateId, + TestData.MerchantId, + TestData.IMEINumber); + }); + } + + [Fact] + public void TransactionAggregate_StartTransaction_TransactionAlreadyCompleted_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + transactionAggregate.CompleteTransaction(); + + Should.Throw(() => + { + transactionAggregate.StartTransaction(TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.TransactionType, + TestData.EstateId, + TestData.MerchantId, + TestData.IMEINumber); + }); + } + + [Theory] + [InlineData(false, "0001", "Logon", true, true, "1234567890" )] + [InlineData(true, "", "Logon", true, true, "1234567890")] + [InlineData(true, null, "Logon", true, true, "1234567890")] + [InlineData(true, "ABCD", "Logon", true, true, "1234567890")] + [InlineData(true, "0001", "", true, true, "1234567890")] + [InlineData(true, "0001", null, true, true, "1234567890")] + [InlineData(true, "0001", "Invalid", true, true, "1234567890")] + [InlineData(true, "0001", "Logon", false, true, "1234567890")] + [InlineData(true, "0001", "Logon", true, false, "1234567890")] + [InlineData(true, "0001", "Logon", true, true, "")] + [InlineData(true, "0001", "Logon", true, true, null)] + [InlineData(true, "0001", "Logon", true, true, "ABCD")] + public void TransactionAggregate_StartTransaction_InvalidData_ErrorThrown(Boolean validTransactionDateTime, String transactionNumber, String transactionType, Boolean validEstateId, Boolean validMerchantId, String imeiNumber) + { + DateTime transactionDateTime = validTransactionDateTime ? TestData.TransactionDateTime : DateTime.MinValue; + Guid estateId = validEstateId ? TestData.EstateId : Guid.Empty; + Guid merchantId = validMerchantId ? TestData.MerchantId : Guid.Empty; + + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + + Should.Throw(() => + { + transactionAggregate.StartTransaction(transactionDateTime, + transactionNumber, + transactionType, + estateId, + merchantId, + imeiNumber); + }); + } + + [Fact] + public void TransactionAggregate_AuthoriseTransactionLocally_TransactionIsAuthorised() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + + transactionAggregate.IsLocallyAuthorised.ShouldBeTrue(); + transactionAggregate.IsAuthorised.ShouldBeFalse(); + transactionAggregate.AuthorisationCode.ShouldBe(TestData.AuthorisationCode); + transactionAggregate.ResponseCode.ShouldBe(TestData.ResponseCode); + transactionAggregate.ResponseMessage.ShouldBe(TestData.ResponseMessage); + } + + [Fact] + public void TransactionAggregate_AuthoriseTransactionLocally_TransactionNotStarted_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + + Should.Throw(() => + { + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, + TestData.ResponseCode, + TestData.ResponseMessage); + }); + } + + [Fact] + public void TransactionAggregate_AuthoriseTransactionLocally_TransactionAlreadyAuthorised_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + + Should.Throw(() => + { + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, + TestData.ResponseCode, + TestData.ResponseMessage); + }); + } + + [Fact] + public void TransactionAggregate_CompleteTransaction_TransactionIsCompleted() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + transactionAggregate.CompleteTransaction(); + + transactionAggregate.IsStarted.ShouldBeFalse(); + transactionAggregate.IsCompleted.ShouldBeTrue(); + } + + [Fact] + public void TransactionAggregate_CompleteTransaction_TransactionNotStarted_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + + Should.Throw(() => + { + transactionAggregate.CompleteTransaction(); + }); + } + + [Fact] + public void TransactionAggregate_CompleteTransaction_TransactionNotAuthorised_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + + Should.Throw(() => + { + transactionAggregate.CompleteTransaction(); + }); + } + [Fact] + public void TransactionAggregate_CompleteTransaction_TransactionAlreadyCompleted_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionType, TestData.EstateId, TestData.MerchantId, TestData.IMEINumber); + transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); + transactionAggregate.CompleteTransaction(); + + Should.Throw(() => + { + transactionAggregate.CompleteTransaction(); + }); + } + + } +} diff --git a/TransactionProcessor.TransactionAggregate.Tests/TransactionProcessor.TransactionAggregate.Tests.csproj b/TransactionProcessor.TransactionAggregate.Tests/TransactionProcessor.TransactionAggregate.Tests.csproj new file mode 100644 index 00000000..9d386d50 --- /dev/null +++ b/TransactionProcessor.TransactionAggregate.Tests/TransactionProcessor.TransactionAggregate.Tests.csproj @@ -0,0 +1,28 @@ + + + + netcoreapp3.0 + None + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs new file mode 100644 index 00000000..4eb08eba --- /dev/null +++ b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs @@ -0,0 +1,242 @@ +namespace TransactionProcessor.TransactionAggregate +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Shared.DomainDrivenDesign.EventSourcing; + using Shared.DomainDrivenDesign.EventStore; + using Shared.General; + using Transaction.DomainEvents; + + /// + /// + /// + /// + public class TransactionAggregate : Aggregate + { + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + [ExcludeFromCodeCoverage] + public TransactionAggregate() + { + // Nothing here + } + + /// + /// Initializes a new instance of the class. + /// + /// The aggregate identifier. + private TransactionAggregate(Guid aggregateId) + { + Guard.ThrowIfInvalidGuid(aggregateId, "Aggregate Id cannot be an Empty Guid"); + + this.AggregateId = aggregateId; + } + + #endregion + + #region Methods + + /// + /// Authorises the transaction. + /// + /// The authorisation code. + /// The response code. + /// The response message. + public void AuthoriseTransactionLocally(String authorisationCode, + String responseCode, + String responseMessage) + { + this.CheckTransactionHasBeenStarted(); + this.CheckTransactionNotAlreadyAuthorised(); + TransactionHasBeenLocallyAuthorisedEvent transactionHasBeenLocallyAuthorisedEvent = TransactionHasBeenLocallyAuthorisedEvent.Create(this.AggregateId, this.EstateId, this.MerchantId, authorisationCode, responseCode, responseMessage); + + this.ApplyAndPend(transactionHasBeenLocallyAuthorisedEvent); + + + } + + private void CheckTransactionNotAlreadyAuthorised() + { + if (this.IsLocallyAuthorised || this.IsAuthorised) + { + String authtype = this.IsLocallyAuthorised ? " locally " : " "; + throw new InvalidOperationException($"Transaction [{this.AggregateId}] has already been{authtype}authorised"); + } + } + + private void CheckTransactionHasBeenStarted() + { + if (this.IsStarted == false) + { + throw new InvalidOperationException($"Transaction [{this.AggregateId}] has not been started"); + } + } + + /// + /// Completes the transaction. + /// + public void CompleteTransaction() + { + this.CheckTransactionHasBeenStarted(); + this.CheckTransactionHasBeenAuthorised(); + this.CheckTransactionNotAlreadyCompleted(); + + TransactionHasBeenCompletedEvent transactionHasBeenCompletedEvent = TransactionHasBeenCompletedEvent.Create(this.AggregateId, this.EstateId, this.MerchantId, + this.ResponseCode, this.ResponseMessage, + true); + + this.ApplyAndPend(transactionHasBeenCompletedEvent); + } + + private void CheckTransactionHasBeenAuthorised() + { + if (this.IsAuthorised == false && this.IsLocallyAuthorised == false) + { + throw new InvalidOperationException($"Transaction [{this.AggregateId}] has not been authorised"); + } + } + + /// + /// Creates the specified aggregate identifier. + /// + /// The aggregate identifier. + /// + public static TransactionAggregate Create(Guid aggregateId) + { + return new TransactionAggregate(aggregateId); + } + + /// + /// Declines the transaction. + /// + public void DeclineTransaction() + { + } + + public DateTime TransactionDateTime { get; private set; } + public String TransactionNumber { get; private set; } + public String TransactionType { get; private set; } + public Guid EstateId { get; private set; } + public Guid MerchantId { get; private set; } + public String IMEINumber { get; private set; } + public Boolean IsStarted { get; private set; } + public Boolean IsCompleted { get; private set; } + + public Boolean IsLocallyAuthorised { get; private set; } + public String AuthorisationCode { get; private set; } + public String ResponseCode { get; private set; } + public String ResponseMessage { get; private set; } + public Boolean IsAuthorised { get; private set; } + /// + /// Starts the transaction. + /// + /// The transaction date time. + /// The transaction number. + /// Type of the transaction. + /// The estate identifier. + /// The merchant identifier. + /// The imei number. + public void StartTransaction(DateTime transactionDateTime, + String transactionNumber, + String transactionType, + Guid estateId, + Guid merchantId, + String imeiNumber) + { + Guard.ThrowIfInvalidDate(transactionDateTime, typeof(ArgumentException), $"Transaction Date Time must not be [{DateTime.MinValue}]"); + Guard.ThrowIfNullOrEmpty(transactionNumber, typeof(ArgumentException), "Transaction Number must not be null or empty"); + if (Int32.TryParse(transactionNumber, out Int32 txnnumber) == false) + { + throw new ArgumentException("Transaction Number must be numeric"); + } + Guard.ThrowIfNullOrEmpty(transactionType, typeof(ArgumentException), "Transaction Type must not be null or empty"); + + // Temporary validation until using enum + if (transactionType != "Logon") + { + throw new ArgumentException($"Invalid Transaction Type [{transactionType}]"); + } + Guard.ThrowIfInvalidGuid(estateId, typeof(ArgumentException), $"Estate Id must not be [{Guid.Empty}]"); + Guard.ThrowIfInvalidGuid(merchantId, typeof(ArgumentException), $"Merchant Id must not be [{Guid.Empty}]"); + Guard.ThrowIfNullOrEmpty(imeiNumber, typeof(ArgumentException), "IMEI Number must not be null or empty"); + if (Int32.TryParse(imeiNumber, out Int32 imei) == false) + { + throw new ArgumentException("IMEI Number must be numeric"); + } + + this.CheckTransactionNotAlreadyStarted(); + this.CheckTransactionNotAlreadyCompleted(); + TransactionHasStartedEvent transactionHasStartedEvent = TransactionHasStartedEvent.Create(this.AggregateId, estateId, merchantId, transactionDateTime, transactionNumber,transactionType, imeiNumber); + + this.ApplyAndPend(transactionHasStartedEvent); + } + + private void CheckTransactionNotAlreadyStarted() + { + if (this.IsStarted) + { + throw new InvalidOperationException($"Transaction Id [{this.AggregateId}] has already been started"); + } + } + + private void CheckTransactionNotAlreadyCompleted() + { + if (this.IsCompleted) + { + throw new InvalidOperationException($"Transaction Id [{this.AggregateId}] has already been completed"); + } + } + + /// + /// Gets the metadata. + /// + /// + [ExcludeFromCodeCoverage] + protected override Object GetMetadata() + { + return new + { + EstateId = this.EstateId + }; + } + + /// + /// Plays the event. + /// + /// The domain event. + protected override void PlayEvent(DomainEvent domainEvent) + { + this.PlayEvent((dynamic)domainEvent); + } + + private void PlayEvent(TransactionHasStartedEvent domainEvent) + { + this.MerchantId = domainEvent.MerchantId; + this.EstateId = domainEvent.EstateId; + this.IMEINumber = domainEvent.ImeiNumber; + this.IsStarted = true; + this.TransactionDateTime = domainEvent.TransactionDateTime; + this.TransactionNumber = domainEvent.TransactionNumber; + this.TransactionType = domainEvent.TransactionType; + } + + private void PlayEvent(TransactionHasBeenLocallyAuthorisedEvent domainEvent) + { + this.IsLocallyAuthorised = true; + this.ResponseMessage = domainEvent.ResponseMessage; + this.ResponseCode = domainEvent.ResponseCode; + this.AuthorisationCode = domainEvent.AuthorisationCode; + } + + private void PlayEvent(TransactionHasBeenCompletedEvent domainEvent) + { + this.IsStarted = false; // Transaction has reached its final state + this.IsCompleted = true; + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj b/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj new file mode 100644 index 00000000..02f1e4f2 --- /dev/null +++ b/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp3.0 + + + + + + + + + + + diff --git a/TransactionProcessor.sln b/TransactionProcessor.sln index 25eabeec..486903cf 100644 --- a/TransactionProcessor.sln +++ b/TransactionProcessor.sln @@ -15,11 +15,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.Busine EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.Models", "TransactionProcessor.Models\TransactionProcessor.Models.csproj", "{97B646C6-7BF7-4F84-A74A-10E50A70CB91}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessor.Tests", "TransactionProcessor.Tests\TransactionProcessor.Tests.csproj", "{99D19D28-C5ED-409B-9A34-DCCBCD8A9532}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.Tests", "TransactionProcessor.Tests\TransactionProcessor.Tests.csproj", "{99D19D28-C5ED-409B-9A34-DCCBCD8A9532}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessor.Testing", "TransactionProcessor.Testing\TransactionProcessor.Testing.csproj", "{7BDDFAA7-0391-4672-94F1-6817E55020FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.Testing", "TransactionProcessor.Testing\TransactionProcessor.Testing.csproj", "{7BDDFAA7-0391-4672-94F1-6817E55020FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionProcessor.BusinessLogic.Tests", "TransactionProcessor.BusinessLogic.Tests\TransactionProcessor.BusinessLogic.Tests.csproj", "{8EAA1681-4095-473B-900B-C09FA823ACD7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.BusinessLogic.Tests", "TransactionProcessor.BusinessLogic.Tests\TransactionProcessor.BusinessLogic.Tests.csproj", "{8EAA1681-4095-473B-900B-C09FA823ACD7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.TransactionAggregate", "TransactionProcessor.TransactionAgrgegate\TransactionProcessor.TransactionAggregate.csproj", "{BE2AF4BD-AED2-4723-AC25-3051C870CAC2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.Transaction.DomainEvents", "TransactionProcessor.Transaction.DomainEvents\TransactionProcessor.Transaction.DomainEvents.csproj", "{AC0E260E-47CC-4DA7-BE62-0714F9266AEA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionProcessor.TransactionAggregate.Tests", "TransactionProcessor.TransactionAggregate.Tests\TransactionProcessor.TransactionAggregate.Tests.csproj", "{69BE1042-5AB9-420B-9A27-E2F1ADFC4E65}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -55,6 +61,18 @@ Global {8EAA1681-4095-473B-900B-C09FA823ACD7}.Debug|Any CPU.Build.0 = Debug|Any CPU {8EAA1681-4095-473B-900B-C09FA823ACD7}.Release|Any CPU.ActiveCfg = Release|Any CPU {8EAA1681-4095-473B-900B-C09FA823ACD7}.Release|Any CPU.Build.0 = Release|Any CPU + {BE2AF4BD-AED2-4723-AC25-3051C870CAC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE2AF4BD-AED2-4723-AC25-3051C870CAC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE2AF4BD-AED2-4723-AC25-3051C870CAC2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE2AF4BD-AED2-4723-AC25-3051C870CAC2}.Release|Any CPU.Build.0 = Release|Any CPU + {AC0E260E-47CC-4DA7-BE62-0714F9266AEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC0E260E-47CC-4DA7-BE62-0714F9266AEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC0E260E-47CC-4DA7-BE62-0714F9266AEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC0E260E-47CC-4DA7-BE62-0714F9266AEA}.Release|Any CPU.Build.0 = Release|Any CPU + {69BE1042-5AB9-420B-9A27-E2F1ADFC4E65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {69BE1042-5AB9-420B-9A27-E2F1ADFC4E65}.Debug|Any CPU.Build.0 = Debug|Any CPU + {69BE1042-5AB9-420B-9A27-E2F1ADFC4E65}.Release|Any CPU.ActiveCfg = Release|Any CPU + {69BE1042-5AB9-420B-9A27-E2F1ADFC4E65}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -67,6 +85,9 @@ Global {99D19D28-C5ED-409B-9A34-DCCBCD8A9532} = {71B30DC4-AB27-4D30-8481-B4C326D074CB} {7BDDFAA7-0391-4672-94F1-6817E55020FD} = {71B30DC4-AB27-4D30-8481-B4C326D074CB} {8EAA1681-4095-473B-900B-C09FA823ACD7} = {71B30DC4-AB27-4D30-8481-B4C326D074CB} + {BE2AF4BD-AED2-4723-AC25-3051C870CAC2} = {749ADE74-A6F0-4469-A638-8FD7E82A8667} + {AC0E260E-47CC-4DA7-BE62-0714F9266AEA} = {749ADE74-A6F0-4469-A638-8FD7E82A8667} + {69BE1042-5AB9-420B-9A27-E2F1ADFC4E65} = {71B30DC4-AB27-4D30-8481-B4C326D074CB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {193D13DE-424B-4D50-B674-01F9E4CC2CA9} diff --git a/TransactionProcessor/Controllers/TransactionController.cs b/TransactionProcessor/Controllers/TransactionController.cs index 739a3f54..cb1414ed 100644 --- a/TransactionProcessor/Controllers/TransactionController.cs +++ b/TransactionProcessor/Controllers/TransactionController.cs @@ -63,7 +63,10 @@ public TransactionController(ICommandRouter commandRouter, public async Task LogonTransaction([FromBody] LogonTransactionRequest logonTransactionRequest, CancellationToken cancellationToken) { - ProcessLogonTransactionCommand command = ProcessLogonTransactionCommand.Create(logonTransactionRequest.EstateId, + Guid transactionId = Guid.NewGuid(); + + ProcessLogonTransactionCommand command = ProcessLogonTransactionCommand.Create( transactionId, + logonTransactionRequest.EstateId, logonTransactionRequest.MerchantId, logonTransactionRequest.IMEINumber, logonTransactionRequest.TransactionType, diff --git a/TransactionProcessor/Startup.cs b/TransactionProcessor/Startup.cs index eb556714..ad5a8033 100644 --- a/TransactionProcessor/Startup.cs +++ b/TransactionProcessor/Startup.cs @@ -19,6 +19,7 @@ namespace TransactionProcessor using BusinessLogic.CommandHandlers; using BusinessLogic.Services; using Common; + using EventStore.ClientAPI; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.Options; @@ -26,10 +27,15 @@ namespace TransactionProcessor using Newtonsoft.Json.Serialization; using NLog.Extensions.Logging; using Shared.DomainDrivenDesign.CommandHandling; + using Shared.DomainDrivenDesign.EventStore; + using Shared.EntityFramework.ConnectionStringConfiguration; + using Shared.EventStore.EventStore; using Shared.Extensions; using Shared.General; + using Shared.Repositories; using Swashbuckle.AspNetCore.Filters; using Swashbuckle.AspNetCore.SwaggerGen; + using ILogger = Microsoft.Extensions.Logging.ILogger; [ExcludeFromCodeCoverage] public class Startup @@ -58,6 +64,50 @@ public void ConfigureServices(IServiceCollection services) public void ConfigureContainer(ContainerBuilder builder) { + ConfigurationReader.Initialise(Startup.Configuration); + String connString = Startup.Configuration.GetValue("EventStoreSettings:ConnectionString"); + String connectionName = Startup.Configuration.GetValue("EventStoreSettings:ConnectionName"); + Int32 httpPort = Startup.Configuration.GetValue("EventStoreSettings:HttpPort"); + + Boolean useConnectionStringConfig = Boolean.Parse(ConfigurationReader.GetValue("AppSettings", "UseConnectionStringConfig")); + EventStoreConnectionSettings settings = EventStoreConnectionSettings.Create(connString, connectionName, httpPort); + builder.RegisterInstance(settings); + + Func eventStoreConnectionFunc = (connectionSettings) => + { + return EventStoreConnection.Create(connectionSettings.ConnectionString); + }; + + builder.RegisterInstance>(eventStoreConnectionFunc); + + Func eventStoreContextFunc = (connectionString) => + { + EventStoreConnectionSettings connectionSettings = EventStoreConnectionSettings.Create(connectionString, connectionName, httpPort); + + IEventStoreContext context = new EventStoreContext(connectionSettings, eventStoreConnectionFunc); + + return context; + }; + + builder.RegisterInstance>(eventStoreContextFunc); + + if (useConnectionStringConfig) + { + String connectionStringConfigurationConnString = ConfigurationReader.GetConnectionString("ConnectionStringConfiguration"); + builder.Register(c => new ConnectionStringConfigurationContext(connectionStringConfigurationConnString)).InstancePerDependency(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().UsingConstructor(typeof(Func), typeof(IConnectionStringConfigurationRepository)).SingleInstance(); + } + else + { + builder.RegisterType().As().UsingConstructor(typeof(IEventStoreContext)).SingleInstance(); + // TODO: Once we have a Read Model + //this.RegisterType().Singleton(); + } + + builder.RegisterType().As(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType>().As>().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); } diff --git a/TransactionProcessor/appsettings.json b/TransactionProcessor/appsettings.json index d9d9a9bf..8fead832 100644 --- a/TransactionProcessor/appsettings.json +++ b/TransactionProcessor/appsettings.json @@ -6,5 +6,20 @@ "Microsoft.Hosting.Lifetime": "Information" } }, + "EventStoreSettings": { + "ConnectionString": "ConnectTo=tcp://admin:changeit@192.168.1.132:1113;VerboseLogging=true;", + "ConnectionName": "Estate Management", + "HttpPort": 2113, + "START_PROJECTIONS": false, + "ContinuousProjectionsFolder": "" + }, + "ConnectionStrings": { + "ConnectionStringConfiguration": "server=localhost;database=ConnectionStringConfiguration;user id=sa;password=sp1ttal" + }, + "AppSettings": { + "HandlerEventTypesToSilentlyHandle": { + }, + "UseConnectionStringConfig": false + }, "AllowedHosts": "*" -} +} \ No newline at end of file From 0b45959327d1517f388343450fbd28f9aa8d64d1 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Mon, 2 Dec 2019 21:05:14 +0000 Subject: [PATCH 2/2] Minor test update --- .../General/BootstrapperTests.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/TransactionProcessor.Tests/General/BootstrapperTests.cs b/TransactionProcessor.Tests/General/BootstrapperTests.cs index 20f6ebb6..bd4cb7f1 100644 --- a/TransactionProcessor.Tests/General/BootstrapperTests.cs +++ b/TransactionProcessor.Tests/General/BootstrapperTests.cs @@ -6,6 +6,7 @@ using Autofac; using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; @@ -32,7 +33,7 @@ public void VerifyBootstrapperIsValid() Startup s = new Startup(hostingEnvironment.Object); s.ConfigureServices(services); - //Startup.Configuration = this.SetupMemoryConfiguration(); + Startup.Configuration = this.SetupMemoryConfiguration(); this.AddTestRegistrations(services, hostingEnvironment.Object); ContainerBuilder builder = new ContainerBuilder(); @@ -48,21 +49,21 @@ public void VerifyBootstrapperIsValid() } } - //private IConfigurationRoot SetupMemoryConfiguration() - //{ - // Dictionary configuration = new Dictionary(); + private IConfigurationRoot SetupMemoryConfiguration() + { + Dictionary configuration = new Dictionary(); - // IConfigurationBuilder builder = new ConfigurationBuilder(); + IConfigurationBuilder builder = new ConfigurationBuilder(); - // configuration.Add("EventStoreSettings:ConnectionString", "ConnectTo=tcp://admin:changeit@127.0.0.1:1112;VerboseLogging=true;"); - // configuration.Add("EventStoreSettings:ConnectionName", "UnitTestConnection"); - // configuration.Add("EventStoreSettings:HttpPort", "2113"); - // configuration.Add("AppSettings:UseConnectionStringConfig", "false"); + configuration.Add("EventStoreSettings:ConnectionString", "ConnectTo=tcp://admin:changeit@127.0.0.1:1112;VerboseLogging=true;"); + configuration.Add("EventStoreSettings:ConnectionName", "UnitTestConnection"); + configuration.Add("EventStoreSettings:HttpPort", "2113"); + configuration.Add("AppSettings:UseConnectionStringConfig", "false"); - // builder.AddInMemoryCollection(configuration); + builder.AddInMemoryCollection(configuration); - // return builder.Build(); - //} + return builder.Build(); + } /// /// Adds the test registrations.