FakeHttpServer.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. using Microsoft.AspNetCore.Builder;
  2. using Microsoft.AspNetCore.Hosting;
  3. using Microsoft.AspNetCore.Http;
  4. using Microsoft.Extensions.Logging;
  5. namespace Tests.Mcp;
  6. /// <summary>
  7. /// A real Kestrel server on a random loopback port, serving captured API fixtures.
  8. /// The discovery tools construct their own HttpClients internally, so unlike the
  9. /// unit tests in Tests.Discovery a message-handler stub cannot reach them — the
  10. /// fake engine has to answer on an actual socket.
  11. /// </summary>
  12. internal sealed class FakeHttpServer : IAsyncDisposable {
  13. private readonly WebApplication _app;
  14. private FakeHttpServer(WebApplication app) => _app = app;
  15. /// <summary>e.g. http://127.0.0.1:49213 — no trailing slash.</summary>
  16. public string BaseUrl => _app.Urls.First();
  17. public string Host => new Uri(BaseUrl).Authority;
  18. public static async Task<FakeHttpServer> StartAsync(Action<WebApplication> map) {
  19. WebApplicationBuilder builder = WebApplication.CreateBuilder();
  20. builder.Logging.ClearProviders();
  21. builder.WebHost.UseUrls("http://127.0.0.1:0");
  22. WebApplication app = builder.Build();
  23. map(app);
  24. await app.StartAsync();
  25. return new FakeHttpServer(app);
  26. }
  27. /// <summary>A fake Docker Engine API with the shared captured fixtures.</summary>
  28. public static Task<FakeHttpServer> StartDockerEngineAsync() =>
  29. StartAsync(app => {
  30. app.MapGet("/containers/json", () => Results.Content(
  31. TestData.Fixture("docker-containers.json"), "application/json"));
  32. app.MapGet("/info", () => Results.Content(
  33. TestData.Fixture("docker-info.json"), "application/json"));
  34. });
  35. /// <summary>
  36. /// A fake Proxmox VE API. Both fixture nodes answer with the same guest lists,
  37. /// which doubles as the migration case: the mapper must dedupe guests by vmid.
  38. /// </summary>
  39. public static Task<FakeHttpServer> StartProxmoxAsync() =>
  40. StartAsync(app => {
  41. string Json(string name) => TestData.Fixture(name);
  42. app.MapGet("/api2/json/cluster/status", () => Results.Content(Json("pve-cluster-status.json"), "application/json"));
  43. app.MapGet("/api2/json/nodes", () => Results.Content(Json("pve-nodes-full.json"), "application/json"));
  44. app.MapGet("/api2/json/nodes/{node}/status", () => Results.Content(Json("pve-node-status.json"), "application/json"));
  45. app.MapGet("/api2/json/nodes/{node}/disks/list", () => Results.Content(Json("pve-disks.json"), "application/json"));
  46. app.MapGet("/api2/json/nodes/{node}/hardware/pci", () => Results.Content(Json("pve-hardware-pci.json"), "application/json"));
  47. app.MapGet("/api2/json/nodes/{node}/qemu", () => Results.Content(Json("pve-qemu.json"), "application/json"));
  48. app.MapGet("/api2/json/nodes/{node}/lxc", () => Results.Content(Json("pve-lxc.json"), "application/json"));
  49. app.MapGet("/api2/json/nodes/{node}/qemu/{vmid}/config", () => Results.Content(Json("pve-qemu-config.json"), "application/json"));
  50. app.MapGet("/api2/json/nodes/{node}/lxc/{vmid}/config", () => Results.Content(Json("pve-lxc-config.json"), "application/json"));
  51. });
  52. public async ValueTask DisposeAsync() => await _app.DisposeAsync();
  53. }