Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions EstateManagementUI.BusinessLogic.Tests/ApiClientTests.cs

Large diffs are not rendered by default.

208 changes: 129 additions & 79 deletions EstateManagementUI.BusinessLogic/Clients/ApiClient.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FileProcessor.Client" Version="2025.8.1" />
<PackageReference Include="FileProcessor.Client" Version="2025.8.2-build99" />
<PackageReference Include="MediatR" Version="13.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.10">
<PrivateAssets>all</PrivateAssets>
Expand All @@ -18,11 +18,12 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Shared" Version="2025.10.2" />
<PackageReference Include="SecurityService.Client" Version="2025.10.1" />
<PackageReference Include="Shared" Version="2025.11.11" />
<PackageReference Include="SimpleResults" Version="4.0.0" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="EstateReportingAPI.Client" Version="2025.8.1" />
<PackageReference Include="TransactionProcessor.Client" Version="2025.9.1" />
<PackageReference Include="EstateReportingAPI.Client" Version="2025.10.2-build92" />
<PackageReference Include="TransactionProcessor.Client" Version="2025.10.2-build261" />
</ItemGroup>

</Project>
154 changes: 79 additions & 75 deletions EstateManagementUI.IntegrationTests/Common/DockerHelper.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using Ductus.FluentDocker.Builders;
using Ductus.FluentDocker.Common;
using Ductus.FluentDocker.Executors;
using Ductus.FluentDocker.Extensions;
using Ductus.FluentDocker.Services;
using Ductus.FluentDocker.Services.Extensions;
using EstateManagementUI.BusinessLogic.PermissionService;
using EstateManagementUI.BusinessLogic.PermissionService.Database;
using EstateManagementUI.BusinessLogic.PermissionService.Database.Entities;
Expand All @@ -23,14 +17,19 @@
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Networks;
using Shared.IntegrationTesting.TestContainers;
using TransactionProcessor.Client;

