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;
///
/// 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.
///
public sealed class NexusTestHost : IAsyncDisposable
{
private readonly WebApplication _app;
private NexusTestHost(WebApplication app, int port, FakeHealthService health)
{
_app = app;
Port = port;
Health = health;
}
/// Loopback port Kestrel bound to.
public int Port { get; }
/// The health fake, so tests can flip .
public FakeHealthService Health { get; }
/// Starts the host on an OS-assigned loopback port.
public static async Task 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();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
WebApplication app = builder.Build();
app.MapGrpcService();
app.MapGrpcService();
app.MapGrpcService();
app.MapGrpcService();
app.MapGrpcService();
await app.StartAsync();
int port = new Uri(app.Urls.Single()).Port;
FakeHealthService health = app.Services.GetRequiredService();
return new NexusTestHost(app, port, health);
}
/// Builds a nexus+<scheme>://127.0.0.1:{port}/{database} connection URI for this host.
public string ConnectionUri(string scheme, string? database = null) =>
string.IsNullOrEmpty(database)
? $"{scheme}://127.0.0.1:{Port}"
: $"{scheme}://127.0.0.1:{Port}/{database}";
///
public async ValueTask DisposeAsync()
{
await _app.StopAsync();
await _app.DisposeAsync();
}
}