From 7ab0e426264707fb85ee38d0a9a73caf41899635 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 29 八月 2026 13:11:40 +0800
Subject: [PATCH] 实现采集器独立实时与历史采样模拟

---
 ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java |   90 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 90 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 de1a699..9e8be45 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,9 +1,14 @@
 package com.ruoyi.device.contract;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.math.BigDecimal;
 import java.time.Duration;
+import java.time.Instant;
 import java.time.ZoneId;
+import java.util.List;
 import java.util.Set;
 import org.junit.jupiter.api.Test;
 import com.ruoyi.device.api.DeviceAdapter;
@@ -16,6 +21,8 @@
 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.CollectorHistoryFaults;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
 import com.ruoyi.device.simulator.BtsSimulatorStateStore.DeviceState;
 import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
 import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
@@ -23,6 +30,89 @@
 class SimulatorPublicContractTest
 {
     @Test
+    void collectorGeneratesIndependentRealtimeAndHistoricalMeasurements() throws Exception
+    {
+        Instant startedAt = Instant.parse("2026-08-29T01:00:00Z");
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            simulator.configureCollectorSampling(1, 200, CollectorHistoryFaults.none());
+            simulator.configureCollectorChannel(1, "S-01", List.of(
+                    new CollectorMetricState("temperature", new BigDecimal("26.5"), "℃"),
+                    new CollectorMetricState("positive_potential", new BigDecimal("3.801"), "V"),
+                    new CollectorMetricState("negative_potential", new BigDecimal("-0.120"), "V"),
+                    new CollectorMetricState("pressure", new BigDecimal("101.2"), "kPa")));
+
+            simulator.advanceCollectors(startedAt);
+            simulator.advanceCollectors(startedAt.plusMillis(400));
+
+            var realtime = simulator.snapshot().collectors().get(0).latestMeasurements();
+            var history = simulator.collectorHistory(1, 0, 1000);
+            assertEquals(13, realtime.size());
+            assertTrue(realtime.stream().allMatch(item -> item.sequenceId() == 3));
+            assertTrue(realtime.stream().anyMatch(item -> item.channelCode().equals("S-01")
+                    && item.metricCode().equals("pressure") && item.unit().equals("kPa")));
+            assertEquals(39, history.total());
+            assertEquals("dev-sim", history.records().get(0).adapterCode());
+            assertEquals("dev-sim-collector-1", history.records().get(0).collectorCode());
+            assertEquals(startedAt, history.records().get(0).deviceTime());
+            assertTrue(history.records().get(0).deviceTimeRaw().startsWith("2026-08-29 09:00:00"));
+            assertEquals(startedAt, history.records().get(0).serverReceivedAt());
+        }
+    }
+
+    @Test
+    void collectorHistorySupportsPagingAndRepeatableFaultScenarios() throws Exception
+    {
+        Instant startedAt = Instant.parse("2026-08-29T02:00:00Z");
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0))
+        {
+            simulator.configureCollectorSampling(1, 100,
+                    new CollectorHistoryFaults(List.of(2L), 1L, 3L, true));
+            simulator.advanceCollectors(startedAt);
+            simulator.advanceCollectors(startedAt.plusMillis(200));
+
+            var first = simulator.collectorHistory(1, 0, 17);
+            var second = simulator.collectorHistory(1, first.nextOffset(), 1000);
+            List<com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord> records =
+                    new java.util.ArrayList<>(first.records());
+            records.addAll(second.records());
+
+            assertEquals(48, first.total());
+            assertTrue(first.hasMore());
+            assertFalse(second.hasMore());
+            assertTrue(records.stream().noneMatch(item -> item.sequenceId() == 2));
+            assertEquals(24, records.stream().filter(item -> item.sequenceId() == 1).count());
+            assertEquals(2, records.stream().filter(item -> item.sequenceId() == 3
+                    && item.channelCode().equals("S-01") && item.metricCode().equals("temperature")).count());
+            assertTrue(records.get(0).sequenceId() >= records.get(records.size() - 1).sequenceId());
+        }
+    }
+
+    @Test
+    void collectorStopsWhileOfflineAndResumesFromPersistedSequence() throws Exception
+    {
+        InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
+        Instant now = Instant.now();
+        try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
+        {
+            simulator.advanceCollectors(now);
+            simulator.updateCollector(1, "127.0.1.2", 4, false);
+            simulator.advanceCollectors(now.plusSeconds(10));
+            assertEquals(1, simulator.snapshot().collectors().get(0).latestMeasurements().get(0).sequenceId());
+        }
+
+        try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store))
+        {
+            restored.updateCollector(1, "127.0.1.2", 4, true);
+            restored.advanceCollectors(Instant.now().plusSeconds(2));
+            assertTrue(restored.snapshot().collectors().get(0).latestMeasurements().get(0).sequenceId() >= 2);
+            assertEquals(List.of("S-01", "S-02", "S-03", "S-04"),
+                    restored.snapshot().collectors().get(0).channels().stream()
+                            .map(channel -> channel.channelCode()).toList());
+        }
+    }
+
+    @Test
     void simulatorIsReusableOutsideTheBtsPackage() throws Exception
     {
         try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator();

--
Gitblit v1.7.1