Init
This commit is contained in:
110
Prefab.Tests/Infrastructure/KestrelInProcApp.cs
Normal file
110
Prefab.Tests/Infrastructure/KestrelInProcApp.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Prefab.Tests.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Hosts a project entry point in-process with Kestrel so integration tests hit real HTTP.
|
||||
/// </summary>
|
||||
public sealed class KestrelInProcApp<TEntryPoint> : WebApplicationFactory<TEntryPoint>, IAsyncLifetime
|
||||
where TEntryPoint : class
|
||||
{
|
||||
private readonly AspireInfraHost _infra;
|
||||
private readonly ProjectResource _project;
|
||||
private readonly int? _port;
|
||||
private readonly IDictionary<string, string?> _overrides;
|
||||
private readonly Action<IServiceCollection>? _configureServices;
|
||||
private Dictionary<string, string?> _config = new(StringComparer.OrdinalIgnoreCase);
|
||||
private Uri? _httpAddress;
|
||||
|
||||
public KestrelInProcApp(
|
||||
AspireInfraHost infra,
|
||||
ProjectResource project,
|
||||
int? port,
|
||||
IDictionary<string, string?>? overrides = null,
|
||||
Action<IServiceCollection>? configureServices = null)
|
||||
{
|
||||
_infra = infra;
|
||||
_project = project;
|
||||
_port = port;
|
||||
_overrides = overrides ?? new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
|
||||
_configureServices = configureServices;
|
||||
|
||||
this.UseKestrel(_port ?? 0);
|
||||
}
|
||||
|
||||
public Uri HttpAddress => _httpAddress ?? throw new InvalidOperationException("Application not started.");
|
||||
public IServiceProvider AppServices => Services;
|
||||
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
_config = await AspireInfraHost.ResolveConfigForProjectAsync(_project, _infra.Services);
|
||||
|
||||
foreach (var (key, value) in _overrides)
|
||||
{
|
||||
_config[key.Replace("__", ":")] = value;
|
||||
}
|
||||
|
||||
using var client = CreateClient();
|
||||
_httpAddress = client.BaseAddress ?? ResolveServerAddress();
|
||||
}
|
||||
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
foreach (var (key, value) in _config)
|
||||
{
|
||||
if (string.Equals(key, "ASPNETCORE_URLS", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.UseSetting(key, value);
|
||||
}
|
||||
|
||||
builder.UseSetting("ASPNETCORE_ENVIRONMENT", "Testing");
|
||||
|
||||
builder.ConfigureServices(services =>
|
||||
{
|
||||
RemoveHostedService(services, "Prefab.Web.Workers.DataSeeder");
|
||||
RemoveHostedService(services, "Prefab.Catalog.Api.Workers.DataSeeder");
|
||||
_configureServices?.Invoke(services);
|
||||
});
|
||||
}
|
||||
|
||||
public override ValueTask DisposeAsync() => base.DisposeAsync();
|
||||
|
||||
private Uri ResolveServerAddress()
|
||||
{
|
||||
var server = Services.GetRequiredService<IServer>();
|
||||
var feature = server.Features.Get<IServerAddressesFeature>();
|
||||
var address = feature?.Addresses.FirstOrDefault();
|
||||
if (address is not null && Uri.TryCreate(address, UriKind.Absolute, out var uri))
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
// Fallback to localhost with known (or dynamic) port.
|
||||
var port = _port.GetValueOrDefault(0);
|
||||
return new Uri($"http://127.0.0.1:{port}");
|
||||
}
|
||||
|
||||
private static void RemoveHostedService(IServiceCollection services, string typeFullName)
|
||||
{
|
||||
var descriptors = services
|
||||
.Where(s => s.ServiceType == typeof(IHostedService) && s.ImplementationType?.FullName == typeFullName)
|
||||
.ToList();
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
services.Remove(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user