diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index 0013646c..903f66fa 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -47,6 +47,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_TransactionIs Mock securityServiceClient = new Mock(); securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEstateResponse); estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponse); @@ -89,6 +90,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_MerchantWithN Mock securityServiceClient = new Mock(); securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEstateResponse); estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithNullDevices); @@ -131,6 +133,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_MerchantWithN Mock securityServiceClient = new Mock(); securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEstateResponse); estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithNoDevices); @@ -173,6 +176,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_IncorrectDevi Mock securityServiceClient = new Mock(); securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEstateResponse); estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponse); @@ -192,7 +196,48 @@ public async Task TransactionDomainService_ProcessLogonTransaction_IncorrectDevi response.ResponseMessage.ShouldBe(TestData.ResponseMessage); } - // Txn for a Different Device (Causes a Validation Exception) + [Fact] + public async Task TransactionDomainService_ProcessLogonTransaction_InvlaidEstate_TransactionIsProcessed() + { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); + ConfigurationReader.Initialise(configurationRoot); + + Logger.Initialise(NullLogger.Instance); + + 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); + + Mock estateClient = new Mock(); + Mock securityServiceClient = new Mock(); + + securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEmptyEstateResponse); + estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponse); + + TransactionDomainService transactionDomainService = + new TransactionDomainService(aggregateRepositoryManager.Object, estateClient.Object, securityServiceClient.Object); + + ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier1, + CancellationToken.None); + + response.ShouldNotBeNull(); + response.ResponseCode.ShouldBe(TestData.ResponseCode); + response.ResponseMessage.ShouldBe(TestData.ResponseMessage); + } } } diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index 0c3315a3..d2aedf48 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -147,6 +147,21 @@ public async Task ProcessLogonTransaction(Guid TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); Logger.LogInformation($"Token is {token.AccessToken}"); + // Validate the Estate Record is a valid estate + var estate = await this.EstateClient.GetEstate(token.AccessToken, estateId, cancellationToken); + + // TODO: Remove this once GetEstate returns correct response when estate not found + if (estate.EstateName == null) + { + + + + + + + throw new TransactionValidationException($"Estate Id [{estateId}] is not a valid estate", TransactionResponseCode.InvalidEstateId); + } + // get the merchant record and validate the device // TODO: Token MerchantResponse merchant = await this.EstateClient.GetMerchant(token.AccessToken, estateId, merchantId, cancellationToken); @@ -187,10 +202,4 @@ await this.EstateClient.AddDeviceToMerchant(token.AccessToken, #endregion } - - public enum TransactionResponseCode - { - Success = 0, - InvalidDeviceIdentifier = 1000 - } } \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs new file mode 100644 index 00000000..73bc2029 --- /dev/null +++ b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs @@ -0,0 +1,10 @@ +namespace TransactionProcessor.BusinessLogic.Services +{ + public enum TransactionResponseCode + { + Success = 0, + + InvalidDeviceIdentifier = 1000, + InvalidEstateId = 1001 + } +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/TestingContext.cs b/TransactionProcessor.IntegrationTests/Common/TestingContext.cs index 4faefd28..f0caa899 100644 --- a/TransactionProcessor.IntegrationTests/Common/TestingContext.cs +++ b/TransactionProcessor.IntegrationTests/Common/TestingContext.cs @@ -56,14 +56,22 @@ public TestingContext() public EstateDetails GetEstateDetails(TableRow tableRow) { String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName"); + EstateDetails estateDetails = null; + + estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); - EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); + if (estateDetails == null && estateName == "InvalidEstate") + { + estateDetails = EstateDetails.Create(Guid.Parse("79902550-64DF-4491-B0C1-4E78943928A3"), estateName); + estateDetails.AddMerchant(Guid.Parse("36AA0109-E2E3-4049-9575-F507A887BB1F"), "Test Merchant 1"); + this.Estates.Add(estateDetails); + } estateDetails.ShouldNotBeNull(); return estateDetails; } - + public EstateDetails GetEstateDetails(String estateName) { EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); diff --git a/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature b/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature index ec18a3e9..af9d7dd7 100644 --- a/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature +++ b/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature @@ -78,3 +78,18 @@ Scenario: Logon Transaction with Invalid Device Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | | Test Estate 1 | Test Merchant 1 | 1 | 1000 | Device Identifier 123456781 not valid for Merchant Test Merchant 1 | + +Scenario: Logon Transaction with Invalid Estate + + Given I have assigned the following devices to the merchants + | DeviceIdentifier | MerchantName | MerchantNumber | EstateName | + | 123456780 | Test Merchant 1 | 00000001 | Test Estate 1 | + + When I perform the following transactions + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | + | Today | 1 | Logon | Test Merchant 1 | 123456781 | InvalidEstate | + + Then transaction response should contain the following information + | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | + | InvalidEstate | Test Merchant 1 | 1 | 1001 | Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate | + diff --git a/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs b/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs index 1e4a5836..78d77aa9 100644 --- a/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs +++ b/TransactionProcessor.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs @@ -389,11 +389,14 @@ public virtual void LogonTransactionWithExistingDevice() [Xunit.SkippableFactAttribute(DisplayName="Logon Transaction with Invalid Device")] [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] [Xunit.TraitAttribute("Description", "Logon Transaction with Invalid Device")] + [Xunit.TraitAttribute("Category", "PRTest")] public virtual void LogonTransactionWithInvalidDevice() { - string[] tagsOfScenario = ((string[])(null)); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Invalid Device", null, ((string[])(null))); -#line 67 + string[] tagsOfScenario = new string[] { + "PRTest"}; + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Invalid Device", null, new string[] { + "PRTest"}); +#line 68 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -426,7 +429,7 @@ public virtual void LogonTransactionWithInvalidDevice() "Test Merchant 1", "00000001", "Test Estate 1"}); -#line 69 +#line 70 testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table13, "Given "); #line hidden TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] { @@ -443,7 +446,7 @@ public virtual void LogonTransactionWithInvalidDevice() "Test Merchant 1", "123456781", "Test Estate 1"}); -#line 73 +#line 74 testRunner.When("I perform the following transactions", ((string)(null)), table14, "When "); #line hidden TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { @@ -458,13 +461,92 @@ public virtual void LogonTransactionWithInvalidDevice() "1", "1000", "Device Identifier 123456781 not valid for Merchant Test Merchant 1"}); -#line 77 +#line 78 testRunner.Then("transaction response should contain the following information", ((string)(null)), table15, "Then "); #line hidden } this.ScenarioCleanup(); } + [Xunit.SkippableFactAttribute(DisplayName="Logon Transaction with Invalid Estate")] + [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] + [Xunit.TraitAttribute("Description", "Logon Transaction with Invalid Estate")] + public virtual void LogonTransactionWithInvalidEstate() + { + string[] tagsOfScenario = ((string[])(null)); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Invalid Estate", null, ((string[])(null))); +#line 82 +this.ScenarioInitialize(scenarioInfo); +#line hidden + bool isScenarioIgnored = default(bool); + bool isFeatureIgnored = default(bool); + if ((tagsOfScenario != null)) + { + isScenarioIgnored = tagsOfScenario.Where(__entry => __entry != null).Where(__entry => String.Equals(__entry, "ignore", StringComparison.CurrentCultureIgnoreCase)).Any(); + } + if ((this._featureTags != null)) + { + isFeatureIgnored = this._featureTags.Where(__entry => __entry != null).Where(__entry => String.Equals(__entry, "ignore", StringComparison.CurrentCultureIgnoreCase)).Any(); + } + if ((isScenarioIgnored || isFeatureIgnored)) + { + testRunner.SkipScenario(); + } + else + { + this.ScenarioStart(); +#line 4 +this.FeatureBackground(); +#line hidden + TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { + "DeviceIdentifier", + "MerchantName", + "MerchantNumber", + "EstateName"}); + table16.AddRow(new string[] { + "123456780", + "Test Merchant 1", + "00000001", + "Test Estate 1"}); +#line 84 + testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table16, "Given "); +#line hidden + TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { + "DateTime", + "TransactionNumber", + "TransactionType", + "MerchantName", + "DeviceIdentifier", + "EstateName"}); + table17.AddRow(new string[] { + "Today", + "1", + "Logon", + "Test Merchant 1", + "123456781", + "InvalidEstate"}); +#line 88 + testRunner.When("I perform the following transactions", ((string)(null)), table17, "When "); +#line hidden + TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { + "EstateName", + "MerchantName", + "TransactionNumber", + "ResponseCode", + "ResponseMessage"}); + table18.AddRow(new string[] { + "InvalidEstate", + "Test Merchant 1", + "1", + "1001", + "Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate"}); +#line 92 + testRunner.Then("transaction response should contain the following information", ((string)(null)), table18, "Then "); +#line hidden + } + this.ScenarioCleanup(); + } + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.1.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index e981709c..3039b755 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -126,5 +126,19 @@ public static TokenResponse TokenResponse() MerchantId = TestData.MerchantId, Devices = new Dictionary() }; + + public static EstateResponse GetEmptyEstateResponse = new EstateResponse + { + EstateName = null, + EstateId = TestData.EstateId + }; + public static String EstateName = "Test Estate 1"; + public static EstateResponse GetEstateResponse = new EstateResponse + { + EstateName = TestData.EstateName, + EstateId = TestData.EstateId + }; + + } }