diff --git a/Directory.Packages.props b/Directory.Packages.props
index 01b27f5..b542dbe 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,8 +4,8 @@
-
-
+
+
@@ -16,7 +16,7 @@
-
+
@@ -39,14 +39,14 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs
index 4fdc0ec..4c61174 100644
--- a/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs
+++ b/FileProcessor.BusinessLogic/Services/FileProcessorDomainService.cs
@@ -398,55 +398,13 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran
return stateResult;
}
- Int32 transactionNumber = Interlocked.Increment(ref TransactionNumber);
-
- Result<(Guid ContractId, Guid OperatorId, Guid ProductId, String MerchantDevice)> detailsForTransaction = await this.GetDetailsForTransaction(cancellationToken,
- fileDetails,
- fileProfile,
- processingContext.OperatorName,
- processingContext);
- if (detailsForTransaction.IsFailed)
- return ResultHelpers.CreateFailure(detailsForTransaction);
-
- processingContext.Stage = FileLineProcessingStage.TransactionDetailsResolved;
- Result saleResult = await this.SendSaleTransaction(fileDetails,
- detailsForTransaction,
- metadataResult.Data,
- transactionNumber,
- processingContext,
- cancellationToken);
- processingContext.TransactionDispatchSucceeded = saleResult.IsSuccess;
- if (saleResult.IsSuccess)
- processingContext.ResponseCode = saleResult.Data.ResponseCode;
-
- // A failed dispatch has no definitive processor response. Leave the line unmodified so
- // the file processing workflow can retry it with the same file and line identity.
- if (saleResult.IsFailed)
- {
- stateResult = fileAggregate.RecordTransactionDispatchFailure(command.LineNumber,
- transactionNumber,
- processingContext.TransactionDispatchFailureType,
- DateTime.UtcNow);
- if (stateResult.IsFailed)
- return stateResult;
-
- dispatchFailureResult = ResultHelpers.CreateFailure(saleResult);
- processingContext.Stage = FileLineProcessingStage.TransactionDispatchAttemptPersisted;
- return Result.Success();
- }
-
- processingContext.Stage = FileLineProcessingStage.FileLineStateUpdate;
- stateResult = saleResult.Data.ResponseCode == "0000"
- ? fileAggregate.RecordFileLineAsSuccessful(command.LineNumber, saleResult.Data.TransactionId)
- : fileAggregate.RecordFileLineAsFailed(command.LineNumber, saleResult.Data.TransactionId, saleResult.Data.ResponseCode, saleResult.Data.ResponseMessage);
-
- ProcessingResult processingResult = saleResult.IsSuccess && saleResult.Data.ResponseCode == "0000"
- ? ProcessingResult.Successful
- : ProcessingResult.Failed;
- FileLineProcessingDiagnostics.LineStateDetermined(processingContext, processingResult);
- if (stateResult.IsSuccess)
- processingContext.Stage = FileLineProcessingStage.FileLineStatePersisted;
-
+ (stateResult, dispatchFailureResult) = await this.ProcessTransaction(fileAggregate,
+ command,
+ fileDetails,
+ fileProfile,
+ metadataResult.Data,
+ processingContext,
+ cancellationToken);
return stateResult;
}, command.FileId, cancellationToken);
@@ -466,6 +424,65 @@ public async Task ProcessTransactionForFileLine(FileCommands.ProcessTran
return result;
}
+ private async Task<(Result StateResult, Result DispatchFailureResult)> ProcessTransaction(FileAggregate fileAggregate,
+ FileCommands.ProcessTransactionForFileLineCommand command,
+ FileDetails fileDetails,
+ FileProfileModel fileProfile,
+ Dictionary transactionMetadata,
+ FileLineProcessingContext processingContext,
+ CancellationToken cancellationToken)
+ {
+ Int32 transactionNumber = Interlocked.Increment(ref TransactionNumber);
+
+ Result<(Guid ContractId, Guid OperatorId, Guid ProductId, String MerchantDevice)> detailsForTransaction = await this.GetDetailsForTransaction(cancellationToken,
+ fileDetails,
+ fileProfile,
+ processingContext.OperatorName,
+ processingContext);
+ if (detailsForTransaction.IsFailed)
+ return (ResultHelpers.CreateFailure(detailsForTransaction), null);
+
+ processingContext.Stage = FileLineProcessingStage.TransactionDetailsResolved;
+ Result saleResult = await this.SendSaleTransaction(fileDetails,
+ detailsForTransaction,
+ transactionMetadata,
+ transactionNumber,
+ processingContext,
+ cancellationToken);
+ processingContext.TransactionDispatchSucceeded = saleResult.IsSuccess;
+ if (saleResult.IsSuccess)
+ processingContext.ResponseCode = saleResult.Data.ResponseCode;
+
+ // A failed dispatch has no definitive processor response. Leave the line unmodified so
+ // the file processing workflow can retry it with the same file and line identity.
+ if (saleResult.IsFailed)
+ {
+ Result stateResult = fileAggregate.RecordTransactionDispatchFailure(command.LineNumber,
+ transactionNumber,
+ processingContext.TransactionDispatchFailureType,
+ DateTime.UtcNow);
+ if (stateResult.IsFailed)
+ return (stateResult, null);
+
+ processingContext.Stage = FileLineProcessingStage.TransactionDispatchAttemptPersisted;
+ return (Result.Success(), ResultHelpers.CreateFailure(saleResult));
+ }
+
+ processingContext.Stage = FileLineProcessingStage.FileLineStateUpdate;
+ Result stateUpdateResult = saleResult.Data.ResponseCode == "0000"
+ ? fileAggregate.RecordFileLineAsSuccessful(command.LineNumber, saleResult.Data.TransactionId)
+ : fileAggregate.RecordFileLineAsFailed(command.LineNumber, saleResult.Data.TransactionId, saleResult.Data.ResponseCode, saleResult.Data.ResponseMessage);
+
+ ProcessingResult processingResult = saleResult.Data.ResponseCode == "0000"
+ ? ProcessingResult.Successful
+ : ProcessingResult.Failed;
+ FileLineProcessingDiagnostics.LineStateDetermined(processingContext, processingResult);
+ if (stateUpdateResult.IsSuccess)
+ processingContext.Stage = FileLineProcessingStage.FileLineStatePersisted;
+
+ return (stateUpdateResult, null);
+ }
+
private Result> BuildTransactionMetadata(FileCommands.ProcessTransactionForFileLineCommand command,
FileLine fileLine,
FileProfileModel fileProfile,
diff --git a/FileProcessor.IntegrationTests/Common/DockerHelper.cs b/FileProcessor.IntegrationTests/Common/DockerHelper.cs
index 8896398..262c883 100644
--- a/FileProcessor.IntegrationTests/Common/DockerHelper.cs
+++ b/FileProcessor.IntegrationTests/Common/DockerHelper.cs
@@ -11,6 +11,7 @@ namespace FileProcessor.IntegrationTests.Common
using Shared.IntegrationTesting;
using Shared.Serialisation;
using System.Net.Http;
+ using System.Threading;
using TestHosts.Clients;
using TransactionProcessor.Client;
@@ -79,7 +80,9 @@ public override ContainerBuilder SetupFileProcessorContainer() {
this.AdditionalVariables[ContainerType.FileProcessor] = variables;
return base.SetupFileProcessorContainer();
}
-
+
+ public String AccessToken;
+
public override async Task StartContainersForScenarioRun(String scenarioName, DockerServices dockerServices){
await base.StartContainersForScenarioRun(scenarioName, dockerServices);
@@ -116,6 +119,13 @@ public override async Task StartContainersForScenarioRun(String scenarioName, Do
this.AgencyBankingClient = new AgencyBankingClient(TestHostServiceBaseAddressResolver, httpClient, Serialise_CamelCase, this.Deserialise_CamelCase);
this.ProjectionManagementClient = new EventStoreProjectionManagementClient(ConfigureEventStoreSettings());
+
+ SimpleResults.Result bootstrapToken = await this.SecurityServiceClient.GetToken("management-bootstrap", "management-bootstrap-secret", CancellationToken.None);
+ if (bootstrapToken.IsFailed || String.IsNullOrWhiteSpace(bootstrapToken.Data?.AccessToken))
+ {
+ throw new InvalidOperationException("Unable to obtain the integration-test management bootstrap token.");
+ }
+ this.AccessToken = bootstrapToken.Data.AccessToken;
}
String Serialise(Object arg)
diff --git a/FileProcessor.IntegrationTests/Steps/SharedSteps.cs b/FileProcessor.IntegrationTests/Steps/SharedSteps.cs
index 2c83ebb..1af950b 100644
--- a/FileProcessor.IntegrationTests/Steps/SharedSteps.cs
+++ b/FileProcessor.IntegrationTests/Steps/SharedSteps.cs
@@ -48,7 +48,7 @@ public SharedSteps(ScenarioContext scenarioContext,
{
ScenarioContext = scenarioContext;
TestingContext = testingContext;
- this.SecurityServiceSteps = new SecurityServiceSteps(testingContext.DockerHelper.SecurityServiceClient);
+ this.SecurityServiceSteps = new SecurityServiceSteps(testingContext.DockerHelper.SecurityServiceClient, testingContext.DockerHelper.AccessToken);
}
private TransactionProcessorSteps GetTransactionProcessorSteps()
diff --git a/FileProcessor/Startup.cs b/FileProcessor/Startup.cs
index acfd704..9735ac5 100644
--- a/FileProcessor/Startup.cs
+++ b/FileProcessor/Startup.cs
@@ -8,26 +8,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using FileProcessor.Bootstrapper;
+using FileProcessor.Common;
+using HealthChecks.UI.Client;
+using Lamar;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Shared.DomainDrivenDesign.EventSourcing;
+using Shared.EventStore.Aggregate;
+using Shared.Extensions;
+using Shared.General;
+using Shared.Logger;
+using Shared.Middleware;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace FileProcessor
{
- using Bootstrapper;
- using Common;
- using HealthChecks.UI.Client;
- using Lamar;
- using Microsoft.AspNetCore.Diagnostics.HealthChecks;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.Logging;
- using Shared.DomainDrivenDesign.EventSourcing;
- using Shared.EventStore.Aggregate;
- using Shared.Extensions;
- using Shared.General;
- using Shared.Logger;
- using Shared.Middleware;
- using System.Diagnostics.CodeAnalysis;
- using System.Reflection;
- using ILogger = Microsoft.Extensions.Logging.ILogger;
-
[ExcludeFromCodeCoverage]
public class Startup
{