namespace EstateManagementUI.IntegrationTests.Common
{
public class DockerHelper : global::Shared.IntegrationTesting.DockerHelper
public class DockerHelper : global::Shared.IntegrationTesting.TestContainers.DockerHelper
{
#region Fields

Expand Down Expand Up @@ -76,15 +75,15 @@ public override void SetupContainerNames() {
private static void AddEntryToHostsFile(String ipaddress,
String hostname)
{
if (FdOs.IsWindows())
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var hostsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), @"drivers\etc\hosts");
using (StreamWriter w = File.AppendText(hostsPath))
{
w.WriteLine($"{ipaddress} {hostname}");
}
}
else if (FdOs.IsLinux())
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
DockerHelper.ExecuteBashCommand($"echo {ipaddress} {hostname} | sudo tee -a /etc/hosts");
}
Expand Down Expand Up @@ -148,8 +147,8 @@ protected override List<String> GetRequiredProjections()
public override ContainerBuilder SetupTransactionProcessorContainer()
{

List<String> variables = new List<String>();
variables.Add($"OperatorConfiguration:PataPawaPrePay:Url=http://{this.TestHostContainerName}:{DockerPorts.TestHostPort}/api/patapawaprepay");
Dictionary<String, String> variables = new Dictionary<String, String>();
variables.Add($"OperatorConfiguration:PataPawaPrePay:Url",$"http://{this.TestHostContainerName}:{DockerPorts.TestHostPort}/api/patapawaprepay");

this.AdditionalVariables.Add(ContainerType.FileProcessor, variables);

Expand Down Expand Up @@ -189,45 +188,55 @@ public override async Task StartContainersForScenarioRun(String scenarioName, Do
this.ProjectionManagementClient = new EventStoreProjectionManagementClient(ConfigureEventStoreSettings());
}

private async Task<IContainerService> StartEstateManagementUiContainer(List<INetworkService> networkServices,
private async Task<IContainer> StartEstateManagementUiContainer(List<INetwork> networkServices,
Int32 securityServiceContainerPort,
Int32 securityServiceLocalPort)
{
TraceX("About to Start Estate Management UI Container");

List<String> environmentVariables = this.GetCommonEnvironmentVariables();
environmentVariables.Add($"AppSettings:Authority=https://{this.SecurityServiceContainerName}:0"); // The port is set to 0 to stop defaulting to 443
environmentVariables.Add($"AppSettings:SecurityServiceLocalPort={securityServiceLocalPort}");
environmentVariables.Add($"AppSettings:SecurityServicePort={securityServiceContainerPort}");
environmentVariables.Add("AppSettings:HttpClientIgnoreCertificateErrors=true");
var environmentVariables = this.GetCommonEnvironmentVariables();

environmentVariables.Remove("AppSettings:ClientId");
environmentVariables.Remove("AppSettings:ClientSecret");

environmentVariables.Add("AppSettings:Authority",$"https://{this.SecurityServiceContainerName}:0"); // The port is set to 0 to stop defaulting to 443
environmentVariables.Add("AppSettings:SecurityServiceLocalPort",$"{securityServiceLocalPort}");
environmentVariables.Add("AppSettings:SecurityServicePort",$"{securityServiceContainerPort}");
environmentVariables.Add("AppSettings:HttpClientIgnoreCertificateErrors",$"true");
//environmentVariables.Add($"AppSettings:PermissionsBypass=true");
environmentVariables.Add($"AppSettings:IsIntegrationTest=true");
environmentVariables.Add($"ASPNETCORE_ENVIRONMENT=Development");
environmentVariables.Add($"EstateManagementScope=estateManagement");
environmentVariables.Add("urls=https://*:5004");
environmentVariables.Add($"AppSettings:ClientId=estateUIClient");
environmentVariables.Add($"AppSettings:ClientSecret=Secret1");
environmentVariables.Add($"DataReloadConfig:DefaultInSeconds=1");
environmentVariables.Add("AppSettings:HttpClientIgnoreCertificateErrors=true");
environmentVariables.Add(this.SetConnectionString("ConnectionStrings:TransactionProcessorReadModel", "TransactionProcessorReadModel", this.UseSecureSqlServerDatabase));
environmentVariables.Add("AppSettings:IsIntegrationTest","true");
environmentVariables.Add("ASPNETCORE_ENVIRONMENT","Development");
environmentVariables.Add("EstateManagementScope","estateManagement");
environmentVariables.Add("urls","https://*:5004");
environmentVariables.Add($"AppSettings:ClientId","estateUIClient");
environmentVariables.Add($"AppSettings:ClientSecret","Secret1");
environmentVariables.Add($"AppSettings:BackEndClientId", "serviceClient");
environmentVariables.Add($"AppSettings:BackEndClientSecret", "Secret1");
environmentVariables.Add($"DataReloadConfig:DefaultInSeconds","1");
environmentVariables.Add("ConnectionStrings:TransactionProcessorReadModel", this.SetConnectionString( "TransactionProcessorReadModel", this.UseSecureSqlServerDatabase));

TraceX("About to Built Estate Management UI Container");
ContainerBuilder containerBuilder = new Builder().UseContainer()
.WithName(this.EstateManagementUiContainerName)
.UseImageDetails(("estatemanagementui", false))
.WithEnvironment(environmentVariables.ToArray())
//.UseNetwork(networkServices.ToArray())
.ExposePort(5004)
.MountHostFolder(this.DockerPlatform, this.HostTraceFolder)
.SetDockerCredentials(this.DockerCredentials);
ContainerBuilder containerBuilder = new ContainerBuilder()
.WithName(this.EstateManagementUiContainerName)
.WithImage("estatemanagementui")
.WithEnvironment(environmentVariables)
.MountHostFolder(this.DockerPlatform, this.HostTraceFolder)
//.UseNetwork(networkServices.ToArray())
.WithPortBinding(5004);
//.MountHostFolder(this.DockerPlatform, this.HostTraceFolder)
//.SetDockerCredentials(this.DockerCredentials);
TraceX("About to Call .Start()");
IContainerService builtContainer = containerBuilder.Build();
foreach (INetwork networkService in networkServices) {
containerBuilder = containerBuilder.WithNetwork(networkService);
}

IContainer? builtContainer = containerBuilder.Build();

try{

builtContainer.Start();
builtContainer.WaitForPort("5004/tcp", 30000);
this.EstateManagementUiPort = builtContainer.ToHostExposedEndpoint($"5004/tcp").Port;
await builtContainer.StartAsync();
//builtContainer.WaitForPort("5004/tcp", 30000);
this.EstateManagementUiPort = builtContainer.GetMappedPublicPort($"5004");

await Task.Delay(5000);

Expand Down Expand Up @@ -317,23 +326,15 @@ private async Task<IContainerService> StartEstateManagementUiContainer(List<INet
}
catch(Exception ex){
TraceX(ex.GetCombinedExceptionMessages());
ConsoleStream<String> logs = builtContainer.Logs(true, CancellationToken.None);
IList<String> xx = logs.ReadToEnd();
while (xx.Any())
{
foreach (String s in xx)
{
TraceX($"Logs|{s}");
}
xx = logs.ReadToEnd();
}

}

TraceX("About to attach networkServices");
foreach (INetworkService networkService in networkServices)
{
networkService.Attach(builtContainer, false);
}
//foreach (INetwork networkService in networkServices)
//{
// //networkService..Attach(builtContainer, false);
// builtContainer.
//}

//Trace("About to get port");
//// Do a health check here
Expand Down Expand Up @@ -374,35 +375,38 @@ public override ContainerBuilder SetupSecurityServiceContainer()



List<String> environmentVariables = this.GetCommonEnvironmentVariables();
environmentVariables.Add($"ServiceOptions:PublicOrigin=https://{this.SecurityServiceContainerName}:{DockerPorts.SecurityServiceDockerPort}");
environmentVariables.Add($"ServiceOptions:IssuerUrl=https://{this.SecurityServiceContainerName}:{DockerPorts.SecurityServiceDockerPort}");
environmentVariables.Add("ASPNETCORE_ENVIRONMENT=IntegrationTest");
environmentVariables.Add($"urls=https://*:{DockerPorts.SecurityServiceDockerPort}");
var environmentVariables = this.GetCommonEnvironmentVariables();
environmentVariables.Add($"ServiceOptions:PublicOrigin",$"https://{this.SecurityServiceContainerName}:{DockerPorts.SecurityServiceDockerPort}");
environmentVariables.Add($"ServiceOptions:IssuerUrl",$"https://{this.SecurityServiceContainerName}:{DockerPorts.SecurityServiceDockerPort}");
environmentVariables.Add("ASPNETCORE_ENVIRONMENT",$"IntegrationTest");
environmentVariables.Add($"urls",$"https://*:{DockerPorts.SecurityServiceDockerPort}");

environmentVariables.Add($"ServiceOptions:PasswordOptions:RequiredLength=6");
environmentVariables.Add($"ServiceOptions:PasswordOptions:RequireDigit=false");
environmentVariables.Add($"ServiceOptions:PasswordOptions:RequireUpperCase=false");
environmentVariables.Add($"ServiceOptions:UserOptions:RequireUniqueEmail=false");
environmentVariables.Add($"ServiceOptions:SignInOptions:RequireConfirmedEmail=false");
environmentVariables.Add($"ServiceOptions:PasswordOptions:RequiredLength","6");
environmentVariables.Add($"ServiceOptions:PasswordOptions:RequireDigit","false");
environmentVariables.Add($"ServiceOptions:PasswordOptions:RequireUpperCase","false");
environmentVariables.Add($"ServiceOptions:UserOptions:RequireUniqueEmail","false");
environmentVariables.Add($"ServiceOptions:SignInOptions:RequireConfirmedEmail","false");

environmentVariables.Add(this.SetConnectionString("ConnectionStrings:PersistedGrantDbContext", $"PersistedGrantStore-{this.TestId}", this.UseSecureSqlServerDatabase));
environmentVariables.Add(this.SetConnectionString("ConnectionStrings:ConfigurationDbContext", $"Configuration-{this.TestId}", this.UseSecureSqlServerDatabase));
environmentVariables.Add(this.SetConnectionString("ConnectionStrings:AuthenticationDbContext", $"Authentication-{this.TestId}", this.UseSecureSqlServerDatabase));
environmentVariables.Add("ConnectionStrings:PersistedGrantDbContext",this.SetConnectionString($"PersistedGrantStore-{this.TestId}", this.UseSecureSqlServerDatabase));
environmentVariables.Add("ConnectionStrings:ConfigurationDbContext", this.SetConnectionString($"Configuration-{this.TestId}", this.UseSecureSqlServerDatabase));
environmentVariables.Add("ConnectionStrings:AuthenticationDbContext",this.SetConnectionString($"Authentication-{this.TestId}", this.UseSecureSqlServerDatabase));

environmentVariables.Add("Logging:LogLevel:Microsoft=Information");
environmentVariables.Add("Logging:LogLevel:Default=Information");
environmentVariables.Add("Logging:EventLog:LogLevel:Default=None");
environmentVariables.Add("Logging:LogLevel:Microsoft","Information");
environmentVariables.Add("Logging:LogLevel:Default","Information");
environmentVariables.Add("Logging:EventLog:LogLevel:Default","None");

var imageDetailsResult = this.GetImageDetails(ContainerType.SecurityService);

ContainerBuilder securityServiceContainer = new Builder().UseContainer().WithName(this.SecurityServiceContainerName)
.WithEnvironment(environmentVariables.ToArray())
.UseImageDetails(imageDetailsResult.Data)
.ExposePort(DockerPorts.SecurityServiceDockerPort)
.MountHostFolder(this.DockerPlatform, this.HostTraceFolder)
.SetDockerCredentials(this.DockerCredentials);

ContainerBuilder securityServiceContainer = new ContainerBuilder()
.WithName(this.SecurityServiceContainerName)
.WithEnvironment(environmentVariables)
.WithImage(imageDetailsResult.Data.imageName)
.MountHostFolder(this.DockerPlatform, this.HostTraceFolder)
.WithPortBinding(DockerPorts.SecurityServiceDockerPort);
//.MountHostFolder(this.DockerPlatform, this.HostTraceFolder)
//.SetDockerCredentials(this.DockerCredentials);


// Now build and return the container
return securityServiceContainer;
}
Expand Down
7 changes: 2 additions & 5 deletions EstateManagementUI.IntegrationTests/Common/GenericSteps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,10 @@ public async Task StartSystem()

await Setup.GlobalSetup(this.TestingContext.DockerHelper);

this.TestingContext.DockerHelper.SqlServerContainer = Setup.DatabaseServerContainer;
this.TestingContext.DockerHelper.SqlServerNetwork = Setup.DatabaseServerNetwork;
this.TestingContext.DockerHelper.DockerCredentials = Setup.DockerCredentials;
this.TestingContext.DockerHelper.SqlCredentials = Setup.SqlCredentials;
this.TestingContext.DockerHelper.SqlServerContainerName = "sharedsqlserver";



this.TestingContext.Logger = logger;
this.TestingContext.Logger.LogInformation("About to Start Containers for Scenario Run");
await this.TestingContext.DockerHelper.StartContainersForScenarioRun(scenarioName, dockerServices).ConfigureAwait(false);
Expand All @@ -59,7 +56,7 @@ public async Task StartSystem()

[AfterScenario(Order = 1)]
public async Task StopSystem(){
DockerServices sharedDockerServices = DockerServices.SqlServer;
DockerServices sharedDockerServices = DockerServices.None;
await this.TestingContext.DockerHelper.StopContainersForScenarioRun(sharedDockerServices).ConfigureAwait(false);
}
}
Expand Down
27 changes: 0 additions & 27 deletions EstateManagementUI.IntegrationTests/Common/Setup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,12 @@ namespace EstateManagementUI.IntegrationTests.Common
[Binding]
public class Setup
{
public static IContainerService DatabaseServerContainer;
public static INetworkService DatabaseServerNetwork;
public static (String usename, String password) SqlCredentials = ("sa", "thisisalongpassword123!");
public static (String url, String username, String password) DockerCredentials = ("https://www.docker.com", "stuartferguson", "Sc0tland");

static object padLock = new object(); // Object to lock on

public static async Task GlobalSetup(DockerHelper dockerHelper)
{
ShouldlyConfiguration.DefaultTaskTimeout = TimeSpan.FromMinutes(1);
dockerHelper.SqlCredentials = Setup.SqlCredentials;
dockerHelper.DockerCredentials = Setup.DockerCredentials;
dockerHelper.SqlServerContainerName = "sharedsqlserver";

lock (Setup.padLock)
{
Setup.DatabaseServerNetwork = dockerHelper.SetupTestNetwork("sharednetwork");

dockerHelper.Logger.LogInformation("in start SetupSqlServerContainer");
Setup.DatabaseServerContainer = dockerHelper.SetupSqlServerContainer(Setup.DatabaseServerNetwork).Result;
}
}

public static String GetConnectionString(String databaseName)
{
return $"server={Setup.DatabaseServerContainer.Name};database={databaseName};user id={Setup.SqlCredentials.usename};password={Setup.SqlCredentials.password}";
}

public static String GetLocalConnectionString(String databaseName)
{
Int32 databaseHostPort = Setup.DatabaseServerContainer.ToHostExposedEndpoint("1433/tcp").Port;

return $"server=localhost,{databaseHostPort};database={databaseName};user id={Setup.SqlCredentials.usename};password={Setup.SqlCredentials.password}";
}
}
}
Loading
Loading