From 56cddf53e7e71afad29885d7fcf773a222b95f6c Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期日, 30 八月 2026 19:38:18 +0800
Subject: [PATCH] 修复采集器断线区间重复关闭

---
 ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java b/ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java
index 518fba3..c69665a 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java
@@ -5,7 +5,10 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import java.lang.reflect.Method;
+import java.math.BigDecimal;
 import java.net.InetAddress;
 import java.time.Instant;
 import java.util.List;
@@ -13,6 +16,7 @@
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.server.ResponseStatusException;
 import com.ruoyi.common.annotation.Anonymous;
 import com.ruoyi.device.bts.BtsDevelopmentSimulator;
 import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
@@ -21,6 +25,7 @@
 import com.ruoyi.device.model.ChannelIdentity;
 import com.ruoyi.device.model.DeviceWorkStatus;
 import com.ruoyi.web.config.BtsDevelopmentSimulatorWebConfig;
+import com.ruoyi.config.DevelopmentCollectorStatusSynchronizer;
 
 class BtsDevelopmentSimulatorControllerTest
 {
@@ -68,6 +73,25 @@
     }
 
     @Test
+    void controllerCreatesNewareDeviceFromExplicitModelProfile() throws Exception
+    {
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            BtsDevelopmentSimulatorController controller = controller(simulator);
+
+            var created = controller.createDevice(new BtsDevelopmentSimulatorController.CreateDeviceCommand(
+                    "127.0.0.8", 0, "CT-4008T-5V6A-S1-F"));
+            var device = created.devices().stream().filter(item -> item.ip().equals("127.0.0.8"))
+                    .findFirst().orElseThrow();
+
+            assertEquals(8, device.channels().size());
+            assertEquals("新威", device.profile().manufacturer());
+            assertEquals("CT-4008T-5V6A-S1-F", device.profile().model());
+            assertEquals(100, device.profile().sampleIntervalMs());
+        }
+    }
+
+    @Test
     void controllerConfiguresCollectorsSeparatelyFromCabinets() throws Exception
     {
         try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
@@ -95,6 +119,90 @@
     }
 
     @Test
+    void controllerExposesCollectorRealtimeAndPagedHistory() throws Exception
+    {
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            BtsDevelopmentSimulatorController controller = controller(simulator);
+            controller.configureCollectorSampling(1,
+                    new BtsDevelopmentSimulatorController.CollectorSamplingCommand(
+                            100, List.of(), null, null, false));
+            controller.configureCollectorChannel(1, "S-01",
+                    new BtsDevelopmentSimulatorController.CollectorChannelCommand(List.of(
+                            new BtsDevelopmentSimulatorController.CollectorMetricCommand(
+                                    "temperature", new BigDecimal("27.2"), "℃"),
+                            new BtsDevelopmentSimulatorController.CollectorMetricCommand(
+                                    "custom_voltage", new BigDecimal("1.234"), "V"))));
+            simulator.advanceCollectors(Instant.parse("2026-08-29T01:00:00Z"));
+
+            var realtime = controller.collectorRealtime(1);
+            var firstPage = controller.collectorHistory(1, 0, 2);
+
+            assertTrue(realtime.online());
+            assertTrue(realtime.measurements().stream().anyMatch(item -> item.metricCode().equals("custom_voltage")));
+            assertEquals(2, firstPage.records().size());
+            assertTrue(firstPage.hasMore());
+            assertEquals(2, firstPage.nextOffset());
+        }
+    }
+
+    @Test
+    void controllerPowersAllSimulatorDevicesWithoutResettingHistory() throws Exception
+    {
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            BtsDevelopmentSimulatorController controller = controller(simulator);
+            simulator.advanceCollectors(Instant.now());
+            long historyCount = controller.state().collectors().get(0).historyRecordCount();
+
+            var poweredOff = controller.setPower(
+                    new BtsDevelopmentSimulatorController.SimulatorPowerCommand(false));
+
+            assertTrue(poweredOff.devices().stream().noneMatch(device -> device.online()
+                    || device.channels().stream().anyMatch(channel -> channel.online())));
+            assertTrue(poweredOff.collectors().stream().noneMatch(collector -> collector.online()));
+            assertEquals(historyCount, poweredOff.collectors().get(0).historyRecordCount());
+
+            var poweredOn = controller.setPower(
+                    new BtsDevelopmentSimulatorController.SimulatorPowerCommand(true));
+            assertTrue(poweredOn.devices().stream().allMatch(device -> device.online()
+                    && device.channels().stream().allMatch(channel -> channel.online()
+                            && channel.workStatus() == DeviceWorkStatus.STOPPED)));
+            assertTrue(poweredOn.collectors().stream().allMatch(collector -> collector.online()));
+        }
+    }
+
+    @Test
+    void powerChangeImmediatelyReconcilesCollectorStatus() throws Exception
+    {
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            DevelopmentCollectorStatusSynchronizer synchronizer = mock(DevelopmentCollectorStatusSynchronizer.class);
+            BtsDevelopmentSimulatorController controller = new BtsDevelopmentSimulatorController(simulator,
+                    new InMemoryDeviceDiscoveryCandidateStore(), synchronizer);
+
+            controller.setPower(new BtsDevelopmentSimulatorController.SimulatorPowerCommand(true));
+
+            verify(synchronizer).synchronizeOnlineStatus();
+        }
+    }
+
+    @Test
+    void simulatorPowerCommandRequiresExplicitState() throws Exception
+    {
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            BtsDevelopmentSimulatorController controller = controller(simulator);
+
+            ResponseStatusException exception = assertThrows(ResponseStatusException.class,
+                    () -> controller.setPower(new BtsDevelopmentSimulatorController.SimulatorPowerCommand(null)));
+
+            assertEquals(400, exception.getStatusCode().value());
+            assertTrue(controller.state().collectors().get(0).online());
+        }
+    }
+
+    @Test
     void virtualIpMustBeUniqueAcrossCabinetsAndCollectors() throws Exception
     {
         try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))

--
Gitblit v1.7.1