using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Tests.Mcp; /// /// A real Kestrel server on a random loopback port, serving captured API fixtures. /// The discovery tools construct their own HttpClients internally, so unlike the /// unit tests in Tests.Discovery a message-handler stub cannot reach them — the /// fake engine has to answer on an actual socket. /// internal sealed class FakeHttpServer : IAsyncDisposable { private readonly WebApplication _app; private FakeHttpServer(WebApplication app) => _app = app; /// e.g. http://127.0.0.1:49213 — no trailing slash. public string BaseUrl => _app.Urls.First(); public string Host => new Uri(BaseUrl).Authority; public static async Task StartAsync(Action map) { WebApplicationBuilder builder = WebApplication.CreateBuilder(); builder.Logging.ClearProviders(); builder.WebHost.UseUrls("http://127.0.0.1:0"); WebApplication app = builder.Build(); map(app); await app.StartAsync(); return new FakeHttpServer(app); } /// A fake Docker Engine API with the shared captured fixtures. public static Task StartDockerEngineAsync() => StartAsync(app => { app.MapGet("/containers/json", () => Results.Content( TestData.Fixture("docker-containers.json"), "application/json")); app.MapGet("/info", () => Results.Content( TestData.Fixture("docker-info.json"), "application/json")); }); /// /// A fake Proxmox VE API. Both fixture nodes answer with the same guest lists, /// which doubles as the migration case: the mapper must dedupe guests by vmid. /// public static Task StartProxmoxAsync() => StartAsync(app => { string Json(string name) => TestData.Fixture(name); app.MapGet("/api2/json/cluster/status", () => Results.Content(Json("pve-cluster-status.json"), "application/json")); app.MapGet("/api2/json/nodes", () => Results.Content(Json("pve-nodes-full.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/status", () => Results.Content(Json("pve-node-status.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/disks/list", () => Results.Content(Json("pve-disks.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/hardware/pci", () => Results.Content(Json("pve-hardware-pci.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/qemu", () => Results.Content(Json("pve-qemu.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/lxc", () => Results.Content(Json("pve-lxc.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/qemu/{vmid}/config", () => Results.Content(Json("pve-qemu-config.json"), "application/json")); app.MapGet("/api2/json/nodes/{node}/lxc/{vmid}/config", () => Results.Content(Json("pve-lxc-config.json"), "application/json")); }); public async ValueTask DisposeAsync() => await _app.DisposeAsync(); }