From 210663040bf65ee00b5f86545fdc31bd0356fddf Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 27 八月 2026 16:31:53 +0800
Subject: [PATCH] feat(device): persist simulator discovery in redis

---
 ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java |  106 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 106 insertions(+), 0 deletions(-)

diff --git a/ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java b/ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java
index 85887f6..de1a699 100644
--- a/ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java
+++ b/ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java
@@ -1,6 +1,7 @@
 package com.ruoyi.device.contract;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import java.time.Duration;
 import java.time.ZoneId;
 import java.util.Set;
@@ -13,6 +14,11 @@
 import com.ruoyi.device.bts.ScriptedBtsTcpSimulator;
 import com.ruoyi.device.model.DetectedChannel;
 import com.ruoyi.device.model.DeviceWorkStatus;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelState;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.DeviceState;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
+import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
 
 class SimulatorPublicContractTest
 {
@@ -137,4 +143,104 @@
             assertEquals(4, adapter.discoverChannels().size());
         }
     }
+
+    @Test
+    void developmentCollectorsNeverEnterBtsCabinetDiscovery() throws Exception
+    {
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0);
+             BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(),
+                     Duration.ofSeconds(1), Duration.ofSeconds(1));
+             DeviceAdapter adapter = new BtsDeviceAdapter("dev-sim", transport,
+                     new BtsXmlCodec("dev-sim", ZoneId.of("Asia/Hong_Kong"))))
+        {
+            assertEquals(4, adapter.discoverChannels().size());
+
+            simulator.addCollector("127.0.1.8", 12);
+
+            assertEquals(4, adapter.discoverChannels().size());
+            assertEquals(2, simulator.snapshot().collectors().size());
+        }
+    }
+
+    @Test
+    void developmentSimulatorRestoresConfigurationNumberingAndStatus() throws Exception
+    {
+        InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
+        try (BtsDevelopmentSimulator first = new BtsDevelopmentSimulator(0, store))
+        {
+            first.updateDevice(1, "127.0.0.9", 2, false);
+            first.addDevice("127.0.0.10", 3);
+            first.updateCollector(1, "127.0.1.9", 7, false);
+        }
+
+        try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store))
+        {
+            assertEquals(2, restored.snapshot().devices().size());
+            assertEquals("127.0.0.9", restored.snapshot().devices().get(0).ip());
+            assertEquals(false, restored.snapshot().devices().get(0).online());
+            assertEquals(7, restored.snapshot().collectors().get(0).channelCount());
+            assertEquals(3, restored.addDevice("127.0.0.11", 1));
+        }
+    }
+
+    @Test
+    void developmentSimulatorDoesNotExposeWriteThroughFailureInMemory() throws Exception
+    {
+        InMemoryBtsSimulatorStateStore delegate = new InMemoryBtsSimulatorStateStore();
+        BtsSimulatorStateStore failing = new BtsSimulatorStateStore()
+        {
+            @Override public SimulatorState loadOrInitialize(SimulatorState value)
+            { return delegate.loadOrInitialize(value); }
+            @Override public void save(SimulatorState value) { throw new IllegalStateException("redis unavailable"); }
+            @Override public java.util.List<RecentRequest> loadRecentRequests()
+            { return delegate.loadRecentRequests(); }
+            @Override public void saveRecentRequests(java.util.List<RecentRequest> requests)
+            { delegate.saveRecentRequests(requests); }
+            @Override public void reset(SimulatorState value) { delegate.reset(value); }
+        };
+
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, failing))
+        {
+            assertThrows(IllegalStateException.class, () -> simulator.addDevice("127.0.0.3", 2));
+            assertEquals(1, simulator.snapshot().devices().size());
+        }
+    }
+
+    @Test
+    void developmentSimulatorRestoresUnfinishedTombstones() throws Exception
+    {
+        InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
+        try (BtsDevelopmentSimulator first = new BtsDevelopmentSimulator(0, store);
+             BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", first.port(),
+                     Duration.ofSeconds(1), Duration.ofSeconds(1));
+             DeviceAdapter adapter = new BtsDeviceAdapter("dev-sim", transport,
+                     new BtsXmlCodec("dev-sim", ZoneId.of("Asia/Hong_Kong"))))
+        {
+            first.deleteDevice(1);
+            assertEquals(4, adapter.discoverChannels().size());
+        }
+
+        try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store);
+             BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", restored.port(),
+                     Duration.ofSeconds(1), Duration.ofSeconds(1));
+             DeviceAdapter adapter = new BtsDeviceAdapter("dev-sim", transport,
+                     new BtsXmlCodec("dev-sim", ZoneId.of("Asia/Hong_Kong"))))
+        {
+            assertEquals(4, adapter.discoverChannels().size());
+            assertEquals(4, adapter.discoverChannels().size());
+            assertEquals(0, adapter.discoverChannels().size());
+        }
+    }
+
+    @Test
+    void developmentSimulatorRejectsNonContiguousRestoredChannelTopology()
+    {
+        SimulatorState damaged = new SimulatorState(BtsSimulatorStateStore.CURRENT_VERSION,
+                java.util.List.of(new DeviceState(1, "127.0.0.2", true,
+                        java.util.List.of(new ChannelState(2, true, DeviceWorkStatus.STOPPED)))),
+                java.util.List.of(), 2, 1, java.util.List.of());
+
+        assertThrows(IllegalStateException.class,
+                () -> new BtsDevelopmentSimulator(0, new InMemoryBtsSimulatorStateStore(damaged)));
+    }
 }

--
Gitblit v1.7.1