From 559890c482f5973f06aafdfec9550fee5ba3c7f2 Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 09 十一月 2026 17:02:15 +0800
Subject: [PATCH] feat: CAN 模拟器 TCP 化 + 多设备并发调试 + 后台生命周期管理

---
 tests/Aging.MvpTests/FacadeLeaseLifecycleTests.cs |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/tests/Aging.MvpTests/FacadeLeaseLifecycleTests.cs b/tests/Aging.MvpTests/FacadeLeaseLifecycleTests.cs
new file mode 100644
index 0000000..aa3a408
--- /dev/null
+++ b/tests/Aging.MvpTests/FacadeLeaseLifecycleTests.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using System.Threading;
+using Aging.Infrastructure.Core;
+using Aging.ResourceContracts;
+using Xunit;
+
+namespace Aging.MvpTests
+{
+    public class FacadeLeaseLifecycleTests : IDisposable
+    {
+        private readonly string _dbPath;
+        private readonly DbLeaseStore _store;
+        public FacadeLeaseLifecycleTests()
+        {
+            _dbPath = Path.Combine(Path.GetTempPath(), "arb_" + Guid.NewGuid().ToString("N") + ".db");
+            _store = new DbLeaseStore(_dbPath, "local-main");
+        }
+        public void Dispose() { try { File.Delete(_dbPath); File.Delete(_dbPath + "-wal"); File.Delete(_dbPath + "-shm"); } catch { } }
+
+        private LeaseGrant Grab(string key, int ttl)
+            => _store.Acquire(new AcquireRequest
+            {
+                OwnerId = "f", OwnerType = OwnerTypeV3.Production,
+                ResourceKeys = new[] { key }, TtlSeconds = ttl
+            }).Grants[0];
+
+        [Fact]
+        public void Heartbeat_Renew_Extends_Expiry()
+        {
+            var g = Grab("can/x", 2);
+            long before = g.ExpiresUtcMs;
+            Thread.Sleep(1200);
+            Assert.True(_store.Renew(g, 2));
+            Assert.True(_store.ProbeConflict("can/x").ExpiresUtcMs > before);
+        }
+
+        [Fact]
+        public void Expired_Sweep_StaleRenew_False_And_RecoveryBlocked()
+        {
+            var g = Grab("can/y", 1);
+            Thread.Sleep(1500);
+            Assert.Equal(1, _store.SweepExpired());
+            Assert.False(_store.Renew(g, 5));
+            Assert.Null(_store.ProbeConflict("can/y"));
+            Assert.Equal(LeasePhase.RecoveryRequired, _store.PhaseOf("can/y"));
+        }
+    }
+}

--
Gitblit v1.9.1