diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index e1803ad..30d7c6a 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -38,3 +38,7 @@ jobs:
- name: Run Integration Tests
run: dotnet test "TransactionProcessorACL.IntegrationTests\TransactionProcessorACL.IntegrationTests.csproj" --filter Category=PRTest
+
+ - name: Setup tmate session
+ if: failure()
+ uses: mxschmitt/action-tmate@v1
diff --git a/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs b/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs
index 32cd19e..2e08e04 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,
+ null,
+ 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 cc34385..6e2c7df 100644
--- a/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature
+++ b/TransactionProcessorACL.IntegrationTests/LogonTransaction/LogonTransaction.feature
@@ -2,25 +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 | MerchantId, EstateId, role |
+
+ 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 |
-@PRTest @ignore
-# ignoring this PR test until the full logon flow implemented
+ 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..3b4ff04 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 splitScopes = scopes.Split(",").ToList();
+ List splitUserClaims = userClaims.Split(",").ToList();
+
+ CreateApiResourceRequest createApiResourceRequest = new CreateApiResourceRequest
+ {
+ Description = String.Empty,
+ DisplayName = displayName,
+ Name = resourceName,
+ Scopes = new List(),
+ Secret = secret,
+ UserClaims = new List()
+ };
+ splitScopes.ForEach(a =>
+ {
+ createApiResourceRequest.Scopes.Add(a.Trim());
+ });
+ splitUserClaims.ForEach(a =>
+ {
+ createApiResourceRequest.UserClaims.Add(a.Trim());
+ });
+
+ CreateApiResourceResponse createApiResourceResponse = await this.TestingContext.DockerHelper.SecurityServiceClient.CreateApiResource(createApiResourceRequest, CancellationToken.None).ConfigureAwait(false);
+
+ createApiResourceResponse.ApiResourceName.ShouldBe(resourceName);
+ }
+ }
+
+ [Given(@"the following clients exist")]
+ public async Task GivenTheFollowingClientsExist(Table table)
+ {
+ foreach (TableRow tableRow in table.Rows)
+ {
+ String clientId = SpecflowTableHelper.GetStringRowValue(tableRow, "ClientId");
+ String clientName = SpecflowTableHelper.GetStringRowValue(tableRow, "ClientName");
+ String secret = SpecflowTableHelper.GetStringRowValue(tableRow, "Secret");
+ String allowedScopes = SpecflowTableHelper.GetStringRowValue(tableRow, "AllowedScopes");
+ String allowedGrantTypes = SpecflowTableHelper.GetStringRowValue(tableRow, "AllowedGrantTypes");
+
+ List splitAllowedScopes = allowedScopes.Split(",").ToList();
+ List splitAllowedGrantTypes = allowedGrantTypes.Split(",").ToList();
+
+ CreateClientRequest createClientRequest = new CreateClientRequest
+ {
+ Secret = secret,
+ AllowedGrantTypes = new List(),
+ AllowedScopes = new List(),
+ ClientDescription = String.Empty,
+ ClientId = clientId,
+ ClientName = clientName
+ };
+
+ splitAllowedScopes.ForEach(a =>
+ {
+ createClientRequest.AllowedScopes.Add(a.Trim());
+ });
+ splitAllowedGrantTypes.ForEach(a =>
+ {
+ createClientRequest.AllowedGrantTypes.Add(a.Trim());
+ });
+
+ CreateClientResponse createClientResponse = await this.TestingContext.DockerHelper.SecurityServiceClient.CreateClient(createClientRequest, CancellationToken.None).ConfigureAwait(false);
+
+ createClientResponse.ClientId.ShouldBe(clientId);
+
+ this.TestingContext.AddClientDetails(clientId, secret, allowedGrantTypes);
+ }
+ }
+
[Given(@"I have created the following estates")]
[When(@"I create the following estates")]
public async Task WhenICreateTheFollowingEstates(Table table)
@@ -46,27 +130,24 @@ public async Task WhenICreateTheFollowingEstates(Table table)
EstateName = estateName
};
- CreateEstateResponse response = await this.TestingContext.DockerHelper.EstateClient.CreateEstate(String.Empty, createEstateRequest, CancellationToken.None).ConfigureAwait(false);
+ CreateEstateResponse response = await this.TestingContext.DockerHelper.EstateClient.CreateEstate(this.TestingContext.AccessToken, createEstateRequest, CancellationToken.None).ConfigureAwait(false);
response.ShouldNotBeNull();
response.EstateId.ShouldNotBe(Guid.Empty);
// Cache the estate id
- this.TestingContext.Estates.Add(estateName, response.EstateId);
+ this.TestingContext.AddEstateDetails(response.EstateId, estateName);
+
+ this.TestingContext.Logger.LogInformation($"Estate {estateName} created with Id {response.EstateId}");
}
foreach (TableRow tableRow in table.Rows)
{
- String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName");
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
- KeyValuePair estateItem = this.TestingContext.Estates.SingleOrDefault(e => e.Key == estateName);
+ EstateResponse estate = await this.TestingContext.DockerHelper.EstateClient.GetEstate(this.TestingContext.AccessToken, estateDetails.EstateId, CancellationToken.None).ConfigureAwait(false);
- estateItem.Key.ShouldNotBeNullOrEmpty();
- estateItem.Value.ShouldNotBe(Guid.Empty);
-
- EstateResponse estate = await this.TestingContext.DockerHelper.EstateClient.GetEstate(String.Empty, estateItem.Value, CancellationToken.None).ConfigureAwait(false);
-
- estate.EstateName.ShouldBe(estateName);
+ estate.EstateName.ShouldBe(estateDetails.EstateName);
}
}
@@ -81,24 +162,25 @@ public async Task WhenICreateTheFollowingOperators(Table table)
Boolean requireCustomTerminalNumber = SpecflowTableHelper.GetBooleanValue(tableRow, "RequireCustomTerminalNumber");
CreateOperatorRequest createOperatorRequest = new CreateOperatorRequest
- {
- Name = operatorName,
- RequireCustomMerchantNumber = requireCustomMerchantNumber,
- RequireCustomTerminalNumber = requireCustomTerminalNumber
- };
+ {
+ Name = operatorName,
+ RequireCustomMerchantNumber = requireCustomMerchantNumber,
+ RequireCustomTerminalNumber = requireCustomTerminalNumber
+ };
// lookup the estate id based on the name in the table
- String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName");
- Guid estateId = this.TestingContext.Estates.Single(e => e.Key == estateName).Value;
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
- CreateOperatorResponse response = await this.TestingContext.DockerHelper.EstateClient.CreateOperator(String.Empty, estateId, createOperatorRequest, CancellationToken.None).ConfigureAwait(false);
+ CreateOperatorResponse response = await this.TestingContext.DockerHelper.EstateClient.CreateOperator(this.TestingContext.AccessToken, estateDetails.EstateId, createOperatorRequest, CancellationToken.None).ConfigureAwait(false);
response.ShouldNotBeNull();
response.EstateId.ShouldNotBe(Guid.Empty);
response.OperatorId.ShouldNotBe(Guid.Empty);
// Cache the estate id
- this.TestingContext.Operators.Add(operatorName, response.OperatorId);
+ estateDetails.AddOperator(response.OperatorId, operatorName);
+
+ this.TestingContext.Logger.LogInformation($"Operator {operatorName} created with Id {response.OperatorId} for Estate {estateDetails.EstateName}");
}
}
@@ -108,6 +190,14 @@ public async Task WhenICreateTheFollowingMerchants(Table table)
{
foreach (TableRow tableRow in table.Rows)
{
+ // lookup the estate id based on the name in the table
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
+ String token = this.TestingContext.AccessToken;
+ if (String.IsNullOrEmpty(estateDetails.AccessToken) == false)
+ {
+ token = estateDetails.AccessToken;
+ }
+
String merchantName = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantName");
CreateMerchantRequest createMerchantRequest = new CreateMerchantRequest
{
@@ -126,80 +216,75 @@ public async Task WhenICreateTheFollowingMerchants(Table table)
}
};
- // lookup the estate id based on the name in the table
- String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName");
- Guid estateId = this.TestingContext.Estates.Single(e => e.Key == estateName).Value;
-
CreateMerchantResponse response = await this.TestingContext.DockerHelper.EstateClient
- .CreateMerchant(String.Empty, estateId, createMerchantRequest, CancellationToken.None).ConfigureAwait(false);
+ .CreateMerchant(token, estateDetails.EstateId, createMerchantRequest, CancellationToken.None).ConfigureAwait(false);
response.ShouldNotBeNull();
- response.EstateId.ShouldBe(estateId);
+ response.EstateId.ShouldBe(estateDetails.EstateId);
response.MerchantId.ShouldNotBe(Guid.Empty);
// Cache the merchant id
- this.TestingContext.Merchants.Add(merchantName, response.MerchantId);
- if (this.TestingContext.EstateMerchants.ContainsKey(estateId))
- {
- List merchantIdList = this.TestingContext.EstateMerchants[estateId];
- merchantIdList.Add(response.MerchantId);
- }
- else
- {
- this.TestingContext.EstateMerchants.Add(estateId, new List { response.MerchantId });
- }
+ estateDetails.AddMerchant(response.MerchantId, merchantName);
+
+ this.TestingContext.Logger.LogInformation($"Merchant {merchantName} created with Id {response.MerchantId} for Estate {estateDetails.EstateName}");
}
foreach (TableRow tableRow in table.Rows)
{
- String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName");
-
- KeyValuePair estateItem = this.TestingContext.Estates.SingleOrDefault(e => e.Key == estateName);
-
- estateItem.Key.ShouldNotBeNullOrEmpty();
- estateItem.Value.ShouldNotBe(Guid.Empty);
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
String merchantName = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantName");
- KeyValuePair merchantItem = this.TestingContext.Merchants.SingleOrDefault(m => m.Key == merchantName);
+ Guid merchantId = estateDetails.GetMerchantId(merchantName);
- merchantItem.Key.ShouldNotBeNullOrEmpty();
- merchantItem.Value.ShouldNotBe(Guid.Empty);
+ String token = this.TestingContext.AccessToken;
+ if (String.IsNullOrEmpty(estateDetails.AccessToken) == false)
+ {
+ token = estateDetails.AccessToken;
+ }
- MerchantResponse merchant = await this.TestingContext.DockerHelper.EstateClient.GetMerchant(String.Empty, estateItem.Value, merchantItem.Value, CancellationToken.None).ConfigureAwait(false);
+ MerchantResponse merchant = await this.TestingContext.DockerHelper.EstateClient.GetMerchant(token, estateDetails.EstateId, merchantId, CancellationToken.None).ConfigureAwait(false);
merchant.MerchantName.ShouldBe(merchantName);
}
}
+ [Given(@"I have assigned the following operator to the merchants")]
[When(@"I assign the following operator to the merchants")]
public async Task WhenIAssignTheFollowingOperatorToTheMerchants(Table table)
{
foreach (TableRow tableRow in table.Rows)
{
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
+
+ String token = this.TestingContext.AccessToken;
+ if (String.IsNullOrEmpty(estateDetails.AccessToken) == false)
+ {
+ token = estateDetails.AccessToken;
+ }
+
// Lookup the merchant id
String merchantName = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantName");
- Guid merchantId = this.TestingContext.Merchants[merchantName];
+ Guid merchantId = estateDetails.GetMerchantId(merchantName);
// Lookup the operator id
String operatorName = SpecflowTableHelper.GetStringRowValue(tableRow, "OperatorName");
- Guid operatorId = this.TestingContext.Operators[operatorName];
-
- // Now find the estate Id
- Guid estateId = this.TestingContext.EstateMerchants.Where(e => e.Value.Contains(merchantId)).Single().Key;
+ Guid operatorId = estateDetails.GetOperatorId(operatorName);
AssignOperatorRequest assignOperatorRequest = new AssignOperatorRequest
- {
- OperatorId = operatorId,
- MerchantNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantNumber"),
- TerminalNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "TerminalNumber"),
- };
+ {
+ OperatorId = operatorId,
+ MerchantNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantNumber"),
+ TerminalNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "TerminalNumber"),
+ };
- AssignOperatorResponse assignOperatorResponse = await this.TestingContext.DockerHelper.EstateClient.AssignOperatorToMerchant(String.Empty, estateId, merchantId, assignOperatorRequest, CancellationToken.None).ConfigureAwait(false);
+ AssignOperatorResponse assignOperatorResponse = await this.TestingContext.DockerHelper.EstateClient.AssignOperatorToMerchant(token, estateDetails.EstateId, merchantId, assignOperatorRequest, CancellationToken.None).ConfigureAwait(false);
- assignOperatorResponse.EstateId.ShouldBe(estateId);
+ assignOperatorResponse.EstateId.ShouldBe(estateDetails.EstateId);
assignOperatorResponse.MerchantId.ShouldBe(merchantId);
assignOperatorResponse.OperatorId.ShouldBe(operatorId);
+
+ this.TestingContext.Logger.LogInformation($"Operator {operatorName} assigned to Estate {estateDetails.EstateName}");
}
}
@@ -208,8 +293,10 @@ public async Task WhenIPerformTheFollowingTransactions(Table table)
{
foreach (TableRow tableRow in table.Rows)
{
- // TODO: Get a token for the merchant somehow...
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
+ String merchantToken = estateDetails.GetMerchantUserToken(tableRow["MerchantName"]);
+
String dateString = SpecflowTableHelper.GetStringRowValue(tableRow, "DateTime");
DateTime transactionDateTime = SpecflowTableHelper.GetDateForDateString(dateString, DateTime.Today);
String transactionNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "TransactionNumber");
@@ -219,7 +306,8 @@ public async Task WhenIPerformTheFollowingTransactions(Table table)
switch (transactionType)
{
case "Logon":
- await this.PerformLogonTransaction(transactionDateTime,
+ await this.PerformLogonTransaction(merchantToken,
+ transactionDateTime,
transactionType,
transactionNumber,
imeiNumber,
@@ -230,7 +318,111 @@ await this.PerformLogonTransaction(transactionDateTime,
}
}
- private async Task PerformLogonTransaction(DateTime transactionDateTime, String transactionType, String transactionNumber, String imeiNumber, CancellationToken cancellationToken)
+ [Given(@"I am logged in as ""(.*)"" with password ""(.*)"" for Merchant ""(.*)"" for Estate ""(.*)"" with client ""(.*)""")]
+ public async Task GivenIAmLoggedInAsWithPasswordForMerchantForEstateWithClient(String username, String password, String merchantName, String estateName, String clientId)
+ {
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(estateName);
+
+ ClientDetails clientDetails = this.TestingContext.GetClientDetails(clientId);
+
+ TokenResponse tokenResponse = await this.TestingContext.DockerHelper.SecurityServiceClient.GetToken(username, password, clientId, clientDetails.ClientSecret, CancellationToken.None).ConfigureAwait(false);
+
+ estateDetails.AddMerchantUserToken(merchantName, username,tokenResponse.AccessToken);
+ }
+
+ [Given(@"the following security roles exist")]
+ public async Task GivenTheFollowingSecurityRolesExist(Table table)
+ {
+ foreach (TableRow tableRow in table.Rows)
+ {
+ String roleName = SpecflowTableHelper.GetStringRowValue(tableRow, "RoleName");
+
+ CreateRoleRequest createRoleRequest = new CreateRoleRequest
+ {
+ RoleName = roleName
+ };
+
+ CreateRoleResponse createRoleResponse = await this.TestingContext.DockerHelper.SecurityServiceClient.CreateRole(createRoleRequest, CancellationToken.None).ConfigureAwait(false);
+
+ createRoleResponse.RoleId.ShouldNotBe(Guid.Empty);
+ }
+ }
+
+ [When(@"I create the following security users")]
+ [Given("I have created the following security users")]
+ public async Task WhenICreateTheFollowingSecurityUsers(Table table)
+ {
+ foreach (TableRow tableRow in table.Rows)
+ {
+ // lookup the estate id based on the name in the table
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
+
+ if (tableRow.ContainsKey("EstateName") && tableRow.ContainsKey("MerchantName") == false)
+ {
+ // Creating an Estate User
+ CreateEstateUserRequest createEstateUserRequest = new CreateEstateUserRequest
+ {
+ EmailAddress = SpecflowTableHelper.GetStringRowValue(tableRow, "EmailAddress"),
+ FamilyName = SpecflowTableHelper.GetStringRowValue(tableRow, "FamilyName"),
+ GivenName = SpecflowTableHelper.GetStringRowValue(tableRow, "GivenName"),
+ MiddleName = SpecflowTableHelper.GetStringRowValue(tableRow, "MiddleName"),
+ Password = SpecflowTableHelper.GetStringRowValue(tableRow, "Password")
+ };
+
+ CreateEstateUserResponse createEstateUserResponse =
+ await this.TestingContext.DockerHelper.EstateClient.CreateEstateUser(this.TestingContext.AccessToken,
+ estateDetails.EstateId,
+ createEstateUserRequest,
+ CancellationToken.None);
+
+ createEstateUserResponse.EstateId.ShouldBe(estateDetails.EstateId);
+ createEstateUserResponse.UserId.ShouldNotBe(Guid.Empty);
+
+ estateDetails.SetEstateUser(createEstateUserRequest.EmailAddress, createEstateUserRequest.Password);
+
+ this.TestingContext.Logger.LogInformation($"Security user {createEstateUserRequest.EmailAddress} assigned to Estate {estateDetails.EstateName}");
+ }
+ else if (tableRow.ContainsKey("MerchantName"))
+ {
+ // Creating a merchant user
+ String token = this.TestingContext.AccessToken;
+ if (String.IsNullOrEmpty(estateDetails.AccessToken) == false)
+ {
+ token = estateDetails.AccessToken;
+ }
+
+ // lookup the merchant id based on the name in the table
+ String merchantName = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantName");
+ Guid merchantId = estateDetails.GetMerchantId(merchantName);
+
+ CreateMerchantUserRequest createMerchantUserRequest = new CreateMerchantUserRequest
+ {
+ EmailAddress = SpecflowTableHelper.GetStringRowValue(tableRow, "EmailAddress"),
+ FamilyName = SpecflowTableHelper.GetStringRowValue(tableRow, "FamilyName"),
+ GivenName = SpecflowTableHelper.GetStringRowValue(tableRow, "GivenName"),
+ MiddleName = SpecflowTableHelper.GetStringRowValue(tableRow, "MiddleName"),
+ Password = SpecflowTableHelper.GetStringRowValue(tableRow, "Password")
+ };
+
+ CreateMerchantUserResponse createMerchantUserResponse =
+ await this.TestingContext.DockerHelper.EstateClient.CreateMerchantUser(token,
+ estateDetails.EstateId,
+ merchantId,
+ createMerchantUserRequest,
+ CancellationToken.None);
+
+ createMerchantUserResponse.EstateId.ShouldBe(estateDetails.EstateId);
+ createMerchantUserResponse.MerchantId.ShouldBe(merchantId);
+ createMerchantUserResponse.UserId.ShouldNotBe(Guid.Empty);
+
+ estateDetails.AddMerchantUser(merchantName, createMerchantUserRequest.EmailAddress, createMerchantUserRequest.Password);
+
+ this.TestingContext.Logger.LogInformation($"Security user {createMerchantUserRequest.EmailAddress} assigned to Merchant {merchantName}");
+ }
+ }
+ }
+
+ private async Task PerformLogonTransaction(String merchantToken, DateTime transactionDateTime, String transactionType, String transactionNumber, String imeiNumber, CancellationToken cancellationToken)
{
LogonTransactionRequestMessage logonTransactionRequestMessage = new LogonTransactionRequestMessage
{
@@ -246,9 +438,11 @@ private async Task PerformLogonTransaction(DateTime transactionDateTime, String
{
TypeNameHandling = TypeNameHandling.All
}), Encoding.UTF8, "application/json");
+
+ this.TestingContext.DockerHelper.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",merchantToken);
- HttpResponseMessage response = await this.TestingContext.DockerHelper.HttpClient.PostAsync(uri, content, cancellationToken);
-
+ HttpResponseMessage response = await this.TestingContext.DockerHelper.HttpClient.PostAsync(uri, content, cancellationToken).ConfigureAwait(false);
+
response.IsSuccessStatusCode.ShouldBeTrue();
}
@@ -257,13 +451,19 @@ public void ThenTransactionResponseShouldContainTheFollowingInformation(Table ta
{
foreach (TableRow tableRow in table.Rows)
{
+ // Get the merchant name
+ EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow);
+
+ String merchantName = SpecflowTableHelper.GetStringRowValue(tableRow, "MerchantName");
+ Guid merchantId = estateDetails.GetMerchantId(merchantName);
+
String transactionNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "TransactionNumber");
- SerialisedMessage serialisedMessage = this.TestingContext.TransactionResponses[transactionNumber];
+ SerialisedMessage serialisedMessage = estateDetails.GetTransactionResponse(merchantId, transactionNumber);
Object transactionResponse = JsonConvert.DeserializeObject(serialisedMessage.SerialisedData,
- new JsonSerializerSettings
- {
- TypeNameHandling = TypeNameHandling.All
- });
+ new JsonSerializerSettings
+ {
+ TypeNameHandling = TypeNameHandling.All
+ });
this.ValidateTransactionResponse((dynamic)transactionResponse, tableRow);
}
}
@@ -278,6 +478,24 @@ private void ValidateTransactionResponse(LogonTransactionResponse logonTransacti
logonTransactionResponse.ResponseMessage.ShouldBe(expectedResponseMessage);
}
+ [Given(@"I have a token to access the estate management and transaction processor acl resources")]
+ public async Task GivenIHaveATokenToAccessTheEstateManagementAndTransactionProcessorAclResources(Table table)
+ {
+ foreach (TableRow tableRow in table.Rows)
+ {
+ String clientId = SpecflowTableHelper.GetStringRowValue(tableRow, "ClientId");
+
+ ClientDetails clientDetails = this.TestingContext.GetClientDetails(clientId);
+
+ if (clientDetails.GrantType == "client_credentials")
+ {
+ TokenResponse tokenResponse = await this.TestingContext.DockerHelper.SecurityServiceClient.GetToken(clientId, clientDetails.ClientSecret, CancellationToken.None).ConfigureAwait(false);
+
+ this.TestingContext.AccessToken = tokenResponse.AccessToken;
+ }
+ }
+ }
+
}
}
diff --git a/TransactionProcessorACL.IntegrationTests/TransactionProcessorACL.IntegrationTests.csproj b/TransactionProcessorACL.IntegrationTests/TransactionProcessorACL.IntegrationTests.csproj
index 585aea8..0053e76 100644
--- a/TransactionProcessorACL.IntegrationTests/TransactionProcessorACL.IntegrationTests.csproj
+++ b/TransactionProcessorACL.IntegrationTests/TransactionProcessorACL.IntegrationTests.csproj
@@ -7,15 +7,17 @@
-
+
-
+
-
+
+
+
-
-
-
+
+
+
diff --git a/TransactionProcessorACL/appsettings.json b/TransactionProcessorACL/appsettings.json
index e166c17..2658dbc 100644
--- a/TransactionProcessorACL/appsettings.json
+++ b/TransactionProcessorACL/appsettings.json
@@ -10,7 +10,7 @@
"SecurityService": "http://192.168.1.133:5001"
},
"SecurityConfiguration": {
- "ApiName": "transactionProcessorACL",
+ "ApiName": "transactionProcessorAcl",
"Authority": "http://192.168.1.133:5001"
},
"AllowedHosts": "*"