73 lines
2.8 KiB
C#
73 lines
2.8 KiB
C#
|
|
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+<scheme>://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();
|
||
|
|
}
|
||
|
|
}
|