diff --git a/src/Tests/AliasVault.E2ETests/Common/AdminPlaywrightTest.cs b/src/Tests/AliasVault.E2ETests/Common/AdminPlaywrightTest.cs
index 7941d0a87..0e60787a2 100644
--- a/src/Tests/AliasVault.E2ETests/Common/AdminPlaywrightTest.cs
+++ b/src/Tests/AliasVault.E2ETests/Common/AdminPlaywrightTest.cs
@@ -58,7 +58,7 @@ public class AdminPlaywrightTest : PlaywrightTest
AppBaseUrl = "http://localhost:" + appPort + "/";
// Start Admin project in-memory.
- _webAppFactory.HostUrl = "http://localhost:" + appPort;
+ _webAppFactory.Port = appPort;
_webAppFactory.CreateDefaultClient();
await SetupPlaywrightBrowserAndContext();
diff --git a/src/Tests/AliasVault.E2ETests/Common/ClientPlaywrightTest.cs b/src/Tests/AliasVault.E2ETests/Common/ClientPlaywrightTest.cs
index 073f1e1b3..8b1848f37 100644
--- a/src/Tests/AliasVault.E2ETests/Common/ClientPlaywrightTest.cs
+++ b/src/Tests/AliasVault.E2ETests/Common/ClientPlaywrightTest.cs
@@ -85,11 +85,11 @@ public class ClientPlaywrightTest : PlaywrightTest
ApiBaseUrl = "http://localhost:" + apiPort + "/";
// Start WebAPI in-memory.
- _apiFactory.HostUrl = "http://localhost:" + apiPort;
+ _apiFactory.Port = apiPort;
_apiFactory.CreateDefaultClient();
// Start Blazor WASM in-memory.
- _clientFactory.HostUrl = "http://localhost:" + appPort;
+ _clientFactory.Port = appPort;
_clientFactory.CreateDefaultClient();
await SetupPlaywrightBrowserAndContext();
diff --git a/src/Tests/AliasVault.E2ETests/Infrastructure/KestrelTestServer.cs b/src/Tests/AliasVault.E2ETests/Infrastructure/KestrelTestServer.cs
new file mode 100644
index 000000000..3d5254342
--- /dev/null
+++ b/src/Tests/AliasVault.E2ETests/Infrastructure/KestrelTestServer.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) lanedirt. All rights reserved.
+// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
+//
+//-----------------------------------------------------------------------
+
+namespace AliasVault.E2ETests.Infrastructure;
+
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+///
+/// A that uses Kestrel as the server.
+///
+public class KestrelTestServer : TestServer, IServer
+{
+ private readonly KestrelServer _server;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to use.
+ public KestrelTestServer(IServiceProvider serviceProvider)
+ : base(serviceProvider)
+ {
+ // We get all the transport factories registered, and the first one is the correct one
+ // Getting the IConnectionListenerFactory directly from the service provider does not work
+ var transportFactory = serviceProvider.GetRequiredService>().First();
+
+ var kestrelOptions = serviceProvider.GetRequiredService>();
+ var loggerFactory = serviceProvider.GetRequiredService();
+ _server = new KestrelServer(kestrelOptions, transportFactory, loggerFactory);
+ }
+
+ ///
+ async Task IServer.StartAsync(IHttpApplication application, CancellationToken cancellationToken)
+ {
+ // We need to also invoke the TestServer's StartAsync method to ensure that the test server is started
+ // Because the TestServer's StartAsync method is implemented explicitly, we need to use reflection to invoke it
+ await InvokeExplicitInterfaceMethod(nameof(IServer.StartAsync), typeof(TContext), [application, cancellationToken]);
+
+ // We also start the Kestrel server in order for localhost to work
+ await _server.StartAsync(application, cancellationToken);
+ }
+
+ ///
+ async Task IServer.StopAsync(CancellationToken cancellationToken)
+ {
+ await InvokeExplicitInterfaceMethod(nameof(IServer.StopAsync), null, [cancellationToken]);
+ await _server.StopAsync(cancellationToken);
+ }
+
+ private Task InvokeExplicitInterfaceMethod(string methodName, Type? genericParameter, object[] args)
+ {
+ var baseMethod = typeof(TestServer).GetInterfaceMap(typeof(IServer)).TargetMethods.First(m => m.Name.EndsWith(methodName));
+ var method = genericParameter == null ? baseMethod : baseMethod.MakeGenericMethod(genericParameter);
+ var task = method.Invoke(this, args) as Task ?? throw new InvalidOperationException("Task not returned");
+ return task;
+ }
+}
diff --git a/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationAdminFactoryFixture.cs b/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationAdminFactoryFixture.cs
index e390940b1..27f723b29 100644
--- a/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationAdminFactoryFixture.cs
+++ b/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationAdminFactoryFixture.cs
@@ -11,6 +11,7 @@ using System.Data.Common;
using AliasServerDb;
using AliasVault.Admin.Services;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
@@ -49,9 +50,9 @@ public class WebApplicationAdminFactoryFixture : WebApplicationFact
}
///
- /// Gets or sets the URL the web application host will listen on.
+ /// Gets or sets the port the web application kestrel host will listen on.
///
- public string HostUrl { get; set; } = "https://localhost:5003";
+ public int Port { get; set; } = 5003;
///
/// Returns the DbContext instance for the test. This can be used to seed the database with test data.
@@ -82,28 +83,23 @@ public class WebApplicationAdminFactoryFixture : WebApplicationFact
///
protected override IHost CreateHost(IHostBuilder builder)
{
- var dummyHost = builder.Build();
+ builder.ConfigureWebHost(webHostBuilder =>
+ {
+ webHostBuilder.UseKestrel(opt => opt.ListenLocalhost(Port));
+ webHostBuilder.ConfigureServices(s => s.AddSingleton());
+ });
- builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel());
-
- var host = builder.Build();
- host.Start();
+ var host = base.CreateHost(builder);
// Get the DbContextFactory instance and store it for later use during tests.
_dbContextFactory = host.Services.GetRequiredService>();
- // This delay prevents "ERR_CONNECTION_REFUSED" errors
- // which happened like 1 out of 10 times when running tests.
- Thread.Sleep(100);
-
- return dummyHost;
+ return host;
}
///
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
- builder.UseUrls(HostUrl);
-
SetEnvironmentVariables();
builder.ConfigureServices(services =>
@@ -129,19 +125,13 @@ public class WebApplicationAdminFactoryFixture : WebApplicationFact
/// The to modify.
private static void RemoveExistingRegistrations(IServiceCollection services)
{
- var descriptorsToRemove = new[]
- {
- services.SingleOrDefault(d => d.ServiceType == typeof(IDbContextFactory)),
- services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)),
- services.SingleOrDefault(d => d.ServiceType == typeof(VersionedContentService)),
- };
+ var descriptorsToRemove = services.Where(d =>
+ d.ServiceType.ToString().Contains("AliasServerDbContext") ||
+ d.ServiceType == typeof(VersionedContentService)).ToList();
foreach (var descriptor in descriptorsToRemove)
{
- if (descriptor != null)
- {
- services.Remove(descriptor);
- }
+ services.Remove(descriptor);
}
}
diff --git a/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationApiFactoryFixture.cs b/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationApiFactoryFixture.cs
index 6a57df006..b7a5cfc22 100644
--- a/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationApiFactoryFixture.cs
+++ b/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationApiFactoryFixture.cs
@@ -11,6 +11,7 @@ using System.Data.Common;
using AliasServerDb;
using AliasVault.Shared.Providers.Time;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
@@ -49,9 +50,9 @@ public class WebApplicationApiFactoryFixture : WebApplicationFactor
}
///
- /// Gets or sets the URL the web application host will listen on.
+ /// Gets or sets the port the web application kestrel host will listen on.
///
- public string HostUrl { get; set; } = "https://localhost:5001";
+ public int Port { get; set; } = 5001;
///
/// Gets the time provider instance for mutating the current time in tests.
@@ -87,28 +88,23 @@ public class WebApplicationApiFactoryFixture : WebApplicationFactor
///
protected override IHost CreateHost(IHostBuilder builder)
{
- var dummyHost = builder.Build();
+ builder.ConfigureWebHost(webHostBuilder =>
+ {
+ webHostBuilder.UseKestrel(opt => opt.ListenLocalhost(Port));
+ webHostBuilder.ConfigureServices(s => s.AddSingleton());
+ });
- builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel());
-
- var host = builder.Build();
- host.Start();
+ var host = base.CreateHost(builder);
// Get the DbContextFactory instance and store it for later use during tests.
_dbContextFactory = host.Services.GetRequiredService>();
- // This delay prevents "ERR_CONNECTION_REFUSED" errors
- // which happened like 1 out of 10 times when running tests.
- Thread.Sleep(100);
-
- return dummyHost;
+ return host;
}
///
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
- builder.UseUrls(HostUrl);
-
SetEnvironmentVariables();
builder.ConfigureServices(services =>
@@ -133,19 +129,13 @@ public class WebApplicationApiFactoryFixture : WebApplicationFactor
/// The to modify.
private static void RemoveExistingRegistrations(IServiceCollection services)
{
- var descriptorsToRemove = new[]
- {
- services.SingleOrDefault(d => d.ServiceType == typeof(IDbContextFactory)),
- services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions)),
- services.SingleOrDefault(d => d.ServiceType == typeof(ITimeProvider)),
- };
+ var descriptorsToRemove = services.Where(d =>
+ d.ServiceType.ToString().Contains("AliasServerDbContext") ||
+ d.ServiceType == typeof(ITimeProvider)).ToList();
foreach (var descriptor in descriptorsToRemove)
{
- if (descriptor != null)
- {
- services.Remove(descriptor);
- }
+ services.Remove(descriptor);
}
}
diff --git a/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationClientFactoryFixture.cs b/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationClientFactoryFixture.cs
index 8653749b4..a28be75bf 100644
--- a/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationClientFactoryFixture.cs
+++ b/src/Tests/AliasVault.E2ETests/Infrastructure/WebApplicationClientFactoryFixture.cs
@@ -8,7 +8,9 @@
namespace AliasVault.E2ETests.Infrastructure;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Mvc.Testing;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
///
@@ -19,30 +21,19 @@ public class WebApplicationClientFactoryFixture : WebApplicationFac
where TEntryPoint : class
{
///
- /// Gets or sets the URL the web application host will listen on.
+ /// Gets or sets the port the web application kestrel host will listen on.
///
- public string HostUrl { get; set; } = "https://localhost:5002";
-
- ///
- protected override void ConfigureWebHost(IWebHostBuilder builder)
- {
- builder.UseUrls(HostUrl);
- }
+ public int Port { get; set; } = 5002;
///
protected override IHost CreateHost(IHostBuilder builder)
{
- var dummyHost = builder.Build();
+ builder.ConfigureWebHost(webHostBuilder =>
+ {
+ webHostBuilder.UseKestrel(opt => opt.ListenLocalhost(Port));
+ webHostBuilder.ConfigureServices(s => s.AddSingleton());
+ });
- builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel());
-
- var host = builder.Build();
- host.Start();
-
- // This delay prevents "ERR_CONNECTION_REFUSED" errors
- // which happened like 1 out of 10 times when running tests.
- Thread.Sleep(100);
-
- return dummyHost;
+ return base.CreateHost(builder);
}
}