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(); } }