From 7259e265b9237286996b09da03038ea5a133e1e0 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 17:45:07 +0800
Subject: [PATCH] 收敛模拟器为设备事实与实时观测
---
battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java | 315 ---------------------------------------------------
1 files changed, 4 insertions(+), 311 deletions(-)
diff --git a/battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java b/battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java
index 3349459..49d5be2 100644
--- a/battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java
+++ b/battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java
@@ -24,10 +24,6 @@
import com.battery.device.simulator.BtsSimulatorStateStore;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
-import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
-import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryBatch;
-import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
-import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.battery.device.simulator.BtsSimulatorStateStore.DeviceState;
@@ -38,182 +34,20 @@
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.battery.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 simulatorPowerSwitchStopsSamplingAndRestoresWithoutDeletingHistory() throws Exception
- {
- InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
- long historyCount;
- try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
- {
- simulator.advanceCollectors(Instant.now());
- historyCount = simulator.snapshot().collectors().get(0).historyRecordCount();
-
- simulator.setAllDevicesPoweredOn(false);
- simulator.advanceCollectors(Instant.now().plusSeconds(10));
-
- var poweredOff = simulator.snapshot();
- assertTrue(poweredOff.devices().stream().noneMatch(device -> device.online()
- || device.channels().stream().anyMatch(channel -> channel.online()
- || channel.workStatus() != DeviceWorkStatus.STOPPED)));
- assertTrue(poweredOff.collectors().stream().noneMatch(collector -> collector.online()));
- assertEquals(historyCount, poweredOff.collectors().get(0).historyRecordCount());
- }
-
- try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store))
- {
- assertFalse(restored.snapshot().collectors().get(0).online());
- assertEquals(historyCount, restored.collectorHistory(1, 0, 1000).total());
-
- restored.setAllDevicesPoweredOn(true);
- var poweredOn = restored.snapshot();
- 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()));
- restored.advanceCollectors(Instant.now().plusSeconds(2));
- assertTrue(restored.snapshot().collectors().get(0).historyRecordCount() > historyCount);
- }
- }
-
- @Test
- void collectorKeepsOnlyBoundedDemoHistory() throws Exception
- {
- Instant startedAt = Instant.parse("2026-08-29T03:00:00Z");
- TrackingHistoryStore store = new TrackingHistoryStore();
- try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
- {
- simulator.configureCollectorSampling(1, 100, CollectorHistoryFaults.none());
- simulator.advanceCollectors(startedAt);
- for (int batch = 1; batch <= 5; batch++)
- simulator.advanceCollectors(startedAt.plusMillis(batch * 100_000L));
-
- store.resetReadStats();
- var page = simulator.collectorHistory(1, 0, 1);
- assertEquals(BtsSimulatorStateStore.MAX_HISTORY_RECORDS, page.total());
- assertTrue(page.records().get(0).sequenceId() > 1);
- assertEquals(1, store.historyReads);
- assertEquals(1, store.recordsRead);
- }
-
- store.resetReadStats();
- try (BtsDevelopmentSimulator ignored = new BtsDevelopmentSimulator(0, store))
- {
- assertTrue(store.historyReads > 1);
- assertEquals(1000, store.maximumRequestedLimit);
- assertEquals(BtsSimulatorStateStore.MAX_HISTORY_RECORDS, store.recordsRead);
- }
- }
-
- @Test
- void collectorRawHistoryIsNotEmbeddedInMainSimulatorState() throws Exception
- {
- InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
- try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
- {
- simulator.advanceCollectors(Instant.parse("2026-08-29T03:30:00Z"));
-
- String mainState = JSON.toJSONString(store.loadOrInitialize(null));
- assertFalse(mainState.contains("\"history\":[{"));
- assertEquals(12, simulator.collectorHistory(1, 0, 100).total());
- }
- }
-
- @Test
void collectorRealtimeDropsMeasurementsRemovedFromCurrentConfiguration() throws Exception
{
Instant startedAt = Instant.parse("2026-08-29T04:00:00Z");
InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore();
try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store))
{
- simulator.advanceCollectors(startedAt);
+ simulator.collectorRealtime(1);
assertEquals(12, simulator.snapshot().collectors().get(0).latestMeasurements().size());
simulator.configureCollectorChannel(1, "S-01", List.of(
new CollectorMetricState("temperature", new BigDecimal("27.0"), "℃")));
simulator.updateCollector(1, "127.0.1.2", 2, true);
+ simulator.collectorRealtime(1);
var snapshot = simulator.snapshot().collectors().get(0);
assertEquals(4, snapshot.latestMeasurements().size());
assertTrue(snapshot.latestMeasurements().stream()
@@ -221,13 +55,11 @@
|| item.channelCode().equals("S-04")
|| item.channelCode().equals("S-01")
&& item.metricCode().equals("positive_potential")));
- assertEquals(12, simulator.collectorHistory(1, 0, 100).total());
}
try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store))
{
- assertEquals(4, restored.snapshot().collectors().get(0).latestMeasurements().size());
- assertEquals(12, restored.collectorHistory(1, 0, 100).total());
+ assertEquals(4, restored.collectorRealtime(1).measurements().size());
}
}
@@ -496,9 +328,7 @@
{
@Override public SimulatorState loadOrInitialize(SimulatorState value)
{ return delegate.loadOrInitialize(value); }
- @Override public void save(SimulatorState value) { delegate.save(value); }
- @Override public void saveAndDeleteCollectorHistory(SimulatorState value, String collectorCode)
- { throw new IllegalStateException("redis unavailable"); }
+ @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)
@@ -551,141 +381,4 @@
() -> new BtsDevelopmentSimulator(0, new InMemoryBtsSimulatorStateStore(damaged)));
}
- @Test
- void developmentSimulatorRejectsDamagedCollectorHistoryIdentity()
- {
- Instant observedAt = Instant.parse("2026-08-29T05:00:00Z");
- List<CollectorChannelState> channels = List.of(new CollectorChannelState("S-01", List.of(
- new CollectorMetricState("temperature", new BigDecimal("25.0"), "℃"))));
- CollectorMeasurementRecord record = new CollectorMeasurementRecord(
- "dev-sim", "wrong-collector", "S-01", 1L, observedAt,
- "2026-08-29 13:00:00.000", observedAt, "temperature",
- new BigDecimal("25.0"), "℃");
- CollectorState collector = new CollectorState(1, "dev-sim-collector-1", "127.0.1.2",
- "02:43:00:00:00:01", "模拟采集器", "开发模拟器", "Virtual Collector", 1, true,
- 1000, 2L, observedAt, channels, List.of(), 1L, CollectorHistoryFaults.none());
- SimulatorState damaged = new SimulatorState(BtsSimulatorStateStore.CURRENT_VERSION,
- List.of(), List.of(collector), 1, 2, List.of());
- InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore(damaged);
- store.save(damaged, List.of(new CollectorHistoryAppend(collector.deviceCode(), List.of(record))));
-
- assertThrows(IllegalStateException.class,
- () -> new BtsDevelopmentSimulator(0, store));
- }
-
- @Test
- void developmentSimulatorRejectsCollectorSequenceBehindPersistedHistory()
- {
- Instant observedAt = Instant.parse("2026-08-29T06:00:00Z");
- List<CollectorChannelState> channels = List.of(new CollectorChannelState("S-01", List.of(
- new CollectorMetricState("temperature", new BigDecimal("25.0"), "℃"))));
- CollectorMeasurementRecord record = new CollectorMeasurementRecord(
- "dev-sim", "dev-sim-collector-1", "S-01", 1L, observedAt,
- "2026-08-29 14:00:00.000", observedAt, "temperature",
- new BigDecimal("25.0"), "℃");
- CollectorState collector = new CollectorState(1, "dev-sim-collector-1", "127.0.1.2",
- "02:43:00:00:00:01", "模拟采集器", "开发模拟器", "Virtual Collector", 1, true,
- 1000, 1L, observedAt, channels, List.of(), 1L, CollectorHistoryFaults.none());
- SimulatorState damaged = new SimulatorState(BtsSimulatorStateStore.CURRENT_VERSION,
- List.of(), List.of(collector), 1, 2, List.of());
- InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore(damaged);
- store.save(damaged, List.of(new CollectorHistoryAppend(collector.deviceCode(), List.of(record))));
-
- assertThrows(IllegalStateException.class,
- () -> new BtsDevelopmentSimulator(0, store));
- }
-
- @Test
- void developmentSimulatorRejectsHistorySequenceRegressionAcrossPages()
- {
- Instant observedAt = Instant.parse("2026-08-29T06:30:00Z");
- List<CollectorChannelState> channels = List.of(new CollectorChannelState("S-01", List.of(
- new CollectorMetricState("temperature", new BigDecimal("25.0"), "℃"))));
- List<CollectorMeasurementRecord> records = new java.util.ArrayList<>();
- for (long sequence = 1; sequence <= 1000; sequence++)
- records.add(new CollectorMeasurementRecord("dev-sim", "dev-sim-collector-1", "S-01", sequence,
- observedAt, "2026-08-29 14:30:00.000", observedAt, "temperature",
- new BigDecimal("25.0"), "℃"));
- records.add(new CollectorMeasurementRecord("dev-sim", "dev-sim-collector-1", "S-01", 999,
- observedAt, "2026-08-29 14:30:00.000", observedAt, "temperature",
- new BigDecimal("25.0"), "℃"));
- CollectorState collector = new CollectorState(1, "dev-sim-collector-1", "127.0.1.2",
- "02:43:00:00:00:01", "模拟采集器", "开发模拟器", "Virtual Collector", 1, true,
- 1000, 1001L, observedAt, channels, List.of(), records.size(), CollectorHistoryFaults.none());
- SimulatorState damaged = new SimulatorState(BtsSimulatorStateStore.CURRENT_VERSION,
- List.of(), List.of(collector), 1, 2, List.of());
- InMemoryBtsSimulatorStateStore store = new InMemoryBtsSimulatorStateStore(damaged);
- store.save(damaged, List.of(new CollectorHistoryAppend(collector.deviceCode(), records)));
-
- assertThrows(IllegalStateException.class,
- () -> new BtsDevelopmentSimulator(0, store));
- }
-
- private static final class TrackingHistoryStore implements BtsSimulatorStateStore
- {
- private final InMemoryBtsSimulatorStateStore delegate = new InMemoryBtsSimulatorStateStore();
- private int historyReads;
- private int maximumRequestedLimit;
- private long recordsRead;
-
- @Override
- public SimulatorState loadOrInitialize(SimulatorState defaultState)
- {
- return delegate.loadOrInitialize(defaultState);
- }
-
- @Override
- public void save(SimulatorState state)
- {
- delegate.save(state);
- }
-
- @Override
- public void save(SimulatorState state, List<CollectorHistoryAppend> historyAppends)
- {
- delegate.save(state, historyAppends);
- }
-
- @Override
- public CollectorHistoryBatch loadCollectorHistoryPage(String collectorCode, long offset, int limit,
- boolean reverse)
- {
- CollectorHistoryBatch batch = delegate.loadCollectorHistoryPage(collectorCode, offset, limit, reverse);
- historyReads++;
- maximumRequestedLimit = Math.max(maximumRequestedLimit, limit);
- recordsRead += batch.records().size();
- return batch;
- }
-
- @Override
- public void saveAndDeleteCollectorHistory(SimulatorState state, String collectorCode)
- {
- delegate.saveAndDeleteCollectorHistory(state, collectorCode);
- }
-
- @Override
- public List<RecentRequest> loadRecentRequests()
- {
- return delegate.loadRecentRequests();
- }
-
- @Override
- public void saveRecentRequests(List<RecentRequest> requests)
- {
- delegate.saveRecentRequests(requests);
- }
-
- @Override
- public void reset(SimulatorState defaultState)
- {
- delegate.reset(defaultState);
- }
-
- private void resetReadStats()
- {
- historyReads = 0;
- maximumRequestedLimit = 0;
- recordsRead = 0;
- }
- }
}
--
Gitblit v1.7.1