mishima-nexus-client-csharp/tests/Robotico.Nexus.Client.Tests/TestSupport/NexusTestHost.cs

73 lines
2.8 KiB
C#
Raw Normal View History

using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Robotico.Nexus.Client.Tests.TestSupport;
/// <summary>
/// Loopback Kestrel host mapping the fake graph/time/document/relational/health gRPC services, so
/// tests exercise the real wire (HTTP/2, protobuf, gRPC status codes) without a live Nexus process.
/// </summary>
public sealed class NexusTestHost : IAsyncDisposable
{
private readonly WebApplication _app;
private NexusTestHost(WebApplication app, int port, FakeHealthService health)
{
_app = app;
Port = port;
Health = health;
}
/// <summary>Loopback port Kestrel bound to.</summary>
public int Port { get; }
/// <summary>The health fake, so tests can flip <see cref="FakeHealthService.Ready"/>.</summary>
public FakeHealthService Health { get; }
/// <summary>Starts the host on an OS-assigned loopback port.</summary>
public static async Task<NexusTestHost> StartAsync()
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.Logging.ClearProviders();
builder.WebHost.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Loopback, 0, listen => listen.Protocols = HttpProtocols.Http2);
});
builder.Services.AddGrpc();
builder.Services.AddSingleton<FakeGraphEngineService>();
builder.Services.AddSingleton<FakeTimeEngineService>();
builder.Services.AddSingleton<FakeDocumentEngineService>();
builder.Services.AddSingleton<FakeRelationalEngineService>();
builder.Services.AddSingleton<FakeHealthService>();
WebApplication app = builder.Build();
app.MapGrpcService<FakeGraphEngineService>();
app.MapGrpcService<FakeTimeEngineService>();
app.MapGrpcService<FakeDocumentEngineService>();
app.MapGrpcService<FakeRelationalEngineService>();
app.MapGrpcService<FakeHealthService>();
await app.StartAsync();
int port = new Uri(app.Urls.Single()).Port;
FakeHealthService health = app.Services.GetRequiredService<FakeHealthService>();
return new NexusTestHost(app, port, health);
}
/// <summary>Builds a <c>nexus+&lt;scheme&gt;://127.0.0.1:{port}/{database}</c> connection URI for this host.</summary>
public string ConnectionUri(string scheme, string? database = null) =>
string.IsNullOrEmpty(database)
? $"{scheme}://127.0.0.1:{Port}"
: $"{scheme}://127.0.0.1:{Port}/{database}";
/// <inheritdoc />
public async ValueTask DisposeAsync()
{
await _app.StopAsync();
await _app.DisposeAsync();
}
}