Sfoglia il codice sorgente

feat(d2-02-t3): acquire 回带培养态(cultivating+embryoCount,注入式不依赖业务类)+3单测

huangjie 3 giorni fa
parent
commit
e87dfc011e

+ 66 - 0
ivf_tl_operate_2.0/control/IvfTl.ControlHost.Tests/DebugAcquireCultivationTests.cs

@@ -0,0 +1,66 @@
+using System;
+using IvfTl.ControlHost.Debug;
+using IvfTl.ControlHost.Tests.Fakes;
+using Xunit;
+
+namespace IvfTl.ControlHost.Tests
+{
+    /// <summary>
+    /// Task7-t3:借用(Acquire)成功时回带培养态(cultivating + embryoCount)。
+    /// 纯逻辑、注入式——cultivationOf 委托提供假培养态,不接真实数据源(下个任务才装配)。
+    /// </summary>
+    public class DebugAcquireCultivationTests
+    {
+        private static readonly DateTime Now = new DateTime(2026, 6, 24, 0, 0, 0, DateTimeKind.Utc);
+
+        private DebugSessionManager NewMgr(FakeGate gate, Func<int, (bool, int)> cultivationOf)
+            => new DebugSessionManager(_ => gate, () => Now, ttlMs: 10000, log: null, cultivationOf: cultivationOf);
+
+        [Fact]
+        public void Acquire_CultivatingHouse_ReturnsCultivationState()
+        {
+            var gate = new FakeGate(6, new FakeSerial());
+            var mgr = NewMgr(gate, sn => (true, 3));
+
+            var r = mgr.Acquire(6);
+
+            Assert.True(r.Ok);
+            Assert.True(r.Cultivating);
+            Assert.Equal(3, r.EmbryoCount);
+            // Result 仍是 sid 字符串(operate 端靠 r.Result 取 sessionId,不能破坏)
+            Assert.IsType<string>(r.Result);
+            Assert.False(string.IsNullOrEmpty((string)r.Result));
+        }
+
+        [Fact]
+        public void Acquire_EmptyHouse_ReturnsNotCultivating()
+        {
+            var gate = new FakeGate(6, new FakeSerial());
+            var mgr = NewMgr(gate, sn => (false, 0));
+
+            var r = mgr.Acquire(6);
+
+            Assert.True(r.Ok);
+            Assert.False(r.Cultivating);
+            Assert.Equal(0, r.EmbryoCount);
+            Assert.IsType<string>(r.Result);
+            Assert.False(string.IsNullOrEmpty((string)r.Result));
+        }
+
+        [Fact]
+        public void Acquire_NoCultivationProvider_DefaultsFalse()
+        {
+            var gate = new FakeGate(6, new FakeSerial());
+            // cultivationOf 传 null(不提供)——Acquire 不应崩,默认 false/0
+            var mgr = NewMgr(gate, null);
+
+            var r = mgr.Acquire(6);
+
+            Assert.True(r.Ok);
+            Assert.False(r.Cultivating);
+            Assert.Equal(0, r.EmbryoCount);
+            Assert.IsType<string>(r.Result);
+            Assert.False(string.IsNullOrEmpty((string)r.Result));
+        }
+    }
+}

+ 2 - 0
ivf_tl_operate_2.0/control/ivf_tl_ControlHost/Debug/DebugCommandResult.cs

@@ -8,6 +8,8 @@ namespace IvfTl.ControlHost.Debug
         [JsonProperty("result", NullValueHandling = NullValueHandling.Ignore)] public object Result { get; set; }
         [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] public string Error { get; set; }
         [JsonProperty("code", NullValueHandling = NullValueHandling.Ignore)] public string Code { get; set; }
+        [JsonProperty("cultivating", NullValueHandling = NullValueHandling.Ignore)] public bool Cultivating { get; set; }
+        [JsonProperty("embryoCount", NullValueHandling = NullValueHandling.Ignore)] public int EmbryoCount { get; set; }
         public static DebugCommandResult Okay(object result = null) => new DebugCommandResult { Ok = true, Result = result };
         public static DebugCommandResult Fail(string code, string error) => new DebugCommandResult { Ok = false, Code = code, Error = error };
     }

+ 11 - 2
ivf_tl_operate_2.0/control/ivf_tl_ControlHost/Debug/DebugSessionManager.cs

@@ -14,10 +14,13 @@ namespace IvfTl.ControlHost.Debug
         private readonly Func<DateTime> _clock;
         private readonly int _ttlMs;
         private readonly Action<string> _log;
+        private readonly Func<int, (bool cultivating, int embryoCount)> _cultivationOf;
         private readonly ConcurrentDictionary<string, DebugSession> _sessions = new ConcurrentDictionary<string, DebugSession>();
-        public DebugSessionManager(Func<int, IHouseGate> gateOf, Func<DateTime> clock, int ttlMs, Action<string> log)
+        public DebugSessionManager(Func<int, IHouseGate> gateOf, Func<DateTime> clock, int ttlMs, Action<string> log,
+                                   Func<int, (bool, int)> cultivationOf = null)
         {
             _gateOf = gateOf; _clock = clock; _ttlMs = ttlMs; _log = log ?? (_ => { });
+            _cultivationOf = cultivationOf;
         }
         public DebugCommandResult Acquire(int houseSn)
         {
@@ -27,8 +30,14 @@ namespace IvfTl.ControlHost.Debug
             if (lease == null) return DebugCommandResult.Fail("BUSY", $"舱{houseSn}被占用,借用超时");
             string sid = Guid.NewGuid().ToString("N");
             _sessions[sid] = new DebugSession(sid, houseSn, lease, _clock());
+            var res = DebugCommandResult.Okay(sid);
+            try
+            {
+                if (_cultivationOf != null) { var c = _cultivationOf(houseSn); res.Cultivating = c.Item1; res.EmbryoCount = c.Item2; }
+            }
+            catch (Exception ex) { _log($"[debug] 取培养态异常 舱{houseSn}: {ex.Message}"); }
             _log($"[debug] acquire 舱{houseSn} sid={sid}");
-            return DebugCommandResult.Okay(sid);
+            return res;
         }
         public DebugCommandResult Heartbeat(string sid)
         {