mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-20 23:52:31 -04:00
Fix E2E tests by switching to new KestrelTestServer (#360)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="KestrelTestServer.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="TestServer"/> that uses Kestrel as the server.
|
||||
/// </summary>
|
||||
public class KestrelTestServer : TestServer, IServer
|
||||
{
|
||||
private readonly KestrelServer _server;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KestrelTestServer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> to use.</param>
|
||||
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<IEnumerable<IConnectionListenerFactory>>().First();
|
||||
|
||||
var kestrelOptions = serviceProvider.GetRequiredService<IOptions<KestrelServerOptions>>();
|
||||
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
|
||||
_server = new KestrelServer(kestrelOptions, transportFactory, loggerFactory);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
async Task IServer.StartAsync<TContext>(IHttpApplication<TContext> 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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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<TEntryPoint> : WebApplicationFact
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public string HostUrl { get; set; } = "https://localhost:5003";
|
||||
public int Port { get; set; } = 5003;
|
||||
|
||||
/// <summary>
|
||||
/// 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<TEntryPoint> : WebApplicationFact
|
||||
/// <inheritdoc />
|
||||
protected override IHost CreateHost(IHostBuilder builder)
|
||||
{
|
||||
var dummyHost = builder.Build();
|
||||
builder.ConfigureWebHost(webHostBuilder =>
|
||||
{
|
||||
webHostBuilder.UseKestrel(opt => opt.ListenLocalhost(Port));
|
||||
webHostBuilder.ConfigureServices(s => s.AddSingleton<IServer, KestrelTestServer>());
|
||||
});
|
||||
|
||||
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<IDbContextFactory<AliasServerDbContext>>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.UseUrls(HostUrl);
|
||||
|
||||
SetEnvironmentVariables();
|
||||
|
||||
builder.ConfigureServices(services =>
|
||||
@@ -129,19 +125,13 @@ public class WebApplicationAdminFactoryFixture<TEntryPoint> : WebApplicationFact
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to modify.</param>
|
||||
private static void RemoveExistingRegistrations(IServiceCollection services)
|
||||
{
|
||||
var descriptorsToRemove = new[]
|
||||
{
|
||||
services.SingleOrDefault(d => d.ServiceType == typeof(IDbContextFactory<AliasServerDbContext>)),
|
||||
services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AliasServerDbContext>)),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TEntryPoint> : WebApplicationFactor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public string HostUrl { get; set; } = "https://localhost:5001";
|
||||
public int Port { get; set; } = 5001;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time provider instance for mutating the current time in tests.
|
||||
@@ -87,28 +88,23 @@ public class WebApplicationApiFactoryFixture<TEntryPoint> : WebApplicationFactor
|
||||
/// <inheritdoc />
|
||||
protected override IHost CreateHost(IHostBuilder builder)
|
||||
{
|
||||
var dummyHost = builder.Build();
|
||||
builder.ConfigureWebHost(webHostBuilder =>
|
||||
{
|
||||
webHostBuilder.UseKestrel(opt => opt.ListenLocalhost(Port));
|
||||
webHostBuilder.ConfigureServices(s => s.AddSingleton<IServer, KestrelTestServer>());
|
||||
});
|
||||
|
||||
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<IDbContextFactory<AliasServerDbContext>>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.UseUrls(HostUrl);
|
||||
|
||||
SetEnvironmentVariables();
|
||||
|
||||
builder.ConfigureServices(services =>
|
||||
@@ -133,19 +129,13 @@ public class WebApplicationApiFactoryFixture<TEntryPoint> : WebApplicationFactor
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to modify.</param>
|
||||
private static void RemoveExistingRegistrations(IServiceCollection services)
|
||||
{
|
||||
var descriptorsToRemove = new[]
|
||||
{
|
||||
services.SingleOrDefault(d => d.ServiceType == typeof(IDbContextFactory<AliasServerDbContext>)),
|
||||
services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AliasServerDbContext>)),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
@@ -19,30 +21,19 @@ public class WebApplicationClientFactoryFixture<TEntryPoint> : WebApplicationFac
|
||||
where TEntryPoint : class
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public string HostUrl { get; set; } = "https://localhost:5002";
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.UseUrls(HostUrl);
|
||||
}
|
||||
public int Port { get; set; } = 5002;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IHost CreateHost(IHostBuilder builder)
|
||||
{
|
||||
var dummyHost = builder.Build();
|
||||
builder.ConfigureWebHost(webHostBuilder =>
|
||||
{
|
||||
webHostBuilder.UseKestrel(opt => opt.ListenLocalhost(Port));
|
||||
webHostBuilder.ConfigureServices(s => s.AddSingleton<IServer, KestrelTestServer>());
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user