CalibrationClientTests.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net;
  4. using System.Net.Http;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using ivf_tl_Operate.Debug;
  8. using Newtonsoft.Json.Linq;
  9. using Xunit;
  10. namespace IvfTl.ControlHost.Tests
  11. {
  12. /// <summary>
  13. /// operate 端 CalibrationClient 纯逻辑单测:用 fake HttpMessageHandler 注入 control 端
  14. /// /debug/calibrate/* 的响应,验证四个端点的路径/请求体/解析。
  15. /// 进度响应是 control 端 JsonConvert.SerializeObject(DebugCommandResult)——result 内嵌
  16. /// CalibProgress(PascalCase 字段,WellCalibState 枚举默认序列化为数字)。
  17. /// </summary>
  18. public class CalibrationClientTests
  19. {
  20. private sealed class FakeHandler : HttpMessageHandler
  21. {
  22. public Func<HttpRequestMessage, string, (HttpStatusCode, string)> Responder;
  23. public string LastPath;
  24. public string LastBody;
  25. protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage req, CancellationToken ct)
  26. {
  27. LastPath = req.RequestUri.AbsolutePath;
  28. LastBody = req.Content != null ? await req.Content.ReadAsStringAsync() : "";
  29. var (code, body) = Responder(req, LastBody);
  30. return new HttpResponseMessage(code) { Content = new StringContent(body) };
  31. }
  32. }
  33. private const string Sid = "sid123";
  34. [Fact]
  35. public async Task StartAsync_PostsToStart_WithSessionIdAndWells_ParsesOk()
  36. {
  37. var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, "{\"ok\":true}") };
  38. var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
  39. var r = await c.StartAsync(new[] { 1, 2, 3 });
  40. Assert.True(r.Ok);
  41. Assert.Equal("/debug/calibrate/start", h.LastPath);
  42. var jo = JObject.Parse(h.LastBody);
  43. Assert.Equal(Sid, jo["sessionId"]?.ToString());
  44. Assert.Equal(new[] { 1, 2, 3 }, ((JArray)jo["wells"]).ToObject<int[]>());
  45. }
  46. [Fact]
  47. public async Task PollProgressAsync_ParsesCalibProgress_TotalCompletedIsRunning_AndWells()
  48. {
  49. // control 端真实形态:DebugCommandResult{ok, result=CalibProgress}(PascalCase,枚举=数字)。
  50. string body =
  51. "{\"ok\":true,\"result\":{" +
  52. "\"Total\":16,\"Completed\":2,\"CurrentWell\":3,\"IsRunning\":true,\"Wells\":[" +
  53. "{\"WellSn\":1,\"State\":2,\"FocusZ\":90000,\"Exposure\":120,\"PeakRatio\":1.8,\"CenterOffsetPct\":0.5,\"CircleFound\":true,\"Note\":\"\"}," +
  54. "{\"WellSn\":2,\"State\":3,\"FocusZ\":0,\"Exposure\":0,\"PeakRatio\":1.0,\"CenterOffsetPct\":0.0,\"CircleFound\":false,\"Note\":\"伪峰\"}" +
  55. "]}}";
  56. var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, body) };
  57. var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
  58. var p = await c.PollProgressAsync();
  59. Assert.Equal("/debug/calibrate/progress", h.LastPath);
  60. Assert.Equal(Sid, JObject.Parse(h.LastBody)["sessionId"]?.ToString());
  61. Assert.NotNull(p);
  62. Assert.Equal(16, p.Total);
  63. Assert.Equal(2, p.Completed);
  64. Assert.Equal(3, p.CurrentWell);
  65. Assert.True(p.IsRunning);
  66. Assert.Equal(2, p.Wells.Count);
  67. Assert.Equal(1, p.Wells[0].WellSn);
  68. Assert.Equal(2, p.Wells[0].State); // Qualified=2
  69. Assert.Equal(90000, p.Wells[0].FocusZ);
  70. Assert.True(p.Wells[0].CircleFound);
  71. Assert.Equal(1.8, p.Wells[0].PeakRatio, 3);
  72. Assert.Equal(3, p.Wells[1].State); // FakePeak=3
  73. Assert.Equal("伪峰", p.Wells[1].Note);
  74. }
  75. [Fact]
  76. public async Task RecalibrateAsync_PostsToRecalibrate_WithWellSn()
  77. {
  78. var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, "{\"ok\":true,\"result\":true}") };
  79. var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
  80. var r = await c.RecalibrateAsync(7);
  81. Assert.True(r.Ok);
  82. Assert.Equal("/debug/calibrate/recalibrate", h.LastPath);
  83. var jo = JObject.Parse(h.LastBody);
  84. Assert.Equal(Sid, jo["sessionId"]?.ToString());
  85. Assert.Equal(7, (int)jo["wellSn"]);
  86. }
  87. [Fact]
  88. public async Task StopAsync_PostsToStop_WithSessionId()
  89. {
  90. var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, "{\"ok\":true}") };
  91. var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
  92. var r = await c.StopAsync();
  93. Assert.True(r.Ok);
  94. Assert.Equal("/debug/calibrate/stop", h.LastPath);
  95. Assert.Equal(Sid, JObject.Parse(h.LastBody)["sessionId"]?.ToString());
  96. }
  97. [Fact]
  98. public async Task SessionExpired_CodeIsReadable()
  99. {
  100. var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.Gone, "{\"ok\":false,\"code\":\"SESSION_EXPIRED\",\"error\":\"会话不存在或已过期\"}") };
  101. var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
  102. var r = await c.StartAsync();
  103. Assert.False(r.Ok);
  104. Assert.Equal("SESSION_EXPIRED", r.Code);
  105. }
  106. }
  107. }