From a8cb86253b58e1d0e025adbb6d1b11f52b750c77 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Wed, 25 Dec 2019 10:16:23 +0000 Subject: [PATCH 1/7] Docker Helper upgraded --- .../Common/DockerHelper.cs | 343 +++++++++-------- .../Common/GenericSteps.cs | 46 ++- .../Common/Setup.cs | 86 +---- .../Common/TestingContext.cs | 229 +++++++++++- .../LogonTransaction/LogonTransaction.feature | 53 ++- .../LogonTransaction.feature.cs | 218 +++++++++-- .../Shared/SharedSteps.cs | 349 ++++++++++++++---- ...actionProcessorACL.IntegrationTests.csproj | 14 +- TransactionProcessorACL/appsettings.json | 7 + 9 files changed, 1002 insertions(+), 343 deletions(-) diff --git a/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs b/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs index 32cd19e..272ad82 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs @@ -1,199 +1,234 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace TransactionProcessor.IntegrationTests.Common +namespace TransactionProcessor.IntegrationTests.Common { + using System; + using System.Collections.Generic; + using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Client; - using Ductus.FluentDocker.Builders; - using Ductus.FluentDocker.Model.Builders; + using Ductus.FluentDocker.Common; using Ductus.FluentDocker.Services; using Ductus.FluentDocker.Services.Extensions; using EstateManagement.Client; - - public class DockerHelper + using global::Shared.Logger; + using SecurityService.Client; + + /// + /// + /// + /// + public class DockerHelper : global::Shared.IntegrationTesting.DockerHelper { - protected INetworkService TestNetwork; + #region Fields - protected Int32 EstateManagementPort; - protected Int32 TransactionProcessorPort; + /// + /// The estate client + /// + public IEstateClient EstateClient; + + /// + /// The HTTP client + /// + public HttpClient HttpClient; + + /// + /// The security service client + /// + public ISecurityServiceClient SecurityServiceClient; + + /// + /// The test identifier + /// + public Guid TestId; + + /// + /// The transaction processor client + /// + public ITransactionProcessorClient TransactionProcessorClient; + + /// + /// The containers + /// + protected List Containers; + + /// + /// The estate management API port + /// + protected Int32 EstateManagementApiPort; + + /// + /// The event store HTTP port + /// + protected Int32 EventStoreHttpPort; + + /// + /// The security service port + /// + protected Int32 SecurityServicePort; + + /// + /// The test networks + /// + protected List TestNetworks; + + /// + /// The transaction processor acl port + /// protected Int32 TransactionProcessorACLPort; - protected Int32 EventStorePort; - protected IContainerService EstateManagementContainer; - protected IContainerService TransactionProcessorContainer; - protected IContainerService TransactionProcessorACLContainer; - protected IContainerService EventStoreContainer; + /// + /// The transaction processor port + /// + protected Int32 TransactionProcessorPort; - public IEstateClient EstateClient; - public HttpClient HttpClient; + /// + /// The logger + /// + private readonly NlogLogger Logger; - protected String EventStoreConnectionString; + #endregion - protected String EstateManagementContainerName; - protected String TransactionProcessorContainerName; - protected String TransactionProcessorACLContainerName; - protected String EventStoreContainerName; + #region Constructors - private void SetupTestNetwork() - { - // Build a network - this.TestNetwork = new Ductus.FluentDocker.Builders.Builder().UseNetwork($"testnetwork{Guid.NewGuid()}").Build(); - } - public Guid TestId; - private void SetupEventStoreContainer(String traceFolder) + /// + /// Initializes a new instance of the class. + /// + /// The logger. + public DockerHelper(NlogLogger logger) { - // Event Store Container - this.EventStoreContainer = new Ductus.FluentDocker.Builders.Builder() - .UseContainer() - .UseImage("eventstore/eventstore:release-5.0.2") - .ExposePort(2113) - .ExposePort(1113) - .WithName(this.EventStoreContainerName) - .WithEnvironment("EVENTSTORE_RUN_PROJECTIONS=all", "EVENTSTORE_START_STANDARD_PROJECTIONS=true") - .UseNetwork(this.TestNetwork) - .Mount(traceFolder, "/var/log/eventstore", MountType.ReadWrite) - .Build() - .Start().WaitForPort("2113/tcp", 30000); + this.Logger = logger; + this.Containers = new List(); + this.TestNetworks = new List(); } - public async Task StartContainersForScenarioRun(String scenarioName) + #endregion + + #region Methods + + /// + /// Starts the containers for scenario run. + /// + /// Name of the scenario. + public override async Task StartContainersForScenarioRun(String scenarioName) { - String traceFolder = $"/home/ubuntu/estatemanagement/trace/{scenarioName}/"; + String traceFolder = FdOs.IsWindows() ? $"D:\\home\\txnproc\\trace\\{scenarioName}" : $"//home//txnproc//trace//{scenarioName}"; Logging.Enabled(); Guid testGuid = Guid.NewGuid(); this.TestId = testGuid; - // Setup the container names - this.EstateManagementContainerName = $"estate{testGuid:N}"; - this.TransactionProcessorContainerName = $"txnprocessor{testGuid:N}"; - this.TransactionProcessorACLContainerName = $"txnprocessoracl{testGuid:N}"; - this.EventStoreContainerName = $"eventstore{testGuid:N}"; - - this.EventStoreConnectionString = - $"EventStoreSettings:ConnectionString=ConnectTo=tcp://admin:changeit@{this.EventStoreContainerName}:1113;VerboseLogging=true;"; + this.Logger.LogInformation($"Test Id is {testGuid}"); - this.SetupTestNetwork(); - this.SetupEventStoreContainer(traceFolder); - this.SetupEstateManagementContainer(traceFolder); - this.SetupTransactionProcessorContainer(traceFolder); - this.SetupTransactionProcessorACLContainer(traceFolder); + // Setup the container names + String securityServiceContainerName = $"securityservice{testGuid:N}"; + String estateManagementApiContainerName = $"estate{testGuid:N}"; + String transactionProcessorContainerName = $"txnprocessor{testGuid:N}"; + String transactionProcessorACLContainerName = $"txnprocessoracl{testGuid:N}"; + String eventStoreContainerName = $"eventstore{testGuid:N}"; + + (String, String, String) dockerCredentials = ("https://www.docker.com", "stuartferguson", "Sc0tland"); + + INetworkService testNetwork = DockerHelper.SetupTestNetwork(); + this.TestNetworks.Add(testNetwork); + IContainerService eventStoreContainer = + DockerHelper.SetupEventStoreContainer(eventStoreContainerName, this.Logger, "eventstore/eventstore:release-5.0.2", testNetwork, traceFolder); + + IContainerService estateManagementContainer = DockerHelper.SetupEstateManagementContainer(estateManagementApiContainerName, + this.Logger, + "stuartferguson/estatemanagement", + new List + { + testNetwork + }, + traceFolder, + dockerCredentials, + securityServiceContainerName, + eventStoreContainerName); + + IContainerService securityServiceContainer = DockerHelper.SetupSecurityServiceContainer(securityServiceContainerName, + this.Logger, + "stuartferguson/securityservice", + testNetwork, + traceFolder, + dockerCredentials); + + IContainerService transactionProcessorContainer = DockerHelper.SetupTransactionProcessorContainer(transactionProcessorContainerName, + this.Logger, + "stuartferguson/transactionprocessor", + new List + { + testNetwork + }, + traceFolder, + dockerCredentials, + securityServiceContainerName, + eventStoreContainerName); + + IContainerService transactionProcessorACLContainer = DockerHelper.SetupTransactionProcessorACLContainer(transactionProcessorACLContainerName, + this.Logger, + "transactionprocessoracl", + testNetwork, + traceFolder, + dockerCredentials, + securityServiceContainerName); + + this.Containers.AddRange(new List + { + eventStoreContainer, + estateManagementContainer, + securityServiceContainer, + transactionProcessorContainer, + transactionProcessorACLContainer + }); // Cache the ports - this.EstateManagementPort = this.EstateManagementContainer.ToHostExposedEndpoint("5000/tcp").Port; - this.TransactionProcessorPort = this.TransactionProcessorContainer.ToHostExposedEndpoint("5002/tcp").Port; - this.TransactionProcessorACLPort = this.TransactionProcessorACLContainer.ToHostExposedEndpoint("5003/tcp").Port; - this.EventStorePort = this.EventStoreContainer.ToHostExposedEndpoint("2113/tcp").Port; - - // Setup the base address resolver - Func estateManagementBaseAddressResolver = api => $"http://127.0.0.1:{this.EstateManagementPort}"; - Func transactionProcessorACLBaseAddressResolver = api => $"http://127.0.0.1:{this.TransactionProcessorACLPort}"; + this.EstateManagementApiPort = estateManagementContainer.ToHostExposedEndpoint("5000/tcp").Port; + this.SecurityServicePort = securityServiceContainer.ToHostExposedEndpoint("5001/tcp").Port; + this.EventStoreHttpPort = eventStoreContainer.ToHostExposedEndpoint("2113/tcp").Port; + this.TransactionProcessorPort = transactionProcessorContainer.ToHostExposedEndpoint("5002/tcp").Port; + this.TransactionProcessorACLPort = transactionProcessorACLContainer.ToHostExposedEndpoint("5003/tcp").Port; + + // Setup the base address resolvers + String EstateManagementBaseAddressResolver(String api) => $"http://127.0.0.1:{this.EstateManagementApiPort}"; + String SecurityServiceBaseAddressResolver(String api) => $"http://127.0.0.1:{this.SecurityServicePort}"; + String TransactionProcessorBaseAddressResolver(String api) => $"http://127.0.0.1:{this.TransactionProcessorPort}"; + String TransactionProcessorAclBaseAddressResolver(String api) => $"http://127.0.0.1:{this.TransactionProcessorACLPort}"; HttpClient httpClient = new HttpClient(); - this.EstateClient = new EstateClient(estateManagementBaseAddressResolver, httpClient); + this.EstateClient = new EstateClient(EstateManagementBaseAddressResolver, httpClient); + this.SecurityServiceClient = new SecurityServiceClient(SecurityServiceBaseAddressResolver, httpClient); + this.TransactionProcessorClient = new TransactionProcessorClient(TransactionProcessorBaseAddressResolver, httpClient); - // TODO: Use this to talk to txn processor scl until we have a client this.HttpClient = new HttpClient(); - this.HttpClient.BaseAddress = new Uri(transactionProcessorACLBaseAddressResolver(String.Empty)); + this.HttpClient.BaseAddress = new Uri(TransactionProcessorAclBaseAddressResolver(string.Empty)); } - public async Task StopContainersForScenarioRun() + /// + /// Stops the containers for scenario run. + /// + public override async Task StopContainersForScenarioRun() { - try + if (this.Containers.Any()) { - if (this.TransactionProcessorACLContainer != null) + foreach (IContainerService containerService in this.Containers) { - this.TransactionProcessorACLContainer.StopOnDispose = true; - this.TransactionProcessorACLContainer.RemoveOnDispose = true; - this.TransactionProcessorACLContainer.Dispose(); - } - - if (this.TransactionProcessorContainer != null) - { - this.TransactionProcessorContainer.StopOnDispose = true; - this.TransactionProcessorContainer.RemoveOnDispose = true; - this.TransactionProcessorContainer.Dispose(); - } - - if (this.EstateManagementContainer != null) - { - this.EstateManagementContainer.StopOnDispose = true; - this.EstateManagementContainer.RemoveOnDispose = true; - this.EstateManagementContainer.Dispose(); - } - - if (this.EventStoreContainer != null) - { - this.EventStoreContainer.StopOnDispose = true; - this.EventStoreContainer.RemoveOnDispose = true; - this.EventStoreContainer.Dispose(); + containerService.StopOnDispose = true; + containerService.RemoveOnDispose = true; + containerService.Dispose(); } + } - if (this.TestNetwork != null) + if (this.TestNetworks.Any()) + { + foreach (INetworkService networkService in this.TestNetworks) { - this.TestNetwork.Stop(); - this.TestNetwork.Remove(true); + networkService.Stop(); + networkService.Remove(true); } } - catch (Exception e) - { - Console.WriteLine(e); - } - } - - private void SetupEstateManagementContainer(String traceFolder) - { - // Management API Container - this.EstateManagementContainer = new Builder() - .UseContainer() - .WithName(this.EstateManagementContainerName) - .WithEnvironment(this.EventStoreConnectionString) //, - //"AppSettings:MigrateDatabase=true", - //"EventStoreSettings:START_PROJECTIONS=true", - //"EventStoreSettings:ContinuousProjectionsFolder=/app/projections/continuous") - .WithCredential("https://www.docker.com", "stuartferguson", "Sc0tland") - .UseImage("stuartferguson/estatemanagement") - .ExposePort(5000) - .UseNetwork(new List { this.TestNetwork, Setup.DatabaseServerNetwork }.ToArray()) - .Mount(traceFolder, "/home", MountType.ReadWrite) - .Build() - .Start().WaitForPort("5000/tcp", 30000); } - private void SetupTransactionProcessorContainer(String traceFolder) - { - // Management API Container - this.TransactionProcessorContainer = new Builder() - .UseContainer() - .WithName(this.TransactionProcessorContainerName) - .WithEnvironment(this.EventStoreConnectionString) //, - //"AppSettings:MigrateDatabase=true", - //"EventStoreSettings:START_PROJECTIONS=true", - //"EventStoreSettings:ContinuousProjectionsFolder=/app/projections/continuous") - .UseImage("stuartferguson/transactionprocessor") - .ExposePort(5002) - .UseNetwork(new List { this.TestNetwork, Setup.DatabaseServerNetwork }.ToArray()) - .Mount(traceFolder, "/home", MountType.ReadWrite) - .Build() - .Start().WaitForPort("5002/tcp", 30000); - } - - private void SetupTransactionProcessorACLContainer(String traceFolder) - { - // Management API Container - this.TransactionProcessorACLContainer = new Builder() - .UseContainer() - .WithName(this.TransactionProcessorACLContainerName) - .UseImage("transactionprocessoracl") - .ExposePort(5003) - .UseNetwork(new List { this.TestNetwork }.ToArray()) - .Mount(traceFolder, "/home", MountType.ReadWrite) - .Build() - .Start().WaitForPort("5003/tcp", 30000); - } + #endregion } -} +} \ No newline at end of file diff --git a/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs b/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs index 93322f0..27852c1 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs @@ -4,7 +4,10 @@ namespace TransactionProcessor.IntegrationTests.Common { + using System.Threading; using System.Threading.Tasks; + using global::Shared.Logger; + using NLog; using TechTalk.SpecFlow; [Binding] @@ -22,17 +25,54 @@ public GenericSteps(ScenarioContext scenarioContext, this.TestingContext = testingContext; } - [BeforeScenario()] + [BeforeScenario] public async Task StartSystem() { + // Initialise a logger String scenarioName = this.ScenarioContext.ScenarioInfo.Title.Replace(" ", ""); - this.TestingContext.DockerHelper = new DockerHelper(); + NlogLogger logger = new NlogLogger(); + logger.Initialise(LogManager.GetLogger(scenarioName), scenarioName); + LogManager.AddHiddenAssembly(typeof(NlogLogger).Assembly); + + this.TestingContext.DockerHelper = new DockerHelper(logger); + this.TestingContext.Logger = logger; + this.TestingContext.Logger.LogInformation("About to Start Containers for Scenario Run"); await this.TestingContext.DockerHelper.StartContainersForScenarioRun(scenarioName).ConfigureAwait(false); + this.TestingContext.Logger.LogInformation("Containers for Scenario Run Started"); + + Thread.Sleep(20000); } - [AfterScenario()] + [AfterScenario] public async Task StopSystem() { + if (this.ScenarioContext.TestError != null) + { + //Exception currentEx = this.ScenarioContext.TestError; + //Console.Out.WriteLine(currentEx.Message); + //while (currentEx.InnerException != null) + //{ + // currentEx = currentEx.InnerException; + // Console.Out.WriteLine(currentEx.Message); + //} + + //// The test has failed, grab the logs from all the containers + //List containers = new List(); + //containers.Add(this.TestingContext.DockerHelper.EstateManagementContainer); + //containers.Add(this.TestingContext.DockerHelper.TransactionProcessorContainer); + + //foreach (IContainerService containerService in containers) + //{ + // ConsoleStream logStream = containerService.Logs(); + // IList logData = logStream.ReadToEnd(); + + // foreach (String s in logData) + // { + // Console.Out.WriteLine(s); + // } + //} + } + await this.TestingContext.DockerHelper.StopContainersForScenarioRun().ConfigureAwait(false); } } diff --git a/TransactionProcessorACL.IntegrationTests/Common/Setup.cs b/TransactionProcessorACL.IntegrationTests/Common/Setup.cs index 6e9e645..c0d729d 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/Setup.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/Setup.cs @@ -25,93 +25,23 @@ public class Setup [BeforeTestRun] protected static void GlobalSetup() { - ShouldlyConfiguration.DefaultTaskTimeout = TimeSpan.FromMinutes(1); + (String, String, String) dockerCredentials = ("https://www.docker.com", "stuartferguson", "Sc0tland"); // Setup a network for the DB Server - DatabaseServerNetwork = new Builder().UseNetwork($"sharednetwork").ReuseIfExist().Build(); + DatabaseServerNetwork = global::Shared.IntegrationTesting.DockerHelper.SetupTestNetwork("sharednetwork", true); // Start the Database Server here - DbConnectionStringWithNoDatabase = StartMySqlContainerWithOpenConnection(); + DbConnectionStringWithNoDatabase = global::Shared.IntegrationTesting.DockerHelper.StartSqlContainerWithOpenConnection("shareddatabasesqlserver", + null, + "stuartferguson/subscriptionservicedatabasesqlserver", + Setup.DatabaseServerNetwork, + "", + dockerCredentials); } public static String GetConnectionString(String databaseName) { return $"{DbConnectionStringWithNoDatabase} database={databaseName};"; } - - private static String StartMySqlContainerWithOpenConnection() - { - String containerName = $"shareddatabasesqlserver"; - DatabaseServerContainer = new Ductus.FluentDocker.Builders.Builder() - .UseContainer() - .WithName(containerName) - .WithCredential("https://docker.io", "stuartferguson", "Sc0tland") - .UseImage("stuartferguson/subscriptionservicedatabasesqlserver") - .WithEnvironment("ACCEPT_EULA=Y", $"SA_PASSWORD=thisisalongpassword123!") - .ExposePort(1433) - .UseNetwork(DatabaseServerNetwork) - .KeepContainer() - .KeepRunning() - .ReuseIfExists() - .Build() - .Start() - .WaitForPort("1433/tcp", 30000); - - IPEndPoint sqlServerEndpoint = DatabaseServerContainer.ToHostExposedEndpoint("1433/tcp"); - - // Try opening a connection - Int32 maxRetries = 10; - Int32 counter = 1; - - String server = "127.0.0.1"; - String database = "SubscriptionServiceConfiguration"; - String user = "sa"; - String password = "thisisalongpassword123!"; - String port = sqlServerEndpoint.Port.ToString(); - - String connectionString = $"server={server},{port};user id={user}; password={password}; database={database};"; - - SqlConnection connection = new SqlConnection(connectionString); - - using (StreamWriter sw = new StreamWriter("C:\\Temp\\testlog.log", true)) - { - while (counter <= maxRetries) - { - try - { - sw.WriteLine($"Attempt {counter}"); - sw.WriteLine(DateTime.Now); - - connection.Open(); - - SqlCommand command = connection.CreateCommand(); - command.CommandText = "SELECT * FROM EventStoreServers"; - command.ExecuteNonQuery(); - - sw.WriteLine("Connection Opened"); - - connection.Close(); - - break; - } - catch (SqlException ex) - { - if (connection.State == ConnectionState.Open) - { - connection.Close(); - } - - sw.WriteLine(ex); - Thread.Sleep(20000); - } - finally - { - counter++; - } - } - } - - return $"server={containerName};user id={user}; password={password};"; - } } } diff --git a/TransactionProcessorACL.IntegrationTests/Common/TestingContext.cs b/TransactionProcessorACL.IntegrationTests/Common/TestingContext.cs index 3786f15..3ad721a 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/TestingContext.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/TestingContext.cs @@ -4,28 +4,239 @@ namespace TransactionProcessor.IntegrationTests.Common { + using System.Linq; using DataTransferObjects; + using global::Shared.Logger; + using Shouldly; + using TechTalk.SpecFlow; public class TestingContext { public TestingContext() { - this.Estates = new Dictionary(); + this.Estates = new List(); + this.Clients = new List(); + } + + public NlogLogger Logger { get; set; } + + public DockerHelper DockerHelper { get; set; } + + private List Clients; + + private List Estates; + + public String AccessToken { get; set; } + + public EstateDetails GetEstateDetails(TableRow tableRow) + { + String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName"); + + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); + + estateDetails.ShouldNotBeNull(); + + return estateDetails; + } + + public EstateDetails GetEstateDetails(String estateName) + { + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); + + estateDetails.ShouldNotBeNull(); + + return estateDetails; + } + + public EstateDetails GetEstateDetails(Guid estateId) + { + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateId == estateId); + + estateDetails.ShouldNotBeNull(); + + return estateDetails; + } + + public void AddEstateDetails(Guid estateId, String estateName) + { + this.Estates.Add(EstateDetails.Create(estateId, estateName)); + } + + public void AddClientDetails(String clientId, + String clientSecret, + String grantType) + { + this.Clients.Add(ClientDetails.Create(clientId, clientSecret, grantType)); + } + + public ClientDetails GetClientDetails(String clientId) + { + ClientDetails clientDetails = this.Clients.SingleOrDefault(c => c.ClientId == clientId); + + clientDetails.ShouldNotBeNull(); + + return clientDetails; + } + } + + public class EstateDetails + { + private EstateDetails(Guid estateId, String estateName) + { + this.EstateId = estateId; + this.EstateName = estateName; this.Merchants = new Dictionary(); this.Operators = new Dictionary(); - this.EstateMerchants = new Dictionary>(); - this.TransactionResponses = new Dictionary(); + this.MerchantUsers = new Dictionary>(); + this.MerchantUsersTokens = new Dictionary>(); + this.TransactionResponses = new Dictionary<(Guid merchantId, String transactionNumber), SerialisedMessage>(); } - public DockerHelper DockerHelper { get; set; } + public void AddTransactionResponse(Guid merchantId, + String transactionNumber, + SerialisedMessage transactionResponse) + { + this.TransactionResponses.Add((merchantId, transactionNumber), transactionResponse); + } + + public SerialisedMessage GetTransactionResponse(Guid merchantId, + String transactionNumber) + { + KeyValuePair<(Guid merchantId, String transactionNumber), SerialisedMessage> transactionResponse = + this.TransactionResponses.Where(t => t.Key.merchantId == merchantId && t.Key.transactionNumber == transactionNumber).SingleOrDefault(); + + return transactionResponse.Value; + } + + private Dictionary<(Guid merchantId, String transactionNumber), SerialisedMessage> TransactionResponses { get; set; } + + public String EstateUser { get; private set; } + public String EstatePassword { get; private set; } + + public String AccessToken { get; private set; } + + public static EstateDetails Create(Guid estateId, + String estateName) + { + return new EstateDetails(estateId, estateName); + } + + public void AddOperator(Guid operatorId, + String operatorName) + { + this.Operators.Add(operatorName, operatorId); + } + + public void AddMerchant(Guid merchantId, + String merchantName) + { + this.Merchants.Add(merchantName, merchantId); + } + + public Guid GetMerchantId(String merchantName) + { + return this.Merchants.Single(m => m.Key == merchantName).Value; + } + + public Guid GetOperatorId(String operatorName) + { + return this.Operators.Single(o => o.Key == operatorName).Value; + } + + public void SetEstateUser(String userName, + String password) + { + this.EstateUser = userName; + this.EstatePassword = password; + } - public Dictionary Estates { get; set; } - public Dictionary Merchants { get; set; } + public void AddMerchantUser(String merchantName, + String userName, + String password) + { + if (this.MerchantUsers.ContainsKey(merchantName)) + { + Dictionary merchantUsersList = this.MerchantUsers[merchantName]; + if (merchantUsersList.ContainsKey(userName) == false) + { + merchantUsersList.Add(userName, password); + } + } + else + { + Dictionary merchantUsersList = new Dictionary(); + merchantUsersList.Add(userName, password); + this.MerchantUsers.Add(merchantName, merchantUsersList); + } + } + + public void AddMerchantUserToken(String merchantName, + String userName, + String token) + { + if (this.MerchantUsersTokens.ContainsKey(merchantName)) + { + Dictionary merchantUsersList = this.MerchantUsersTokens[merchantName]; + if (merchantUsersList.ContainsKey(userName) == false) + { + merchantUsersList.Add(userName, token); + } + } + else + { + Dictionary merchantUsersList = new Dictionary(); + merchantUsersList.Add(userName, token); + this.MerchantUsersTokens.Add(merchantName, merchantUsersList); + } + } + + public String GetMerchantUserToken(String merchantName) + { + KeyValuePair> x = this.MerchantUsersTokens.SingleOrDefault(x => x.Key == merchantName); + + if (x.Value != null) + { + return x.Value.First().Value; + } + + return String.Empty; + } + public void SetEstateUserToken(String accessToken) + { + this.AccessToken = accessToken; + } + + public Guid EstateId { get; private set; } + public String EstateName { get; private set; } + + private Dictionary Operators; - public Dictionary Operators { get; set; } + private Dictionary Merchants; - public Dictionary> EstateMerchants { get; set; } + private Dictionary> MerchantUsers; + private Dictionary> MerchantUsersTokens; + } + + public class ClientDetails + { + public String ClientId { get; private set; } + public String ClientSecret { get; private set; } + public String GrantType { get; private set; } - public Dictionary TransactionResponses { get; set; } + private ClientDetails(String clientId, + String clientSecret, + String grantType) + { + this.ClientId = clientId; + this.ClientSecret = clientSecret; + this.GrantType = grantType; + } + + public static ClientDetails Create(String clientId, + String clientSecret, + String grantType) + { + return new ClientDetails(clientId, clientSecret, grantType); + } } } diff --git a/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature b/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature index 2a3ddb0..dd67c7c 100644 --- a/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature +++ b/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature @@ -2,24 +2,69 @@ Feature: LogonTransaction Background: + + Given the following security roles exist + | RoleName | + | Merchant | + + Given the following api resources exist + | ResourceName | DisplayName | Secret | Scopes | UserClaims | + | estateManagement | Estate Managememt REST | Secret1 | estateManagement | MerchantId, EstateId, role | + | transactionProcessorAcl | Transaction Processor ACL REST | Secret1 | transactionProcessorAcl | | + + Given the following clients exist + | ClientId | ClientName | Secret | AllowedScopes | AllowedGrantTypes | + | serviceClient | Service Client | Secret1 | estateManagement,transactionProcessorAcl | client_credentials | + | merchantClient | Merchant Client | Secret1 | transactionProcessorAcl | password | + + Given I have a token to access the estate management and transaction processor acl resources + | ClientId | + | serviceClient | + Given I have created the following estates | EstateName | | Test Estate 1 | | Test Estate 2 | + Given I have created the following operators + | EstateName | OperatorName | RequireCustomMerchantNumber | RequireCustomTerminalNumber | + | Test Estate 1 | Test Operator 1 | True | True | + | Test Estate 2 | Test Operator 1 | True | True | + Given I create the following merchants | MerchantName | AddressLine1 | Town | Region | Country | ContactName | EmailAddress | EstateName | | Test Merchant 1 | Address Line 1 | TestTown | Test Region | United Kingdom | Test Contact 1 | testcontact1@merchant1.co.uk | Test Estate 1 | | Test Merchant 2 | Address Line 1 | TestTown | Test Region | United Kingdom | Test Contact 2 | testcontact2@merchant2.co.uk | Test Estate 1 | | Test Merchant 3 | Address Line 1 | TestTown | Test Region | United Kingdom | Test Contact 3 | testcontact3@merchant2.co.uk | Test Estate 2 | + Given I have created the following security users + | EmailAddress | Password | GivenName | FamilyName | EstateName | MerchantName | + | merchantuser@testmerchant1.co.uk | 123456 | TestMerchant | User1 | Test Estate 1 | Test Merchant 1 | + | merchantuser@testmerchant2.co.uk | 123456 | TestMerchant | User2 | Test Estate 1 | Test Merchant 2 | + | merchantuser@testmerchant3.co.uk | 123456 | TestMerchant | User3 | Test Estate 2 | Test Merchant 3 | + + Given I have assigned the following operator to the merchants + | OperatorName | MerchantName | MerchantNumber | TerminalNumber | EstateName | + | Test Operator 1 | Test Merchant 1 | 00000001 | 10000001 | Test Estate 1 | + | Test Operator 1 | Test Merchant 2 | 00000001 | 10000001 | Test Estate 1 | + | Test Operator 1 | Test Merchant 3 | 00000001 | 10000001 | Test Estate 2 | + @PRTest Scenario: Logon Transaction + Given I am logged in as "merchantuser@testmerchant1.co.uk" with password "123456" for Merchant "Test Merchant 1" for Estate "Test Estate 1" with client "merchantClient" + When I perform the following transactions + | DateTime | TransactionNumber | TransactionType | MerchantName | IMEINumber | EstateName | + | Today | 1 | Logon | Test Merchant 1 | 123456789 | Test Estate 1 | + + Given I am logged in as "merchantuser@testmerchant2.co.uk" with password "123456" for Merchant "Test Merchant 2" for Estate "Test Estate 1" with client "merchantClient" + When I perform the following transactions + | DateTime | TransactionNumber | TransactionType | MerchantName | IMEINumber | EstateName | + | Today | 2 | Logon | Test Merchant 2 | 123456789 | Test Estate 1 | + + Given I am logged in as "merchantuser@testmerchant3.co.uk" with password "123456" for Merchant "Test Merchant 3" for Estate "Test Estate 2" with client "merchantClient" When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | IMEINumber | - | Today | 1 | Logon | Test Merchant 1 | 123456789 | - | Today | 2 | Logon | Test Merchant 2 | 123456789 | - | Today | 3 | Logon | Test Merchant 3 | 123456789 | + | DateTime | TransactionNumber | TransactionType | MerchantName | IMEINumber | EstateName | + | Today | 3 | Logon | Test Merchant 3 | 123456789 | Test Estate 2 | # TODO: Add in once the logon flow is implemented #Then transaction response should contain the following information diff --git a/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs b/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs index 5efd21f..b997adf 100644 --- a/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs +++ b/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature.cs @@ -21,7 +21,7 @@ namespace TransactionProcessorACL.IntegrationTests.LogonTransaction [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [Xunit.TraitAttribute("Category", "base")] [Xunit.TraitAttribute("Category", "shared")] - public partial class LogonTransactionFeature : Xunit.IClassFixture, System.IDisposable + public partial class LogonTransactionFeature : object, Xunit.IClassFixture, System.IDisposable { private static TechTalk.SpecFlow.ITestRunner testRunner; @@ -35,7 +35,7 @@ public partial class LogonTransactionFeature : Xunit.IClassFixture